dp-zp-agent/tools/crzp/answering/terms.py
2026-11-15 03:36:33 +01:00

74 lines
3.1 KiB
Python

"""Alternative search terms of a topic (synonyms, expanded abbreviations, English).
CRZP matches exact words, so "LLM" does not find a thesis that only writes
"jazykový model". A small reviewed table comes first; the model may add
proposals up to two alternatives in total. A model proposal is unverified: it
is searched only when CRZP itself uses it next to the topic (a work found for
the topic has it in its title or keywords) or when the topic alone finds
nothing (see answer.find). Each alternative is a separate CRZP search, the
answer names all searched terms, and every listed work contains one of them.
"""
from __future__ import annotations
import re
from tools.crzp.source.parse import fold
MAX_ALTERNATIVES = 2
# Reviewed by hand; keys and values are search terms as they appear in CRZP titles and keywords.
TABLE = {
"llm": ["jazykový model", "GPT"],
"velky jazykovy model": ["LLM", "GPT"],
"jazykovy model": ["LLM"],
"ai": ["umelá inteligencia"],
"umela inteligencia": ["artificial intelligence"],
"nlp": ["spracovanie prirodzeného jazyka"],
"spracovanie prirodzeneho jazyka": ["NLP"],
"ml": ["strojové učenie"],
"strojove ucenie": ["machine learning"],
"chatbot": ["dialógový systém", "konverzačný agent"],
"dialogovy system": ["chatbot"],
"rag": ["retrieval augmented generation"],
"iot": ["internet vecí"],
"internet veci": ["IoT"],
"neuronova siet": ["neural network"],
"hlboke ucenie": ["deep learning"],
"rozpoznavanie reci": ["speech recognition", "prepis reči"],
"pocitacove videnie": ["computer vision"],
"kyberneticka bezpecnost": ["cybersecurity"],
"blockchain": ["distribuovaná účtovná kniha"],
}
def valid(term: str, topic: str) -> bool:
"""A short search phrase, different from the topic, no names or digits only."""
term = term.strip()
return (2 <= len(term) <= 40 and len(term.split()) <= 4 and fold(term) != fold(topic)
and not re.fullmatch(r"[\d\s]+", term) and not re.search(r"[\"„“{}<>]", term))
def reviewed(topic: str) -> list[str]:
return TABLE.get(" ".join(fold(topic).split()), [])
def expands(term: str, topic: str) -> bool:
"""The term spells out the abbreviation: "LLM" -> "large language model", "IoT" -> "internet of things"."""
letters = re.sub(r"[^a-z]", "", fold(topic))
words = re.findall(r"[^\W\d_]+", fold(term))
return (sum(c.isupper() for c in topic) >= 2 and 2 <= len(letters) <= 6 and len(words) == len(letters)
and "".join(w[0] for w in words) == letters)
def is_reviewed(term: str, topic: str) -> bool:
"""In the reviewed table, or the exact expansion of the abbreviation."""
return fold(term.strip()) in {fold(t) for t in reviewed(topic)} or expands(term, topic)
def alternatives(topic: str, proposed: list | None = None) -> list[str]:
"""Up to MAX_ALTERNATIVES terms: the reviewed table first, then the model's valid proposals."""
result = []
for term in [*reviewed(topic), *(proposed or [])]:
if isinstance(term, str) and valid(term, topic) and fold(term) not in {fold(t) for t in result}:
result.append(term.strip())
return result[:MAX_ALTERNATIVES]