修复:CI 部署环境与 ref 错配、迁移碎片化、图片意图 source_span、章节物化脏版式、会话历史与本地语音不一致

新增:TTS 上传 COS 与分片、章节 reading_segments 物化与快照、markdown 清洗、会话消息 repository、语音 store 重构与相关测试
This commit is contained in:
Kevin
2026-03-20 16:36:42 +08:00
parent 7317bf10cd
commit 8af37e5e8e
65 changed files with 1704 additions and 504 deletions

View File

@@ -39,6 +39,7 @@ class ConversationAgent:
is_from_voice: bool = False,
voice_session_id: str | None = None,
user_message_timestamp: datetime | None = None,
audio_duration_seconds: int | None = None,
) -> List[str]:
"""委托 ChatOrchestrator/ProfileAgent 生成资料追问"""
return await self._orchestrator.generate_profile_followup(
@@ -50,6 +51,7 @@ class ConversationAgent:
is_from_voice=is_from_voice,
voice_session_id=voice_session_id,
user_message_timestamp=user_message_timestamp,
audio_duration_seconds=audio_duration_seconds,
)
async def generate_profile_greeting(
@@ -74,6 +76,7 @@ class ConversationAgent:
is_from_voice: bool = False,
voice_session_id: str | None = None,
user_message_timestamp: datetime | None = None,
audio_duration_seconds: int | None = None,
) -> List[str]:
"""委托 ChatOrchestrator/InterviewAgent 生成访谈回复"""
return await self._orchestrator.generate_response_with_state(
@@ -84,6 +87,7 @@ class ConversationAgent:
is_from_voice=is_from_voice,
voice_session_id=voice_session_id,
user_message_timestamp=user_message_timestamp,
audio_duration_seconds=audio_duration_seconds,
)
async def generate_opening_message(

View File

@@ -38,6 +38,7 @@ async def save_message(
message_type: str = "text",
voice_session_id: str | None = None,
timestamp: datetime | str | int | None = None,
audio_duration_seconds: int | None = None,
) -> None:
"""保存消息到 Redis"""
await redis_service.add_message(
@@ -49,4 +50,5 @@ async def save_message(
timestamp=timestamp.isoformat()
if isinstance(timestamp, datetime)
else timestamp,
audio_duration_seconds=audio_duration_seconds,
)

View File

@@ -44,6 +44,7 @@ class ChatOrchestrator:
get_missing_profile_fields_fn,
get_filled_profile_fields_fn,
user_message_timestamp: Optional[datetime] = None,
audio_duration_seconds: Optional[int] = None,
) -> List[str]:
"""
处理用户消息,返回 AI 回复列表。
@@ -78,6 +79,7 @@ class ChatOrchestrator:
is_from_voice=is_from_voice,
voice_session_id=voice_session_id,
user_message_timestamp=user_message_timestamp,
audio_duration_seconds=audio_duration_seconds,
)
return responses
except Exception as e:
@@ -117,6 +119,7 @@ class ChatOrchestrator:
is_from_voice=is_from_voice,
voice_session_id=voice_session_id,
user_message_timestamp=user_message_timestamp,
audio_duration_seconds=audio_duration_seconds,
)
return responses
@@ -128,9 +131,17 @@ class ChatOrchestrator:
is_from_voice: bool = False,
voice_session_id: Optional[str] = None,
user_message_timestamp: Optional[datetime] = None,
audio_duration_seconds: Optional[int] = None,
) -> None:
"""统一写入 Human + AI 消息到 Redis"""
human_msg_type = "audio" if is_from_voice else "text"
human_duration = (
audio_duration_seconds
if is_from_voice
and audio_duration_seconds is not None
and audio_duration_seconds > 0
else None
)
await save_message(
conversation_id,
"human",
@@ -138,6 +149,7 @@ class ChatOrchestrator:
message_type=human_msg_type,
voice_session_id=voice_session_id,
timestamp=user_message_timestamp,
audio_duration_seconds=human_duration,
)
await save_message(conversation_id, "ai", response_text)
@@ -162,6 +174,7 @@ class ChatOrchestrator:
is_from_voice: bool = False,
voice_session_id: str | None = None,
user_message_timestamp: datetime | None = None,
audio_duration_seconds: int | None = None,
) -> List[str]:
"""委托 ProfileAgent 生成资料追问,并写入 Redis"""
responses = await self.profile_agent.generate_profile_followup(
@@ -179,6 +192,7 @@ class ChatOrchestrator:
is_from_voice=is_from_voice,
voice_session_id=voice_session_id,
user_message_timestamp=user_message_timestamp,
audio_duration_seconds=audio_duration_seconds,
)
return responses
@@ -207,6 +221,7 @@ class ChatOrchestrator:
is_from_voice: bool = False,
voice_session_id: str | None = None,
user_message_timestamp: datetime | None = None,
audio_duration_seconds: int | None = None,
) -> List[str]:
"""委托 InterviewAgent 生成访谈回复,并写入 Redis"""
responses = await self.interview_agent.generate_response_with_state(
@@ -223,6 +238,7 @@ class ChatOrchestrator:
is_from_voice=is_from_voice,
voice_session_id=voice_session_id,
user_message_timestamp=user_message_timestamp,
audio_duration_seconds=audio_duration_seconds,
)
return responses