Files
life-echo/api/app/features/conversation/session_history.py
Kevin 8af37e5e8e 修复:CI 部署环境与 ref 错配、迁移碎片化、图片意图 source_span、章节物化脏版式、会话历史与本地语音不一致
新增:TTS 上传 COS 与分片、章节 reading_segments 物化与快照、markdown 清洗、会话消息 repository、语音 store 重构与相关测试
2026-03-20 16:43:02 +08:00

69 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
会话 transcript 与 Redis 历史条目的纯映射(无 I/O
仅由 ConversationService 使用:对齐 ChatOrchestrator 经 save_message 写入 Redis 的字段形状,
不属于 Agent 层 —— 多 Agent 模块只消费已就绪的 history不负责从 DB 重建。
"""
from __future__ import annotations
from datetime import timezone
from typing import Any, Dict, List
from app.features.conversation.models import Segment
def _voice_session_id_from_audio_url(audio_url: str | None) -> str | None:
if not audio_url:
return None
prefix = "audio-segment:"
if not audio_url.startswith(prefix):
return None
payload = audio_url[len(prefix) :]
voice_session_id_raw, sep, _ = payload.rpartition(":")
if sep and voice_session_id_raw:
return voice_session_id_raw
return None
def _segment_timestamp_iso(seg: Segment) -> str | None:
if not seg.created_at:
return None
dt = seg.created_at
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
return dt.isoformat()
def segments_to_redis_history(segments: List[Segment]) -> List[Dict[str, Any]]:
"""Segment 行 → Redis conversation history 项(与 ChatOrchestrator 写入格式一致)。"""
history: List[Dict[str, Any]] = []
for seg in segments:
ts = _segment_timestamp_iso(seg)
is_voice = bool(seg.audio_url)
human: Dict[str, Any] = {
"role": "human",
"content": seg.transcript_text or "",
"messageType": "audio" if is_voice else "text",
"timestamp": ts,
}
vsid = _voice_session_id_from_audio_url(seg.audio_url)
if vsid:
human["voiceSessionId"] = vsid
ads = getattr(seg, "audio_duration_seconds", None)
if ads is not None and ads > 0:
human["durationSeconds"] = int(ads)
history.append(human)
if seg.agent_response and seg.agent_response.strip():
ai_item: Dict[str, Any] = {
"role": "ai",
"content": seg.agent_response.strip(),
"messageType": "text",
"timestamp": ts,
}
tts = getattr(seg, "tts_audio_urls", None)
if isinstance(tts, list) and tts:
ai_item["ttsAudioUrls"] = [u for u in tts if isinstance(u, str)]
history.append(ai_item)
return history