mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 18:05:03 +00:00
69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
# VESTI — извлечение потенциальных источников из текста поста (без LLM, regex).
|
|
import re
|
|
from urllib.parse import urlparse
|
|
|
|
_MAX_PER_POST = 5
|
|
|
|
# t.me/handle, t.me/s/handle, telegram.me/handle
|
|
_TG_RE = re.compile(
|
|
r"(?:https?://)?(?:www\.)?(?:t\.me|telegram\.me)/(?:s/)?([a-zA-Z][a-zA-Z0-9_]{3,31})"
|
|
)
|
|
# @handle (не email, не на конце слова)
|
|
_AT_RE = re.compile(r"(?<!\w)@([a-zA-Z][a-zA-Z0-9_]{3,31})\b")
|
|
# внешние http(s)-ссылки
|
|
_URL_RE = re.compile(r"https?://([^\s<>\"']+)", re.I)
|
|
|
|
_TG_DOMAINS = ("t.me", "telegram.me")
|
|
|
|
|
|
def _domain_of(url: str) -> str:
|
|
return (urlparse(url if "://" in url else "https://" + url).netloc or "").lower()
|
|
|
|
|
|
def extract_sources_from_text(text: str, exclude_tg_url: str | None = None) -> list[dict]:
|
|
"""Ищет TG-каналы и внешние сайты в тексте поста.
|
|
|
|
exclude_tg_url — url самого поста (t.me/channel/postid): ссылку на него
|
|
отбрасываем (это адрес поста, а не источник).
|
|
|
|
Возвращает список dict: {"kind": "telegram"|"site", "address": str,
|
|
"slug_hint": str|None, "domain": str|None}
|
|
максимум _MAX_PER_POST элементов.
|
|
"""
|
|
out: list[dict] = []
|
|
seen: set[tuple] = set()
|
|
|
|
def add(kind: str, address: str, slug_hint: str | None, domain: str | None):
|
|
key = (kind, slug_hint or domain or address)
|
|
if key in seen:
|
|
return
|
|
seen.add(key)
|
|
out.append({"kind": kind, "address": address, "slug_hint": slug_hint, "domain": domain})
|
|
|
|
text = (text or "")[:4000]
|
|
|
|
for m in _TG_RE.finditer(text):
|
|
ch = m.group(1)
|
|
if exclude_tg_url and f"/{ch}/" in exclude_tg_url:
|
|
continue # ссылка на сам пост
|
|
add("telegram", f"https://t.me/{ch}", ch, None)
|
|
if len(out) >= _MAX_PER_POST:
|
|
break
|
|
|
|
for m in _AT_RE.finditer(text):
|
|
add("telegram", f"https://t.me/{m.group(1)}", m.group(1), None)
|
|
if len(out) >= _MAX_PER_POST:
|
|
break
|
|
|
|
for m in _URL_RE.finditer(text):
|
|
u = m.group(1).rstrip(".,;:!?)]}\"'")
|
|
dom = _domain_of(u)
|
|
if not dom:
|
|
continue
|
|
if dom in _TG_DOMAINS or dom.endswith(".t.me"):
|
|
continue # уже обработано выше
|
|
add("site", u, None, dom)
|
|
if len(out) >= _MAX_PER_POST:
|
|
break
|
|
|
|
return out[:_MAX_PER_POST] |