戒酒的李白

The private database analysis agent has been basically completed.

@@ -19,7 +19,7 @@ from .nodes import ( @@ -19,7 +19,7 @@ from .nodes import (
19 ReportFormattingNode 19 ReportFormattingNode
20 ) 20 )
21 from .state import State 21 from .state import State
22 -from .tools import TavilyNewsAgency, TavilyResponse 22 +from .tools import MediaCrawlerDB, DBResponse
23 from .utils import Config, load_config, format_search_results_for_prompt 23 from .utils import Config, load_config, format_search_results_for_prompt
24 24
25 25
@@ -39,8 +39,16 @@ class DeepSearchAgent: @@ -39,8 +39,16 @@ class DeepSearchAgent:
39 # 初始化LLM客户端 39 # 初始化LLM客户端
40 self.llm_client = self._initialize_llm() 40 self.llm_client = self._initialize_llm()
41 41
  42 + # 设置数据库环境变量
  43 + os.environ["DB_HOST"] = self.config.db_host or ""
  44 + os.environ["DB_USER"] = self.config.db_user or ""
  45 + os.environ["DB_PASSWORD"] = self.config.db_password or ""
  46 + os.environ["DB_NAME"] = self.config.db_name or ""
  47 + os.environ["DB_PORT"] = str(self.config.db_port)
  48 + os.environ["DB_CHARSET"] = self.config.db_charset
  49 +
42 # 初始化搜索工具集 50 # 初始化搜索工具集
43 - self.search_agency = TavilyNewsAgency(api_key=self.config.tavily_api_key) 51 + self.search_agency = MediaCrawlerDB()
44 52
45 # 初始化节点 53 # 初始化节点
46 self._initialize_nodes() 54 self._initialize_nodes()
@@ -53,7 +61,7 @@ class DeepSearchAgent: @@ -53,7 +61,7 @@ class DeepSearchAgent:
53 61
54 print(f"Deep Search Agent 已初始化") 62 print(f"Deep Search Agent 已初始化")
55 print(f"使用LLM: {self.llm_client.get_model_info()}") 63 print(f"使用LLM: {self.llm_client.get_model_info()}")
56 - print(f"搜索工具集: TavilyNewsAgency (支持6种搜索工具)") 64 + print(f"搜索工具集: MediaCrawlerDB (支持5种本地数据库查询工具)")
57 65
58 def _initialize_llm(self) -> BaseLLM: 66 def _initialize_llm(self) -> BaseLLM:
59 """初始化LLM客户端""" 67 """初始化LLM客户端"""
@@ -103,46 +111,53 @@ class DeepSearchAgent: @@ -103,46 +111,53 @@ class DeepSearchAgent:
103 except ValueError: 111 except ValueError:
104 return False 112 return False
105 113
106 - def execute_search_tool(self, tool_name: str, query: str, **kwargs) -> TavilyResponse: 114 + def execute_search_tool(self, tool_name: str, query: str, **kwargs) -> DBResponse:
107 """ 115 """
108 - 执行指定的搜索工具 116 + 执行指定的数据库查询工具
109 117
110 Args: 118 Args:
111 tool_name: 工具名称,可选值: 119 tool_name: 工具名称,可选值:
112 - - "basic_search_news": 基础新闻搜索(快速、通用)  
113 - - "deep_search_news": 深度新闻分析  
114 - - "search_news_last_24_hours": 24小时内最新新闻  
115 - - "search_news_last_week": 本周新闻  
116 - - "search_images_for_news": 新闻图片搜索  
117 - - "search_news_by_date": 按日期范围搜索新闻  
118 - query: 搜索查询  
119 - **kwargs: 额外参数(如start_date, end_date, max_results) 120 + - "search_hot_content": 查找热点内容
  121 + - "search_topic_globally": 全局话题搜索
  122 + - "search_topic_by_date": 按日期搜索话题
  123 + - "get_comments_for_topic": 获取话题评论
  124 + - "search_topic_on_platform": 平台定向搜索
  125 + query: 搜索关键词/话题
  126 + **kwargs: 额外参数(如start_date, end_date, platform, limit等)
120 127
121 Returns: 128 Returns:
122 - TavilyResponse对象 129 + DBResponse对象
123 """ 130 """
124 - print(f" → 执行搜索工具: {tool_name}")  
125 -  
126 - if tool_name == "basic_search_news":  
127 - max_results = kwargs.get("max_results", 7)  
128 - return self.search_agency.basic_search_news(query, max_results)  
129 - elif tool_name == "deep_search_news":  
130 - return self.search_agency.deep_search_news(query)  
131 - elif tool_name == "search_news_last_24_hours":  
132 - return self.search_agency.search_news_last_24_hours(query)  
133 - elif tool_name == "search_news_last_week":  
134 - return self.search_agency.search_news_last_week(query)  
135 - elif tool_name == "search_images_for_news":  
136 - return self.search_agency.search_images_for_news(query)  
137 - elif tool_name == "search_news_by_date": 131 + print(f" → 执行数据库查询工具: {tool_name}")
  132 +
  133 + if tool_name == "search_hot_content":
  134 + time_period = kwargs.get("time_period", "week")
  135 + limit = kwargs.get("limit", 10)
  136 + return self.search_agency.search_hot_content(time_period=time_period, limit=limit)
  137 + elif tool_name == "search_topic_globally":
  138 + limit_per_table = kwargs.get("limit_per_table", 5)
  139 + return self.search_agency.search_topic_globally(topic=query, limit_per_table=limit_per_table)
  140 + elif tool_name == "search_topic_by_date":
138 start_date = kwargs.get("start_date") 141 start_date = kwargs.get("start_date")
139 end_date = kwargs.get("end_date") 142 end_date = kwargs.get("end_date")
  143 + limit_per_table = kwargs.get("limit_per_table", 10)
140 if not start_date or not end_date: 144 if not start_date or not end_date:
141 - raise ValueError("search_news_by_date工具需要start_date和end_date参数")  
142 - return self.search_agency.search_news_by_date(query, start_date, end_date) 145 + raise ValueError("search_topic_by_date工具需要start_date和end_date参数")
  146 + return self.search_agency.search_topic_by_date(topic=query, start_date=start_date, end_date=end_date, limit_per_table=limit_per_table)
  147 + elif tool_name == "get_comments_for_topic":
  148 + limit = kwargs.get("limit", 50)
  149 + return self.search_agency.get_comments_for_topic(topic=query, limit=limit)
  150 + elif tool_name == "search_topic_on_platform":
  151 + platform = kwargs.get("platform")
  152 + start_date = kwargs.get("start_date")
  153 + end_date = kwargs.get("end_date")
  154 + limit = kwargs.get("limit", 20)
  155 + if not platform:
  156 + raise ValueError("search_topic_on_platform工具需要platform参数")
  157 + return self.search_agency.search_topic_on_platform(platform=platform, topic=query, start_date=start_date, end_date=end_date, limit=limit)
