Skip to content

Commit 6aa7f5b

Browse files
committed
Unify translation logic between translate_only.py and graph.py
- Extract translate_content() as unified translation function - Both translate_only.py and graph.py now use the same translation logic - Consistent error handling, validation, and progress reporting - graph.py dynamically imports translate_content from translate_only.py - Fallback to direct translator call if translate_only.py not found
1 parent 6d62bbc commit 6aa7f5b

File tree

3 files changed

+115
-51
lines changed

3 files changed

+115
-51
lines changed

tools/ai-markmap-agent/src/agents/translator.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,25 @@ def translate(self, content: str, output_type: str) -> str:
137137
# Save LLM input
138138
self._save_llm_call_input(messages, "translate")
139139

140-
# Call LLM
141-
response = self.llm.invoke(messages)
140+
# Show progress info
141+
model_name = self.model_config.get("model", "unknown")
142+
prompt_size = len(prompt)
143+
content_size = len(content)
144+
print(f" 📤 Sending request to {model_name}...")
145+
print(f" Prompt: {prompt_size:,} chars, Content: {content_size:,} chars")
146+
print(f" This may take 30-120 seconds depending on content size...")
147+
148+
# Call LLM with timeout handling
149+
import time
150+
start_time = time.time()
151+
try:
152+
response = self.llm.invoke(messages)
153+
elapsed = time.time() - start_time
154+
print(f" ⏱️ API call completed in {elapsed:.1f} seconds")
155+
except Exception as e:
156+
elapsed = time.time() - start_time
157+
print(f" ❌ API call failed after {elapsed:.1f} seconds")
158+
raise
142159

143160
# Validate response
144161
if response is None:

tools/ai-markmap-agent/src/graph.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -739,13 +739,6 @@ def run_translations(state: WorkflowState) -> WorkflowState:
739739
target_lang = tr_config["target_lang"]
740740
model = tr_config["model"]
741741

742-
translator = TranslatorAgent(
743-
source_language=source_lang,
744-
target_language=target_lang,
745-
model=model,
746-
config=config,
747-
)
748-
749742
for output_key, content in writer_outputs.items():
750743
# Parse output_key format: "{type}_{lang}" (e.g., "general_en")
751744
parts = output_key.rsplit("_", 1)
@@ -760,40 +753,49 @@ def run_translations(state: WorkflowState) -> WorkflowState:
760753
else:
761754
continue # Skip if source_lang not found
762755

763-
# Translate the content
756+
# Translate the content using unified translation function
764757
try:
765758
if debug.enabled:
766759
debug.save_translation(content, output_key, target_key, is_before=True)
767760

768-
translated_content = translator.translate(content, "general")
769-
770-
# Validate translation result
771-
if not translated_content:
772-
raise ValueError(
773-
f"Translation returned empty content (None). "
774-
f"Source: {source_lang} → Target: {target_lang}, "
775-
f"Model: {model}, Output: {output_key}"
776-
)
777-
if len(translated_content.strip()) == 0:
778-
raise ValueError(
779-
f"Translation returned only whitespace. "
780-
f"Source: {source_lang} → Target: {target_lang}, "
781-
f"Model: {model}, Output: {output_key}"
782-
)
761+
# Import unified translation function from translate_only.py
762+
import sys
763+
import importlib.util
764+
from pathlib import Path
783765

784-
# Clean up LLM artifacts
785-
translated_content = clean_translated_content(translated_content)
766+
# Get path to translate_only.py
767+
translate_only_path = Path(__file__).parent.parent.parent / "translate_only.py"
786768

