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