143 else: 158 else:
144 - print(f" ⚠️ 未知的搜索工具: {tool_name},使用默认基础搜索")  
145 - return self.search_agency.basic_search_news(query) 159 + print(f" ⚠️ 未知的搜索工具: {tool_name},使用默认全局搜索")
  160 + return self.search_agency.search_topic_globally(topic=query)
146 161
147 def research(self, query: str, save_report: bool = True) -> str: 162 def research(self, query: str, save_report: bool = True) -> str:
148 """ 163 """
@@ -231,7 +246,7 @@ class DeepSearchAgent: @@ -231,7 +246,7 @@ class DeepSearchAgent:
231 print(" - 生成搜索查询...") 246 print(" - 生成搜索查询...")
232 search_output = self.first_search_node.run(search_input) 247 search_output = self.first_search_node.run(search_input)
233 search_query = search_output["search_query"] 248 search_query = search_output["search_query"]
234 - search_tool = search_output.get("search_tool", "basic_search_news") # 默认工具 249 + search_tool = search_output.get("search_tool", "search_topic_globally") # 默认工具
235 reasoning = search_output["reasoning"] 250 reasoning = search_output["reasoning"]
236 251
237 print(f" - 搜索查询: {search_query}") 252 print(f" - 搜索查询: {search_query}")
@@ -239,11 +254,13 @@ class DeepSearchAgent: @@ -239,11 +254,13 @@ class DeepSearchAgent:
239 print(f" - 推理: {reasoning}") 254 print(f" - 推理: {reasoning}")
240 255
241 # 执行搜索 256 # 执行搜索
242 - print(" - 执行网络搜索...") 257 + print(" - 执行数据库查询...")
243 258
244 - # 处理search_news_by_date的特殊参数 259 + # 处理特殊参数
245 search_kwargs = {} 260 search_kwargs = {}
246 - if search_tool == "search_news_by_date": 261 +
  262 + # 处理需要日期的工具
  263 + if search_tool in ["search_topic_by_date", "search_topic_on_platform"]:
247 start_date = search_output.get("start_date") 264 start_date = search_output.get("start_date")
248 end_date = search_output.get("end_date") 265 end_date = search_output.get("end_date")
249 266
@@ -254,12 +271,35 @@ class DeepSearchAgent: @@ -254,12 +271,35 @@ class DeepSearchAgent:
254 search_kwargs["end_date"] = end_date 271 search_kwargs["end_date"] = end_date
255 print(f" - 时间范围: {start_date} 到 {end_date}") 272 print(f" - 时间范围: {start_date} 到 {end_date}")
256 else: 273 else:
257 - print(f" ⚠️ 日期格式错误(应为YYYY-MM-DD),改用基础搜索") 274 + print(f" ⚠️ 日期格式错误(应为YYYY-MM-DD),改用全局搜索")
258 print(f" 提供的日期: start_date={start_date}, end_date={end_date}") 275 print(f" 提供的日期: start_date={start_date}, end_date={end_date}")
259 - search_tool = "basic_search_news" 276 + search_tool = "search_topic_globally"
  277 + elif search_tool == "search_topic_by_date":
  278 + print(f" ⚠️ search_topic_by_date工具缺少时间参数,改用全局搜索")
  279 + search_tool = "search_topic_globally"
  280 +
  281 + # 处理需要平台参数的工具
  282 + if search_tool == "search_topic_on_platform":
  283 + platform = search_output.get("platform")
  284 + if platform:
  285 + search_kwargs["platform"] = platform
  286 + print(f" - 指定平台: {platform}")
260 else: 287 else:
261 - print(f" ⚠️ search_news_by_date工具缺少时间参数,改用基础搜索")  
262 - search_tool = "basic_search_news" 288 + print(f" ⚠️ search_topic_on_platform工具缺少平台参数,改用全局搜索")
  289 + search_tool = "search_topic_globally"
  290 +
  291 + # 处理限制参数
  292 + if search_tool == "search_hot_content":
  293 + time_period = search_output.get("time_period", "week")
  294 + limit = search_output.get("limit", 10)
  295 + search_kwargs["time_period"] = time_period
  296 + search_kwargs["limit"] = limit
  297 + elif search_tool in ["search_topic_globally", "search_topic_by_date"]:
  298 + limit_per_table = search_output.get("limit_per_table", 5)
  299 + search_kwargs["limit_per_table"] = limit_per_table
  300 + elif search_tool in ["get_comments_for_topic", "search_topic_on_platform"]:
  301 + limit = search_output.get("limit", 20)
  302 + search_kwargs["limit"] = limit
263 303
264 search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs) 304 search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs)
265 305
@@ -270,12 +310,16 @@ class DeepSearchAgent: @@ -270,12 +310,16 @@ class DeepSearchAgent:
270 max_results = min(len(search_response.results), 10) 310 max_results = min(len(search_response.results), 10)
271 for result in search_response.results[:max_results]: 311 for result in search_response.results[:max_results]:
272 search_results.append({ 312 search_results.append({
273 - 'title': result.title,  
274 - 'url': result.url,  
275 - 'content': result.content,  
276 - 'score': result.score,  
277 - 'raw_content': result.raw_content,  
278 - 'published_date': result.published_date # 新增字段 313 + 'title': result.title_or_content,
  314 + 'url': result.url or "",
  315 + 'content': result.title_or_content,
  316 + 'score': result.hotness_score,
  317 + 'raw_content': result.title_or_content,
  318 + 'published_date': result.publish_time.isoformat() if result.publish_time else None,
  319 + 'platform': result.platform,
  320 + 'content_type': result.content_type,
  321 + 'author': result.author_nickname,
  322 + 'engagement': result.engagement
279 }) 323 })
280 324
281 if search_results: 325 if search_results:
@@ -324,7 +368,7 @@ class DeepSearchAgent: @@ -324,7 +368,7 @@ class DeepSearchAgent:
324 # 生成反思搜索查询 368 # 生成反思搜索查询
325 reflection_output = self.reflection_node.run(reflection_input) 369 reflection_output = self.reflection_node.run(reflection_input)
326 search_query = reflection_output["search_query"] 370 search_query = reflection_output["search_query"]
327 - search_tool = reflection_output.get("search_tool", "basic_search_news") # 默认工具 371 + search_tool = reflection_output.get("search_tool", "search_topic_globally") # 默认工具
328 reasoning = reflection_output["reasoning"] 372 reasoning = reflection_output["reasoning"]
329 373
330 print(f" 反思查询: {search_query}") 374 print(f" 反思查询: {search_query}")
@@ -332,9 +376,11 @@ class DeepSearchAgent: @@ -332,9 +376,11 @@ class DeepSearchAgent:
332 print(f" 反思推理: {reasoning}") 376 print(f" 反思推理: {reasoning}")
333 377
334 # 执行反思搜索 378 # 执行反思搜索
335 - # 处理search_news_by_date的特殊参数 379 + # 处理特殊参数
336 search_kwargs = {} 380 search_kwargs = {}
337 - if search_tool == "search_news_by_date": 381 +
  382 + # 处理需要日期的工具
  383 + if search_tool in ["search_topic_by_date", "search_topic_on_platform"]:
