.
This commit is contained in:
@@ -1352,6 +1352,61 @@ def fallback_classify(title: str, text: str) -> tuple[str, str]:
|
||||
return t[:200], ", ".join(seen)
|
||||
|
||||
|
||||
KEYWORDS_MAX_LEN = 300 # rip_help_sections.keywords VARCHAR(300)
|
||||
|
||||
|
||||
def parse_keyword_list(raw: str) -> list[str]:
|
||||
"""Разделя ключови думи. Запетая/точка и запетая = фрази; иначе — интервал."""
|
||||
text = (raw or "").strip()
|
||||
if not text:
|
||||
return []
|
||||
if "," in text or ";" in text:
|
||||
parts = re.split(r"[,;]+", text)
|
||||
else:
|
||||
parts = text.split()
|
||||
out: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for p in parts:
|
||||
k = " ".join(p.split())
|
||||
if not k:
|
||||
continue
|
||||
key = k.casefold()
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
out.append(k)
|
||||
return out
|
||||
|
||||
|
||||
def merge_section_keywords(
|
||||
manual: str,
|
||||
generated: str,
|
||||
max_len: int = KEYWORDS_MAX_LEN,
|
||||
) -> str:
|
||||
"""Ръчните думи първи, после генерираните; без дубликати (без значение на регистъра)."""
|
||||
first = parse_keyword_list(manual)
|
||||
seen = {k.casefold() for k in first}
|
||||
rest: list[str] = []
|
||||
for k in parse_keyword_list(generated):
|
||||
key = k.casefold()
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
rest.append(k)
|
||||
merged = first + rest
|
||||
if not merged:
|
||||
return ""
|
||||
out: list[str] = []
|
||||
used = 0
|
||||
for i, k in enumerate(merged):
|
||||
extra = len(k) + (2 if i else 0) # ", "
|
||||
if used + extra > max_len:
|
||||
break
|
||||
out.append(k)
|
||||
used += extra
|
||||
return ", ".join(out)
|
||||
|
||||
|
||||
def classify_section(client: anthropic.Anthropic, title: str, text: str) -> tuple[str, str]:
|
||||
"""Връща (наименование, 'кл1, кл2, кл3') чрез Claude."""
|
||||
snippet = text[:MAX_AI_CHARS]
|
||||
@@ -1420,6 +1475,7 @@ def process_file(
|
||||
force: bool = False,
|
||||
remote_root: Optional[str] = None,
|
||||
source_key: Optional[str] = None,
|
||||
seed_keywords: str = "",
|
||||
) -> dict:
|
||||
"""Обработва един файл. Връща статистика (saved, codes, ok)."""
|
||||
rel = source_key or path.name
|
||||
@@ -1512,6 +1568,7 @@ def process_file(
|
||||
if not (keywords or "").strip():
|
||||
title, keywords = fallback_classify(title or sec.title or f"Секция {sec_index}", text)
|
||||
ai_errors += 1
|
||||
keywords = merge_section_keywords(seed_keywords, keywords)
|
||||
|
||||
images_json = json.dumps(image_rel_paths, ensure_ascii=False)
|
||||
ps = ProcessedSection(
|
||||
@@ -1558,6 +1615,7 @@ def process_directory(
|
||||
force: bool = False,
|
||||
purge_missing: bool = False,
|
||||
remote_root: Optional[str] = None,
|
||||
seed_keywords: str = "",
|
||||
):
|
||||
if not _PREFIX_RE.match(prefix):
|
||||
raise ValueError(
|
||||
@@ -1598,6 +1656,7 @@ def process_directory(
|
||||
path, idx, db, client, output_dir,
|
||||
prefix=prefix, force=force, remote_root=remote_root,
|
||||
source_key=identity,
|
||||
seed_keywords=seed_keywords,
|
||||
)
|
||||
file_results.append(info)
|
||||
total_sections += int(info.get("saved") or 0)
|
||||
@@ -1693,6 +1752,11 @@ def main():
|
||||
"Файловете се пишат локално; в БД се записва remote път. "
|
||||
"Или env HELP_REMOTE_ROOT."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--keywords",
|
||||
default="",
|
||||
help="Ръчни ключови думи (запетая). Стоят в началото на всяка секция от това сканиране."
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.api_key:
|
||||
@@ -1709,6 +1773,7 @@ def main():
|
||||
force=args.force,
|
||||
purge_missing=args.purge_missing,
|
||||
remote_root=args.remote_root,
|
||||
seed_keywords=args.keywords,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user