"""Синхронизировать тексты pn_*-записей с data/panels.json. Панель переотдаёт тот же url, поэтому store писал её один раз и число бесплатных моделей в выдаче застывало. Скрипт переписывает title/text/score по актуальному free_count (строгое правило: prompt и completion = 0). Запуск: python tools/sync_panel_items.py [--dry] """ from __future__ import annotations import argparse import json import sqlite3 import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def plural(n: int) -> str: if n % 10 == 1 and n % 100 != 11: return "модель" if n % 10 in (2, 3, 4) and n % 100 not in (12, 13, 14): return "модели" return "моделей" def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--dry", action="store_true") a = ap.parse_args() rows = json.load((ROOT / "data" / "panels.json").open(encoding="utf-8"))["panels"] by = {} for x in rows: host = str(x.get("host") or "").strip() if not host: continue by["pn_" + host.replace(".", "_").replace("-", "_")] = ( host, int(x.get("free_count") or 0), int(x.get("models") or 0), x.get("free") or []) c = sqlite3.connect(str(ROOT / "data" / "omni.sqlite3")) c.execute("PRAGMA busy_timeout=60000") n = 0 for src, (host, free, total, names) in by.items(): item = c.execute("SELECT id FROM items WHERE source=? LIMIT 1", (src,)).fetchone() if not item: continue title = "%s: %d бесплатных %s из %d" % (host, free, plural(free), total) text = title + ("\n" + ", ".join(str(x) for x in names[:12]) if names else "") if a.dry: n += 1 continue c.execute("UPDATE items SET title=?, text=? WHERE id=?", (title, text, item[0])) c.execute("UPDATE items_fts SET title=?, text=? WHERE rowid=?", (title, text, item[0])) c.execute("UPDATE abuse_idx SET score=? WHERE id=?", (70 + min(free // 3, 110), item[0])) n += 1 if not a.dry: c.commit() print("синхронизировано панелей:", n, "| с free:", sum(1 for v in by.values() if v[1] > 0)) return 0 if __name__ == "__main__": sys.exit(main())