338 start_date = reflection_output.get("start_date") 384 start_date = reflection_output.get("start_date")
339 end_date = reflection_output.get("end_date") 385 end_date = reflection_output.get("end_date")
340 386
@@ -345,12 +391,35 @@ class DeepSearchAgent: @@ -345,12 +391,35 @@ class DeepSearchAgent:
345 search_kwargs["end_date"] = end_date 391 search_kwargs["end_date"] = end_date
346 print(f" 时间范围: {start_date} 到 {end_date}") 392 print(f" 时间范围: {start_date} 到 {end_date}")
347 else: 393 else:
348 - print(f" ⚠️ 日期格式错误(应为YYYY-MM-DD),改用基础搜索") 394 + print(f" ⚠️ 日期格式错误(应为YYYY-MM-DD),改用全局搜索")
349 print(f" 提供的日期: start_date={start_date}, end_date={end_date}") 395 print(f" 提供的日期: start_date={start_date}, end_date={end_date}")
350 - search_tool = "basic_search_news" 396 + search_tool = "search_topic_globally"
  397 + elif search_tool == "search_topic_by_date":
  398 + print(f" ⚠️ search_topic_by_date工具缺少时间参数,改用全局搜索")
  399 + search_tool = "search_topic_globally"
  400 +
  401 + # 处理需要平台参数的工具
  402 + if search_tool == "search_topic_on_platform":
  403 + platform = reflection_output.get("platform")
  404 + if platform:
  405 + search_kwargs["platform"] = platform
  406 + print(f" 指定平台: {platform}")
351 else: 407 else:
352 - print(f" ⚠️ search_news_by_date工具缺少时间参数,改用基础搜索")  
353 - search_tool = "basic_search_news" 408 + print(f" ⚠️ search_topic_on_platform工具缺少平台参数,改用全局搜索")
  409 + search_tool = "search_topic_globally"
  410 +
  411 + # 处理限制参数
  412 + if search_tool == "search_hot_content":
  413 + time_period = reflection_output.get("time_period", "week")
  414 + limit = reflection_output.get("limit", 10)
  415 + search_kwargs["time_period"] = time_period
  416 + search_kwargs["limit"] = limit
  417 + elif search_tool in ["search_topic_globally", "search_topic_by_date"]:
  418 + limit_per_table = reflection_output.get("limit_per_table", 5)
  419 + search_kwargs["limit_per_table"] = limit_per_table
  420 + elif search_tool in ["get_comments_for_topic", "search_topic_on_platform"]:
  421 + limit = reflection_output.get("limit", 20)
  422 + search_kwargs["limit"] = limit
354 423
355 search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs) 424 search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs)
356 425
@@ -361,12 +430,16 @@ class DeepSearchAgent: @@ -361,12 +430,16 @@ class DeepSearchAgent:
361 max_results = min(len(search_response.results), 10) 430 max_results = min(len(search_response.results), 10)
362 for result in search_response.results[:max_results]: 431 for result in search_response.results[:max_results]:
363 search_results.append({ 432 search_results.append({
364 - 'title': result.title,  
365 - 'url': result.url,  
366 - 'content': result.content,  
367 - 'score': result.score,  
368 - 'raw_content': result.raw_content,  
369 - 'published_date': result.published_date 433 + 'title': result.title_or_content,
  434 + 'url': result.url or "",
  435 + 'content': result.title_or_content,
  436 + 'score': result.hotness_score,
  437 + 'raw_content': result.title_or_content,
  438 + 'published_date': result.publish_time.isoformat() if result.publish_time else None,
  439 + 'platform': result.platform,
  440 + 'content_type': result.content_type,
  441 + 'author': result.author_nickname,
  442 + 'engagement': result.engagement
370 }) 443 })
371 444
372 if search_results: 445 if search_results:
@@ -35,8 +35,12 @@ output_schema_first_search = { @@ -35,8 +35,12 @@ output_schema_first_search = {
35 "search_query": {"type": "string"}, 35 "search_query": {"type": "string"},
36 "search_tool": {"type": "string"}, 36 "search_tool": {"type": "string"},
37 "reasoning": {"type": "string"}, 37 "reasoning": {"type": "string"},
38 - "start_date": {"type": "string", "description": "开始日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"},  
39 - "end_date": {"type": "string", "description": "结束日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"} 38 + "start_date": {"type": "string", "description": "开始日期,格式YYYY-MM-DD,search_topic_by_date和search_topic_on_platform工具可能需要"},
  39 + "end_date": {"type": "string", "description": "结束日期,格式YYYY-MM-DD,search_topic_by_date和search_topic_on_platform工具可能需要"},
  40 + "platform": {"type": "string", "description": "平台名称,search_topic_on_platform工具必需,可选值:bilibili, weibo, douyin, kuaishou, xhs, zhihu, tieba"},
  41 + "time_period": {"type": "string", "description": "时间周期,search_hot_content工具可选,可选值:24h, week, year"},
  42 + "limit": {"type": "integer", "description": "结果数量限制,各工具可选参数"},
  43 + "limit_per_table": {"type": "integer", "description": "每表结果数量限制,search_topic_globally和search_topic_by_date工具可选"}
40 }, 44 },
41 "required": ["search_query", "search_tool", "reasoning"] 45 "required": ["search_query", "search_tool", "reasoning"]
42 } 46 }
@@ -80,8 +84,12 @@ output_schema_reflection = { @@ -80,8 +84,12 @@ output_schema_reflection = {
80 "search_query": {"type": "string"}, 84 "search_query": {"type": "string"},
81 "search_tool": {"type": "string"}, 85 "search_tool": {"type": "string"},
82 "reasoning": {"type": "string"}, 86 "reasoning": {"type": "string"},
83 - "start_date": {"type": "string", "description": "开始日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"},  
84 - "end_date": {"type": "string", "description": "结束日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"} 87 + "start_date": {"type": "string", "description": "开始日期,格式YYYY-MM-DD,search_topic_by_date和search_topic_on_platform工具可能需要"},
  88 + "end_date": {"type": "string", "description": "结束日期,格式YYYY-MM-DD,search_topic_by_date和search_topic_on_platform工具可能需要"},
  89 + "platform": {"type": "string", "description": "平台名称,search_topic_on_platform工具必需,可选值:bilibili, weibo, douyin, kuaishou, xhs, zhihu, tieba"},
  90 + "time_period": {"type": "string", "description": "时间周期,search_hot_content工具可选,可选值:24h, week, year"},
  91 + "limit": {"type": "integer", "description": "结果数量限制,各工具可选参数"},
  92 + "limit_per_table": {"type": "integer", "description": "每表结果数量限制,search_topic_globally和search_topic_by_date工具可选"}
85 }, 93 },
86 "required": ["search_query", "search_tool", "reasoning"] 94 "required": ["search_query", "search_tool", "reasoning"]
87 } 95 }
@@ -141,47 +149,83 @@ SYSTEM_PROMPT_REPORT_STRUCTURE = f""" @@ -141,47 +149,83 @@ SYSTEM_PROMPT_REPORT_STRUCTURE = f"""
141 149
142 # 每个段落第一次搜索的系统提示词 150 # 每个段落第一次搜索的系统提示词
143 SYSTEM_PROMPT_FIRST_SEARCH = f""" 151 SYSTEM_PROMPT_FIRST_SEARCH = f"""
144 -你是一位深度研究助手。你将获得报告中的一个段落,其标题和预期内容将按照以下JSON模式定义提供: 152 +你是一位专业的舆情分析师。你将获得报告中的一个段落,其标题和预期内容将按照以下JSON模式定义提供:
145 153
146 <INPUT JSON SCHEMA> 154 <INPUT JSON SCHEMA>
147 {json.dumps(input_schema_first_search, indent=2, ensure_ascii=False)} 155 {json.dumps(input_schema_first_search, indent=2, ensure_ascii=False)}
148 </INPUT JSON SCHEMA> 156 </INPUT JSON SCHEMA>
149 157
150 -你可以使用以下6种专业的新闻搜索工具 158 +你可以使用以下5种专业的本地舆情数据库查询工具来挖掘真实的民意和公众观点
151 159
152 -1. **basic_search_news** - 基础新闻搜索工具  
153 - - 适用于:一般性的新闻搜索,不确定需要何种特定搜索时  
154 - - 特点:快速、标准的通用搜索,是最常用的基础工具 160 +1. **search_hot_content** - 查找热点内容工具
  161 + - 适用于:挖掘当前最受关注的舆情事件和话题
  162 + - 特点:基于真实的点赞、评论、分享数据发现热门话题
  163 + - 参数:time_period ('24h', 'week', 'year'),limit(数量限制)
