This commit is contained in:
k
2026-04-21 19:33:24 +08:00
parent 9a72566753
commit 3268080401
26 changed files with 1816 additions and 318 deletions
+86
View File
@@ -0,0 +1,86 @@
"""
把 AI 信号写回数据库。
跳过纯RT/URL帖子和已有signal的帖子。
并发执行提速,自动限速避免API超限。
用法: python scripts/backfill_signals.py [--limit 500] [--overwrite]
"""
import asyncio
import argparse
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app.services.analysis import analyze_post
from app.database import AsyncSessionLocal
from app.models import Post
from sqlalchemy import select
CONCURRENCY = 5 # 并发数,避免触发API限速
async def process_one(post: Post, semaphore: asyncio.Semaphore, overwrite: bool) -> str:
"""分析单条帖子并写回DB,返回状态字符串"""
if not overwrite and post.signal is not None:
return "skip"
async with semaphore:
analysis = await analyze_post(post.text)
await asyncio.sleep(0.1) # 轻度限速
async with AsyncSessionLocal() as db:
result = await db.execute(select(Post).where(Post.id == post.id))
p = result.scalar_one_or_none()
if p:
p.sentiment = analysis["sentiment"]
p.signal = analysis["signal"]
p.ai_confidence = analysis["confidence"]
p.ai_reasoning = analysis["reasoning"]
p.relevant = analysis["relevant"]
p.prefilter_reason = analysis.get("prefilter_reason")
p.analysis_version = analysis.get("analysis_version")
if analysis["relevant"] and analysis["asset"] and not p.price_impact_asset:
p.price_impact_asset = analysis["asset"]
await db.commit()
sig = analysis["signal"]
return f"{sig}:{analysis['confidence']}%"
async def main(limit: int, overwrite: bool):
async with AsyncSessionLocal() as db:
result = await db.execute(
select(Post).order_by(Post.published_at.desc()).limit(limit)
)
posts = result.scalars().all()
total = len(posts)
print(f"{total} 条帖子,并发={CONCURRENCY}overwrite={overwrite}\n")
semaphore = asyncio.Semaphore(CONCURRENCY)
tasks = [process_one(p, semaphore, overwrite) for p in posts]
done = 0
buy = short = sell = hold = skipped = 0
for coro in asyncio.as_completed(tasks):
status = await coro
done += 1
if status == "skip":
skipped += 1
elif status.startswith("buy"): buy += 1
elif status.startswith("short"): short += 1
elif status.startswith("sell"): sell += 1
else: hold += 1
if done % 20 == 0 or done == total:
print(f" 进度 {done}/{total} | BUY={buy} SHORT={short} SELL={sell} HOLD={hold} SKIP={skipped}")
print(f"\n✅ 完成: BUY={buy} SHORT={short} SELL={sell} HOLD={hold} SKIP={skipped}")
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("--limit", type=int, default=400)
ap.add_argument("--overwrite", action="store_true", help="重新分析已有signal的帖子")
args = ap.parse_args()
asyncio.run(main(args.limit, args.overwrite))