Files
omni-parse/omni/rank.py
Vlad Gothbreach 16512bf4a1
Some checks failed
ci / test (3.10) (push) Has been cancelled
ci / test (3.11) (push) Has been cancelled
ci / test (3.12) (push) Has been cancelled
абузы: free-панели new-api на вкладке (роут /api/panels + грид), CSS вынесен из JS, панельный классификатор даёт freeapi-вес, тесты
2026-10-27 02:06:32 +03:00

51 lines
1.9 KiB
Python

"""Скор записи: вес провайдера + вовлечённость + свежесть + ценник + объём текста + сигнал абуза."""
import re
import time
from .dates import parse_published
WEIGHT = {"reddit": 1.15, "x": 1.10, "forums": 1.0, "tavily": 1.0, "exa": 1.0,
"firecrawl": 0.9, "you": 0.9, "ddg": 0.75, "cards": 0.35, "treg": 0.8}
ABUSE_TERMS = re.compile(
r"(cve-\d{4}-\d+|0day|0-day|zero[- ]day|exploit|rce|sqli|xss|ssrf|rce|"
r"leak|leaked|dump|breach|combo[- ]?list|stealer|ransomware|botnet|credentials|"
r"password[s]?|api[- ]?key[s]?|token[s]?|аккаунт\w*|база|слив\w*|утечк\w*|комбо|"
r"взлом|эксплойт|уязвим\w*|парол\w*|ключи)",
re.I)
def _abuse(it):
"""Реальные абузы должны всплывать выше новостей: считаем сигнальные термины."""
blob = f"{it.title} {it.text}"[:2000]
hits = len({m.group(0).lower() for m in ABUSE_TERMS.finditer(blob)})
return min(4, hits)
KIND_BONUS = {"tweet": 0.15, "thread": 0.25, "tg_post": 0.2, "card": 0.05, "result": 0.1, "post": 0.1}
def _fresh(published):
"""Unix seconds/milliseconds, ISO or RFC 2822. Return freshness in 0..1."""
dt = parse_published(published)
if dt is None:
return 0.3
days = max(0.0, (time.time() - dt.timestamp()) / 86400)
return max(0.0, 1.0 - days / 30.0)
def score(it):
base = it.score if it.score else 0.0
w = WEIGHT.get(it.provider, 0.7)
fresh = _fresh(it.published)
priced = 0.35 if it.price else 0.0
body = min(1.0, len(it.text) / 1200.0)
eng = min(3.0, base ** 0.5) if base > 1 else base
total = (w * (1.0 + eng) + fresh * 1.2 + priced + body + KIND_BONUS.get(it.kind, 0.0)
+ 0.45 * _abuse(it))
it.score = round(total, 4)
return it
def rank(items):
return sorted((score(i) for i in items), key=lambda x: -x.score)