Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

203 lines
5.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TradingAgents/publish/wechat_publisher.py
"""
将 TradingAgents 的股票分析结果发布到微信公众号和个人博客。
依赖:baoyu-post-to-wechat 技能(位于 workspace/skills/baoyu-post-to-wechat)
"""
import os
import sys
import logging
from pathlib import Path
from typing import Dict, Any, Optional
logger = logging.getLogger(__name__)
# 技能路径(与 baoyu-post-to-wechat 在同一目录)
_SKILL_DIR = "/home/ubuntu/.nanobot/workspace/skills/baoyu-post-to-wechat"
def _build_markdown(final_state: Dict[str, Any], ticker: str, trade_date) -> str:
"""将 final_state 组装成完整 Markdown 文章。"""
date_str = trade_date if isinstance(trade_date, str) else str(trade_date)
title = f"【{ticker}】股票分析报告 - {date_str}"
lines = [
"---",
f"title: {title}",
f"date: {date_str}",
f"author: TradingAgents",
"---",
"",
f"# {title}",
"",
"## 📊 市场分析报告",
"",
final_state.get("market_report", "暂无"),
"",
"## 💬 情绪分析报告",
"",
final_state.get("sentiment_report", "暂无"),
"",
"## 📰 新闻分析报告",
"",
final_state.get("news_report", "暂无"),
"",
"## 📈 基本面分析报告",
"",
final_state.get("fundamentals_report", "暂无"),
"",
]
def _append_history(items):
"""兼容 list 和 str 类型,避免逐字符遍历字符串。
注意:debate 内容本身可能就是带 Markdown 格式的大段文章
(含标题、列表等),如果强行加 '- ' 前缀会破坏内部结构,
导致 '###' 子标题被当作列表项文本而失效。
因此直接输出原始段落,不再套一层无序列表。
"""
if isinstance(items, list):
for msg in items:
lines.append(str(msg))
lines.append("") # 段间空行,保持可读性
elif isinstance(items, str):
if items.strip():
lines.append(items.strip())
# 其他类型忽略
# 多空辩论
debate = final_state.get("investment_debate_state", {})
bull = debate.get("bull_history", [])
bear = debate.get("bear_history", [])
judge = debate.get("judge_decision", "")
lines.extend([
"## ⚖️ 多空辩论",
"",
"### 多头观点",
"",
])
_append_history(bull)
lines.extend([
"",
"### 空头观点",
"",
])
_append_history(bear)
lines.extend([
"",
"### 裁判决策",
"",
judge if judge else "暂无",
"",
])
# 风险辩论
risk = final_state.get("risk_debate_state", {})
agg = risk.get("aggressive_history", [])
cons = risk.get("conservative_history", [])
neut = risk.get("neutral_history", [])
risk_judge = risk.get("judge_decision", "")
lines.extend([
"## 🛡️ 风险辩论",
"",
"### 激进观点",
"",
])
_append_history(agg)
lines.extend([
"",
"### 保守观点",
"",
])
_append_history(cons)
lines.extend([
"",
"### 中性观点",
"",
])
_append_history(neut)
lines.extend([
"",
"### 裁判决策",
"",
risk_judge if risk_judge else "暂无",
"",
])
# 投资计划与最终决策
lines.extend([
"## 📋 投资计划",
"",
final_state.get("investment_plan", "暂无"),
"",
"## 🎯 最终交易决策",
"",
final_state.get("final_trade_decision", "暂无"),
"",
])
return "\n".join(lines)
def publish_analysis_result(
final_state: Dict[str, Any],
ticker: str,
trade_date,
results_dir: Optional[str] = None,
) -> Dict[str, Any]:
"""
将股票分析结果发布到微信公众号和个人博客。
Args:
final_state: 图执行后的最终状态字典。
ticker: 股票代码/公司名称。
trade_date: 交易日期。
results_dir: 结果保存目录,默认使用 ~/TradingAgents/results。
Returns:
{"success": bool, ...} 发布结果字典。
"""
try:
date_str = trade_date if isinstance(trade_date, str) else str(trade_date)
safe_ticker = ticker.replace("/", "_").replace("\\", "_")
# 1. 组装 Markdown
markdown_content = _build_markdown(final_state, ticker, trade_date)
# 2. 保存到结果目录
if results_dir is None:
results_dir = os.path.join(os.path.expanduser("~"), "TradingAgents", "results")
publish_dir = Path(results_dir) / safe_ticker / "published"
publish_dir.mkdir(parents=True, exist_ok=True)
md_path = publish_dir / f"analysis_{date_str}.md"
with open(md_path, "w", encoding="utf-8") as f:
f.write(markdown_content)
logger.info("Markdown report saved: %s", md_path)
print(f"📄 Markdown report saved: {md_path}")
# 3. 导入并调用 baoyu-post-to-wechat
if _SKILL_DIR not in sys.path:
sys.path.insert(0, _SKILL_DIR)
from baoyu_optimized import WeChatPublisher
publisher = WeChatPublisher()
result = publisher.publish_markdown_with_images(
markdown_path=str(md_path),
title=f"【{ticker}】股票分析报告 - {date_str}",
author="TradingAgents",
)
return result
except Exception as e:
logger.exception("Failed to publish analysis result to WeChat")
print(f"⚠️ 发布到公众号失败: {e}")
return {"success": False, "error": str(e)}