Files
novelmaster/noma/scripts/data_modules/genre_profile_builder.py
T
2026-06-23 20:29:02 +08:00

108 lines
2.9 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Genre profile parsing helpers for ContextManager.
"""
from __future__ import annotations
import re
from typing import List
from .genre_aliases import normalize_genre_token
def parse_genre_tokens(
genre_raw: str,
*,
support_composite: bool,
separators: tuple[str, ...],
) -> List[str]:
text = str(genre_raw or "").strip()
if not text:
return []
if not support_composite:
normalized_single = normalize_genre_token(text)
return [normalized_single] if normalized_single else [text]
pattern = "|".join(re.escape(str(token)) for token in separators if str(token))
if not pattern:
normalized_single = normalize_genre_token(text)
return [normalized_single] if normalized_single else [text]
tokens = [chunk.strip() for chunk in re.split(pattern, text) if chunk and chunk.strip()]
deduped: List[str] = []
seen = set()
for token in tokens:
normalized_token = normalize_genre_token(token)
if not normalized_token:
continue
lower = normalized_token.lower()
if lower in seen:
continue
seen.add(lower)
deduped.append(normalized_token)
if deduped:
return deduped
fallback_token = normalize_genre_token(text)
return [fallback_token] if fallback_token else [text]
def extract_genre_section(text: str, genre: str) -> str:
if not text:
return ""
lines = text.splitlines()
capture: List[str] = []
active = False
target = genre.strip().lower()
for line in lines:
normalized = line.strip().lower()
if normalized.startswith("## ") or normalized.startswith("### "):
if active:
break
active = target in normalized
if active:
capture.append(line)
continue
if active:
capture.append(line)
if capture:
return "\n".join(capture).strip()
return "\n".join(lines[:80]).strip()
def extract_markdown_refs(text: str, max_items: int = 8) -> List[str]:
if not text:
return []
refs: List[str] = []
for line in text.splitlines():
row = line.strip().lstrip("-*").strip()
if not row or row.startswith("#"):
continue
refs.append(row)
if len(refs) >= max(1, max_items):
break
return refs
def build_composite_genre_hints(genres: List[str], refs: List[str]) -> List[str]:
if len(genres) <= 1:
return []
primary = genres[0]
secondaries = genres[1:]
hints: List[str] = []
hints.append(
f"以“{primary}”作为主引擎推进主线,每章至少保留1处“{'/'.join(secondaries)}”特征表达。"
)
if refs:
hints.append(f"复合题材执行参考:{refs[0]}")
hints.append("主辅题材冲突时,优先保证主题材读者承诺,辅题材用于制造新鲜感。")
return hints