fix: mo_bridge news fallback to akshare + market review cache-only in cron
This commit is contained in:
+57
-37
@@ -83,7 +83,7 @@ def _ensure_dsa_config():
|
|||||||
# ── 1. 新闻搜索 ─────────────────────────────────────────────────────
|
# ── 1. 新闻搜索 ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
def get_stock_news(stock_code: str, stock_name: str = "", max_results: int = 5) -> str:
|
def get_stock_news(stock_code: str, stock_name: str = "", max_results: int = 5) -> str:
|
||||||
"""通过 DSA 的 7 个搜索引擎获取股票相关新闻。
|
"""获取股票相关新闻。优先 DSA 搜索引擎,失败则 fallback 到东方财富 akshare。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
stock_code: 股票代码 (如 '600519', '00700', 'AAPL')
|
stock_code: 股票代码 (如 '600519', '00700', 'AAPL')
|
||||||
@@ -93,48 +93,64 @@ def get_stock_news(stock_code: str, stock_name: str = "", max_results: int = 5)
|
|||||||
Returns:
|
Returns:
|
||||||
str: Markdown 格式新闻摘要,可直接注入分析 prompt。失败时返回 ''。
|
str: Markdown 格式新闻摘要,可直接注入分析 prompt。失败时返回 ''。
|
||||||
"""
|
"""
|
||||||
|
lines = [f"## 📰 {stock_name or stock_code} 最新情报"]
|
||||||
|
got_any = False
|
||||||
|
|
||||||
|
# 主通道: DSA SearchService(7 个搜索引擎,需要 API Key)
|
||||||
service = _ensure_dsa_search()
|
service = _ensure_dsa_search()
|
||||||
if not service:
|
if service:
|
||||||
return ""
|
try:
|
||||||
|
intel = service.search_comprehensive_intel(
|
||||||
|
stock_code, stock_name or stock_code, max_searches=2
|
||||||
|
)
|
||||||
|
if intel:
|
||||||
|
news = intel.get("latest_news")
|
||||||
|
if news and news.results:
|
||||||
|
lines.append("\n### 最新新闻")
|
||||||
|
for r in news.results[:max_results]:
|
||||||
|
date_str = f" ({r.published_date})" if r.published_date else ""
|
||||||
|
snippet = r.snippet[:150] if r.snippet else ""
|
||||||
|
lines.append(f"- **{r.title}**{date_str}: {snippet}")
|
||||||
|
got_any = True
|
||||||
|
|
||||||
|
risk = intel.get("risk_check")
|
||||||
|
if risk and risk.results:
|
||||||
|
lines.append("\n### ⚠️ 风险关注")
|
||||||
|
for r in risk.results[:3]:
|
||||||
|
lines.append(f"- {r.title}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug("DSA 搜索失败: %s", e)
|
||||||
|
|
||||||
try:
|
# Fallback: 东方财富 akshare(免费,国内直连,无需 API Key)
|
||||||
intel = service.search_comprehensive_intel(
|
if not got_any:
|
||||||
stock_code, stock_name or stock_code, max_searches=3
|
try:
|
||||||
)
|
import sys, os
|
||||||
if not intel:
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
return ""
|
from mofin_news import search_akshare_news
|
||||||
|
articles = search_akshare_news(stock_code, max_results)
|
||||||
lines = [f"## 📰 {stock_name or stock_code} 最新情报"]
|
if articles:
|
||||||
|
lines.append("\n### 最新新闻 (东方财富)")
|
||||||
news = intel.get("latest_news")
|
for a in articles:
|
||||||
if news and news.results:
|
snippet = a.get('content', '')[:120] if a.get('content') else ''
|
||||||
lines.append("\n### 最新新闻")
|
lines.append(f"- **{a.get('title', '')}**: {snippet}")
|
||||||
for r in news.results[:max_results]:
|
got_any = True
|
||||||
date_str = f" ({r.published_date})" if r.published_date else ""
|
except Exception as e:
|
||||||
snippet = r.snippet[:150] if r.snippet else ""
|
logger.debug("akshare 新闻 fallback 失败: %s", e)
|
||||||
lines.append(f"- **{r.title}**{date_str}: {snippet}")
|
|
||||||
|
|
||||||
risk = intel.get("risk_check")
|
|
||||||
if risk and risk.results:
|
|
||||||
lines.append("\n### ⚠️ 风险关注")
|
|
||||||
for r in risk.results[:3]:
|
|
||||||
lines.append(f"- {r.title}: {r.snippet[:100] if r.snippet else ''}")
|
|
||||||
|
|
||||||
return "\n".join(lines)
|
|
||||||
|
|
||||||
except Exception as e:
|
return "\n".join(lines) if got_any else ""
|
||||||
logger.warning("DSA 新闻搜索失败: %s", e)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
# ── 2. 大盘复盘 ─────────────────────────────────────────────────────
|
# ── 2. 大盘复盘 ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
def get_market_review(region: str = "cn") -> str:
|
def get_market_review(region: str = "cn", force_refresh: bool = False) -> str:
|
||||||
"""获取 DSA 的大盘复盘报告。
|
"""获取 DSA 的大盘复盘报告。
|
||||||
优先读本地缓存(24h内),没有则调用 DSA 实时生成。
|
|
||||||
|
cron 场景:默认只读缓存(快,不阻塞)。每天第一次调用时 DSA 可能已经生成了缓存。
|
||||||
|
手动场景:force_refresh=True 实时调用 DSA 生成(慢,5-10秒)。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
region: 'cn'=A股, 'hk'=港股, 'us'=美股, 'both'=全市场
|
region: 'cn'=A股, 'hk'=港股, 'us'=美股
|
||||||
|
force_refresh: 是否强制实时生成(默认 False,只读缓存)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Markdown 格式大盘复盘摘要
|
str: Markdown 格式大盘复盘摘要
|
||||||
@@ -142,7 +158,7 @@ def get_market_review(region: str = "cn") -> str:
|
|||||||
if not _HAS_DSA:
|
if not _HAS_DSA:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
# 先读缓存
|
# 先读缓存(优先,快)
|
||||||
cache_dir = Path(str(_DSA_BASE)) / "data" / "market_review"
|
cache_dir = Path(str(_DSA_BASE)) / "data" / "market_review"
|
||||||
if cache_dir.exists():
|
if cache_dir.exists():
|
||||||
try:
|
try:
|
||||||
@@ -155,7 +171,11 @@ def get_market_review(region: str = "cn") -> str:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# 实时调用 DSA
|
# cron 场景不走实时(太慢),直接返回空
|
||||||
|
if not force_refresh:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# 手动场景:实时调用 DSA(慢,需要 LLM)
|
||||||
try:
|
try:
|
||||||
from src.core.market_review import run_market_review
|
from src.core.market_review import run_market_review
|
||||||
|
|
||||||
@@ -168,14 +188,14 @@ def get_market_review(region: str = "cn") -> str:
|
|||||||
result = run_market_review(
|
result = run_market_review(
|
||||||
notifier=StubNotifier(), config=config,
|
notifier=StubNotifier(), config=config,
|
||||||
override_region=region, send_notification=False,
|
override_region=region, send_notification=False,
|
||||||
save_report_file=False, persist_history=False,
|
save_report_file=True, persist_history=True,
|
||||||
trigger_source="mofin",
|
trigger_source="mofin",
|
||||||
)
|
)
|
||||||
if result and isinstance(result, str):
|
if result and isinstance(result, str):
|
||||||
lines = [l for l in result.split("\n")[:25] if len(l.strip()) > 3]
|
lines = [l for l in result.split("\n")[:25] if len(l.strip()) > 3]
|
||||||
return "## 📈 今日大盘复盘\n" + "\n".join(lines)
|
return "## 📈 今日大盘复盘\n" + "\n".join(lines)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("DSA 大盘复盘失败: %s", e)
|
logger.warning("DSA 大盘复盘生成失败: %s", e)
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user