787-
# Validate cleaned content
788-
if not translated_content or len(translated_content.strip()) == 0:
789-
raise ValueError(
790-
f"After cleaning, translation is empty. "
791-
f"Source: {source_lang} → Target: {target_lang}, "
792-
f"Model: {model}, Output: {output_key}"
769+
if translate_only_path.exists():
770+
# Dynamically import translate_content function
771+
spec = importlib.util.spec_from_file_location("translate_only", translate_only_path)
772+
translate_module = importlib.util.module_from_spec(spec)
773+
spec.loader.exec_module(translate_module)
774+
translate_content = translate_module.translate_content
775+
776+
translated_content = translate_content(
777+
content=content,
778+
source_lang=source_lang,
779+
target_lang=target_lang,
780+
model=model,
781+
config=config,
782+
output_key=f"{output_key}{target_key}",
783+
)
784+
else:
785+
# Fallback: use translator directly (old behavior)
786+
translator = TranslatorAgent(
787+
source_language=source_lang,
788+
target_language=target_lang,
789+
model=model,
790+
config=config,
793791
)
792+
translated_content = translator.translate(content, "general")
793+
translated_content = clean_translated_content(translated_content)
794+
if not translated_content or len(translated_content.strip()) == 0:
795+
raise ValueError(f"Translation returned empty content")
796+
print(f" ✓ Translated: {output_key}{target_key}")
794797

795798
translated[target_key] = translated_content
796-
print(f" ✓ Translated: {output_key}{target_key}")
797799

798800
if debug.enabled:
799801
debug.save_translation(translated_content, output_key, target_key, is_before=False)

tools/ai-markmap-agent/translate_only.py

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,27 +66,31 @@ def find_latest_english_output(config: dict) -> Path | None:
6666
return None
6767

6868

69-
def translate_file(
70-
input_path: Path,
71-
output_path: Path,
69+
def translate_content(
70+
content: str,
7271
source_lang: str,
7372
target_lang: str,
7473
model: str,
7574
config: dict,
75+
output_key: str | None = None,
7676
) -> str:
77-
"""Translate a file and save the result."""
78-
print(f"\n📄 Input: {input_path}")
79-
print(f"🌐 Translation: {source_lang}{target_lang}")
80-
print(f"🤖 Model: {model}")
81-
82-
# Check if input file exists
83-
if not input_path.exists():
84-
raise FileNotFoundError(f"Input file not found: {input_path}")
77+
"""
78+
Translate content using TranslatorAgent.
8579
86-
# Read input
87-
content = input_path.read_text(encoding="utf-8")
88-
print(f" Read {len(content)} chars, {len(content.splitlines())} lines")
80+
This is the unified translation function used by both translate_only.py
81+
and graph.py to ensure consistent behavior.
8982
83+
Args:
84+
content: Content to translate
85+
source_lang: Source language code
86+
target_lang: Target language code
87+
model: Model name to use
88+
config: Configuration dictionary
89+
output_key: Optional output key for logging (used in pipeline)
90+
91+
Returns:
92+
Translated content
93+
"""
9094
# Create translator
9195
translator = TranslatorAgent(
9296
source_language=source_lang,
@@ -96,7 +100,11 @@ def translate_file(
96100
)
97101

98102
# Translate
99-
print("\n⏳ Translating...")
103+
if output_key:
104+
print(f" ⏳ Translating {output_key} ({source_lang}{target_lang})...")
105+
else:
106+
print(f"\n⏳ Translating ({source_lang}{target_lang})...")
107+
100108
try:
101109
translated = translator.translate(content, "general")
102110
except Exception as e:
@@ -177,7 +185,8 @@ def translate_file(
177185
f" - Verify model configuration in config file"
178186
)
179187

180-
print(f" Raw translation: {len(translated)} chars")
188+
if not output_key:
189+
print(f" Raw translation: {len(translated)} chars")
181190

182191
# Clean up LLM artifacts
183192
translated = clean_translated_content(translated)
@@ -210,7 +219,43 @@ def translate_file(
210219
f" - Verify API response format matches expectations"
211220
)
212221

213-
print(f" ✓ Cleaned translation: {len(translated)} chars, {len(translated.splitlines())} lines")
222+
if output_key:
223+
print(f" ✓ Translated: {output_key} ({len(translated)} chars, {len(translated.splitlines())} lines)")
224+
else:
225+
print(f" ✓ Cleaned translation: {len(translated)} chars, {len(translated.splitlines())} lines")
226+
227+
return translated
228+
229+
230+
def translate_file(
231+
input_path: Path,
232+
output_path: Path,
233+
source_lang: str,
234+
target_lang: str,
235+
model: str,
236+
config: dict,
237+
) -> str:
238+
"""Translate a file and save the result."""
239+
print(f"\n📄 Input: {input_path}")
240+
print(f"🌐 Translation: {source_lang}{target_lang}")
241+
print(f"🤖 Model: {model}")
242+
243+
# Check if input file exists
244+
if not input_path.exists():
245+
raise FileNotFoundError(f"Input file not found: {input_path}")
246+
247+
# Read input
248+
content = input_path.read_text(encoding="utf-8")
249+
print(f" Read {len(content)} chars, {len(content.splitlines())} lines")
250+
251+
# Use unified translation function
252+
translated = translate_content(
253+
content=content,
254+
source_lang=source_lang,
255+
target_lang=target_lang,
256+
model=model,
257+
config=config,
258+
)
214259

215260
# Save output
216261
output_path.parent.mkdir(parents=True, exist_ok=True)

0 commit comments

Comments
 (0)