155 164
156 -2. **deep_search_news** - 深度新闻分析工具  
157 - - 适用于:需要全面深入了解某个主题时  
158 - - 特点:提供最详细的分析结果,包含高级AI摘要 165 +2. **search_topic_globally** - 全局话题搜索工具
  166 + - 适用于:全面了解公众对特定话题的讨论和观点
  167 + - 特点:覆盖B站、微博、抖音、快手、小红书、知乎、贴吧等主流平台的真实用户声音
  168 + - 参数:limit_per_table(每个表的结果数量限制)
159 169
160 -3. **search_news_last_24_hours** - 24小时最新新闻工具  
161 - - 适用于:需要了解最新动态、突发事件时  
162 - - 特点:只搜索过去24小时的新闻 170 +3. **search_topic_by_date** - 按日期搜索话题工具
  171 + - 适用于:追踪舆情事件的时间线发展和公众情绪变化
  172 + - 特点:精确的时间范围控制,适合分析舆情演变过程
  173 + - 特殊要求:需要提供start_date和end_date参数,格式为'YYYY-MM-DD'
  174 + - 参数:limit_per_table(每个表的结果数量限制)
163 175
164 -4. **search_news_last_week** - 本周新闻工具  
165 - - 适用于:需要了解近期发展趋势时  
166 - - 特点:搜索过去一周的新闻报道 176 +4. **get_comments_for_topic** - 获取话题评论工具
  177 + - 适用于:深度挖掘网民的真实态度、情感和观点
  178 + - 特点:直接获取用户评论,了解民意走向和情感倾向
  179 + - 参数:limit(评论总数量限制)
167 180
168 -5. **search_images_for_news** - 图片搜索工具  
169 - - 适用于:需要可视化信息、图片资料时  
170 - - 特点:提供相关图片和图片描述 181 +5. **search_topic_on_platform** - 平台定向搜索工具
  182 + - 适用于:分析特定社交平台用户群体的观点特征
  183 + - 特点:针对不同平台用户群体的观点差异进行精准分析
  184 + - 特殊要求:需要提供platform参数,可选start_date和end_date
  185 + - 参数:platform(必须),start_date, end_date(可选),limit(数量限制)
