Files
life-echo/api/app/agents/memoir/narrative_agent.py
Kevin a3f61fcc0f feat(api+app): 对话阶段化、回忆录流水线与客户端会话体验
- DB: segments 用户输入文本(Alembic 0002)
- Chat: 阶段检测/阶段提示/回复限制,编排与访谈/画像 prompts 调整
- Memoir: 忠实度检查 agent,叙事与分类等链路更新
- Core: agent 日志、Alembic 启动、LangChain/日志/配置等
- Story: time_hints;Memory 检索与相关测试
- Expo: 助手头像、会话页与消息拆分、实时会话与文案/i18n
- Docs/scripts/tests: 迁移脚本、LLM JSON/记忆检索文档、新增单测
2026-03-26 12:13:36 +08:00

114 lines
3.7 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.
"""
NarrativeAgent生成创意标题和叙事改写。
对应现有逻辑get_creative_title_json_prompt、get_narrative_json_prompt
"""
from __future__ import annotations
import json
from typing import Any, Dict, Optional
from app.agents.memoir.prompts import (
get_creative_title_json_prompt,
get_narrative_json_prompt,
get_narrative_merge_json_prompt,
)
from app.core.langchain_llm import invoke_json_object
from app.core.logging import get_logger
from app.features.memoir.memoir_images.json_payload import extract_json_payload
logger = get_logger(__name__)
class NarrativeAgent:
"""生成章节标题和叙事正文"""
def generate_title(
self,
stage: str,
emotion: str,
slots: Dict[str, str],
user_profile: str = "",
birth_year: Optional[int] = None,
llm: Any = None,
) -> str:
"""生成创意标题。若无 LLM 则返回默认标题"""
if not llm:
return f"{stage} 回忆"
try:
prompt = get_creative_title_json_prompt(
stage=stage,
emotion=emotion,
slots=slots,
user_profile=user_profile,
birth_year=birth_year,
)
raw = invoke_json_object(
llm,
prompt,
max_tokens=256,
agent="NarrativeAgent.generate_title",
)
data = json.loads(extract_json_payload(raw))
title = (data.get("title") or "").strip() if isinstance(data, dict) else ""
if title:
return title.strip('"')
return f"{stage} 回忆"
except Exception as e:
logger.warning("NarrativeAgent 生成标题失败: {}", e)
return f"{stage} 回忆"
def generate_narrative(
self,
stage: str,
slots: Dict[str, str],
new_content: str,
existing_content: str = "",
user_profile: str = "",
birth_year: Optional[int] = None,
llm: Any = None,
) -> str:
"""将新对话改写为叙述。若无 LLM 则直接拼接。
若 `existing_content` 非空append 路径),使用整篇合并提示,输出覆盖全篇的有序段落。
"""
if not llm:
if existing_content:
return f"{existing_content}\n\n{new_content}"
return new_content
try:
merge_mode = bool((existing_content or "").strip())
if merge_mode:
prompt = get_narrative_merge_json_prompt(
stage=stage,
slots=slots,
new_content=new_content,
existing_content=existing_content,
user_profile=user_profile,
birth_year=birth_year,
)
max_tokens = 8192
agent_name = "NarrativeAgent.generate_narrative_merge"
else:
prompt = get_narrative_json_prompt(
stage=stage,
slots=slots,
new_content=new_content,
existing_content=existing_content,
user_profile=user_profile,
birth_year=birth_year,
)
max_tokens = 4096
agent_name = "NarrativeAgent.generate_narrative"
return invoke_json_object(
llm,
prompt,
max_tokens=max_tokens,
agent=agent_name,
).strip()
except Exception as e:
logger.warning("NarrativeAgent 生成叙事失败: {}", e)
if existing_content:
return f"{existing_content}\n\n{new_content}"
return new_content