Publish documentation / publish (push) Successful in 34s
Reset the activity panel when starting a new question so the landing navigation is restored. Detect and persist the original question language, pass it through runtime and widget descriptors, and scope HITL controls to that language. Validated with gate, session, backend and frontend tests, TypeScript checks, Ruff and strict docs build. Rebuilt and restarted local core/frontend; both healthy and serving HTTP successfully.
61 lines
2.3 KiB
Python
61 lines
2.3 KiB
Python
"""Session language policy, independent of workspace document content."""
|
|
import re
|
|
from functools import lru_cache
|
|
|
|
from langdetect import DetectorFactory, LangDetectException
|
|
from langdetect.detector_factory import PROFILES_DIRECTORY
|
|
|
|
_LANGUAGE_TAG = re.compile(
|
|
r"(?P<language>[A-Za-z]{2,8})(?:-(?P<script>[A-Za-z]{4}))?"
|
|
r"(?:-(?P<region>[A-Za-z]{2}|[0-9]{3}))?"
|
|
r"(?P<rest>(?:-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*"
|
|
r"(?:-[0-9A-WY-Za-wy-z](?:-[A-Za-z0-9]{2,8})+)*"
|
|
r"(?:-[xX](?:-[A-Za-z0-9]{1,8})+)?)"
|
|
)
|
|
|
|
|
|
def validate_language_tag(value: str) -> str:
|
|
"""Validate syntax and normalize casing without depending on UI catalogs."""
|
|
match = _LANGUAGE_TAG.fullmatch(value) if isinstance(value, str) else None
|
|
if match is None:
|
|
raise ValueError("interaction_language must be a BCP-47 language tag")
|
|
parts = [match["language"].lower()]
|
|
if match["script"]:
|
|
parts.append(match["script"].title())
|
|
if match["region"]:
|
|
parts.append(match["region"].upper())
|
|
return "-".join(parts) + match["rest"].lower()
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def _question_detector_factory() -> DetectorFactory:
|
|
factory = DetectorFactory()
|
|
factory.seed = 0
|
|
factory.load_profile(PROFILES_DIRECTORY)
|
|
return factory
|
|
|
|
|
|
def question_interaction_language(question: str, fallback: str) -> str:
|
|
"""Pin confidently detected prose language; short/ambiguous/code input uses the hint."""
|
|
fallback = validate_language_tag(fallback)
|
|
prose = re.sub(r"```[\s\S]*?```|`[^`]*`|\b\w*_\w*\b", " ", question)
|
|
if re.match(
|
|
r"\s*(?:SELECT\s+.+\s+FROM\b|WITH\s+\w+\s+AS\s*\(|INSERT\s+INTO\b|"
|
|
r"UPDATE\s+\w+\s+SET\b|DELETE\s+FROM\b|CREATE\s+TABLE\b)",
|
|
prose, re.IGNORECASE | re.DOTALL,
|
|
):
|
|
return fallback
|
|
if sum(character.isalpha() for character in prose) < 12:
|
|
return fallback
|
|
detector = _question_detector_factory().create()
|
|
detector.append(prose)
|
|
try:
|
|
candidates = detector.get_probabilities()
|
|
except LangDetectException:
|
|
return fallback
|
|
if not candidates or candidates[0].prob < 0.90:
|
|
return fallback
|
|
detected = validate_language_tag(candidates[0].lang)
|
|
# Preserve a regional preference when it agrees with the detected language.
|
|
return fallback if detected.split("-")[0] == fallback.split("-")[0] else detected
|