171 186
172 -6. **search_news_by_date** - 按日期范围搜索工具  
173 - - 适用于:需要研究特定历史时期时  
174 - - 特点:可以指定开始和结束日期进行搜索  
175 - - 特殊要求:需要提供start_date和end_date参数,格式为'YYYY-MM-DD'  
176 - - 注意:只有这个工具需要额外的时间参数 187 +**你的核心使命:挖掘真实的民意和人情味**
177 188
178 你的任务是: 189 你的任务是:
179 -1. 根据段落主题选择最合适的搜索工具  
180 -2. 制定最佳的搜索查询  
181 -3. 如果选择search_news_by_date工具,必须同时提供start_date和end_date参数(格式:YYYY-MM-DD)  
182 -4. 解释你的选择理由  
183 -  
184 -注意:除了search_news_by_date工具外,其他工具都不需要额外参数。 190 +1. **深度理解段落需求**:根据段落主题,思考需要了解哪些具体的公众观点和情感
  191 +2. **精准选择查询工具**:选择最能获取真实民意数据的工具
  192 +3. **设计接地气的搜索词**:**这是最关键的环节!**
  193 + - **避免官方术语**:不要用"舆情传播"、"公众反应"、"情绪倾向"等书面语
  194 + - **使用网民真实表达**:模拟普通网友会怎么谈论这个话题
  195 + - **贴近生活语言**:用简单、直接、口语化的词汇
  196 + - **包含情感词汇**:网民常用的褒贬词、情绪词
  197 + - **考虑话题热词**:相关的网络流行语、缩写、昵称
  198 +4. **参数优化配置**:
  199 + - search_topic_by_date: 必须提供start_date和end_date参数(格式:YYYY-MM-DD)
  200 + - search_topic_on_platform: 必须提供platform参数(bilibili, weibo, douyin, kuaishou, xhs, zhihu, tieba之一)
  201 + - 其他工具:合理配置limit参数以获取足够的样本
  202 +5. **阐述选择理由**:说明为什么这样的查询能够获得最真实的民意反馈
  203 +
  204 +**搜索词设计核心原则**:
  205 +- **想象网友怎么说**:如果你是个普通网友,你会怎么讨论这个话题?
  206 +- **避免学术词汇**:杜绝"舆情"、"传播"、"倾向"等专业术语
  207 +- **使用具体词汇**:用具体的事件、人名、地名、现象描述
  208 +- **包含情感表达**:如"支持"、"反对"、"担心"、"愤怒"、"点赞"等
  209 +- **考虑网络文化**:网民的表达习惯、缩写、俚语、表情符号文字描述
  210 +
  211 +**举例说明**:
  212 +- ❌ 错误:"武汉大学舆情 公众反应"
  213 +- ✅ 正确:"武大" 或 "武汉大学怎么了" 或 "武大学生"
  214 +- ❌ 错误:"校园事件 学生反应"
  215 +- ✅ 正确:"学校出事" 或 "同学们都在说" 或 "校友群炸了"
  216 +
  217 +**不同平台语言特色参考**:
  218 +- **微博**:热搜词汇、话题标签,如 "武大又上热搜"、"心疼武大学子"
  219 +- **知乎**:问答式表达,如 "如何看待武汉大学"、"武大是什么体验"
  220 +- **B站**:弹幕文化,如 "武大yyds"、"武大人路过"、"我武最强"
  221 +- **贴吧**:直接称呼,如 "武大吧"、"武大的兄弟们"
  222 +- **抖音/快手**:短视频描述,如 "武大日常"、"武大vlog"
  223 +- **小红书**:分享式,如 "武大真的很美"、"武大攻略"
  224 +
  225 +**情感表达词汇库**:
  226 +- 正面:"太棒了"、"牛逼"、"绝了"、"爱了"、"yyds"、"666"
  227 +- 负面:"无语"、"离谱"、"绝了"、"服了"、"麻了"、"破防"
  228 +- 中性:"围观"、"吃瓜"、"路过"、"有一说一"、"实名"
185 请按照以下JSON模式定义格式化输出(文字请使用中文): 229 请按照以下JSON模式定义格式化输出(文字请使用中文):
186 230
187 <OUTPUT JSON SCHEMA> 231 <OUTPUT JSON SCHEMA>
@@ -194,13 +238,27 @@ SYSTEM_PROMPT_FIRST_SEARCH = f""" @@ -194,13 +238,27 @@ SYSTEM_PROMPT_FIRST_SEARCH = f"""
194 238
195 # 每个段落第一次总结的系统提示词 239 # 每个段落第一次总结的系统提示词
196 SYSTEM_PROMPT_FIRST_SUMMARY = f""" 240 SYSTEM_PROMPT_FIRST_SUMMARY = f"""
197 -你是一位深度研究助手。你将获得搜索查询、搜索结果以及你正在研究的报告段落,数据将按照以下JSON模式定义提供 241 +你是一位专业的舆情分析师和报告撰写专家。你将获得搜索查询、真实的社交媒体数据以及你正在研究的舆情报告段落
198 242
199 <INPUT JSON SCHEMA> 243 <INPUT JSON SCHEMA>
200 {json.dumps(input_schema_first_summary, indent=2, ensure_ascii=False)} 244 {json.dumps(input_schema_first_summary, indent=2, ensure_ascii=False)}
201 </INPUT JSON SCHEMA> 245 </INPUT JSON SCHEMA>
202 246
203 -你的任务是作为研究者,使用搜索结果撰写与段落主题一致的内容,并适当地组织结构以便纳入报告中。 247 +**你的核心任务:将真实的民意数据转化为有温度的舆情分析**
  248 +
  249 +撰写要求:
  250 +1. **突出真实民意**:优先引用具体的用户评论、真实案例和情感表达
  251 +2. **展现多元观点**:呈现不同平台、不同群体的观点差异和讨论重点
  252 +3. **数据支撑分析**:用具体的点赞数、评论数、转发数等数据说明舆情热度
  253 +4. **情感色彩描述**:准确描述公众的情感倾向(愤怒、支持、担忧、期待等)
  254 +5. **避免套话官话**:使用贴近民众的语言,避免过度官方化的表述
  255 +
  256 +撰写风格:
  257 +- 语言生动,有感染力
  258 +- 引用真实的网民声音和具体案例
  259 +- 体现舆情的复杂性和多面性
  260 +- 突出社会情绪和价值观念的碰撞
  261 +- 让读者感受到真实的民意脉搏
204 请按照以下JSON模式定义格式化输出: 262 请按照以下JSON模式定义格式化输出:
205 263
206 <OUTPUT JSON SCHEMA> 264 <OUTPUT JSON SCHEMA>
@@ -213,29 +271,67 @@ SYSTEM_PROMPT_FIRST_SUMMARY = f""" @@ -213,29 +271,67 @@ SYSTEM_PROMPT_FIRST_SUMMARY = f"""
213 271
214 # 反思(Reflect)的系统提示词 272 # 反思(Reflect)的系统提示词
215 SYSTEM_PROMPT_REFLECTION = f""" 273 SYSTEM_PROMPT_REFLECTION = f"""
216 -你是一位深度研究助手。你负责为研究报告构建全面的段落。你将获得段落标题、计划内容摘要,以及你已经创建的段落最新状态,所有这些都将按照以下JSON模式定义提供 274 +你是一位资深的舆情分析师。你负责深化舆情报告的内容,让其更贴近真实的民意和社会情感。你将获得段落标题、计划内容摘要,以及你已经创建的段落最新状态
217 275
218 <INPUT JSON SCHEMA> 276 <INPUT JSON SCHEMA>
219 {json.dumps(input_schema_reflection, indent=2, ensure_ascii=False)} 277 {json.dumps(input_schema_reflection, indent=2, ensure_ascii=False)}
220 </INPUT JSON SCHEMA> 278 </INPUT JSON SCHEMA>
221 279
222 -你可以使用以下6种专业的新闻搜索工具 280 +你可以使用以下5种专业的本地舆情数据库查询工具来深度挖掘民意
223 281
224 -1. **basic_search_news** - 基础新闻搜索工具  
225 -2. **deep_search_news** - 深度新闻分析工具  
226 -3. **search_news_last_24_hours** - 24小时最新新闻工具  
227 -4. **search_news_last_week** - 本周新闻工具  
228 -5. **search_images_for_news** - 图片搜索工具  
229 -6. **search_news_by_date** - 按日期范围搜索工具(需要时间参数) 282 +1. **search_hot_content** - 查找热点内容工具
  283 +2. **search_topic_globally** - 全局话题搜索工具
  284 +3. **search_topic_by_date** - 按日期搜索话题工具
  285 +4. **get_comments_for_topic** - 获取话题评论工具
  286 +5. **search_topic_on_platform** - 平台定向搜索工具
