初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,92 @@
|
||||
"""会话目标自动持久化服务。
|
||||
|
||||
从用户消息自动持久化会话目标到 goals 表。
|
||||
如果已有该 character 的活跃 session 级目标,判断内容是否显著不同:
|
||||
- 内容相似 → 复用
|
||||
- 内容不同 → 完成旧目标,创建新目标
|
||||
"""
|
||||
|
||||
from app.models.governance import Goal
|
||||
from app.repositories import governance as governance_repo
|
||||
|
||||
_TOPIC_SHIFT_MIN_LENGTH = 20
|
||||
|
||||
|
||||
async def auto_persist_session_goal(
|
||||
session,
|
||||
character_id: str,
|
||||
content: str,
|
||||
) -> Goal | None:
|
||||
"""自动持久化会话目标:复用活跃的 session 目标或新建。
|
||||
|
||||
内容过短(<10 字)不产生目标。
|
||||
如果已有活跃 session 目标但内容显著不同,先完成旧目标再新建。
|
||||
|
||||
Returns:
|
||||
持久化后的 Goal(可能为 None)。
|
||||
"""
|
||||
goal_text = (content or "").strip()
|
||||
if not goal_text or len(goal_text) < 10:
|
||||
return None
|
||||
|
||||
existing = await governance_repo.list_active_session_goal(session, character_id)
|
||||
if existing is not None:
|
||||
# 判断是否话题转换:内容不再相似时完成旧目标
|
||||
if _is_topic_shift(existing.title, goal_text):
|
||||
existing.status = "completed"
|
||||
existing.progress = 1.0
|
||||
# 创建新目标
|
||||
goal = Goal(
|
||||
character_id=character_id,
|
||||
title=goal_text[:120],
|
||||
description=f"从对话自动提取的会话目标:{goal_text[:500]}",
|
||||
level="session",
|
||||
type="mission",
|
||||
status="active",
|
||||
priority=50,
|
||||
)
|
||||
await governance_repo.add_goal(session, goal)
|
||||
return goal
|
||||
return existing
|
||||
|
||||
# 新建 session 目标
|
||||
goal = Goal(
|
||||
character_id=character_id,
|
||||
title=goal_text[:120],
|
||||
description=f"从对话自动提取的会话目标:{goal_text[:500]}",
|
||||
level="session",
|
||||
type="mission",
|
||||
status="active",
|
||||
priority=50,
|
||||
)
|
||||
await governance_repo.add_goal(session, goal)
|
||||
return goal
|
||||
|
||||
|
||||
def _is_topic_shift(existing_title: str, new_content: str) -> bool:
|
||||
"""判断新内容与旧目标标题是否话题转换。
|
||||
|
||||
简单规则:如果新内容较长且与旧标题共享的关键词很少,视为话题转换。
|
||||
这是启发式方法,后续可升级为 LLM 判断。
|
||||
"""
|
||||
if len(new_content) < _TOPIC_SHIFT_MIN_LENGTH:
|
||||
return False
|
||||
# 提取关键词集合(按空格/标点分割)
|
||||
import re
|
||||
old_words = set(re.split(r"[\s,。!?、;:,\.!?;:]+", existing_title.lower()))
|
||||
new_words = set(re.split(r"[\s,。!?、;:,\.!?;:]+", new_content.lower()))
|
||||
# 排除常见的助词
|
||||
stop_words = {"的", "了", "是", "在", "有", "和", "就", "不", "人", "都", "一",
|
||||
"一个", "上", "也", "很", "到", "说", "要", "去", "你", "我", "他",
|
||||
"这", "那", "吗", "啊", "呢", "吧", "地", "得"}
|
||||
old_keywords = old_words - stop_words
|
||||
new_keywords = new_words - stop_words
|
||||
|
||||
if not old_keywords or not new_keywords:
|
||||
return False
|
||||
|
||||
overlap = old_keywords & new_keywords
|
||||
# 如果旧关键词的一个都没有出现在新内容中,或者重合率极低
|
||||
if not overlap:
|
||||
return True
|
||||
return len(overlap) / max(len(old_keywords), len(new_keywords)) < 0.15
|
||||
Reference in new issue
Block a user