feat(i18n): replace all user-visible Chinese logger messages in zep_tools.py

These are shown to users via ConsoleLogger in the report page.
This commit is contained in:
ghostubborn 2026-04-01 17:46:39 +08:00
parent e79569ab4f
commit 24e9bee5be
1 changed files with 52 additions and 53 deletions

View File

@ -18,7 +18,7 @@ from zep_cloud.client import Zep
from ..config import Config
from ..utils.logger import get_logger
from ..utils.llm_client import LLMClient
from ..utils.locale import get_locale
from ..utils.locale import get_locale, t
from ..utils.zep_paging import fetch_all_nodes, fetch_all_edges
logger = get_logger('mirofish.zep_tools')
@ -430,7 +430,7 @@ class ZepToolsService:
self.client = Zep(api_key=self.api_key)
# LLM客户端用于InsightForge生成子问题
self._llm_client = llm_client
logger.info("ZepToolsService 初始化完成")
logger.info(t("console.zepToolsInitialized"))
@property
def llm(self) -> LLMClient:
@ -452,13 +452,12 @@ class ZepToolsService:
last_exception = e
if attempt < max_retries - 1:
logger.warning(
f"Zep {operation_name}{attempt + 1} 次尝试失败: {str(e)[:100]}, "
f"{delay:.1f}秒后重试..."
t("console.zepRetryAttempt", operation=operation_name, attempt=attempt + 1, error=str(e)[:100], delay=f"{delay:.1f}")
)
time.sleep(delay)
delay *= 2
else:
logger.error(f"Zep {operation_name}{max_retries} 次尝试后仍失败: {str(e)}")
logger.error(t("console.zepAllRetriesFailed", operation=operation_name, retries=max_retries, error=str(e)))
raise last_exception
@ -484,7 +483,7 @@ class ZepToolsService:
Returns:
SearchResult: 搜索结果
"""
logger.info(f"图谱搜索: graph_id={graph_id}, query={query[:50]}...")
logger.info(t("console.graphSearch", graphId=graph_id, query=query[:50]))
# 尝试使用Zep Cloud Search API
try:
@ -496,7 +495,7 @@ class ZepToolsService:
scope=scope,
reranker="cross_encoder"
),
operation_name=f"图谱搜索(graph={graph_id})"
operation_name=t("console.graphSearchOp", graphId=graph_id)
)
facts = []
@ -529,7 +528,7 @@ class ZepToolsService:
if hasattr(node, 'summary') and node.summary:
facts.append(f"[{node.name}]: {node.summary}")
logger.info(f"搜索完成: 找到 {len(facts)} 条相关事实")
logger.info(t("console.searchComplete", count=len(facts)))
return SearchResult(
facts=facts,
@ -540,7 +539,7 @@ class ZepToolsService:
)
except Exception as e:
logger.warning(f"Zep Search API失败降级为本地搜索: {str(e)}")
logger.warning(t("console.zepSearchApiFallback", error=str(e)))
# 降级:使用本地关键词匹配搜索
return self._local_search(graph_id, query, limit, scope)
@ -565,7 +564,7 @@ class ZepToolsService:
Returns:
SearchResult: 搜索结果
"""
logger.info(f"使用本地搜索: query={query[:30]}...")
logger.info(t("console.usingLocalSearch", query=query[:30]))
facts = []
edges_result = []
@ -635,10 +634,10 @@ class ZepToolsService:
if node.summary:
facts.append(f"[{node.name}]: {node.summary}")
logger.info(f"本地搜索完成: 找到 {len(facts)} 条相关事实")
logger.info(t("console.localSearchComplete", count=len(facts)))
except Exception as e:
logger.error(f"本地搜索失败: {str(e)}")
logger.error(t("console.localSearchFailed", error=str(e)))
return SearchResult(
facts=facts,
@ -658,7 +657,7 @@ class ZepToolsService:
Returns:
节点列表
"""
logger.info(f"获取图谱 {graph_id} 的所有节点...")
logger.info(t("console.fetchingAllNodes", graphId=graph_id))
nodes = fetch_all_nodes(self.client, graph_id)
@ -673,7 +672,7 @@ class ZepToolsService:
attributes=node.attributes or {}
))
logger.info(f"获取到 {len(result)} 个节点")
logger.info(t("console.fetchedNodes", count=len(result)))
return result
def get_all_edges(self, graph_id: str, include_temporal: bool = True) -> List[EdgeInfo]:
@ -687,7 +686,7 @@ class ZepToolsService:
Returns:
边列表包含created_at, valid_at, invalid_at, expired_at
"""
logger.info(f"获取图谱 {graph_id} 的所有边...")
logger.info(t("console.fetchingAllEdges", graphId=graph_id))
edges = fetch_all_edges(self.client, graph_id)
@ -711,7 +710,7 @@ class ZepToolsService:
result.append(edge_info)
logger.info(f"获取到 {len(result)} 条边")
logger.info(t("console.fetchedEdges", count=len(result)))
return result
def get_node_detail(self, node_uuid: str) -> Optional[NodeInfo]:
@ -724,12 +723,12 @@ class ZepToolsService:
Returns:
节点信息或None
"""
logger.info(f"获取节点详情: {node_uuid[:8]}...")
logger.info(t("console.fetchingNodeDetail", uuid=node_uuid[:8]))
try:
node = self._call_with_retry(
func=lambda: self.client.graph.node.get(uuid_=node_uuid),
operation_name=f"获取节点详情(uuid={node_uuid[:8]}...)"
operation_name=t("console.fetchNodeDetailOp", uuid=node_uuid[:8])
)
if not node:
@ -743,7 +742,7 @@ class ZepToolsService:
attributes=node.attributes or {}
)
except Exception as e:
logger.error(f"获取节点详情失败: {str(e)}")
logger.error(t("console.fetchNodeDetailFailed", error=str(e)))
return None
def get_node_edges(self, graph_id: str, node_uuid: str) -> List[EdgeInfo]:
@ -759,7 +758,7 @@ class ZepToolsService:
Returns:
边列表
"""
logger.info(f"获取节点 {node_uuid[:8]}... 的相关边")
logger.info(t("console.fetchingNodeEdges", uuid=node_uuid[:8]))
try:
# 获取图谱所有边,然后过滤
@ -771,11 +770,11 @@ class ZepToolsService:
if edge.source_node_uuid == node_uuid or edge.target_node_uuid == node_uuid:
result.append(edge)
logger.info(f"找到 {len(result)} 条与节点相关的边")
logger.info(t("console.foundNodeEdges", count=len(result)))
return result
except Exception as e:
logger.warning(f"获取节点边失败: {str(e)}")
logger.warning(t("console.fetchNodeEdgesFailed", error=str(e)))
return []
def get_entities_by_type(
@ -793,7 +792,7 @@ class ZepToolsService:
Returns:
符合类型的实体列表
"""
logger.info(f"获取类型为 {entity_type} 的实体...")
logger.info(t("console.fetchingEntitiesByType", type=entity_type))
all_nodes = self.get_all_nodes(graph_id)
@ -803,7 +802,7 @@ class ZepToolsService:
if entity_type in node.labels:
filtered.append(node)
logger.info(f"找到 {len(filtered)}{entity_type} 类型的实体")
logger.info(t("console.foundEntitiesByType", count=len(filtered), type=entity_type))
return filtered
def get_entity_summary(
@ -823,7 +822,7 @@ class ZepToolsService:
Returns:
实体摘要信息
"""
logger.info(f"获取实体 {entity_name} 的关系摘要...")
logger.info(t("console.fetchingEntitySummary", name=entity_name))
# 先搜索该实体相关的信息
search_result = self.search_graph(
@ -863,7 +862,7 @@ class ZepToolsService:
Returns:
统计信息
"""
logger.info(f"获取图谱 {graph_id} 的统计信息...")
logger.info(t("console.fetchingGraphStats", graphId=graph_id))
nodes = self.get_all_nodes(graph_id)
edges = self.get_all_edges(graph_id)
@ -907,7 +906,7 @@ class ZepToolsService:
Returns:
模拟上下文信息
"""
logger.info(f"获取模拟上下文: {simulation_requirement[:50]}...")
logger.info(t("console.fetchingSimContext", requirement=simulation_requirement[:50]))
# 搜索与模拟需求相关的信息
search_result = self.search_graph(
@ -971,7 +970,7 @@ class ZepToolsService:
Returns:
InsightForgeResult: 深度洞察检索结果
"""
logger.info(f"InsightForge 深度洞察检索: {query[:50]}...")
logger.info(t("console.insightForgeStart", query=query[:50]))
result = InsightForgeResult(
query=query,
@ -987,7 +986,7 @@ class ZepToolsService:
max_queries=max_sub_queries
)
result.sub_queries = sub_queries
logger.info(f"生成 {len(sub_queries)} 个子问题")
logger.info(t("console.generatedSubQueries", count=len(sub_queries)))
# Step 2: 对每个子问题进行语义搜索
all_facts = []
@ -1087,7 +1086,7 @@ class ZepToolsService:
result.relationship_chains = relationship_chains
result.total_relationships = len(relationship_chains)
logger.info(f"InsightForge完成: {result.total_facts}条事实, {result.total_entities}个实体, {result.total_relationships}条关系")
logger.info(t("console.insightForgeComplete", facts=result.total_facts, entities=result.total_entities, relationships=result.total_relationships))
return result
def _generate_sub_queries(
@ -1134,7 +1133,7 @@ class ZepToolsService:
return [str(sq) for sq in sub_queries[:max_queries]]
except Exception as e:
logger.warning(f"生成子问题失败: {str(e)},使用默认子问题")
logger.warning(t("console.generateSubQueriesFailed", error=str(e)))
# 降级:返回基于原问题的变体
return [
query,
@ -1169,7 +1168,7 @@ class ZepToolsService:
Returns:
PanoramaResult: 广度搜索结果
"""
logger.info(f"PanoramaSearch 广度搜索: {query[:50]}...")
logger.info(t("console.panoramaSearchStart", query=query[:50]))
result = PanoramaResult(query=query)
@ -1232,7 +1231,7 @@ class ZepToolsService:
result.active_count = len(active_facts)
result.historical_count = len(historical_facts)
logger.info(f"PanoramaSearch完成: {result.active_count}条有效, {result.historical_count}条历史")
logger.info(t("console.panoramaSearchComplete", active=result.active_count, historical=result.historical_count))
return result
def quick_search(
@ -1257,7 +1256,7 @@ class ZepToolsService:
Returns:
SearchResult: 搜索结果
"""
logger.info(f"QuickSearch 简单搜索: {query[:50]}...")
logger.info(t("console.quickSearchStart", query=query[:50]))
# 直接调用现有的search_graph方法
result = self.search_graph(
@ -1267,7 +1266,7 @@ class ZepToolsService:
scope="edges"
)
logger.info(f"QuickSearch完成: {result.total_count}条结果")
logger.info(t("console.quickSearchComplete", count=result.total_count))
return result
def interview_agents(
@ -1307,7 +1306,7 @@ class ZepToolsService:
"""
from .simulation_runner import SimulationRunner
logger.info(f"InterviewAgents 深度采访真实API: {interview_requirement[:50]}...")
logger.info(t("console.interviewAgentsStart", requirement=interview_requirement[:50]))
result = InterviewResult(
interview_topic=interview_requirement,
@ -1318,12 +1317,12 @@ class ZepToolsService:
profiles = self._load_agent_profiles(simulation_id)
if not profiles:
logger.warning(f"未找到模拟 {simulation_id} 的人设文件")
logger.warning(t("console.profilesNotFound", simId=simulation_id))
result.summary = "未找到可采访的Agent人设文件"
return result
result.total_agents = len(profiles)
logger.info(f"加载到 {len(profiles)} 个Agent人设")
logger.info(t("console.loadedProfiles", count=len(profiles)))
# Step 2: 使用LLM选择要采访的Agent返回agent_id列表
selected_agents, selected_indices, selection_reasoning = self._select_agents_for_interview(
@ -1335,7 +1334,7 @@ class ZepToolsService:
result.selected_agents = selected_agents
result.selection_reasoning = selection_reasoning
logger.info(f"选择了 {len(selected_agents)} 个Agent进行采访: {selected_indices}")
logger.info(t("console.selectedAgentsForInterview", count=len(selected_agents), indices=selected_indices))
# Step 3: 生成采访问题(如果没有提供)
if not result.interview_questions:
@ -1344,7 +1343,7 @@ class ZepToolsService:
simulation_requirement=simulation_requirement,
selected_agents=selected_agents
)
logger.info(f"生成了 {len(result.interview_questions)} 个采访问题")
logger.info(t("console.generatedInterviewQuestions", count=len(result.interview_questions)))
# 将问题合并为一个采访prompt
combined_prompt = "\n".join([f"{i+1}. {q}" for i, q in enumerate(result.interview_questions)])
@ -1374,7 +1373,7 @@ class ZepToolsService:
# 不指定platformAPI会在twitter和reddit两个平台都采访
})
logger.info(f"调用批量采访API双平台: {len(interviews_request)} 个Agent")
logger.info(t("console.callingBatchInterviewApi", count=len(interviews_request)))
# 调用 SimulationRunner 的批量采访方法不传platform双平台采访
api_result = SimulationRunner.interview_agents_batch(
@ -1384,12 +1383,12 @@ class ZepToolsService:
timeout=180.0 # 双平台需要更长超时
)
logger.info(f"采访API返回: {api_result.get('interviews_count', 0)} 个结果, success={api_result.get('success')}")
logger.info(t("console.interviewApiReturned", count=api_result.get('interviews_count', 0), success=api_result.get('success')))
# 检查API调用是否成功
if not api_result.get("success", False):
error_msg = api_result.get("error", "未知错误")
logger.warning(f"采访API返回失败: {error_msg}")
logger.warning(t("console.interviewApiReturnedFailure", error=error_msg))
result.summary = f"采访API调用失败{error_msg}。请检查OASIS模拟环境状态。"
return result
@ -1462,11 +1461,11 @@ class ZepToolsService:
except ValueError as e:
# 模拟环境未运行
logger.warning(f"采访API调用失败环境未运行: {e}")
logger.warning(t("console.interviewApiCallFailed", error=e))
result.summary = f"采访失败:{str(e)}。模拟环境可能已关闭请确保OASIS环境正在运行。"
return result
except Exception as e:
logger.error(f"采访API调用异常: {e}")
logger.error(t("console.interviewApiCallException", error=e))
import traceback
logger.error(traceback.format_exc())
result.summary = f"采访过程发生错误:{str(e)}"
@ -1479,7 +1478,7 @@ class ZepToolsService:
interview_requirement=interview_requirement
)
logger.info(f"InterviewAgents完成: 采访了 {result.interviewed_count} 个Agent双平台")
logger.info(t("console.interviewAgentsComplete", count=result.interviewed_count))
return result
@staticmethod
@ -1522,10 +1521,10 @@ class ZepToolsService:
try:
with open(reddit_profile_path, 'r', encoding='utf-8') as f:
profiles = json.load(f)
logger.info(f"从 reddit_profiles.json 加载了 {len(profiles)} 个人设")
logger.info(t("console.loadedRedditProfiles", count=len(profiles)))
return profiles
except Exception as e:
logger.warning(f"读取 reddit_profiles.json 失败: {e}")
logger.warning(t("console.readRedditProfilesFailed", error=e))
# 尝试读取Twitter CSV格式
twitter_profile_path = os.path.join(sim_dir, "twitter_profiles.csv")
@ -1542,10 +1541,10 @@ class ZepToolsService:
"persona": row.get("user_char", ""),
"profession": "未知"
})
logger.info(f"从 twitter_profiles.csv 加载了 {len(profiles)} 个人设")
logger.info(t("console.loadedTwitterProfiles", count=len(profiles)))
return profiles
except Exception as e:
logger.warning(f"读取 twitter_profiles.csv 失败: {e}")
logger.warning(t("console.readTwitterProfilesFailed", error=e))
return profiles
@ -1626,7 +1625,7 @@ class ZepToolsService:
return selected_agents, valid_indices, reasoning
except Exception as e:
logger.warning(f"LLM选择Agent失败使用默认选择: {e}")
logger.warning(t("console.llmSelectAgentFailed", error=e))
# 降级选择前N个
selected = profiles[:max_agents]
indices = list(range(min(max_agents, len(profiles))))
@ -1674,7 +1673,7 @@ class ZepToolsService:
return response.get("questions", [f"关于{interview_requirement},您有什么看法?"])
except Exception as e:
logger.warning(f"生成采访问题失败: {e}")
logger.warning(t("console.generateInterviewQuestionsFailed", error=e))
return [
f"关于{interview_requirement},您的观点是什么?",
"这件事对您或您所代表的群体有什么影响?",
@ -1732,6 +1731,6 @@ class ZepToolsService:
return summary
except Exception as e:
logger.warning(f"生成采访摘要失败: {e}")
logger.warning(t("console.generateInterviewSummaryFailed", error=e))
# 降级:简单拼接
return f"共采访了{len(interviews)}位受访者,包括:" + "".join([i.agent_name for i in interviews])