Tabele per urzadzenie (migracja 0037): clip_seen (wykluczenie, wiersz przy
podaniu klipu), clip_feed_events (append-only: impression z dwell, skip,
complete, like, unlike, not_interested, autoswipe), clip_affinity (wagi
tag/nisza/tworca w JSONB), clip_favorites, clip_blacklist. GIN na clips.niches.
GET /clips/feed: kursor base64 {seed, pk, page} zamiast offsetu; 80% z puli
afinicznosci (skany po tagu/niszy/tworcy od losowego uuid, punktacja
sum wag + 0,3 ln(1+lajki) + swiezosc, max 2 klipy tworcy na strone) + 20%
explore (okno 2000 id po PK, losowanie wazone lajkami, zawijanie na koncu).
Bez wag 100% explore. POST /clips/events: zapis, podniesienie outcome,
ulubione, delty wag (like +5, complete +3, dwell>=10 s +1, skip<2 s -1,
not_interested -4 i -8 na wskazany cel). Onboarding 3 tapow, opcje,
blacklista tag/nisza/tworca, reset feedu, ulubione. Import miedzy
urzadzeniami kopiuje clip_seen, clip_favorites i clip_blacklist.
Job clips-maintenance co 24 h: decay wag x0,97, retencja zdarzen 90 dni,
reaper (HEAD na 2000 najdawniej sprawdzanych). Logika bez bazy w
app/clips_feed.py z testami (kursor, delty, cap/decay, punktacja, sklad).
25 lines
807 B
Python
25 lines
807 B
Python
"""Reaper martwych klipów, ręczne uruchomienie. Logika w `app.scheduler.clips_ingest.reap_dead`
|
|
(ta sama, którą raz na dobę odpala job `clips-maintenance`).
|
|
|
|
python -m scripts.clips_reap_dead --limit 500 # dry-run
|
|
python -m scripts.clips_reap_dead --limit 500 --yes # zapisz dead_at
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import logging
|
|
|
|
from app.scheduler.clips_ingest import reap_dead
|
|
|
|
|
|
def main() -> None:
|
|
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--limit", type=int, default=500)
|
|
ap.add_argument("--yes", action="store_true", help="zapisz dead_at (bez tego dry-run)")
|
|
a = ap.parse_args()
|
|
print(reap_dead(limit=a.limit, apply=a.yes))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|