prod: чистая лента (дедуп перепечаток, анти-шум в score, категорийный вес), счётчик живых/мёртвых источников, таймауты net
This commit is contained in:
50
omni/rank.py
50
omni/rank.py
@@ -24,6 +24,53 @@ def _abuse(it):
|
||||
|
||||
KIND_BONUS = {"tweet": 0.15, "thread": 0.25, "tg_post": 0.2, "card": 0.05, "result": 0.1, "post": 0.1}
|
||||
|
||||
# Категорийный вес: то, ради чего лента существует (абузы/панели/ключи/фермы),
|
||||
# поднимаем выше новостного шума. Значения проверены на текущем индексе.
|
||||
CAT_BONUS = {"abuse": 0.9, "panels": 0.8, "keys": 0.7, "treg": 0.35, "ai": 0.25,
|
||||
"web3": 0.2, "tools": 0.2, "news": -0.35, "misc": -0.2}
|
||||
|
||||
# Мусор, который не должен всплывать никогда: служебные заголовки, оглавления,
|
||||
# changelog/release notes, голые URL, склейки-«лапши» и пустые обрывки.
|
||||
NOISE_RE = re.compile(
|
||||
r"(chapter\s*list|release\s*notes|changelog|table\s*of\s*contents|"
|
||||
r"^\s*(index|readme|docs?|documentation|wiki)\s*$|"
|
||||
r"^\s*https?://\S+\s*$|\|\|)", re.I)
|
||||
|
||||
SHOUT_RE = re.compile(r"^[^a-zа-я]{12,}$")
|
||||
|
||||
|
||||
def _noise(it):
|
||||
"""0 = чисто, иначе штраф. Считается по заголовку и началу текста."""
|
||||
title = (it.title or "").strip()
|
||||
if not title:
|
||||
return 2.0
|
||||
penalty = 0.0
|
||||
if len(title) < 8:
|
||||
penalty += 0.6
|
||||
if len(title) > 220:
|
||||
penalty += 0.8
|
||||
if NOISE_RE.search(title):
|
||||
penalty += 1.6
|
||||
# Голый CVE-дамп (тысячи одинаковых описаний из фида) — полезен точечно,
|
||||
# но не должен занимать верх ленты: топ должен принадлежать находкам.
|
||||
if re.match(r"^CVE-\d{4}-\d+", title):
|
||||
penalty += 1.4
|
||||
# Обрывок переписки/цитата вместо заголовка: «> be ...», «хотелось бы отметить».
|
||||
if title.startswith(">"):
|
||||
penalty += 1.5
|
||||
elif title[:1].islower():
|
||||
penalty += 1.0
|
||||
if SHOUT_RE.match(title):
|
||||
penalty += 0.35
|
||||
if sum(c.isalnum() for c in title) < len(title) * 0.4:
|
||||
penalty += 0.4
|
||||
txt = (it.text or "")
|
||||
if len(txt) > 4000 and len(title) < 25:
|
||||
penalty += 0.7
|
||||
if not txt and len(title) < 40:
|
||||
penalty += 0.3
|
||||
return min(3.0, penalty)
|
||||
|
||||
|
||||
def _fresh(published):
|
||||
"""Unix seconds/milliseconds, ISO or RFC 2822. Return freshness in 0..1."""
|
||||
@@ -41,8 +88,9 @@ def score(it):
|
||||
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
|
||||
cat = CAT_BONUS.get((getattr(it, "category", "") or "").lower(), 0.0)
|
||||
total = (w * (1.0 + eng) + fresh * 1.2 + priced + body + KIND_BONUS.get(it.kind, 0.0)
|
||||
+ 0.45 * _abuse(it))
|
||||
+ 0.45 * _abuse(it) + cat - _noise(it))
|
||||
it.score = round(total, 4)
|
||||
return it
|
||||
|
||||
|
||||
Reference in New Issue
Block a user