cleanup/core/suggest.py
2026-09-05 15:24:52 +02:00

50 lines
1.9 KiB
Python

"""
Folder suggestion: plain token overlap between the text you've typed
(filename, topic, subtopic — whatever's available) and each candidate
destination folder's path segments.
Deliberately simple and inspectable rather than clever — no ML, nothing
that runs over the network, and you can always see exactly why a folder
was suggested (shared words) rather than trusting a black box. If the
suggestions turn out too weak once you try it on real files, the obvious
next upgrade is peeking at file content for .md/.txt files — but that's
worth trying this simple version against real data first.
"""
import re
from pathlib import Path
from typing import List
from .sanitiser import UMLAUT_MAP
def _tokens(text: str) -> set:
"""Split on ANY run of non-alphanumeric characters (underscore, hyphen,
space, ...) — folder names use underscores (04_ARBEIT), typed text uses
spaces, so the tokeniser has to treat both as word boundaries. This is
deliberately more lenient than sanitise(), which is for building the
final filename, not for comparing words."""
folded = text.lower()
for src, repl in UMLAUT_MAP.items():
folded = folded.replace(src, repl)
return {t for t in re.split(r"[^a-z0-9]+", folded) if len(t) > 2}
def suggest_folders(query_text: str, all_folders: List[str], top_n: int = 5) -> List[str]:
"""Rank candidate folders by shared tokens with query_text.
Returns [] if query_text has no usable tokens — never guesses blind."""
query_tokens = _tokens(query_text)
if not query_tokens:
return []
scored = []
for folder in all_folders:
folder_tokens = set()
for segment in Path(folder).parts:
folder_tokens |= _tokens(segment)
overlap = len(query_tokens & folder_tokens)
if overlap:
scored.append((overlap, folder))
scored.sort(key=lambda pair: (-pair[0], pair[1]))
return [folder for _, folder in scored[:top_n]]