Browse Source

feat: - 女性角色接口进行完善,增加长期记忆、知识库预检、情绪状态机

zhangwl 1 week ago
parent
commit
3aea693ef9
1 changed files with 64 additions and 7 deletions
  1. 64 7
      app/routers/chat_tools.py

+ 64 - 7
app/routers/chat_tools.py

@@ -900,15 +900,16 @@ async def femininity_chat(request: RoleBasedChatRequest):
                     if group_context:
                     if group_context:
                         cache_group_context(group_id, group_context, ttl=120)
                         cache_group_context(group_id, group_context, ttl=120)
 
 
-                # 构造多模态消息格式
+                # 构造多模态消息格式,同步更新群情绪状态(去重由 update_group_mood 内部处理)
                 if group_context:
                 if group_context:
                     for msg in group_context[-20:]:  # 最近20条
                     for msg in group_context[-20:]:  # 最近20条
-                        user_id = msg['user_id']
+                        msg_user_id = msg['user_id']
                         content_parts = []
                         content_parts = []
 
 
-                        # 添加文本内容
+                        # 添加文本内容,并更新群情绪
                         if msg.get('content'):
                         if msg.get('content'):
-                            content_parts.append({"type": "input_text", "text": f"{user_id}: {msg['content']}"})
+                            content_parts.append({"type": "input_text", "text": f"{msg_user_id}: {msg['content']}"})
+                            update_group_mood(group_id, msg_user_id, msg['content'])
 
 
                         # 添加图片
                         # 添加图片
                         for img_url in msg.get('images', []):
                         for img_url in msg.get('images', []):
@@ -997,6 +998,24 @@ async def femininity_chat(request: RoleBasedChatRequest):
 如果不需要回应,保持沉默(不输出任何内容)。
 如果不需要回应,保持沉默(不输出任何内容)。
 """
 """
 
 
+        # 【v3.0新增】注入用户长期记忆(已确认的事实背景)
+        mem = get_user_memory(request.user_id, group_id, "femininity")
+        if mem and mem.get("facts"):
+            fact_lines = [
+                f"- {f['key']}: {f['value']}"
+                for f in mem["facts"]
+                if isinstance(f, dict) and f.get("key") and f.get("value")
+            ]
+            if fact_lines:
+                system_prompt += (
+                    "\n\n## 你对当前发言用户的已知背景\n"
+                    + "\n".join(fact_lines)
+                    + "\n参照这些背景给出更贴近她实际情况的回应,但不要生硬复述。"
+                )
+
+        # 【v3.0新增】注入群情绪状态
+        system_prompt += build_mood_block(group_id)
+
         # 构造请求消息
         # 构造请求消息
         system_msg = {"role": "system", "content": [{"type": "input_text", "text": system_prompt}]}
         system_msg = {"role": "system", "content": [{"type": "input_text", "text": system_prompt}]}
 
 
@@ -1015,10 +1034,37 @@ async def femininity_chat(request: RoleBasedChatRequest):
         else:
         else:
             api_messages = [system_msg, {"role": "user", "content": user_content}]
             api_messages = [system_msg, {"role": "user", "content": user_content}]
 
 
-        # 配置工具:联网搜索 + 知识库
-        tools = get_web_search_tools()
+        # 【v3.0新增】知识库预检:直接调用 Viking SDK 检索
+        # 有命中 → 将切片内容作为上下文注入,不挂 Ark 知识库工具
+        # 无命中 → 挂联网搜索工具
+        tools = []
         if knowledge_id:
         if knowledge_id:
-            tools += get_knowledge_search_tools(knowledge_id,request.app_name)
+            try:
+                kb_results = await search_knowledge(
+                    resource_id=knowledge_id,
+                    query=request.message,
+                    limit=5,
+                )
+            except Exception as e:
+                print(f"知识库预检失败,降级到联网搜索: {e}")
+                kb_results = []
+        else:
+            kb_results = []
+
+        if kb_results:
+            # 提取切片内容,拼接成上下文段落
+            kb_texts = [r.content for r in kb_results if r.content]
+            if kb_texts:
+                kb_context_block = [{"type": "input_text", "text": "【知识库参考资料】\n" + "\n\n".join(kb_texts) + "\n\n请优先基于以上资料回答,资料中没有的内容不要编造。"}]
+                # 将知识库上下文插入到 user content 前面
+                if context_messages:
+                    api_messages[-1]["content"] = kb_context_block + api_messages[-1]["content"]
+                else:
+                    api_messages[-1]["content"] = kb_context_block + user_content
+            # 有知识库命中时不挂任何工具
+        else:
+            # 无命中,降级到联网搜索
+            tools = get_web_search_tools()
 
 
         # 调用 AI 客户端
         # 调用 AI 客户端
         response = client.responses.create(
         response = client.responses.create(
@@ -1058,6 +1104,17 @@ async def femininity_chat(request: RoleBasedChatRequest):
                 app_name=request.app_name,
                 app_name=request.app_name,
             )
             )
 
 
+        # 【v3.0新增】异步抽取用户记忆(fire-and-forget,失败不影响主流程)
+        if result:
+            asyncio.create_task(_extract_memory(
+                user_id=request.user_id,
+                group_id=group_id,
+                ai_role="femininity",
+                trigger_msg=request.message,
+                ai_reply=result,
+                app_name=request.app_name,
+            ))
+
         if not result:
         if not result:
             save_chat_log(
             save_chat_log(
                 user_id=request.user_id,
                 user_id=request.user_id,