1. 统一为使用基于pydantic的.env环境变量管理配置

2. 全项目基于loguru进行日志管理
This commit is contained in:
Doiiars
2025-11-05 14:56:49 +08:00
parent 1d2e23d8c1
commit 537d682861
50 changed files with 1404 additions and 1731 deletions
+3 -5
View File
@@ -3,12 +3,11 @@ Report Engine节点基类
定义所有处理节点的基础接口
"""
import logging
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional
from ..llms.base import LLMClient
from ..state.state import ReportState
from loguru import logger
class BaseNode(ABC):
"""节点基类"""
@@ -23,7 +22,6 @@ class BaseNode(ABC):
"""
self.llm_client = llm_client
self.node_name = node_name or self.__class__.__name__
self.logger = logging.getLogger('ReportEngine')
@abstractmethod
def run(self, input_data: Any, **kwargs) -> Any:
@@ -66,12 +64,12 @@ class BaseNode(ABC):
def log_info(self, message: str):
"""记录信息日志"""
formatted_message = f"[{self.node_name}] {message}"
self.logger.info(formatted_message)
logger.info(formatted_message)
def log_error(self, message: str):
"""记录错误日志"""
formatted_message = f"[{self.node_name}] {message}"
self.logger.error(formatted_message)
logger.error(formatted_message)
class StateMutationNode(BaseNode):
+9 -8
View File
@@ -6,6 +6,7 @@ HTML生成节点
import json
from datetime import datetime
from typing import Dict, Any
from loguru import logger
from .base_node import StateMutationNode
from ..llms.base import LLMClient
@@ -42,7 +43,7 @@ class HTMLGenerationNode(StateMutationNode):
Returns:
生成的HTML内容
"""
self.log_info("开始生成HTML报告...")
logger.info("开始生成HTML报告...")
try:
# 准备LLM输入数据
@@ -64,11 +65,11 @@ class HTMLGenerationNode(StateMutationNode):
# 处理响应(简化版)
processed_response = self.process_output(response)
self.log_info("HTML报告生成完成")
logger.info("HTML报告生成完成")
return processed_response
except Exception as e:
self.log_error(f"HTML生成失败: {str(e)}")
logger.exception(f"HTML生成失败: {str(e)}")
# 返回备用HTML
return self._generate_fallback_html(input_data)
@@ -104,7 +105,7 @@ class HTMLGenerationNode(StateMutationNode):
HTML内容
"""
try:
self.log_info(f"处理LLM原始输出,长度: {len(output)} 字符")
logger.info(f"处理LLM原始输出,长度: {len(output)} 字符")
html_content = output.strip()
@@ -120,14 +121,14 @@ class HTMLGenerationNode(StateMutationNode):
# 如果内容为空,返回原始输出
if not html_content:
self.log_info("处理后内容为空,返回原始输出")
logger.info("处理后内容为空,返回原始输出")
html_content = output
self.log_info(f"HTML处理完成,最终长度: {len(html_content)} 字符")
logger.info(f"HTML处理完成,最终长度: {len(html_content)} 字符")
return html_content
except Exception as e:
self.log_error(f"处理HTML输出失败: {str(e)},返回原始输出")
logger.exception(f"处理HTML输出失败: {str(e)},返回原始输出")
return output
def _generate_fallback_html(self, input_data: Dict[str, Any]) -> str:
@@ -140,7 +141,7 @@ class HTMLGenerationNode(StateMutationNode):
Returns:
备用HTML内容
"""
self.log_info("使用备用HTML生成方法")
logger.info("使用备用HTML生成方法")
query = input_data.get('query', '智能舆情分析报告')
query_report = input_data.get('query_engine_report', '')
+15 -14
View File
@@ -6,6 +6,7 @@
import os
import json
from typing import Dict, Any, List, Optional
from loguru import logger
from .base_node import BaseNode
from ..prompts import SYSTEM_PROMPT_TEMPLATE_SELECTION
@@ -38,7 +39,7 @@ class TemplateSelectionNode(BaseNode):
Returns:
选择的模板信息
"""
self.log_info("开始模板选择...")
logger.info("开始模板选择...")
query = input_data.get('query', '')
reports = input_data.get('reports', [])
@@ -48,7 +49,7 @@ class TemplateSelectionNode(BaseNode):
available_templates = self._get_available_templates()
if not available_templates:
self.log_info("未找到预设模板,使用内置默认模板")
logger.info("未找到预设模板,使用内置默认模板")
return self._get_fallback_template()
# 使用LLM进行模板选择
@@ -57,7 +58,7 @@ class TemplateSelectionNode(BaseNode):
if llm_result:
return llm_result
except Exception as e:
self.log_error(f"LLM模板选择失败: {str(e)}")
logger.exception(f"LLM模板选择失败: {str(e)}")
# 如果LLM选择失败,使用备选方案
return self._get_fallback_template()
@@ -67,7 +68,7 @@ class TemplateSelectionNode(BaseNode):
def _llm_template_selection(self, query: str, reports: List[Any], forum_logs: str,
available_templates: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
"""使用LLM进行模板选择"""
self.log_info("尝试使用LLM进行模板选择...")
logger.info("尝试使用LLM进行模板选择...")
# 构建模板列表
template_list = "\n".join([f"- {t['name']}: {t['description']}" for t in available_templates])
@@ -118,10 +119,10 @@ class TemplateSelectionNode(BaseNode):
# 检查响应是否为空
if not response or not response.strip():
self.log_error("LLM返回空响应")
logger.error("LLM返回空响应")
return None
self.log_info(f"LLM原始响应: {response}")
logger.info(f"LLM原始响应: {response}")
# 尝试解析JSON响应
try:
@@ -133,18 +134,18 @@ class TemplateSelectionNode(BaseNode):
selected_template_name = result.get('template_name', '')
for template in available_templates:
if template['name'] == selected_template_name or selected_template_name in template['name']:
self.log_info(f"LLM选择模板: {selected_template_name}")
logger.info(f"LLM选择模板: {selected_template_name}")
return {
'template_name': template['name'],
'template_content': template['content'],
'selection_reason': result.get('selection_reason', 'LLM智能选择')
}
self.log_error(f"LLM选择的模板不存在: {selected_template_name}")
logger.error(f"LLM选择的模板不存在: {selected_template_name}")
return None
except json.JSONDecodeError as e:
self.log_error(f"JSON解析失败: {str(e)}")
logger.exception(f"JSON解析失败: {str(e)}")
# 尝试从文本响应中提取模板信息
return self._extract_template_from_text(response, available_templates)
@@ -163,7 +164,7 @@ class TemplateSelectionNode(BaseNode):
def _extract_template_from_text(self, response: str, available_templates: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
"""从文本响应中提取模板信息"""
self.log_info("尝试从文本响应中提取模板信息")
logger.info("尝试从文本响应中提取模板信息")
# 查找响应中是否包含模板名称
for template in available_templates:
@@ -175,7 +176,7 @@ class TemplateSelectionNode(BaseNode):
for variant in template_name_variants:
if variant in response:
self.log_info(f"在响应中找到模板: {template['name']}")
logger.info(f"在响应中找到模板: {template['name']}")
return {
'template_name': template['name'],
'template_content': template['content'],
@@ -189,7 +190,7 @@ class TemplateSelectionNode(BaseNode):
templates = []
if not os.path.exists(self.template_dir):
self.log_error(f"模板目录不存在: {self.template_dir}")
logger.error(f"模板目录不存在: {self.template_dir}")
return templates
# 查找所有markdown模板文件
@@ -210,7 +211,7 @@ class TemplateSelectionNode(BaseNode):
'description': description
})
except Exception as e:
self.log_error(f"读取模板文件失败 {filename}: {str(e)}")
logger.exception(f"读取模板文件失败 {filename}: {str(e)}")
return templates
@@ -235,7 +236,7 @@ class TemplateSelectionNode(BaseNode):
def _get_fallback_template(self) -> Dict[str, Any]:
"""获取备用默认模板(空模板,让LLM自行发挥)"""
self.log_info("未找到合适模板,使用空模板让LLM自行发挥")
logger.info("未找到合适模板,使用空模板让LLM自行发挥")
return {
'template_name': '自由发挥模板',