11"""
2- Dynamic technical example generator for translation prompts.
2+ Static technical example for translation prompts.
33
4- This module generates simple, technical examples on-demand using the LLM.
5- These examples demonstrate WHAT to preserve (placeholders) with simple
6- sentences that present no translation difficulty.
4+ This module provides a simple, static English example demonstrating
5+ placeholder preservation. No LLM generation is used to avoid random errors.
76
87For examples showing HOW to translate idiomatically (cultural adaptation,
98avoiding literal translation), see cultural_examples.py.
109"""
1110
12- import asyncio
13- import json
14- from pathlib import Path
1511from typing import Dict , Optional , Any
1612
1713from .constants import TAG0 , TAG1
1814
1915
20- # Cache file location
21- CACHE_FILE = Path (__file__ ).parent / "technical_cache.json"
22-
23- # Simple source template - easy to translate, focus on technical preservation
24- PLACEHOLDER_TEMPLATE_EN = f"This is { TAG0 } important{ TAG1 } text."
25-
26-
27- def _load_cache () -> Dict [str , Dict [str , Any ]]:
28- """Load cached examples from file."""
29- if CACHE_FILE .exists ():
30- try :
31- with open (CACHE_FILE , "r" , encoding = "utf-8" ) as f :
32- return json .load (f )
33- except (json .JSONDecodeError , IOError ):
34- return {}
35- return {}
36-
37-
38- def _save_cache (cache : Dict [str , Dict [str , Any ]]) -> None :
39- """Save cache to file."""
40- try :
41- with open (CACHE_FILE , "w" , encoding = "utf-8" ) as f :
42- json .dump (cache , f , ensure_ascii = False , indent = 2 )
43- except IOError as e :
44- print (f"[WARNING] Could not save technical cache: { e } " )
45-
46-
47- def _get_cache_key (source_lang : str , target_lang : str , example_type : str ) -> str :
48- """Generate cache key for a language pair and type."""
49- return f"{ source_lang .lower ()} :{ target_lang .lower ()} :{ example_type } "
16+ # Static English example for placeholder preservation
17+ STATIC_PLACEHOLDER_EXAMPLE = {
18+ "source" : f"This is { TAG0 } important{ TAG1 } text." ,
19+ "correct" : f"This is { TAG0 } important{ TAG1 } text." ,
20+ "wrong" : "This is important text."
21+ }
5022
5123
5224def get_cached_technical_example (
@@ -55,127 +27,26 @@ def get_cached_technical_example(
5527 example_type : str # "placeholder"
5628) -> Optional [Dict [str , str ]]:
5729 """
58- Get a cached technical example.
30+ Get the static technical example.
31+
32+ Always returns the same English example regardless of language pair.
5933
6034 Returns:
61- Dict with "source", "correct", "wrong" or None if not cached .
35+ Dict with "source", "correct", "wrong".
6236 """
63- cache = _load_cache ()
64- key = _get_cache_key (source_lang , target_lang , example_type )
65- return cache .get (key )
66-
67-
68- def save_technical_example (
69- source_lang : str ,
70- target_lang : str ,
71- example_type : str ,
72- example : Dict [str , str ]
73- ) -> None :
74- """Save a generated example to the cache."""
75- cache = _load_cache ()
76- key = _get_cache_key (source_lang , target_lang , example_type )
77- cache [key ] = example
78- _save_cache (cache )
79-
37+ if example_type == "placeholder" :
38+ return STATIC_PLACEHOLDER_EXAMPLE
39+ return None
8040
81- def _build_placeholder_prompt (source_lang : str , target_lang : str ) -> str :
82- """Build prompt to generate a placeholder preservation example."""
83- return f"""Translate this simple sentence from { source_lang } to { target_lang } .
8441
85- CRITICAL: Keep { TAG0 } and { TAG1 } EXACTLY as they appear. Do NOT modify them.
86-
87- Sentence: { PLACEHOLDER_TEMPLATE_EN }
88-
89- Reply with ONLY the translated sentence, nothing else."""
90-
91-
92- async def generate_placeholder_example_async (
93- source_lang : str ,
94- target_lang : str ,
95- provider : Any
96- ) -> Optional [Dict [str , str ]]:
42+ def get_placeholder_example () -> Dict [str , str ]:
9743 """
98- Generate a placeholder preservation example using the LLM.
99-
100- Args:
101- source_lang: Source language name
102- target_lang: Target language name
103- provider: An LLMProvider instance
44+ Get the static placeholder preservation example.
10445
10546 Returns:
106- Dict with "source", "correct", "wrong" or None if failed .
47+ Dict with "source", "correct", "wrong" keys .
10748 """
108- try :
109- # Get source sentence if not English
110- if source_lang .lower () == "english" :
111- source_text = PLACEHOLDER_TEMPLATE_EN
112- else :
113- # First get the source sentence in the source language
114- source_prompt = f'Translate to { source_lang } : "This is important text."\n Reply with ONLY the translation.'
115- source_response = await provider .generate (source_prompt , timeout = 30 )
116- if not source_response :
117- return None
118- base_source = source_response .strip ().strip ('"\' ' )
119- # Insert tags around "important" equivalent
120- # For simplicity, just wrap the whole middle section
121- source_text = f"{ TAG0 } { base_source } { TAG1 } "
122-
123- # Generate target translation
124- if target_lang .lower () == "english" :
125- translated = PLACEHOLDER_TEMPLATE_EN
126- else :
127- prompt = _build_placeholder_prompt (source_lang , target_lang )
128- response = await provider .generate (prompt , timeout = 30 )
129- if not response :
130- return None
131- translated = response .strip ().strip ('"\' ' )
132-
133- # Validate placeholders preserved
134- if TAG0 not in translated or TAG1 not in translated :
135- print (f"[WARNING] LLM did not preserve placeholders for { source_lang } ->{ target_lang } " )
136- return None
137-
138- # Build wrong example (placeholders removed)
139- wrong = translated .replace (TAG0 , "" ).replace (TAG1 , "" )
140- wrong = " " .join (wrong .split ())
141-
142- example = {
143- "source" : source_text ,
144- "correct" : translated ,
145- "wrong" : wrong
146- }
147-
148- save_technical_example (source_lang , target_lang , "placeholder" , example )
149- return example
150-
151- except Exception as e :
152- print (f"[WARNING] Failed to generate placeholder example: { e } " )
153- return None
154-
155-
156- def generate_placeholder_example_sync (
157- source_lang : str ,
158- target_lang : str ,
159- provider : Any
160- ) -> Optional [Dict [str , str ]]:
161- """Synchronous wrapper for placeholder example generation."""
162- try :
163- loop = asyncio .get_event_loop ()
164- if loop .is_running ():
165- import concurrent .futures
166- with concurrent .futures .ThreadPoolExecutor () as executor :
167- future = executor .submit (
168- asyncio .run ,
169- generate_placeholder_example_async (source_lang , target_lang , provider )
170- )
171- return future .result (timeout = 60 )
172- else :
173- return loop .run_until_complete (
174- generate_placeholder_example_async (source_lang , target_lang , provider )
175- )
176- except Exception as e :
177- print (f"[WARNING] Sync placeholder generation failed: { e } " )
178- return None
49+ return STATIC_PLACEHOLDER_EXAMPLE
17950
18051
18152async def ensure_technical_examples_ready (
@@ -185,29 +56,17 @@ async def ensure_technical_examples_ready(
18556 fast_mode : bool = False
18657) -> bool :
18758 """
188- Ensure technical examples exist for the language pair .
59+ Check if technical examples are ready .
18960
190- Generates missing examples using the LLM if a provider is given .
61+ Always returns True since we use static examples .
19162
19263 Args:
193- source_lang: Source language name
194- target_lang: Target language name
195- provider: Optional LLMProvider instance
64+ source_lang: Source language name (ignored)
65+ target_lang: Target language name (ignored)
66+ provider: Optional LLMProvider instance (ignored)
19667 fast_mode: If True, skips placeholder examples (not needed)
19768
19869 Returns:
199- True if all required examples exist or were generated .
70+ True always (static examples are always available) .
20071 """
201- if fast_mode :
202- # Fast mode doesn't need placeholder examples
203- return True
204-
205- # Placeholder examples for standard mode
206- if not get_cached_technical_example (source_lang , target_lang , "placeholder" ):
207- if provider :
208- result = await generate_placeholder_example_async (source_lang , target_lang , provider )
209- return result is not None
210- else :
211- return False
212-
21372 return True
0 commit comments