"""Last presentation pass over every accepted ZP Wiki answer (RAG and GraphRAG). It changes wording only, never facts: - sources are written as full links, never as numbers ("[1]"); - notices that explain the system instead of answering ("Vedúci je určený podľa autora profilovej stránky…", "Profil obsahuje aj záznamy bez úplného dátumu…", "Rok nedopĺňam…") are dropped; - "this detail is not recorded" lines stay only when the answer has nothing else; then one plain sentence says so; - technical labels ("Názov / téma zo zdroja:") become plain words. """ from __future__ import annotations import re DROP = [ r"Vedúci je určený podľa autora profilovej stránky[^\n]*", r"Profil obsahuje aj záznamy bez úplného dátumu[^\n]*", r"Rok nedopĺňam z roku práce\.?", r"Údaje sú z indexovan[^\n]*", r"Indexovan[éý][^\n]*", r"Zobrazený je obmedzený výber[^\n]*", ] PHASE_TAG = re.compile(r"\s+\((?:zaznamenaný výsledok|priebežný stav|plán|zadanie|podklad|navrhovaný cieľ|téma alebo názov|" r"úloha označená ako splnená)\)(?=\s*$)", re.M) # Students whose only match is an assignment/plan or reading: one line at the end instead of a block each. SIDE = {"téma je v zadaní, téme alebo pláne práce; zaznamenaný výsledok k nej sa nenašiel.": "Téma je len v zadaní alebo pláne, bez zaznamenaného výsledku", "záznamy dokladajú len štúdium alebo poznámky k téme, nie vlastnú realizáciu.": "Len štúdium alebo poznámky k téme"} BULLET = re.compile(r"^- (?P[^;\n:]+?); (?P[^;:\n]+?)(?:; záznam (?P[^:\n]+?))?: (?P.*)$", re.M) LABEL_PREFIX = re.compile(r"^(?:-\s+|\*(?:Názov|Meno)[^*]*\*:\s*|(?:Názov|Téma)\s*:\s*)+") def _bullet(match: re.Match) -> str: text = LABEL_PREFIX.sub("", match.group("text").strip()).strip() if not text or text.startswith("#"): return "" # a bare heading ("## Diplomový projekt 2") says nothing if re.fullmatch(r"(?:Vedúci\w*:\s*)?(?:(?:Ing|Mgr|doc|prof|Bc|RNDr)\.\s*)*[A-ZÁ-Ž]\w+\s+[A-ZÁ-Ž]\w+(?:,\s*PhD\.?)?\.?", text): return "" # only the supervisor's name, already the subject of the answer date = (match.group("date") or "").replace("(rok neuvedený)", "").strip(" :()") return f"- {match.group('work').strip()}" + (f" ({date})" if date else "") + f": {text}" def _collapse_side_people(blocks: list[str]) -> list[str]: groups, current = [], [] for block in blocks: if re.fullmatch(r"\*\*[^*\n]+\*\*", block) and current: groups.append(current) current = [] current.append(block) if current: groups.append(current) kept, side = [], {} for group in groups: head = re.fullmatch(r"\*\*([^*\n]+)\*\*", group[0]) label = next((v for k, v in SIDE.items() for b in group if b.endswith(k)), None) if head and label: side.setdefault(label, []).append(head.group(1)) else: kept += group return kept + [f"{label}: {', '.join(names)}." for label, names in side.items()] MISSING = re.compile(r"(?:požadovaný údaj nie je v tomto zápise doložený|v podkladoch chýbajú doložené údaje|" r"Požadované údaje k tomuto stretnutiu nie sú v dostupnom výbere doložené)", re.I) RENAME = [ (r"Názov / téma zo zdroja:\s*(?:\*Názov [^*]*\*:\s*)?", "Téma: "), (r"Vedúci práce \(autor profilu študenta\):", "Vedúci práce:"), (r"Konzultant práce \(zo zdroja\):", "Konzultant:"), ] INLINE_CITE = re.compile(r"\s*(?:\[\d+\])+(?!\(|:)") REFERENCE_LINE = re.compile(r"^\[\d+\]:\s*\S+\s*$", re.M) SOURCES = re.compile(r"^Zdroj(?:e)?:\s*(.+)$", re.M) def _links(line: str) -> list[str]: urls = re.findall(r"\]\((https?://[^)\s]+)\)", line) or re.findall(r"https?://[^\s,)\]]+", line) return list(dict.fromkeys(urls)) def finalize(text: str, source_urls: list[str] | None = None) -> str: if not isinstance(text, str) or not text.strip(): return text out = REFERENCE_LINE.sub("", text) sources, label = [], None for match in SOURCES.finditer(out): sources += _links(match.group(1)) label = label or match.group(0).split(":", 1)[0] out = SOURCES.sub("", out) out = INLINE_CITE.sub("", out) for pattern in DROP: out = re.sub(pattern, "", out) for pattern, replacement in RENAME: out = re.sub(pattern, replacement, out) out = PHASE_TAG.sub("", out) out = BULLET.sub(_bullet, out) out = re.sub(r"^- Téma alebo názov doložený pri tej istej práci:\s*(?:\*[^*]*\*:\s*)?", "- Téma: ", out, flags=re.M) out = re.sub(r"(?m)^(\s*- [^:\n]+:)\s+-\s+", r"\1 ", out) # "Diplomový projekt: - Rozpoznávanie…' blocks = _collapse_side_people([b.strip() for b in re.split(r"\n\s*\n", out) if b.strip()]) substantive = [b for b in blocks if not MISSING.search(b) and not re.fullmatch(r"\*\*[^*]+\*\*", b) and not re.fullmatch(r"(?:\*\*[^*]+\*\*\s*)?(?:Posledný záznam[^\n]*|Zadanie a ciele:)", b)] if substantive: blocks = [b for b in blocks if not MISSING.search(b)] blocks = [b for i, b in enumerate(blocks) # a heading left without its content if not (re.fullmatch(r"[A-ZÁ-Ž][^\n]{0,40}:", b) and (i + 1 == len(blocks) or blocks[i + 1].startswith("**")))] else: heads = [b for b in blocks if re.fullmatch(r"\*\*[^*]+\*\*", b) or b.startswith("**")] blocks = heads[:1] + ["ZP Wiki k tomu nemá záznam."] sources = list(dict.fromkeys(sources)) # rewrite the answer's own source line, never add one if sources: blocks.append((label or "Zdroje") + ": " + ", ".join(sources)) return "\n\n".join(blocks)