230 287
231 -你的任务是:  
232 -1. 反思段落文本的当前状态,思考是否遗漏了主题的某些关键方面  
233 -2. 选择最合适的搜索工具来补充缺失信息  
234 -3. 制定精确的搜索查询  
235 -4. 如果选择search_news_by_date工具,必须同时提供start_date和end_date参数(格式:YYYY-MM-DD)  
236 -5. 解释你的选择和推理 288 +**反思的核心目标:让报告更有人情味和真实感**
237 289
238 -注意:除了search_news_by_date工具外,其他工具都不需要额外参数。 290 +你的任务是:
  291 +1. **深度反思内容质量**:
  292 + - 当前段落是否过于官方化、套路化?
  293 + - 是否缺乏真实的民众声音和情感表达?
  294 + - 是否遗漏了重要的公众观点和争议焦点?
  295 + - 是否需要补充具体的网民评论和真实案例?
  296 +
  297 +2. **识别信息缺口**:
  298 + - 缺少哪个平台的用户观点?(如B站年轻人、微博话题讨论、知乎深度分析等)
  299 + - 缺少哪个时间段的舆情变化?
  300 + - 缺少哪些具体的民意表达和情感倾向?
  301 +
  302 +3. **精准补充查询**:
  303 + - 选择最能填补信息缺口的查询工具
  304 + - **设计接地气的搜索关键词**:
  305 + * 避免继续使用官方化、书面化的词汇
  306 + * 思考网民会用什么词来表达这个观点
  307 + * 使用具体的、有情感色彩的词汇
  308 + * 考虑不同平台的语言特色(如B站弹幕文化、微博热搜词汇等)
  309 + - 重点关注评论区和用户原创内容
  310 +
  311 +4. **参数配置要求**:
  312 + - search_topic_by_date: 必须提供start_date和end_date参数(格式:YYYY-MM-DD)
  313 + - search_topic_on_platform: 必须提供platform参数(bilibili, weibo, douyin, kuaishou, xhs, zhihu, tieba之一)
  314 + - 其他工具:合理配置参数以获取多样化的民意样本
  315 +
  316 +5. **阐述补充理由**:明确说明为什么需要这些额外的民意数据
  317 +
  318 +**反思重点**:
  319 +- 报告是否反映了真实的社会情绪?
  320 +- 是否包含了不同群体的观点和声音?
  321 +- 是否有具体的用户评论和真实案例支撑?
  322 +- 是否体现了舆情的复杂性和多面性?
  323 +- 语言表达是否贴近民众,避免过度官方化?
  324 +
  325 +**搜索词优化示例(重要!)**:
  326 +- 如果需要了解"武汉大学"相关内容:
  327 + * ❌ 不要用:"武汉大学舆情"、"校园事件"、"学生反应"
  328 + * ✅ 应该用:"武大"、"武汉大学"、"珞珈山"、"樱花大道"
  329 +- 如果需要了解争议话题:
  330 + * ❌ 不要用:"争议事件"、"公众争议"
  331 + * ✅ 应该用:"出事了"、"怎么回事"、"翻车"、"炸了"
  332 +- 如果需要了解情感态度:
  333 + * ❌ 不要用:"情感倾向"、"态度分析"
  334 + * ✅ 应该用:"支持"、"反对"、"心疼"、"气死"、"666"、"绝了"
239 请按照以下JSON模式定义格式化输出: 335 请按照以下JSON模式定义格式化输出:
240 336
241 <OUTPUT JSON SCHEMA> 337 <OUTPUT JSON SCHEMA>
@@ -248,18 +344,28 @@ SYSTEM_PROMPT_REFLECTION = f""" @@ -248,18 +344,28 @@ SYSTEM_PROMPT_REFLECTION = f"""
248 344
249 # 总结反思的系统提示词 345 # 总结反思的系统提示词
250 SYSTEM_PROMPT_REFLECTION_SUMMARY = f""" 346 SYSTEM_PROMPT_REFLECTION_SUMMARY = f"""
251 -你是一位深度研究助手。  
252 -你将获得搜索查询、搜索结果、段落标题以及你正在研究的报告段落的预期内容。  
253 -你正在迭代完善这个段落,并且段落的最新状态也会提供给你。 347 +你是一位资深的舆情分析师和内容优化专家。
  348 +你正在深化和完善舆情报告段落,让其更贴近真实民意、更有说服力和感染力。
254 数据将按照以下JSON模式定义提供: 349 数据将按照以下JSON模式定义提供:
255 350
256 <INPUT JSON SCHEMA> 351 <INPUT JSON SCHEMA>
257 {json.dumps(input_schema_reflection_summary, indent=2, ensure_ascii=False)} 352 {json.dumps(input_schema_reflection_summary, indent=2, ensure_ascii=False)}
258 </INPUT JSON SCHEMA> 353 </INPUT JSON SCHEMA>
259 354
260 -你的任务是根据搜索结果和预期内容丰富段落的当前最新状态。  
261 -不要删除最新状态中的关键信息,尽量丰富它,只添加缺失的信息。  
262 -适当地组织段落结构以便纳入报告中。 355 +**你的任务:让段落更有人情味和真实感**
  356 +
  357 +优化策略:
  358 +1. **融入新的民意数据**:将补充搜索到的真实用户声音整合到段落中
  359 +2. **丰富情感表达**:增加具体的情感描述和社会情绪分析
  360 +3. **补充遗漏观点**:添加之前缺失的不同群体、平台的观点
  361 +4. **强化数据支撑**:用具体数字和案例让分析更有说服力
  362 +5. **优化语言表达**:让文字更生动、更贴近民众,减少官方套话
  363 +
  364 +注意事项:
  365 +- 保留段落的核心观点和重要信息
  366 +- 增强内容的真实性和可信度
  367 +- 体现舆情的复杂性和多样性
  368 +- 让读者能感受到真实的社会脉搏
