fix/various fixes
This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
"""Conversation service — 对话编排(列表、创建、结束、删除、消息、整理)。"""
|
||||
|
||||
from app.core.logging import get_logger
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.cos_url_keys import extract_cos_object_key_if_owned
|
||||
from app.core.logging import get_logger
|
||||
from app.core.redis import redis_service
|
||||
from app.core.storage_purge import delete_object_storage_keys_best_effort
|
||||
from app.features.conversation import repo
|
||||
from app.features.conversation.models import Conversation, Segment
|
||||
from app.features.conversation.models import Conversation
|
||||
from app.features.conversation.session_history import segments_to_redis_history
|
||||
from app.features.memory import repo as memory_repo
|
||||
from app.features.quota.service import QuotaService
|
||||
from app.ports.storage import ObjectStorage
|
||||
from app.tasks.memoir_tasks import process_memoir_segments
|
||||
|
||||
logger = get_logger(__name__)
|
||||
@@ -75,23 +81,44 @@ def _build_messages_from_history(
|
||||
|
||||
|
||||
class ConversationService:
|
||||
def __init__(self, db: AsyncSession, quota_service: QuotaService):
|
||||
def __init__(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
quota_service: QuotaService,
|
||||
*,
|
||||
object_storage: ObjectStorage | None = None,
|
||||
):
|
||||
self._db = db
|
||||
self._quota = quota_service
|
||||
self._object_storage = object_storage
|
||||
|
||||
async def _get_history(self, conversation_id: str) -> list[dict]:
|
||||
from app.core.redis import redis_service
|
||||
|
||||
return await redis_service.get_conversation_history(conversation_id)
|
||||
|
||||
async def _clear_history(self, conversation_id: str) -> None:
|
||||
try:
|
||||
from app.core.redis import redis_service
|
||||
|
||||
await redis_service.clear_conversation_history(conversation_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def ensure_redis_history_from_segments(
|
||||
self, conversation_id: str
|
||||
) -> list[dict]:
|
||||
"""
|
||||
供 WS 与 get_messages 使用:优先 Redis;若为空则用 DB segments 重建并写回。
|
||||
会话层编排,非 Agent 职责(ChatOrchestrator 只读写已存在的 Redis 流)。
|
||||
"""
|
||||
history = await redis_service.get_conversation_history(conversation_id)
|
||||
if history:
|
||||
return history
|
||||
segments = await repo.get_segments_for_conversation(conversation_id, self._db)
|
||||
if not segments:
|
||||
return []
|
||||
rebuilt = segments_to_redis_history(segments)
|
||||
if rebuilt:
|
||||
await redis_service.set_conversation_history(conversation_id, rebuilt)
|
||||
return rebuilt
|
||||
|
||||
async def list_for_user(self, user_id: str) -> list[dict]:
|
||||
conversations = await repo.get_user_conversations(user_id, self._db)
|
||||
result = []
|
||||
@@ -134,7 +161,7 @@ class ConversationService:
|
||||
|
||||
async def get_or_404(self, conversation_id: str, user_id: str) -> Conversation:
|
||||
conv = await repo.get_conversation(conversation_id, self._db)
|
||||
if not conv or conv.user_id != user_id:
|
||||
if not conv or conv.user_id != user_id or conv.deleted_at is not None:
|
||||
raise HTTPException(status_code=404, detail="Conversation not found")
|
||||
return conv
|
||||
|
||||
@@ -170,14 +197,31 @@ class ConversationService:
|
||||
|
||||
async def delete(self, conversation_id: str, user_id: str) -> None:
|
||||
conv = await self.get_or_404(conversation_id, user_id)
|
||||
cos_keys: set[str] = set(
|
||||
await memory_repo.list_storage_keys_for_conversation(
|
||||
self._db, conversation_id
|
||||
)
|
||||
)
|
||||
segments = await repo.get_segments_for_conversation(conversation_id, self._db)
|
||||
for seg in segments:
|
||||
k = extract_cos_object_key_if_owned(seg.audio_url)
|
||||
if k:
|
||||
cos_keys.add(k)
|
||||
|
||||
await self._clear_history(conversation_id)
|
||||
await self._db.delete(conv)
|
||||
conv.deleted_at = datetime.now(timezone.utc)
|
||||
await self._db.commit()
|
||||
|
||||
delete_object_storage_keys_best_effort(
|
||||
self._object_storage,
|
||||
sorted(cos_keys),
|
||||
log_prefix=f"conversation_soft_delete id={conversation_id}",
|
||||
)
|
||||
|
||||
async def get_messages(self, conversation_id: str, user_id: str) -> list[dict]:
|
||||
conv = await self.get_or_404(conversation_id, user_id)
|
||||
try:
|
||||
history = await self._get_history(conversation_id)
|
||||
history = await self.ensure_redis_history_from_segments(conversation_id)
|
||||
return _build_messages_from_history(
|
||||
conversation_id=conversation_id,
|
||||
history=history,
|
||||
|
||||
Reference in New Issue
Block a user