CharacterChatBot / engine /translator.py
cereeenn120's picture
Add logger with verbosity
832430f
Raw History Blame Contribute Delete
4.08 kB
"""
Translation layer — translates between the user's language and English.
The main LLM always receives and produces English.
This module handles conversion in both directions so the UI shows the user's language.
Formatting rules:
Text inside (parentheses) and *asterisks* is roleplay markup — it must be
preserved as-is so the parser can still identify actions and thoughts.
"""
import logging
import time
from huggingface_hub import InferenceClient
logger = logging.getLogger(__name__)
_TO_EN = (
"You are a professional translator. "
"Translate the following text to English. "
"Translate ALL content, including text inside parentheses ( ) and asterisks *. "
"Keep the parentheses ( ) and asterisks * markers exactly in place — do not remove or add them. "
"Return ONLY the translated text, no explanations or extra text."
)
_FROM_EN = (
"You are a professional translator. "
"Translate the following text to {language}. "
"Translate ALL content, including text inside parentheses ( ) and asterisks *. "
"Keep the parentheses ( ) and asterisks * markers exactly in place — do not remove or add them. "
"Return ONLY the translated text, no explanations or extra text."
)
def translate_to_english(
text: str,
source_language: str,
client: InferenceClient,
model: str,
) -> str:
"""
Translate `text` from `source_language` to English.
Returns the original text unchanged if already English or on any failure.
"""
if not text.strip() or source_language.strip().lower() == "english":
logger.debug("[Translator] to_english skipped (already English or empty).")
return text
logger.info(f"[Translator] ▶ {source_language}→EN | model='{model}' | {len(text)} chars")
start = time.time()
try:
response = client.chat_completion(
messages=[
{"role": "system", "content": _TO_EN},
{"role": "user", "content": text},
],
model=model,
max_tokens=1024,
stream=False,
temperature=0.1,
)
result = response.choices[0].message.content.strip()
elapsed = time.time() - start
logger.info(f"[Translator] ✓ {source_language}→EN | {elapsed:.1f}s | {len(result)} chars")
logger.debug(f"[Translator] {source_language}→EN: {text[:80]!r} → {result[:80]!r}")
return result
except Exception as e:
logger.error(f"[Translator] to_english FAILED | model='{model}' | error: {e}", exc_info=True)
return text
def translate_from_english(
text: str,
target_language: str,
client: InferenceClient,
model: str,
) -> str:
"""
Translate `text` from English to `target_language`.
Returns the original text unchanged if target is English or on any failure.
"""
if not text.strip() or target_language.strip().lower() == "english":
logger.debug("[Translator] from_english skipped (target is English or empty).")
return text
logger.info(f"[Translator] ▶ EN→{target_language} | model='{model}' | {len(text)} chars")
start = time.time()
try:
system = _FROM_EN.format(language=target_language)
response = client.chat_completion(
messages=[
{"role": "system", "content": system},
{"role": "user", "content": text},
],
model=model,
max_tokens=1024,
stream=False,
temperature=0.1,
)
result = response.choices[0].message.content.strip()
elapsed = time.time() - start
logger.info(f"[Translator] ✓ EN→{target_language} | {elapsed:.1f}s | {len(result)} chars")
logger.debug(f"[Translator] EN→{target_language}: {text[:80]!r} → {result[:80]!r}")
return result
except Exception as e:
logger.error(f"[Translator] from_english FAILED | model='{model}' | error: {e}", exc_info=True)
return text