263 请按照以下JSON模式定义格式化输出: 369 请按照以下JSON模式定义格式化输出:
264 370
265 <OUTPUT JSON SCHEMA> 371 <OUTPUT JSON SCHEMA>
@@ -272,14 +378,28 @@ SYSTEM_PROMPT_REFLECTION_SUMMARY = f""" @@ -272,14 +378,28 @@ SYSTEM_PROMPT_REFLECTION_SUMMARY = f"""
272 378
273 # 最终研究报告格式化的系统提示词 379 # 最终研究报告格式化的系统提示词
274 SYSTEM_PROMPT_REPORT_FORMATTING = f""" 380 SYSTEM_PROMPT_REPORT_FORMATTING = f"""
275 -你是一位深度研究助手。你已经完成了研究并构建了报告中所有段落的最终版本。 381 +你是一位专业的舆情报告编辑和格式化专家。你已经完成了深度的舆情分析并构建了报告中所有段落的最终版本。
276 你将获得以下JSON格式的数据: 382 你将获得以下JSON格式的数据:
277 383
278 <INPUT JSON SCHEMA> 384 <INPUT JSON SCHEMA>
279 {json.dumps(input_schema_report_formatting, indent=2, ensure_ascii=False)} 385 {json.dumps(input_schema_report_formatting, indent=2, ensure_ascii=False)}
280 </INPUT JSON SCHEMA> 386 </INPUT JSON SCHEMA>
281 387
282 -你的任务是将报告格式化为美观的形式,并以Markdown格式返回。  
283 -如果没有结论段落,请根据其他段落的最新状态在报告末尾添加一个结论。  
284 -使用段落标题来创建报告的标题。 388 +**你的任务:将舆情分析格式化为专业、有感染力的报告**
  389 +
  390 +格式化要求:
  391 +1. **标题设计**:创建吸引人、有概括性的报告标题
  392 +2. **结构优化**:确保段落逻辑清晰,层次分明
  393 +3. **突出重点**:用**粗体**、*斜体*等格式突出关键观点和数据
  394 +4. **数据可视**:用表格或列表呈现重要的舆情数据
  395 +5. **增强可读性**:合理使用分段、标题层级和格式化元素
  396 +
  397 +结论撰写(如果需要):
  398 +- 总结主要的舆情发现和民意倾向
  399 +- 突出不同平台和群体的观点特征
  400 +- 提炼深层的社会情绪和价值观念
  401 +- 用数据和具体案例支撑结论
  402 +- 语言简洁有力,避免空洞套话
  403 +
  404 +最终输出:专业的Markdown格式舆情分析报告
285 """ 405 """
1 """ 1 """
2 工具调用模块 2 工具调用模块
3 -提供外部工具接口,如网络搜索 3 +提供外部工具接口,如本地数据库查询
4 """ 4 """
5 5
6 from .search import ( 6 from .search import (
7 - TavilyNewsAgency,  
8 - SearchResult,  
9 - TavilyResponse,  
10 - ImageResult, 7 + MediaCrawlerDB,
  8 + QueryResult,
  9 + DBResponse,
11 print_response_summary 10 print_response_summary
12 ) 11 )
13 12
14 __all__ = [ 13 __all__ = [
15 - "TavilyNewsAgency",  
16 - "SearchResult",  
17 - "TavilyResponse",  
18 - "ImageResult", 14 + "MediaCrawlerDB",
  15 + "QueryResult",
  16 + "DBResponse",
19 "print_response_summary" 17 "print_response_summary"
20 ] 18 ]
@@ -14,7 +14,14 @@ class Config: @@ -14,7 +14,14 @@ class Config:
14 # API密钥 14 # API密钥
15 deepseek_api_key: Optional[str] = None 15 deepseek_api_key: Optional[str] = None
16 openai_api_key: Optional[str] = None 16 openai_api_key: Optional[str] = None
17 - tavily_api_key: Optional[str] = None 17 +
  18 + # 数据库配置
  19 + db_host: Optional[str] = None
  20 + db_user: Optional[str] = None
  21 + db_password: Optional[str] = None
  22 + db_name: Optional[str] = None
  23 + db_port: int = 3306
  24 + db_charset: str = "utf8mb4"
18 25
19 # 模型配置 26 # 模型配置
20 default_llm_provider: str = "deepseek" # deepseek 或 openai 27 default_llm_provider: str = "deepseek" # deepseek 或 openai
@@ -44,8 +51,8 @@ class Config: @@ -44,8 +51,8 @@ class Config:
44 print("错误: OpenAI API Key未设置") 51 print("错误: OpenAI API Key未设置")
45 return False 52 return False
46 53
47 - if not self.tavily_api_key:  
48 - print("错误: Tavily API Key未设置") 54 + if not all([self.db_host, self.db_user, self.db_password, self.db_name]):
  55 + print("错误: 数据库连接信息不完整")
