Repository navigation
Tibetan Translator V1
TenzinGayche edited this page Dec 17, 2025
·
1 revision
The original tibetan_translator module provides a commentary-driven translation pipeline for Tibetan Buddhist texts.
This version uses traditional scholarly commentaries to guide translation. It:
- Translates 3 commentaries in parallel
- Combines them into a unified interpretation
- Generates translation based on combined commentary
- Evaluates and refines iteratively
- Extracts glossary terms
┌─────────────────────────────────────────────────────────────────────────────┐
│ tibetan_translator Workflow │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ │
│ │ START │ │
│ └────┬────┘ │
│ │ │
│ ┌─────────────────────────┼─────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ commentary_ │ │ commentary_ │ │ commentary_ │ │
│ │ translator_1 │ │ translator_2 │ │ translator_3 │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────────────┼─────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ aggregator │ │
│ │ │ │
│ │ Combines into │ │
│ │ unified comment │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ translation_generator │◄────────────┐ │
│ │ │ │ │
│ │ Uses commentary to │ │ │
│ │ generate translation │ │ │
│ └────────────┬─────────────┘ │ │
│ │ │ │
│ ▼ │ │
│ ┌──────────────────────────┐ │ │
│ │ llm_call_evaluator │ │ │
│ │ │ │ │
│ │ • Language check │ │ │
│ │ • Content evaluation │ │ │
│ │ • Format verification │ │ │
│ └────────────┬─────────────┘ │ │
│ │ │ │
│ ┌──────┴──────┐ │ │
│ │ route_ │ │ │
│ │ translation │ │ │
│ └──────┬──────┘ │ │
│ │ │ │
│ ┌─────────────────┼─────────────────┐ │ │
│ │ │ │ │ │
│ ▼ ▼ │ │ │
│ "Accepted" "Rejected + Feedback"───┴─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ generate_ │ │
│ │ glossary │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌───────┐ │
│ │ END │ │
│ └───────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
tibetan_translator/
├── __init__.py # Package exports
├── cli.py # Command-line interface
├── config.py # Configuration (API keys, model settings)
├── llm_provider.py # LLM provider abstraction (V1 only!)
├── models.py # Pydantic models
├── prompts.py # Prompt templates
├── utils.py # Utilities and LLM setup
├── workflow.py # LangGraph workflow definition
└── processors/
├── __init__.py
├── commentary.py # Commentary translation functions
├── translation.py # Translation generation
├── evaluation.py # Quality evaluation
├── formatting.py # Format checking (deprecated)
├── glossary.py # Glossary extraction
└── post_translation.py
Three parallel nodes translate commentaries:
def commentary_translator_1(state: State):
"""Translate first commentary with expertise focus."""
if not state['commentary1']:
return {"commentary1": None, "commentary1_translation": None}
prompt = get_commentary_translation_prompt(
state['sanskrit'],
state['source'],
state['commentary1'],
language=state.get('language', 'English')
)
return {
"commentary1": state['commentary1'],
"commentary1_translation": state['commentary1']
}Combines translated commentaries:
def aggregator(state: State):
"""Combine commentaries based on availability."""
# Logic:
# - If no commentaries → create source analysis
# - If one commentary → use directly
# - If multiple → combine using LLM
combined = ""
if has_commentary1:
combined += f"Commentary 1:\n{state['commentary1_translation']}\n\n"
if has_commentary2:
combined += f"Commentary 2:\n{state['commentary2_translation']}\n\n"
if has_commentary3:
combined += f"Commentary 3:\n{state['commentary3_translation']}\n\n"
# Use thinking LLM for analysis
response = llm_thinking.invoke(prompt_messages)
return {"combined_commentary": commentary_content,
"commentary_source": "traditional"}Generates or refines translation:
def translation_generator(state: State):
"""Generate improved translation based on commentary and feedback."""
if state.get("feedback_history"):
# Improvement mode - address feedback
prompt = get_translation_improvement_prompt(...)
msg = llm.invoke(prompt)
else:
# Initial translation mode
if is_source_focused:
prompt = get_enhanced_translation_prompt(...)
else:
prompt = get_initial_translation_prompt(...)
# Use thinking LLM for primary translation
thinking_response = llm_thinking.invoke(prompt)
return {
"translation": [...new_translation...],
"plaintext_translation": plain_translation,
"itteration": current_iteration + 1
}Evaluates translation quality:
def llm_call_evaluator(state: State):
"""Evaluate translation quality AND formatting."""
# 1. Check if translation is in target language
language_check = check_translation_language(state['translation'][-1], language)
if not language_check.is_target_language:
return {"grade": "bad", "is_target_language": False, ...}
# 2. Verify against commentary
verification = verify_against_commentary(
state['translation'][-1],
state['combined_commentary']
)
# 3. Full evaluation
evaluation = llm.with_structured_output(Feedback).invoke(prompt)
return {
"grade": evaluation.grade,
"formated": evaluation.format_matched,
"feedback_history": [...updated...],
}Routes based on quality:
def route_translation(state: State):
"""Route based on translation quality and formatting."""
if state["grade"] == "great" and state["formated"]:
return "Accepted"
elif state["itteration"] >= MAX_TRANSLATION_ITERATIONS:
return "Accepted"
else:
return "Rejected + Feedback"Extracts terminology:
def generate_glossary(state: State):
"""Extract glossary terms from final translation."""
prompt = get_glossary_extraction_prompt(
source=state['source'],
combined_commentary=state['combined_commentary'],
final_translation=state['translation'][-1],
language=state.get('language', 'English')
)
glossary = llm.with_structured_output(GlossaryExtraction).invoke(prompt)
return {"glossary": glossary.entries}class State(TypedDict):
# Translations
translation: List[str] # History of translations
plaintext_translation: str # Plain text version
# Commentaries
commentary1: str # Input commentary 1
commentary2: str # Input commentary 2
commentary3: str # Input commentary 3
commentary1_translation: str # Translated commentary 1
commentary2_translation: str # Translated commentary 2
commentary3_translation: str # Translated commentary 3
combined_commentary: str # Unified commentary
commentary_source: str # "traditional" or "source_analysis"
# Source
source: str # Tibetan source text
sanskrit: str # Sanskrit reference
language: str # Target language
# Feedback
feedback_history: List[str] # All feedback
format_feedback_history: List[str] # Format-specific feedback
# Analysis
key_points: List[KeyPoint] # Key points from commentary
glossary: List[GlossaryEntry] # Extracted terms
# Control
itteration: int # Translation iteration count
format_iteration: int # Format correction iteration
formated: bool # Format statuspython -m tibetan_translator.cli \
--input input_data.json \
--output output_results.jsonl \
--batch_size 8 \
--preprocessfrom tibetan_translator import optimizer_workflow
# Prepare initial state
state = {
"source": "བོད་ཀྱི་བསྡུད་མ་འདུག",
"sanskrit": "Buddhist text in Sanskrit",
"commentary1": "Commentary 1 explanation",
"commentary2": "Commentary 2 explanation",
"commentary3": "Commentary 3 explanation",
"language": "English",
"feedback_history": [],
"format_feedback_history": [],
"itteration": 0,
"format_iteration": 0,
"formated": False,
"glossary": [],
"translation": [],
"key_points": [],
"combined_commentary": "",
"commentary_source": "",
"plaintext_translation": "",
"commentary1_translation": "",
"commentary2_translation": "",
"commentary3_translation": "",
}
# Run workflow
result = optimizer_workflow.invoke(state)
# Access results
final_translation = result["translation"][-1]
glossary = result["glossary"]
print(f"Translation: {final_translation}")
print(f"Glossary entries: {len(glossary)}"){
"root": "Tibetan root text",
"sanskrit": "Corresponding Sanskrit text",
"commentary_1": "First commentary",
"commentary_2": "Second commentary",
"commentary_3": "Third commentary",
"language": "English"
}{
"translation": ["Final English translation"],
"commentary1_translation": "Translated commentary 1",
"commentary2_translation": "Translated commentary 2",
"commentary3_translation": "Translated commentary 3",
"combined_commentary": "Unified commentary",
"glossary": [
{
"tibetan_term": "བྱང་ཆུབ་སེམས",
"translation": "bodhicitta",
"context": "The mind of enlightenment",
"category": "philosophical"
}
],
"plaintext_translation": "Plain text version"
}# API Configuration
ANTHROPIC_API_KEY = os.environ.get("ANTHROPIC_API_KEY")
# Model Configuration
MODEL_NAME = "claude-3-5-sonnet-latest"
MAX_TOKENS = 8192
# Translation Settings
MAX_TRANSLATION_ITERATIONS = 3 # Max refinement iterations
MAX_FORMAT_ITERATIONS = 2 # Max format correction iterations
PRESERVE_SOURCE_FORMATTING = True- Tibetan-Translator-Comparison - V1 vs V2 differences
- Tibetan-Translator-V2 - V2 documentation
- Translator-Prompts - Prompt templates
- Translator-Models - Data models