Feature/memory work (#68)

* feat(memory): add conversation title to conversation list response for frontend display

* feat(memory): optimize conversation retrieval, enable working memory to return conversation question summaries

* fix(memory): fix conversation re-generation logic

* style(desc): improve description of get_conversation function
This commit is contained in:
Eternity
2026-01-12 12:16:04 +08:00
committed by GitHub
parent d9f03a7e94
commit 2a12be310d
5 changed files with 50 additions and 31 deletions

View File

@@ -2,14 +2,13 @@ import uuid
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.core.response_utils import success, fail
from app.core.logging_config import get_api_logger
from app.core.response_utils import success
from app.db import get_db
from app.dependencies import get_current_user
from app.models import User
from app.schemas.response_schema import ApiResponse
from app.services import conversation_service
from app.services.conversation_service import ConversationService
api_logger = get_api_logger()
@@ -54,8 +53,7 @@ def get_conversations(
"""
conversation_service = ConversationService(db)
conversations = conversation_service.get_user_conversations(
group_id,
current_user.current_workspace_id
group_id
)
return success(data=[
{
@@ -88,9 +86,17 @@ def get_messages(
- Logging can be added for audit and debugging.
"""
conversation_service = ConversationService(db)
messages = conversation_service.get_conversation_history(
messages_obj = conversation_service.get_messages(
conversation_id,
)
messages = [
{
"role": message.role,
"content": message.content,
"created_at": int(message.created_at.timestamp() * 1000),
}
for message in messages_obj
]
return success(data=messages, msg="get conversation history success")

View File

@@ -65,9 +65,9 @@ class ConversationDetail(Base):
conversation_id = Column(UUID(as_uuid=True), ForeignKey("conversations.id"))
theme = Column(String, comment="会话主题")
theme_intro = Column(String, comment="主题介绍")
summary = Column(String, comment="会话摘要")
takeaways = Column(JSON, comment="会话要点")
question = Column(JSON, comment="用户问题")
info_score = Column(Integer, comment="会话信息量评分")

View File

@@ -89,7 +89,7 @@ class ChatResponse(BaseModel):
# ---------- Conversation Summary Schemas ----------
class ConversationOut(BaseModel):
theme: str
theme_intro: str
question: list[str]
summary: str
takeaways: list[str]
info_score: int

View File

@@ -118,25 +118,22 @@ class ConversationService:
def get_user_conversations(
self,
user_id: uuid.UUID,
workspace_id: uuid.UUID,
user_id: uuid.UUID
) -> list[Conversation]:
"""
Retrieve recent conversations for a specific user within a workspace.
Retrieve recent conversations for a specific user
This method delegates persistence logic to the repository layer and
applies service-level defaults (e.g. recent conversation limit).
Args:
user_id (uuid.UUID): Unique identifier of the user.
workspace_id (uuid.UUID): Workspace scope for the query.
Returns:
list[Conversation]: A list of recent conversation entities.
"""
conversations = self.conversation_repo.get_conversation_by_user_id(
user_id,
workspace_id,
limit=10
)
return conversations
@@ -465,11 +462,17 @@ class ConversationService:
conversation = self.get_conversation(
conversation_id=conversation_id,
)
if conversation_detail:
if not conversation:
raise BusinessException("Conversation not found", BizCode.INVALID_CONVERSATION)
is_stable = (
conversation.updated_at
and datetime.now() - conversation.updated_at > timedelta(days=1)
)
if conversation_detail and is_stable:
logger.info(f"Conversation detail found in repository for conversation_id={conversation_id}")
return ConversationOut(
theme=conversation_detail.theme,
theme_intro=conversation_detail.theme_intro,
question=conversation_detail.question if conversation_detail.question else [],
summary=conversation_detail.summary,
takeaways=conversation_detail.takeaways,
info_score=conversation_detail.info_score,
@@ -526,6 +529,7 @@ class ConversationService:
language=language,
conversation=str(conversation_messages)
)
messages = [
(RoleType.SYSTEM, rendered_system_message),
(RoleType.USER, rendered_user_message),
@@ -547,28 +551,37 @@ class ConversationService:
summary = result.get('summary', "")
theme = result.get('theme', "")
theme_intro = result.get("theme_intro", "")
question = result.get("question") or []
takeaways = result.get("takeaways") or []
info_score = result.get("info_score", 50)
if datetime.now() - conversation.updated_at > timedelta(days=1):
logger.info(f"Updating conversation detail in DB for conversation_id={conversation_id}")
conversation_detail = ConversationDetail(
conversation_id=conversation.id,
summary=summary,
theme=theme,
theme_intro=theme_intro,
takeaways=takeaways,
info_score=info_score
)
self.conversation_repo.add_conversation_detail(conversation_detail)
if not is_stable:
if not conversation_detail:
logger.info(f"Creating conversation detail in DB for conversation_id={conversation_id}")
conversation_detail = ConversationDetail(
conversation_id=conversation.id,
summary=summary,
theme=theme,
question=question,
takeaways=takeaways,
info_score=info_score
)
self.conversation_repo.add_conversation_detail(conversation_detail)
else:
logger.info(f"Updating conversation detail in DB for conversation_id={conversation_id}")
conversation_detail.summary = summary
conversation_detail.theme = theme
conversation_detail.question = question
conversation_detail.takeaways = takeaways
conversation_detail.info_score = info_score
self.db.commit()
self.db.refresh(conversation_detail)
logger.info(f"Returning conversation summary for conversation_id={conversation_id}")
conversation_out = ConversationOut(
theme=theme,
theme_intro=theme_intro,
question=question,
summary=summary,
takeaways=takeaways,
info_score=info_score

View File

@@ -33,18 +33,18 @@ You are a professional dialogue content summarizer, specializing in extracting c
- Language: Please strictly output content in the language specified by the <Language> tag.
- Structure: JSON object with five fields,:
1. `theme`: A concise phrase describing the conversations core topic (e.g., "inquiry about delivery time rules");
2. `theme_intro`: A brief explanation of the conversations core theme to clarify its specific scope and focus (e.g., "The conversation focuses on the user's inquiry about delivery time standards for regular and remote areas");
3. `summary`: A single sentence including "user request + AI response + interaction logic" (≤100 words);
4. `takeaways`: A list of brief bullet-point takeaways summarizing the key points from the conversation (e.g., ["User clarified delivery time differences between regular and remote areas"]).
2. `summary`: A single sentence including "user request + AI response + interaction logic" (≤150 words);
3. `takeaways`: A list of brief bullet-point takeaways summarizing the key points from the conversation (e.g., ["User clarified delivery time differences between regular and remote areas"]).
4. `question`: A list of brief declarative statements summarizing the pitfalls the user encountered during the current conversation.Return an empty list if none are present.
5. `info_score`: Numerical score (0100) representing conversation information richness.
- Language Style: Concise, objective, conversational (avoid overly formal terms).
# Example JSON Output
{
"theme": string,
"theme_intro": string,
"summary": string,
"takeaways": array[string],
"question": array[string]
"info_score": 85
}
{% endraw %}