2026-04-25 18:29:23 +08:00
|
|
|
|
"""
|
2026-04-25 18:47:09 +08:00
|
|
|
|
资讯子图节点 - 完善版(使用API客户端)
|
|
|
|
|
|
News Analysis Subgraph Nodes - Complete (with API Client)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from typing import Dict, Any
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
|
|
from .state import (
|
|
|
|
|
|
NewsAnalysisState,
|
|
|
|
|
|
NewsAction,
|
|
|
|
|
|
NewsItem,
|
|
|
|
|
|
NewsSource
|
|
|
|
|
|
)
|
2026-04-25 18:47:09 +08:00
|
|
|
|
from .api_client import news_api
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_intent(state: NewsAnalysisState) -> NewsAnalysisState:
|
|
|
|
|
|
"""
|
|
|
|
|
|
解析用户意图节点
|
|
|
|
|
|
确定用户想做什么操作
|
|
|
|
|
|
"""
|
|
|
|
|
|
state.current_phase = "intent_parsing"
|
|
|
|
|
|
|
|
|
|
|
|
query_lower = state.user_query.lower()
|
|
|
|
|
|
|
|
|
|
|
|
# 简单的关键词匹配
|
|
|
|
|
|
if any(keyword in query_lower for keyword in ["资讯", "新闻", "news", "report"]):
|
|
|
|
|
|
state.action = NewsAction.QUERY_NEWS
|
|
|
|
|
|
|
|
|
|
|
|
elif any(keyword in query_lower for keyword in ["分析", "analyze", "url", "链接"]):
|
|
|
|
|
|
state.action = NewsAction.ANALYZE_URL
|
|
|
|
|
|
|
|
|
|
|
|
elif any(keyword in query_lower for keyword in ["关键词", "keyword", "提取"]):
|
|
|
|
|
|
state.action = NewsAction.EXTRACT_KEYWORDS
|
|
|
|
|
|
|
|
|
|
|
|
elif any(keyword in query_lower for keyword in ["报告", "生成", "generate"]):
|
|
|
|
|
|
state.action = NewsAction.GENERATE_REPORT
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
# 默认查询资讯
|
|
|
|
|
|
state.action = NewsAction.QUERY_NEWS
|
|
|
|
|
|
|
|
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def query_news(state: NewsAnalysisState) -> NewsAnalysisState:
|
|
|
|
|
|
"""
|
|
|
|
|
|
查询资讯节点
|
|
|
|
|
|
"""
|
|
|
|
|
|
state.current_phase = "querying_news"
|
|
|
|
|
|
|
|
|
|
|
|
query = state.user_query
|
|
|
|
|
|
|
2026-04-25 18:47:09 +08:00
|
|
|
|
# 使用API客户端查询资讯
|
|
|
|
|
|
news_data = news_api.query_news_mock(query)
|
|
|
|
|
|
|
|
|
|
|
|
# 转换为NewsItem对象
|
|
|
|
|
|
for news in news_data:
|
|
|
|
|
|
state.news_items.append(
|
|
|
|
|
|
NewsItem(
|
|
|
|
|
|
title=news.get("title", ""),
|
|
|
|
|
|
source=news.get("source", ""),
|
|
|
|
|
|
summary=news.get("summary", ""),
|
|
|
|
|
|
keywords=news.get("keywords", []),
|
|
|
|
|
|
author=news.get("author", ""),
|
|
|
|
|
|
published_at=news.get("published_at", None)
|
|
|
|
|
|
)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
state.success = True
|
|
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def analyze_url(state: NewsAnalysisState) -> NewsAnalysisState:
|
|
|
|
|
|
"""
|
|
|
|
|
|
分析资讯URL节点
|
|
|
|
|
|
"""
|
|
|
|
|
|
state.current_phase = "analyzing_url"
|
|
|
|
|
|
|
|
|
|
|
|
urls = state.custom_urls or [state.action_params.get("url", "")]
|
|
|
|
|
|
|
2026-04-25 18:47:09 +08:00
|
|
|
|
# 使用API客户端分析URL
|
2026-04-25 18:29:23 +08:00
|
|
|
|
for url in urls:
|
|
|
|
|
|
if url:
|
2026-04-25 18:47:09 +08:00
|
|
|
|
result = news_api.analyze_url_mock(url)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
state.news_items.append(
|
|
|
|
|
|
NewsItem(
|
2026-04-25 18:47:09 +08:00
|
|
|
|
title=result.get("title", ""),
|
|
|
|
|
|
source=result.get("source", ""),
|
|
|
|
|
|
summary=result.get("summary", ""),
|
|
|
|
|
|
keywords=result.get("keywords", [])
|
2026-04-25 18:29:23 +08:00
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
state.success = True
|
|
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def extract_keywords(state: NewsAnalysisState) -> NewsAnalysisState:
|
|
|
|
|
|
"""
|
|
|
|
|
|
提取关键词节点
|
|
|
|
|
|
"""
|
|
|
|
|
|
state.current_phase = "extracting_keywords"
|
|
|
|
|
|
|
|
|
|
|
|
text = state.user_query
|
|
|
|
|
|
|
2026-04-25 18:47:09 +08:00
|
|
|
|
# 使用API客户端提取关键词
|
|
|
|
|
|
state.extracted_keywords = news_api.extract_keywords_mock(text)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
|
|
|
|
|
state.success = True
|
|
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_report(state: NewsAnalysisState) -> NewsAnalysisState:
|
|
|
|
|
|
"""
|
|
|
|
|
|
生成报告节点
|
|
|
|
|
|
"""
|
|
|
|
|
|
state.current_phase = "generating_report"
|
|
|
|
|
|
|
|
|
|
|
|
query = state.user_query
|
|
|
|
|
|
|
2026-04-25 18:47:09 +08:00
|
|
|
|
# 使用API客户端生成报告
|
|
|
|
|
|
state.report_content = news_api.generate_report_mock(query)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
|
|
|
|
|
state.success = True
|
|
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def format_result(state: NewsAnalysisState) -> NewsAnalysisState:
|
|
|
|
|
|
"""
|
2026-04-25 18:47:09 +08:00
|
|
|
|
格式化结果节点 - 精美展示
|
2026-04-25 18:29:23 +08:00
|
|
|
|
"""
|
|
|
|
|
|
state.current_phase = "formatting"
|
|
|
|
|
|
|
|
|
|
|
|
if state.action == NewsAction.QUERY_NEWS and state.news_items:
|
2026-04-25 18:47:09 +08:00
|
|
|
|
result = []
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
result.append("📰 最新资讯")
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
result.append("")
|
|
|
|
|
|
|
2026-04-25 18:29:23 +08:00
|
|
|
|
for i, item in enumerate(state.news_items, 1):
|
2026-04-25 18:47:09 +08:00
|
|
|
|
result.append(f"{i}. {item.title}")
|
|
|
|
|
|
result.append(f" 来源:{item.source}")
|
|
|
|
|
|
result.append(f" 摘要:{item.summary}")
|
|
|
|
|
|
if item.keywords:
|
|
|
|
|
|
result.append(f" 🏷️ 关键词:{', '.join(item.keywords)}")
|
|
|
|
|
|
result.append("")
|
|
|
|
|
|
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
result.append("💡 提示:点击资讯查看详情,或生成分析报告")
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
2026-04-25 18:47:09 +08:00
|
|
|
|
state.final_result = "\n".join(result)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
|
|
|
|
|
elif state.action == NewsAction.ANALYZE_URL and state.news_items:
|
2026-04-25 18:47:09 +08:00
|
|
|
|
result = []
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
result.append("🔍 资讯分析结果")
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
result.append("")
|
|
|
|
|
|
|
2026-04-25 18:29:23 +08:00
|
|
|
|
for i, item in enumerate(state.news_items, 1):
|
2026-04-25 18:47:09 +08:00
|
|
|
|
result.append(f"{i}. {item.title}")
|
|
|
|
|
|
result.append(f" {item.summary}")
|
|
|
|
|
|
if item.keywords:
|
|
|
|
|
|
result.append(f" 🏷️ 关键词:{', '.join(item.keywords)}")
|
|
|
|
|
|
result.append("")
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
2026-04-25 18:47:09 +08:00
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
|
|
|
|
|
|
state.final_result = "\n".join(result)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
|
|
|
|
|
elif state.action == NewsAction.EXTRACT_KEYWORDS and state.extracted_keywords:
|
2026-04-25 18:47:09 +08:00
|
|
|
|
result = []
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
result.append("🏷️ 提取的关键词")
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
result.append("")
|
|
|
|
|
|
result.append(" " + ", ".join(state.extracted_keywords))
|
|
|
|
|
|
result.append("")
|
|
|
|
|
|
result.append("═══════════════════════════════════════════")
|
|
|
|
|
|
|
|
|
|
|
|
state.final_result = "\n".join(result)
|
2026-04-25 18:29:23 +08:00
|
|
|
|
|
|
|
|
|
|
elif state.action == NewsAction.GENERATE_REPORT and state.report_content:
|
|
|
|
|
|
state.final_result = state.report_content
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
if not state.final_result:
|
|
|
|
|
|
state.final_result = "资讯操作完成"
|
|
|
|
|
|
|
|
|
|
|
|
state.current_phase = "done"
|
|
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def should_continue(state: NewsAnalysisState) -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
条件路由:决定下一步该做什么
|
|
|
|
|
|
"""
|
|
|
|
|
|
if state.error_message:
|
|
|
|
|
|
return "format_result"
|
|
|
|
|
|
|
|
|
|
|
|
# 根据action路由
|
|
|
|
|
|
if state.action == NewsAction.NONE:
|
|
|
|
|
|
return "parse_intent"
|
|
|
|
|
|
elif state.action == NewsAction.QUERY_NEWS:
|
|
|
|
|
|
return "query_news"
|
|
|
|
|
|
elif state.action == NewsAction.ANALYZE_URL:
|
|
|
|
|
|
return "analyze_url"
|
|
|
|
|
|
elif state.action == NewsAction.EXTRACT_KEYWORDS:
|
|
|
|
|
|
return "extract_keywords"
|
|
|
|
|
|
elif state.action == NewsAction.GENERATE_REPORT:
|
|
|
|
|
|
return "generate_report"
|
|
|
|
|
|
else:
|
|
|
|
|
|
return "format_result"
|