增加大模型
This commit is contained in:
+16
-4
@@ -18,7 +18,7 @@ from .llm_service import get_interpret_state, run_interpretation_batch
|
||||
from .scheduler import job_finalize_yesterday, job_push_wecom, job_refresh_today, start_scheduler, startup_tasks, stop_scheduler
|
||||
from .stats import compute_three_day_stats
|
||||
from .aggregator import aggregate_period
|
||||
from .wecom import build_markdown, send_wecom_markdown
|
||||
from .wecom import build_markdown, build_push_payload, send_wecom_markdown
|
||||
from .state import get_today_cache
|
||||
|
||||
logging.basicConfig(
|
||||
@@ -93,8 +93,17 @@ async def api_stats_three_day():
|
||||
return compute_three_day_stats()
|
||||
|
||||
|
||||
@app.get("/api/push/preview")
|
||||
async def api_push_preview():
|
||||
"""预览企微推送内容(三日交集,列表排版)。"""
|
||||
return build_push_payload()
|
||||
|
||||
|
||||
@app.post("/api/push/test")
|
||||
async def api_push_test():
|
||||
payload = build_push_payload()
|
||||
if not payload.get("ok"):
|
||||
raise HTTPException(400, payload.get("message") or "三日交集数据未就绪")
|
||||
snap = get_latest_snapshot("yesterday")
|
||||
if not snap:
|
||||
start, end = get_yesterday_period()
|
||||
@@ -104,12 +113,15 @@ async def api_push_test():
|
||||
snap = get_latest_snapshot("yesterday")
|
||||
if not snap:
|
||||
raise HTTPException(500, "无法生成昨日数据")
|
||||
content = build_markdown(snap)
|
||||
ok, msg = await send_wecom_markdown(content)
|
||||
ok, msg = await send_wecom_markdown(payload["markdown"])
|
||||
log_push(snap["period_start"], snap["period_end"], ok, msg)
|
||||
if not ok:
|
||||
raise HTTPException(500, f"推送失败: {msg}")
|
||||
return {"success": True, "message": "推送成功"}
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"已推送 {payload.get('count', 0)} 个三日交集币种",
|
||||
"count": payload.get("count", 0),
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/refresh/yesterday")
|
||||
|
||||
@@ -15,7 +15,7 @@ from .funding_store import prefetch_funding
|
||||
from .kline_store import prefetch_symbols
|
||||
from .llm_service import run_interpretation_batch, schedule_interpret_background
|
||||
from .stats import compute_three_day_stats
|
||||
from .wecom import build_markdown, send_wecom_markdown
|
||||
from .wecom import build_push_payload, send_wecom_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -84,7 +84,11 @@ async def job_finalize_yesterday() -> None:
|
||||
|
||||
|
||||
async def job_push_wecom() -> None:
|
||||
logger.info("Job: WeCom push")
|
||||
logger.info("Job: WeCom push (three-day intersection)")
|
||||
try:
|
||||
await job_refresh_today()
|
||||
except Exception as e:
|
||||
logger.warning("Pre-push today refresh failed: %s", e)
|
||||
start, end = get_yesterday_period()
|
||||
snapshot = get_latest_snapshot("yesterday")
|
||||
if not snapshot and not binance_client.is_rate_limited():
|
||||
@@ -106,8 +110,11 @@ async def job_push_wecom() -> None:
|
||||
logger.info("Already pushed for period %s ~ %s", ps, pe)
|
||||
return
|
||||
|
||||
content = build_markdown(snapshot)
|
||||
ok, msg = await send_wecom_markdown(content)
|
||||
payload = build_push_payload()
|
||||
if not payload.get("ok"):
|
||||
logger.warning("WeCom push skipped: %s", payload.get("message"))
|
||||
return
|
||||
ok, msg = await send_wecom_markdown(payload["markdown"])
|
||||
log_push(ps, pe, ok, msg)
|
||||
if ok:
|
||||
logger.info("WeCom push succeeded")
|
||||
|
||||
+91
-29
@@ -1,9 +1,11 @@
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
from .config import settings
|
||||
from .http_client import httpx_client_kwargs
|
||||
from .stats import compute_three_day_stats
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -14,36 +16,96 @@ def _format_period_label(period_start: str, period_end: str) -> str:
|
||||
return f"{start} ~ {end}"
|
||||
|
||||
|
||||
def build_markdown(snapshot: dict) -> str:
|
||||
items = snapshot.get("items", [])
|
||||
period_label = _format_period_label(
|
||||
snapshot.get("period_start", ""),
|
||||
snapshot.get("period_end", ""),
|
||||
)
|
||||
lines = [
|
||||
"## 币安 U本位合约 成交额 Top30",
|
||||
f"> 统计周期(北京时间 8:00 切日)",
|
||||
f"> **{period_label}**",
|
||||
"",
|
||||
"| 排名 | 合约 | 成交额(USDT) | 涨跌幅 | 资金费率 | 标记 |",
|
||||
"| --- | --- | --- | --- | --- | --- |",
|
||||
]
|
||||
for row in items:
|
||||
tags = []
|
||||
if row.get("is_high_volume"):
|
||||
tags.append("千万+")
|
||||
if row.get("is_high_change"):
|
||||
tags.append("涨跌5%+")
|
||||
tag_str = " ".join(tags) if tags else "-"
|
||||
vol = row.get("quote_volume_fmt") or f"{row.get('quote_volume', 0):.0f}"
|
||||
pct = row.get("price_change_pct_fmt") or f"{row.get('price_change_pct', 0):+.2f}%"
|
||||
fr = row.get("funding_rate_fmt") or "-"
|
||||
lines.append(
|
||||
f"| {row['rank']} | {row['symbol']} | {vol} | {pct} | {fr} | {tag_str} |"
|
||||
def _day_line(label: str, row: dict | None) -> str:
|
||||
if not row or row.get("rank") is None:
|
||||
return f"> {label}:—"
|
||||
pct = row.get("price_change_pct_fmt") or f"{row.get('price_change_pct', 0):+.2f}%"
|
||||
vol = row.get("quote_volume_fmt") or str(row.get("quote_volume", ""))
|
||||
fr = row.get("funding_rate_fmt") or "—"
|
||||
return f"> {label}:#{row['rank']} · 额 {vol} · 涨跌 {pct} · 费率 {fr}"
|
||||
|
||||
|
||||
def build_push_payload() -> dict[str, Any]:
|
||||
"""构建企微推送内容:仅三日 Top30 交集,列表排版(非表格)。"""
|
||||
stats = compute_three_day_stats()
|
||||
periods = stats.get("periods") or {}
|
||||
y_meta = periods.get("yesterday") or {}
|
||||
period_label = ""
|
||||
if y_meta.get("ready"):
|
||||
period_label = _format_period_label(
|
||||
y_meta.get("period_start", ""),
|
||||
y_meta.get("period_end", ""),
|
||||
)
|
||||
lines.append("")
|
||||
lines.append("> 标记说明:千万+ = 成交额≥1000万 USDT;涨跌5%+ = |涨跌幅|≥5%")
|
||||
return "\n".join(lines)
|
||||
|
||||
if not stats.get("ok"):
|
||||
md = "\n".join(
|
||||
[
|
||||
"## 币安 U本位 · 三日Top30交集",
|
||||
"",
|
||||
f"> 昨日周期 {period_label or '—'}",
|
||||
"",
|
||||
f"**暂无法推送**:{stats.get('message', '数据未就绪')}",
|
||||
]
|
||||
)
|
||||
return {
|
||||
"ok": False,
|
||||
"message": stats.get("message", ""),
|
||||
"count": 0,
|
||||
"period_label": period_label,
|
||||
"markdown": md,
|
||||
"items": [],
|
||||
}
|
||||
|
||||
items = stats.get("items") or []
|
||||
lines = [
|
||||
"## 币安 U本位 · 三日Top30交集",
|
||||
"",
|
||||
f"> **昨日周期**(北京时间 8:00 切日)",
|
||||
f"> {period_label}",
|
||||
f"> 连续三日成交额均为 Top{settings.top_n},共 **{len(items)}** 个",
|
||||
"",
|
||||
]
|
||||
|
||||
preview_items: list[dict] = []
|
||||
for i, row in enumerate(items, 1):
|
||||
sym = row["symbol"]
|
||||
t, y, b = row.get("today"), row.get("yesterday"), row.get("daybefore")
|
||||
lines.append(f"### {i}. {sym}")
|
||||
lines.append(_day_line("昨日", y))
|
||||
lines.append(_day_line("今日", t))
|
||||
lines.append(_day_line("前日", b))
|
||||
lines.append("")
|
||||
preview_items.append(
|
||||
{
|
||||
"rank": i,
|
||||
"symbol": sym,
|
||||
"today": t,
|
||||
"yesterday": y,
|
||||
"daybefore": b,
|
||||
"total_quote_volume": row.get("total_quote_volume"),
|
||||
}
|
||||
)
|
||||
|
||||
if not items:
|
||||
lines.append("**暂无交集币种**(请确认今日/昨日/前日快照均已生成)")
|
||||
|
||||
lines.append("---")
|
||||
lines.append("> 说明:仅推送三日均为成交额 Top30 的合约;涨跌不限")
|
||||
|
||||
return {
|
||||
"ok": True,
|
||||
"message": stats.get("criteria", ""),
|
||||
"count": len(items),
|
||||
"period_label": period_label,
|
||||
"markdown": "\n".join(lines),
|
||||
"items": preview_items,
|
||||
}
|
||||
|
||||
|
||||
def build_markdown(snapshot: dict | None = None) -> str:
|
||||
"""兼容旧调用:返回企微 Markdown 文本(忽略 snapshot,以三日交集为准)。"""
|
||||
_ = snapshot
|
||||
return build_push_payload()["markdown"]
|
||||
|
||||
|
||||
async def send_wecom_markdown(content: str) -> tuple[bool, str]:
|
||||
|
||||
Reference in New Issue
Block a user