From f36e605aedc54f47726d39565b408af31cdf4387 Mon Sep 17 00:00:00 2001 From: rainv123 <2148537152@qq.com> Date: Wed, 15 Apr 2026 15:26:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8DPowerMem=E5=92=8CMem0AI?= =?UTF-8?q?=E8=AE=B0=E5=BF=86=E6=A8=A1=E5=9E=8B=E4=B8=8D=E4=BC=9A=E6=80=BB?= =?UTF-8?q?=E7=BB=93=E4=BC=9A=E8=AF=9D=E6=A0=87=E9=A2=98=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/providers/memory/mem0ai/mem0ai.py | 53 +++++------ .../providers/memory/powermem/powermem.py | 88 ++++++++++--------- 2 files changed, 73 insertions(+), 68 deletions(-) diff --git a/main/xiaozhi-server/core/providers/memory/mem0ai/mem0ai.py b/main/xiaozhi-server/core/providers/memory/mem0ai/mem0ai.py index 80dbfeb5..8c593669 100644 --- a/main/xiaozhi-server/core/providers/memory/mem0ai/mem0ai.py +++ b/main/xiaozhi-server/core/providers/memory/mem0ai/mem0ai.py @@ -2,6 +2,7 @@ import json import traceback from ..base import MemoryProviderBase, logger +from config.manage_api_client import generate_and_save_chat_summary from mem0 import MemoryClient from core.utils.util import check_model_key @@ -30,38 +31,40 @@ class MemoryProvider(MemoryProviderBase): self.use_mem0 = False async def save_memory(self, msgs, session_id=None): - if not self.use_mem0: - return None - if len(msgs) < 2: - return None - try: - # Format the content as a message list for mem0 - messages = [] - for message in msgs: - if message.role == "system": - continue + if self.use_mem0 and len(msgs) >= 2: + # Format the content as a message list for mem0 + messages = [] + for message in msgs: + if message.role == "system": + continue - content = message.content + content = message.content - # Extract content from JSON format if present (for ASR with emotion/language tags) - # Same logic as in query_memory method - try: - if content and content.strip().startswith("{") and content.strip().endswith("}"): - data = json.loads(content) - if "content" in data: - content = data["content"] - except (json.JSONDecodeError, KeyError, TypeError): - # If parsing fails, use original content - pass + # Extract content from JSON format if present (for ASR with emotion/language tags) + # Same logic as in query_memory method + try: + if content and content.strip().startswith("{") and content.strip().endswith("}"): + data = json.loads(content) + if "content" in data: + content = data["content"] + except (json.JSONDecodeError, KeyError, TypeError): + # If parsing fails, use original content + pass - messages.append({"role": message.role, "content": content}) + messages.append({"role": message.role, "content": content}) - result = self.client.add(messages, user_id=self.role_id) - logger.bind(tag=TAG).debug(f"Save memory result: {result}") + result = self.client.add(messages, user_id=self.role_id) + logger.bind(tag=TAG).debug(f"Save memory result: {result}") except Exception as e: logger.bind(tag=TAG).error(f"保存记忆失败: {str(e)}") - return None + + # Generate and save chat summary (SLM summarizes session title) + # This is independent of Mem0AI's memory saving + if session_id: + await generate_and_save_chat_summary(session_id) + + return None async def query_memory(self, query: str) -> str: if not self.use_mem0: diff --git a/main/xiaozhi-server/core/providers/memory/powermem/powermem.py b/main/xiaozhi-server/core/providers/memory/powermem/powermem.py index 615787f7..d7787f5a 100644 --- a/main/xiaozhi-server/core/providers/memory/powermem/powermem.py +++ b/main/xiaozhi-server/core/providers/memory/powermem/powermem.py @@ -16,6 +16,7 @@ import traceback from typing import Optional, Dict, Any from ..base import MemoryProviderBase, logger +from config.manage_api_client import generate_and_save_chat_summary TAG = __name__ @@ -162,59 +163,60 @@ class MemoryProvider(MemoryProviderBase): Returns: Result from PowerMem API or None if failed """ - if not self.use_powermem or self.memory_client is None: - logger.bind(tag=TAG).warning("PowerMem is not available, skipping save_memory") - return None - - if len(msgs) < 2: - logger.bind(tag=TAG).debug("Not enough messages to save (need at least 2)") - return None - try: - # Format the content as a message list for PowerMem - messages = [] - for message in msgs: - if message.role == "system": - continue + if self.use_powermem and self.memory_client is not None and len(msgs) >= 2: + # Format the content as a message list for PowerMem + messages = [] + for message in msgs: + if message.role == "system": + continue - content = message.content + content = message.content - # Extract content from JSON format if present (for ASR with emotion/language tags) - # Same logic as in query_memory method - try: - if content and content.strip().startswith("{") and content.strip().endswith("}"): - data = json.loads(content) - if "content" in data: - content = data["content"] - except (json.JSONDecodeError, KeyError, TypeError): - # If parsing fails, use original content - pass + # Extract content from JSON format if present (for ASR with emotion/language tags) + # Same logic as in query_memory method + try: + if content and content.strip().startswith("{") and content.strip().endswith("}"): + data = json.loads(content) + if "content" in data: + content = data["content"] + except (json.JSONDecodeError, KeyError, TypeError): + # If parsing fails, use original content + pass - messages.append({"role": message.role, "content": content}) + messages.append({"role": message.role, "content": content}) - # Add memory using PowerMem SDK - result = self.memory_client.add( - messages=messages, - user_id=self.role_id - ) - # Handle both sync and async returns - if asyncio.iscoroutine(result): - result = await result + # Add memory using PowerMem SDK + result = self.memory_client.add( + messages=messages, + user_id=self.role_id + ) + # Handle both sync and async returns + if asyncio.iscoroutine(result): + result = await result - logger.bind(tag=TAG).debug(f"Save memory result: {result}") - - # Cache user profile if UserMemory mode and profile was extracted - if self.enable_user_profile and result: - if result.get('profile_extracted'): - self.last_profile_content = result.get('profile_content', '') - logger.bind(tag=TAG).debug(f"User profile extracted: {self.last_profile_content}") - - return result + logger.bind(tag=TAG).debug(f"Save memory result: {result}") + # Cache user profile if UserMemory mode and profile was extracted + if self.enable_user_profile and result: + if result.get('profile_extracted'): + self.last_profile_content = result.get('profile_content', '') + logger.bind(tag=TAG).debug(f"User profile extracted: {self.last_profile_content}") + else: + if not self.use_powermem or self.memory_client is None: + logger.bind(tag=TAG).warning("PowerMem is not available, skipping save_memory") + elif len(msgs) < 2: + logger.bind(tag=TAG).debug("Not enough messages to save (need at least 2)") except Exception as e: logger.bind(tag=TAG).error(f"Error saving memory: {str(e)}") logger.bind(tag=TAG).debug(f"Detailed error: {traceback.format_exc()}") - return None + + # Generate and save chat summary (SLM summarizes session title) + # This is independent of PowerMem's memory saving + if session_id: + await generate_and_save_chat_summary(session_id) + + return None async def query_memory(self, query: str) -> str: """