Files
life-echo/api/app/agents/memoir/narrative_agent.py

117 lines
3.9 KiB
Python
Raw Normal View History

2026-03-19 10:38:11 +08:00
"""
NarrativeAgent生成创意标题和叙事改写
叙事正文走 `get_narrative_json_prompt` / `get_narrative_merge_json_prompt`传记作家式书面语 + 事实边界
2026-03-19 10:38:11 +08:00
"""
2026-03-19 14:36:14 +08:00
2026-03-19 10:38:11 +08:00
from __future__ import annotations
import json
2026-03-19 10:38:11 +08:00
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,
2026-03-19 10:38:11 +08:00
)
from app.core.langchain_llm import invoke_json_object
2026-03-20 15:15:35 +08:00
from app.core.logging import get_logger
from app.features.memoir.memoir_images.json_payload import extract_json_payload
2026-03-19 10:38:11 +08:00
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(
2026-03-19 10:38:11 +08:00
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} 回忆"
2026-03-19 10:38:11 +08:00
except Exception as e:
logger.warning("NarrativeAgent 生成标题失败: {}", e)
2026-03-19 10:38:11 +08:00
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,
background_voice: str = "default",
2026-03-19 10:38:11 +08:00
) -> str:
"""将新对话改写为叙述。若无 LLM 则直接拼接。
`existing_content` 非空append 路径使用整篇合并提示输出覆盖全篇的有序段落
"""
2026-03-19 10:38:11 +08:00
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,
background_voice=background_voice,
)
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,
background_voice=background_voice,
)
max_tokens = 4096
agent_name = "NarrativeAgent.generate_narrative"
return invoke_json_object(
llm,
prompt,
max_tokens=max_tokens,
agent=agent_name,
).strip()
2026-03-19 10:38:11 +08:00
except Exception as e:
logger.warning("NarrativeAgent 生成叙事失败: {}", e)
2026-03-19 10:38:11 +08:00
if existing_content:
return f"{existing_content}\n\n{new_content}"
return new_content