Files
trumpsignal-backend/scripts/backfill_prefilter.py
T
2026-04-21 19:33:24 +08:00

73 lines
2.2 KiB
Python

"""
Zero-token backfill:
- Mark old posts with prefilter_reason (rt_only / url_only / empty) where applicable
- Fill ai_reasoning for posts that have a signal but empty reasoning
- Stamp analysis_version='legacy' on anything still missing it
Run once after the schema migration. Safe to re-run.
"""
from __future__ import annotations
import asyncio
import os
import sys
from typing import Optional
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from sqlalchemy import select
from app.database import AsyncSessionLocal
from app.models import Post
def classify(text: str) -> Optional[str]:
stripped = (text or "").strip()
if not stripped:
return "empty"
if stripped.startswith("RT: https://") and len(stripped) < 60:
return "rt_only"
if stripped.startswith("https://") and " " not in stripped:
return "url_only"
return None
PREFILTER_MSG = {
"rt_only": "Pre-filtered: retweet with no added commentary.",
"url_only": "Pre-filtered: bare URL with no text content.",
"empty": "Pre-filtered: empty post body.",
}
async def main():
async with AsyncSessionLocal() as db:
posts = (await db.execute(select(Post))).scalars().all()
pre = ai_fix = ver = 0
for p in posts:
reason = classify(p.text)
if reason and not p.prefilter_reason:
p.prefilter_reason = reason
if not p.ai_reasoning:
p.ai_reasoning = PREFILTER_MSG[reason]
ai_fix += 1
pre += 1
# Any remaining signal'd post with empty reasoning: fill a minimal note
if p.signal and not p.ai_reasoning:
p.ai_reasoning = "(legacy) reasoning not recorded for this post."
ai_fix += 1
if not p.analysis_version:
p.analysis_version = "legacy"
ver += 1
await db.commit()
print(f"✅ prefilter_reason set on {pre} posts")
print(f"✅ ai_reasoning filled on {ai_fix} posts")
print(f"✅ analysis_version stamped 'legacy' on {ver} posts")
if __name__ == "__main__":
asyncio.run(main())