feat(i18n): replace all user-visible Chinese in report_agent.py

Covers ReportLogger message fields and logger messages shown via ConsoleLogger.
This commit is contained in:
ghostubborn
2026-04-01 17:44:52 +08:00
parent 1d358fc492
commit e79569ab4f

View File

@@ -106,7 +106,7 @@ class ReportLogger:
"simulation_id": simulation_id, "simulation_id": simulation_id,
"graph_id": graph_id, "graph_id": graph_id,
"simulation_requirement": simulation_requirement, "simulation_requirement": simulation_requirement,
"message": "报告生成任务开始" "message": t('report.taskStarted')
} }
) )
@@ -115,7 +115,7 @@ class ReportLogger:
self.log( self.log(
action="planning_start", action="planning_start",
stage="planning", stage="planning",
details={"message": "开始规划报告大纲"} details={"message": t('report.planningStart')}
) )
def log_planning_context(self, context: Dict[str, Any]): def log_planning_context(self, context: Dict[str, Any]):
@@ -124,7 +124,7 @@ class ReportLogger:
action="planning_context", action="planning_context",
stage="planning", stage="planning",
details={ details={
"message": "获取模拟上下文信息", "message": t('report.fetchSimContext'),
"context": context "context": context
} }
) )
@@ -135,7 +135,7 @@ class ReportLogger:
action="planning_complete", action="planning_complete",
stage="planning", stage="planning",
details={ details={
"message": "大纲规划完成", "message": t('report.planningComplete'),
"outline": outline_dict "outline": outline_dict
} }
) )
@@ -147,7 +147,7 @@ class ReportLogger:
stage="generating", stage="generating",
section_title=section_title, section_title=section_title,
section_index=section_index, section_index=section_index,
details={"message": f"开始生成章节: {section_title}"} details={"message": t('report.sectionStart', title=section_title)}
) )
def log_react_thought(self, section_title: str, section_index: int, iteration: int, thought: str): def log_react_thought(self, section_title: str, section_index: int, iteration: int, thought: str):
@@ -160,7 +160,7 @@ class ReportLogger:
details={ details={
"iteration": iteration, "iteration": iteration,
"thought": thought, "thought": thought,
"message": f"ReACT 第{iteration}轮思考" "message": t('report.reactThought', iteration=iteration)
} }
) )
@@ -182,7 +182,7 @@ class ReportLogger:
"iteration": iteration, "iteration": iteration,
"tool_name": tool_name, "tool_name": tool_name,
"parameters": parameters, "parameters": parameters,
"message": f"调用工具: {tool_name}" "message": t('report.toolCall', toolName=tool_name)
} }
) )
@@ -205,7 +205,7 @@ class ReportLogger:
"tool_name": tool_name, "tool_name": tool_name,
"result": result, # 完整结果,不截断 "result": result, # 完整结果,不截断
"result_length": len(result), "result_length": len(result),
"message": f"工具 {tool_name} 返回结果" "message": t('report.toolResult', toolName=tool_name)
} }
) )
@@ -230,7 +230,7 @@ class ReportLogger:
"response_length": len(response), "response_length": len(response),
"has_tool_calls": has_tool_calls, "has_tool_calls": has_tool_calls,
"has_final_answer": has_final_answer, "has_final_answer": has_final_answer,
"message": f"LLM 响应 (工具调用: {has_tool_calls}, 最终答案: {has_final_answer})" "message": t('report.llmResponse', hasToolCalls=has_tool_calls, hasFinalAnswer=has_final_answer)
} }
) )
@@ -251,7 +251,7 @@ class ReportLogger:
"content": content, # 完整内容,不截断 "content": content, # 完整内容,不截断
"content_length": len(content), "content_length": len(content),
"tool_calls_count": tool_calls_count, "tool_calls_count": tool_calls_count,
"message": f"章节 {section_title} 内容生成完成" "message": t('report.sectionContentDone', title=section_title)
} }
) )
@@ -274,7 +274,7 @@ class ReportLogger:
details={ details={
"content": full_content, "content": full_content,
"content_length": len(full_content), "content_length": len(full_content),
"message": f"章节 {section_title} 生成完成" "message": t('report.sectionComplete', title=section_title)
} }
) )
@@ -286,7 +286,7 @@ class ReportLogger:
details={ details={
"total_sections": total_sections, "total_sections": total_sections,
"total_time_seconds": round(total_time_seconds, 2), "total_time_seconds": round(total_time_seconds, 2),
"message": "报告生成完成" "message": t('report.reportComplete')
} }
) )
@@ -299,7 +299,7 @@ class ReportLogger:
section_index=None, section_index=None,
details={ details={
"error": error_message, "error": error_message,
"message": f"发生错误: {error_message}" "message": t('report.errorOccurred', error=error_message)
} }
) )
@@ -914,7 +914,7 @@ class ReportAgent:
# 控制台日志记录器(在 generate_report 中初始化) # 控制台日志记录器(在 generate_report 中初始化)
self.console_logger: Optional[ReportConsoleLogger] = None self.console_logger: Optional[ReportConsoleLogger] = None
logger.info(f"ReportAgent 初始化完成: graph_id={graph_id}, simulation_id={simulation_id}") logger.info(t('report.agentInitDone', graphId=graph_id, simulationId=simulation_id))
def _define_tools(self) -> Dict[str, Dict[str, Any]]: def _define_tools(self) -> Dict[str, Dict[str, Any]]:
"""定义可用工具""" """定义可用工具"""
@@ -965,7 +965,7 @@ class ReportAgent:
Returns: Returns:
工具执行结果(文本格式) 工具执行结果(文本格式)
""" """
logger.info(f"执行工具: {tool_name}, 参数: {parameters}") logger.info(t('report.executingTool', toolName=tool_name, params=parameters))
try: try:
if tool_name == "insight_forge": if tool_name == "insight_forge":
@@ -1024,7 +1024,7 @@ class ReportAgent:
elif tool_name == "search_graph": elif tool_name == "search_graph":
# 重定向到 quick_search # 重定向到 quick_search
logger.info("search_graph 已重定向到 quick_search") logger.info(t('report.redirectToQuickSearch'))
return self._execute_tool("quick_search", parameters, report_context) return self._execute_tool("quick_search", parameters, report_context)
elif tool_name == "get_graph_statistics": elif tool_name == "get_graph_statistics":
@@ -1041,7 +1041,7 @@ class ReportAgent:
elif tool_name == "get_simulation_context": elif tool_name == "get_simulation_context":
# 重定向到 insight_forge因为它更强大 # 重定向到 insight_forge因为它更强大
logger.info("get_simulation_context 已重定向到 insight_forge") logger.info(t('report.redirectToInsightForge'))
query = parameters.get("query", self.simulation_requirement) query = parameters.get("query", self.simulation_requirement)
return self._execute_tool("insight_forge", {"query": query}, report_context) return self._execute_tool("insight_forge", {"query": query}, report_context)
@@ -1058,7 +1058,7 @@ class ReportAgent:
return f"未知工具: {tool_name}。请使用以下工具之一: insight_forge, panorama_search, quick_search" return f"未知工具: {tool_name}。请使用以下工具之一: insight_forge, panorama_search, quick_search"
except Exception as e: except Exception as e:
logger.error(f"工具执行失败: {tool_name}, 错误: {str(e)}") logger.error(t('report.toolExecFailed', toolName=tool_name, error=str(e)))
return f"工具执行失败: {str(e)}" return f"工具执行失败: {str(e)}"
# 合法的工具名称集合,用于裸 JSON 兜底解析时校验 # 合法的工具名称集合,用于裸 JSON 兜底解析时校验
@@ -1149,7 +1149,7 @@ class ReportAgent:
Returns: Returns:
ReportOutline: 报告大纲 ReportOutline: 报告大纲
""" """
logger.info("开始规划报告大纲...") logger.info(t('report.startPlanningOutline'))
if progress_callback: if progress_callback:
progress_callback("planning", 0, t('progress.analyzingRequirements')) progress_callback("planning", 0, t('progress.analyzingRequirements'))
@@ -1202,11 +1202,11 @@ class ReportAgent:
if progress_callback: if progress_callback:
progress_callback("planning", 100, t('progress.outlinePlanComplete')) progress_callback("planning", 100, t('progress.outlinePlanComplete'))
logger.info(f"大纲规划完成: {len(sections)} 个章节") logger.info(t('report.outlinePlanDone', count=len(sections)))
return outline return outline
except Exception as e: except Exception as e:
logger.error(f"大纲规划失败: {str(e)}") logger.error(t('report.outlinePlanFailed', error=str(e)))
# 返回默认大纲3个章节作为fallback # 返回默认大纲3个章节作为fallback
return ReportOutline( return ReportOutline(
title="未来预测报告", title="未来预测报告",
@@ -1246,7 +1246,7 @@ class ReportAgent:
Returns: Returns:
章节内容Markdown格式 章节内容Markdown格式
""" """
logger.info(f"ReACT生成章节: {section.title}") logger.info(t('report.reactGenerateSection', title=section.title))
# 记录章节开始日志 # 记录章节开始日志
if self.report_logger: if self.report_logger:
@@ -1310,7 +1310,7 @@ class ReportAgent:
# 检查 LLM 返回是否为 NoneAPI 异常或内容为空) # 检查 LLM 返回是否为 NoneAPI 异常或内容为空)
if response is None: if response is None:
logger.warning(f"章节 {section.title}{iteration + 1} 次迭代: LLM 返回 None") logger.warning(t('report.sectionIterNone', title=section.title, iteration=iteration + 1))
# 如果还有迭代次数,添加消息并重试 # 如果还有迭代次数,添加消息并重试
if iteration < max_iterations - 1: if iteration < max_iterations - 1:
messages.append({"role": "assistant", "content": "(响应为空)"}) messages.append({"role": "assistant", "content": "(响应为空)"})
@@ -1330,8 +1330,7 @@ class ReportAgent:
if has_tool_calls and has_final_answer: if has_tool_calls and has_final_answer:
conflict_retries += 1 conflict_retries += 1
logger.warning( logger.warning(
f"章节 {section.title}{iteration+1} 轮: " t('report.sectionConflict', title=section.title, iteration=iteration+1, conflictCount=conflict_retries)
f"LLM 同时输出工具调用和 Final Answer{conflict_retries} 次冲突)"
) )
if conflict_retries <= 2: if conflict_retries <= 2:
@@ -1351,8 +1350,7 @@ class ReportAgent:
else: else:
# 第三次:降级处理,截断到第一个工具调用,强制执行 # 第三次:降级处理,截断到第一个工具调用,强制执行
logger.warning( logger.warning(
f"章节 {section.title}: 连续 {conflict_retries} 次冲突," t('report.sectionConflictDowngrade', title=section.title, conflictCount=conflict_retries)
"降级为截断执行第一个工具调用"
) )
first_tool_end = response.find('</tool_call>') first_tool_end = response.find('</tool_call>')
if first_tool_end != -1: if first_tool_end != -1:
@@ -1392,7 +1390,7 @@ class ReportAgent:
# 正常结束 # 正常结束
final_answer = response.split("Final Answer:")[-1].strip() final_answer = response.split("Final Answer:")[-1].strip()
logger.info(f"章节 {section.title} 生成完成(工具调用: {tool_calls_count}次)") logger.info(t('report.sectionGenDone', title=section.title, count=tool_calls_count))
if self.report_logger: if self.report_logger:
self.report_logger.log_section_content( self.report_logger.log_section_content(
@@ -1420,7 +1418,7 @@ class ReportAgent:
# 只执行第一个工具调用 # 只执行第一个工具调用
call = tool_calls[0] call = tool_calls[0]
if len(tool_calls) > 1: if len(tool_calls) > 1:
logger.info(f"LLM 尝试调用 {len(tool_calls)} 个工具,只执行第一个: {call['name']}") logger.info(t('report.multiToolOnlyFirst', total=len(tool_calls), toolName=call['name']))
if self.report_logger: if self.report_logger:
self.report_logger.log_tool_call( self.report_logger.log_tool_call(
@@ -1489,7 +1487,7 @@ class ReportAgent:
# 工具调用已足够LLM 输出了内容但没带 "Final Answer:" 前缀 # 工具调用已足够LLM 输出了内容但没带 "Final Answer:" 前缀
# 直接将这段内容作为最终答案,不再空转 # 直接将这段内容作为最终答案,不再空转
logger.info(f"章节 {section.title} 未检测到 'Final Answer:' 前缀直接采纳LLM输出作为最终内容工具调用: {tool_calls_count}次)") logger.info(t('report.sectionNoPrefix', title=section.title, count=tool_calls_count))
final_answer = response.strip() final_answer = response.strip()
if self.report_logger: if self.report_logger:
@@ -1502,7 +1500,7 @@ class ReportAgent:
return final_answer return final_answer
# 达到最大迭代次数,强制生成内容 # 达到最大迭代次数,强制生成内容
logger.warning(f"章节 {section.title} 达到最大迭代次数,强制生成") logger.warning(t('report.sectionMaxIter', title=section.title))
messages.append({"role": "user", "content": REACT_FORCE_FINAL_MSG}) messages.append({"role": "user", "content": REACT_FORCE_FINAL_MSG})
response = self.llm.chat( response = self.llm.chat(
@@ -1513,8 +1511,8 @@ class ReportAgent:
# 检查强制收尾时 LLM 返回是否为 None # 检查强制收尾时 LLM 返回是否为 None
if response is None: if response is None:
logger.error(f"章节 {section.title} 强制收尾时 LLM 返回 None使用默认错误提示") logger.error(t('report.sectionForceFailed', title=section.title))
final_answer = f"本章节生成失败LLM 返回空响应,请稍后重试)" final_answer = t('report.sectionGenFailedContent')
elif "Final Answer:" in response: elif "Final Answer:" in response:
final_answer = response.split("Final Answer:")[-1].strip() final_answer = response.split("Final Answer:")[-1].strip()
else: else:
@@ -1627,7 +1625,7 @@ class ReportAgent:
) )
ReportManager.save_report(report) ReportManager.save_report(report)
logger.info(f"大纲已保存到文件: {report_id}/outline.json") logger.info(t('report.outlineSavedToFile', reportId=report_id))
# 阶段2: 逐章节生成(分章节保存) # 阶段2: 逐章节生成(分章节保存)
report.status = ReportStatus.GENERATING report.status = ReportStatus.GENERATING
@@ -1685,7 +1683,7 @@ class ReportAgent:
full_content=full_section_content.strip() full_content=full_section_content.strip()
) )
logger.info(f"章节已保存: {report_id}/section_{section_num:02d}.md") logger.info(t('report.sectionSaved', reportId=report_id, sectionNum=f"{section_num:02d}"))
# 更新进度 # 更新进度
ReportManager.update_progress( ReportManager.update_progress(
@@ -1730,7 +1728,7 @@ class ReportAgent:
if progress_callback: if progress_callback:
progress_callback("completed", 100, t('progress.reportComplete')) progress_callback("completed", 100, t('progress.reportComplete'))
logger.info(f"报告生成完成: {report_id}") logger.info(t('report.reportGenDone', reportId=report_id))
# 关闭控制台日志记录器 # 关闭控制台日志记录器
if self.console_logger: if self.console_logger:
@@ -1740,7 +1738,7 @@ class ReportAgent:
return report return report
except Exception as e: except Exception as e:
logger.error(f"报告生成失败: {str(e)}") logger.error(t('report.reportGenFailed', error=str(e)))
report.status = ReportStatus.FAILED report.status = ReportStatus.FAILED
report.error = str(e) report.error = str(e)
@@ -1786,7 +1784,7 @@ class ReportAgent:
"sources": [信息来源] "sources": [信息来源]
} }
""" """
logger.info(f"Report Agent对话: {message[:50]}...") logger.info(t('report.agentChat', message=message[:50]))
chat_history = chat_history or [] chat_history = chat_history or []
@@ -1800,7 +1798,7 @@ class ReportAgent:
if len(report.markdown_content) > 15000: if len(report.markdown_content) > 15000:
report_content += "\n\n... [报告内容已截断] ..." report_content += "\n\n... [报告内容已截断] ..."
except Exception as e: except Exception as e:
logger.warning(f"获取报告内容失败: {e}") logger.warning(t('report.fetchReportFailed', error=e))
system_prompt = CHAT_SYSTEM_PROMPT_TEMPLATE.format( system_prompt = CHAT_SYSTEM_PROMPT_TEMPLATE.format(
simulation_requirement=self.simulation_requirement, simulation_requirement=self.simulation_requirement,
@@ -2091,7 +2089,7 @@ class ReportManager:
with open(cls._get_outline_path(report_id), 'w', encoding='utf-8') as f: with open(cls._get_outline_path(report_id), 'w', encoding='utf-8') as f:
json.dump(outline.to_dict(), f, ensure_ascii=False, indent=2) json.dump(outline.to_dict(), f, ensure_ascii=False, indent=2)
logger.info(f"大纲已保存: {report_id}") logger.info(t('report.outlineSaved', reportId=report_id))
@classmethod @classmethod
def save_section( def save_section(
@@ -2127,7 +2125,7 @@ class ReportManager:
with open(file_path, 'w', encoding='utf-8') as f: with open(file_path, 'w', encoding='utf-8') as f:
f.write(md_content) f.write(md_content)
logger.info(f"章节已保存: {report_id}/{file_suffix}") logger.info(t('report.sectionFileSaved', reportId=report_id, fileSuffix=file_suffix))
return file_path return file_path
@classmethod @classmethod
@@ -2296,7 +2294,7 @@ class ReportManager:
with open(full_path, 'w', encoding='utf-8') as f: with open(full_path, 'w', encoding='utf-8') as f:
f.write(md_content) f.write(md_content)
logger.info(f"完整报告已组装: {report_id}") logger.info(t('report.fullReportAssembled', reportId=report_id))
return md_content return md_content
@classmethod @classmethod
@@ -2443,7 +2441,7 @@ class ReportManager:
with open(cls._get_report_markdown_path(report.report_id), 'w', encoding='utf-8') as f: with open(cls._get_report_markdown_path(report.report_id), 'w', encoding='utf-8') as f:
f.write(report.markdown_content) f.write(report.markdown_content)
logger.info(f"报告已保存: {report.report_id}") logger.info(t('report.reportSaved', reportId=report.report_id))
@classmethod @classmethod
def get_report(cls, report_id: str) -> Optional[Report]: def get_report(cls, report_id: str) -> Optional[Report]:
@@ -2556,7 +2554,7 @@ class ReportManager:
# 新格式:删除整个文件夹 # 新格式:删除整个文件夹
if os.path.exists(folder_path) and os.path.isdir(folder_path): if os.path.exists(folder_path) and os.path.isdir(folder_path):
shutil.rmtree(folder_path) shutil.rmtree(folder_path)
logger.info(f"报告文件夹已删除: {report_id}") logger.info(t('report.reportFolderDeleted', reportId=report_id))
return True return True
# 兼容旧格式:删除单独的文件 # 兼容旧格式:删除单独的文件