49 return False 56 return False
50 57
51 return True 58 return True
@@ -65,7 +72,14 @@ class Config: @@ -65,7 +72,14 @@ class Config:
65 return cls( 72 return cls(
66 deepseek_api_key=getattr(config_module, "DEEPSEEK_API_KEY", None), 73 deepseek_api_key=getattr(config_module, "DEEPSEEK_API_KEY", None),
67 openai_api_key=getattr(config_module, "OPENAI_API_KEY", None), 74 openai_api_key=getattr(config_module, "OPENAI_API_KEY", None),
68 - tavily_api_key=getattr(config_module, "TAVILY_API_KEY", None), 75 +
  76 + db_host=getattr(config_module, "DB_HOST", None),
  77 + db_user=getattr(config_module, "DB_USER", None),
  78 + db_password=getattr(config_module, "DB_PASSWORD", None),
  79 + db_name=getattr(config_module, "DB_NAME", None),
  80 + db_port=getattr(config_module, "DB_PORT", 3306),
  81 + db_charset=getattr(config_module, "DB_CHARSET", "utf8mb4"),
  82 +
69 default_llm_provider=getattr(config_module, "DEFAULT_LLM_PROVIDER", "deepseek"), 83 default_llm_provider=getattr(config_module, "DEFAULT_LLM_PROVIDER", "deepseek"),
70 deepseek_model=getattr(config_module, "DEEPSEEK_MODEL", "deepseek-chat"), 84 deepseek_model=getattr(config_module, "DEEPSEEK_MODEL", "deepseek-chat"),
71 openai_model=getattr(config_module, "OPENAI_MODEL", "gpt-4o-mini"), 85 openai_model=getattr(config_module, "OPENAI_MODEL", "gpt-4o-mini"),
@@ -92,7 +106,14 @@ class Config: @@ -92,7 +106,14 @@ class Config:
92 return cls( 106 return cls(
93 deepseek_api_key=config_dict.get("DEEPSEEK_API_KEY"), 107 deepseek_api_key=config_dict.get("DEEPSEEK_API_KEY"),
94 openai_api_key=config_dict.get("OPENAI_API_KEY"), 108 openai_api_key=config_dict.get("OPENAI_API_KEY"),
95 - tavily_api_key=config_dict.get("TAVILY_API_KEY"), 109 +
  110 + db_host=config_dict.get("DB_HOST"),
  111 + db_user=config_dict.get("DB_USER"),
  112 + db_password=config_dict.get("DB_PASSWORD"),
  113 + db_name=config_dict.get("DB_NAME"),
  114 + db_port=int(config_dict.get("DB_PORT", "3306")),
  115 + db_charset=config_dict.get("DB_CHARSET", "utf8mb4"),
  116 +
96 default_llm_provider=config_dict.get("DEFAULT_LLM_PROVIDER", "deepseek"), 117 default_llm_provider=config_dict.get("DEFAULT_LLM_PROVIDER", "deepseek"),
97 deepseek_model=config_dict.get("DEEPSEEK_MODEL", "deepseek-chat"), 118 deepseek_model=config_dict.get("DEEPSEEK_MODEL", "deepseek-chat"),
98 openai_model=config_dict.get("OPENAI_MODEL", "gpt-4o-mini"), 119 openai_model=config_dict.get("OPENAI_MODEL", "gpt-4o-mini"),
@@ -147,7 +168,7 @@ def print_config(config: Config): @@ -147,7 +168,7 @@ def print_config(config: Config):
147 print(f"LLM提供商: {config.default_llm_provider}") 168 print(f"LLM提供商: {config.default_llm_provider}")
148 print(f"DeepSeek模型: {config.deepseek_model}") 169 print(f"DeepSeek模型: {config.deepseek_model}")
149 print(f"OpenAI模型: {config.openai_model}") 170 print(f"OpenAI模型: {config.openai_model}")
150 - print(f"最大搜索结果数: {config.max_search_results}") 171 +
151 print(f"搜索超时: {config.search_timeout}秒") 172 print(f"搜索超时: {config.search_timeout}秒")
152 print(f"最大内容长度: {config.max_content_length}") 173 print(f"最大内容长度: {config.max_content_length}")
153 print(f"最大反思次数: {config.max_reflections}") 174 print(f"最大反思次数: {config.max_reflections}")
@@ -155,8 +176,11 @@ def print_config(config: Config): @@ -155,8 +176,11 @@ def print_config(config: Config):
155 print(f"输出目录: {config.output_dir}") 176 print(f"输出目录: {config.output_dir}")
156 print(f"保存中间状态: {config.save_intermediate_states}") 177 print(f"保存中间状态: {config.save_intermediate_states}")
157 178
158 - # 显示API密钥状态(不显示实际密钥) 179 + # 显示API密钥和数据库状态(不显示实际密钥)
159 print(f"DeepSeek API Key: {'已设置' if config.deepseek_api_key else '未设置'}") 180 print(f"DeepSeek API Key: {'已设置' if config.deepseek_api_key else '未设置'}")
160 print(f"OpenAI API Key: {'已设置' if config.openai_api_key else '未设置'}") 181 print(f"OpenAI API Key: {'已设置' if config.openai_api_key else '未设置'}")
161 - print(f"Tavily API Key: {'已设置' if config.tavily_api_key else '未设置'}") 182 + print(f"数据库连接: {'已配置' if all([config.db_host, config.db_user, config.db_password, config.db_name]) else '未配置'}")
  183 + print(f"数据库主机: {config.db_host}")
  184 + print(f"数据库端口: {config.db_port}")
  185 + print(f"数据库名称: {config.db_name}")
162 print("==================\n") 186 print("==================\n")
@@ -12,8 +12,8 @@ import json @@ -12,8 +12,8 @@ import json
12 # 添加src目录到Python路径 12 # 添加src目录到Python路径
13 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '.')) 13 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '.'))
14 14
15 -from QueryEngine import DeepSearchAgent, Config  
16 -from config import DEEPSEEK_API_KEY, TAVILY_API_KEY 15 +from InsightEngine import DeepSearchAgent, Config
  16 +from config import DEEPSEEK_API_KEY, DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_PORT, DB_CHARSET
17 17
18 18
19 def main(): 19 def main():
@@ -24,8 +24,8 @@ def main(): @@ -24,8 +24,8 @@ def main():
24 layout="wide" 24 layout="wide"
25 ) 25 )
26 26
27 - st.title("Deep Search Agent")  
28 - st.markdown("基于DeepSeek的无框架深度搜索AI代理") 27 + st.title("Insight Engine Agent")
  28 + st.markdown("基于DeepSeek的本地舆情数据库深度分析AI代理")
29 29
30 # 侧边栏配置 30 # 侧边栏配置
31 with st.sidebar: 31 with st.sidebar:
@@ -96,21 +96,31 @@ def main(): @@ -96,21 +96,31 @@ def main():
96 st.error("请提供OpenAI API Key") 96 st.error("请提供OpenAI API Key")
97 return 97 return
98 98
99 - # 自动使用配置文件中的API密钥 99 + # 自动使用配置文件中的API密钥和数据库配置
100 deepseek_key = DEEPSEEK_API_KEY 100 deepseek_key = DEEPSEEK_API_KEY
101 - tavily_key = TAVILY_API_KEY 101 + db_host = DB_HOST
  102 + db_user = DB_USER
  103 + db_password = DB_PASSWORD
  104 + db_name = DB_NAME
  105 + db_port = DB_PORT
  106 + db_charset = DB_CHARSET
102 107
103 # 创建配置 108 # 创建配置
104 config = Config( 109 config = Config(
105 deepseek_api_key=deepseek_key if llm_provider == "deepseek" else None, 110 deepseek_api_key=deepseek_key if llm_provider == "deepseek" else None,
106 openai_api_key=openai_key if llm_provider == "openai" else None, 111 openai_api_key=openai_key if llm_provider == "openai" else None,
107 - tavily_api_key=tavily_key, 112 + db_host=db_host,
  113 + db_user=db_user,
  114 + db_password=db_password,
  115 + db_name=db_name,
  116 + db_port=db_port,
  117 + db_charset=db_charset,
108 default_llm_provider=llm_provider, 118 default_llm_provider=llm_provider,
109 deepseek_model=model_name if llm_provider == "deepseek" else "deepseek-chat", 119 deepseek_model=model_name if llm_provider == "deepseek" else "deepseek-chat",
110 openai_model=model_name if llm_provider == "openai" else "gpt-4o-mini", 120 openai_model=model_name if llm_provider == "openai" else "gpt-4o-mini",
111 max_reflections=max_reflections, 121 max_reflections=max_reflections,
112 max_content_length=max_content_length, 122 max_content_length=max_content_length,
113 - output_dir="query_engine_streamlit_reports" 123 + output_dir="insight_engine_streamlit_reports"
114 ) 124 )
115 125
116 # 执行研究 126 # 执行研究