Skip to content

Commit 090f94f

Browse files
committed
Fix reviewer feedback: timeout constant, simplified error message, test integration
1 parent be1ddc3 commit 090f94f

File tree

4 files changed

+184
-249
lines changed

4 files changed

+184
-249
lines changed

src/co_op_translator/core/llm/markdown_translator.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class MarkdownTranslator(ABC):
2929
Provides common utilities and abstract methods to be implemented by providers.
3030
"""
3131

32+
TRANSLATION_TIMEOUT_SECONDS = 300 # Translation timeout in seconds
33+
3234
def __init__(self, root_dir: Path = None):
3335
"""Initialize translator with project configuration.
3436
@@ -165,19 +167,23 @@ async def _run_prompts_sequentially(self, prompts, md_file_path):
165167
for index, prompt in enumerate(prompts):
166168
try:
167169
result = await asyncio.wait_for(
168-
self._run_prompt(prompt, index + 1, len(prompts)), timeout=300
170+
self._run_prompt(prompt, index + 1, len(prompts)),
171+
timeout=self.TRANSLATION_TIMEOUT_SECONDS,
169172
)
170173
results.append(result)
171174
except asyncio.TimeoutError:
172175
logger.warning(
173-
f"Translation timeout for chunk {index + 1} of file '{md_file_path.name}': Request exceeded 300 seconds. Check your network connection and API response time."
176+
f"Translation timeout for chunk {index + 1} of file '{md_file_path.name}': "
177+
f"Request exceeded {self.TRANSLATION_TIMEOUT_SECONDS} seconds. "
178+
f"Check your network connection and API response time."
174179
)
175180
results.append(
176181
f"Translation for chunk {index + 1} of '{md_file_path.name}' skipped due to timeout."
177182
)
178183
except Exception as e:
179184
logger.error(
180-
f"Translation failed for chunk {index + 1} of file '{md_file_path.name}': {str(e)}. Check your API configuration and network connection."
185+
f"Translation failed for chunk {index + 1} of file '{md_file_path.name}': {str(e)}. "
186+
f"Check your API configuration and network connection."
181187
)
182188
results.append(
183189
f"Error translating chunk {index + 1} of '{md_file_path.name}': {str(e)}"

src/co_op_translator/core/vision/image_translator.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ def extract_line_bounding_boxes(self, image_path):
109109
return line_bounding_boxes
110110
else:
111111
raise Exception(
112-
f"No text detected in image '{Path(image_path).name}': The image may not contain readable text, or the text quality is too poor for recognition. Try using images with clear, high-contrast text."
112+
f"No text detected in image '{Path(image_path).name}': "
113+
f"The image may not contain clear, high-contrast text, or the text quality is too poor for recognition. "
114+
f"Please ensure the image contains readable text."
113115
)
114116

115117
def plot_annotated_image(
@@ -204,7 +206,8 @@ def plot_annotated_image(
204206
base_font = ImageFont.truetype(font_path, font_size)
205207
except IOError:
206208
logger.error(
207-
f"Font file not found for language '{target_language_code}' at '{font_path}' in image '{Path(image_path).name}': Using default font. Install the required font or check font configuration."
209+
f"Font file not found for language '{target_language_code}' at '{font_path}' in image '{Path(image_path).name}': "
210+
f"Using default font. Install the required font or check font configuration."
208211
)
209212
base_font = ImageFont.load_default()
210213

@@ -229,7 +232,9 @@ def plot_annotated_image(
229232
bounding_box_flat = line_info.get("bounding_box", [])
230233
if len(bounding_box_flat) != 8:
231234
logger.error(
232-
f"Invalid text detection data in image '{Path(image_path).name}': Expected 8 coordinates but got {len(bounding_box_flat)}. The text detection may be corrupted."
235+
f"Invalid text detection data in image '{Path(image_path).name}': "
236+
f"Expected 8 coordinates but got {len(bounding_box_flat)}. "
237+
f"The text detection may be corrupted."
233238
)
234239
continue
235240

@@ -238,7 +243,8 @@ def plot_annotated_image(
238243
)
239244
if len(bounding_box_tuples) < 4:
240245
logger.error(
241-
f"Insufficient bounding box points in image '{Path(image_path).name}': Text detection data is incomplete. Try re-processing the image."
246+
f"Insufficient bounding box points in image '{Path(image_path).name}': "
247+
f"Text detection data is incomplete. Try re-processing the image."
242248
)
243249
continue
244250

@@ -250,7 +256,8 @@ def plot_annotated_image(
250256
angle = -angle # Invert angle for proper rotation.
251257
except ValueError:
252258
logger.error(
253-
f"Invalid bounding box coordinates in image '{Path(image_path).name}': Text detection geometry is malformed. The image may have distorted text regions."
259+
f"Invalid bounding box coordinates in image '{Path(image_path).name}': "
260+
f"Text detection geometry is malformed. The image may have distorted text regions."
254261
)
255262
continue
256263

@@ -288,7 +295,8 @@ def plot_annotated_image(
288295
font = ImageFont.truetype(font_path, optimal_font_size)
289296
except IOError:
290297
logger.error(
291-
f"Font file not found for language '{target_language_code}' at '{font_path}' in image '{Path(image_path).name}': Using default font. Install the required font or check font configuration."
298+
f"Font file not found for language '{target_language_code}' at '{font_path}' in image '{Path(image_path).name}': "
299+
f"Using default font. Install the required font or check font configuration."
292300
)
293301
font = ImageFont.load_default()
294302

@@ -353,7 +361,8 @@ def plot_annotated_image(
353361
font = ImageFont.truetype(font_path, font_size)
354362
except IOError:
355363
logger.error(
356-
f"Font file not found for language '{target_language_code}' at '{font_path}' in image '{Path(image_path).name}': Using default font. Install the required font or check font configuration."
364+
f"Font file not found for language '{target_language_code}' at '{font_path}' in image '{Path(image_path).name}': "
365+
f"Using default font. Install the required font or check font configuration."
357366
)
358367
font = ImageFont.load_default()
359368

@@ -461,7 +470,9 @@ def translate_image(
461470
# Check if any text was recognized
462471
if not line_bounding_boxes:
463472
logger.info(
464-
f"No text detected in image '{image_path.name}': Saving original image as translation result. The image may not contain readable text or text may be too small/blurry to detect."
473+
f"No text detected in image '{image_path.name}': "
474+
f"Saving original image as translation result. "
475+
f"The image may not contain readable text or text may be too small/blurry to detect."
465476
)
466477

467478
# Load the original image and save it with the new name
@@ -492,7 +503,8 @@ def translate_image(
492503

493504
except Exception as e:
494505
logger.error(
495-
f"Failed to translate image '{image_path.name}': {str(e)}. Saving original image instead. Check Computer Vision API configuration and image file accessibility."
506+
f"Failed to translate image '{image_path.name}': {str(e)}. "
507+
f"Saving original image instead."
496508
)
497509

498510
# Load the original image and save it with the new name
@@ -543,5 +555,7 @@ def create(
543555
except (ImportError, ValueError) as e:
544556
logger.warning(f"Computer Vision is not properly configured: {e}")
545557
raise ValueError(
546-
"Computer Vision not configured: Missing required environment variables (AZURE_COMPUTER_VISION_KEY, AZURE_COMPUTER_VISION_ENDPOINT). Please check your .env file and API configuration."
558+
"Image translation is not configured: Missing required environment variables "
559+
"(AZURE_AI_SERVICE_API_KEY, AZURE_AI_SERVICE_ENDPOINT). "
560+
"Please check your .env file and ensure your Azure AI service credentials are set correctly."
547561
)

tests/co_op_translator/core/project/test_project_translator.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,154 @@ async def test_markdown_only_mode(temp_project_dir):
155155
]
156156
is True
157157
)
158+
159+
160+
class TestProjectTranslatorErrorMessages:
161+
"""Test improved error messages in ProjectTranslator.
162+
163+
This test class verifies error message improvements made for issue #46.
164+
These tests ensure that error messages are user-friendly and provide helpful context.
165+
"""
166+
167+
def test_computer_vision_config_error_message(self, tmp_path, caplog):
168+
"""Test Computer Vision configuration error message."""
169+
# Set logging level to capture info messages
170+
caplog.set_level("INFO")
171+
172+
with patch(
173+
"co_op_translator.core.vision.image_translator.ImageTranslator.create",
174+
side_effect=ValueError("CV error"),
175+
):
176+
with patch(
177+
"co_op_translator.core.llm.text_translator.TextTranslator.create"
178+
):
179+
with patch(
180+
"co_op_translator.core.llm.markdown_translator.MarkdownTranslator.create"
181+
):
182+
translator = ProjectTranslator(
183+
"ko", str(tmp_path), markdown_only=False
184+
)
185+
186+
# Check that it auto-switched to markdown_only
187+
assert translator.markdown_only is True
188+
189+
# Check improved log message
190+
log_text = caplog.text
191+
assert "Computer Vision not configured" in log_text
192+
assert "AZURE_COMPUTER_VISION_KEY" in log_text
193+
194+
def test_markdown_only_mode_message(self, tmp_path, caplog):
195+
"""Test markdown-only mode initialization message."""
196+
# Set logging level to capture info messages
197+
caplog.set_level("INFO")
198+
199+
with patch("co_op_translator.core.llm.text_translator.TextTranslator.create"):
200+
with patch(
201+
"co_op_translator.core.llm.markdown_translator.MarkdownTranslator.create"
202+
):
203+
translator = ProjectTranslator("ko", str(tmp_path), markdown_only=True)
204+
205+
# Check improved log message for markdown-only mode
206+
log_text = caplog.text
207+
assert "Running in markdown-only mode" in log_text
208+
assert "Image translation disabled" in log_text
209+
210+
def test_missing_api_keys_scenario(self, tmp_path):
211+
"""Test scenario where all API keys are missing."""
212+
with patch(
213+
"co_op_translator.config.llm_config.config.LLMConfig.get_available_provider",
214+
return_value=None,
215+
):
216+
with patch(
217+
"co_op_translator.config.vision_config.config.VisionConfig.get_available_provider",
218+
side_effect=ValueError("No CV"),
219+
):
220+
# Should raise error when trying to create without proper config
221+
with pytest.raises(ValueError) as exc_info:
222+
ProjectTranslator("ko", str(tmp_path), markdown_only=False)
223+
224+
# Check error message contains the actual message from the code
225+
error_msg = str(exc_info.value)
226+
assert "No valid LLM provider configured" in error_msg
227+
228+
def test_project_initialization_with_missing_services(self, tmp_path, caplog):
229+
"""Test ProjectTranslator initialization when services are missing."""
230+
# Set logging level to capture info messages
231+
caplog.set_level("INFO")
232+
233+
with patch("co_op_translator.core.llm.text_translator.TextTranslator.create"):
234+
with patch(
235+
"co_op_translator.core.llm.markdown_translator.MarkdownTranslator.create"
236+
):
237+
with patch(
238+
"co_op_translator.core.vision.image_translator.ImageTranslator.create",
239+
side_effect=ValueError("No CV"),
240+
):
241+
translator = ProjectTranslator(
242+
"ko ja", str(tmp_path), markdown_only=False
243+
)
244+
245+
# Should auto-switch to markdown-only
246+
assert translator.markdown_only is True
247+
assert translator.image_translator is None
248+
249+
# Should have helpful error message
250+
log_text = caplog.text
251+
assert "Computer Vision not configured" in log_text
252+
assert "AZURE_COMPUTER_VISION_KEY" in log_text
253+
254+
def test_environment_variable_references_in_logs(self, tmp_path, caplog):
255+
"""Test that log messages reference environment variables."""
256+
caplog.set_level("INFO")
257+
258+
with patch(
259+
"co_op_translator.core.vision.image_translator.ImageTranslator.create",
260+
side_effect=ValueError("Image translation error"),
261+
):
262+
with patch(
263+
"co_op_translator.core.llm.text_translator.TextTranslator.create"
264+
):
265+
with patch(
266+
"co_op_translator.core.llm.markdown_translator.MarkdownTranslator.create"
267+
):
268+
ProjectTranslator("ko", str(tmp_path), markdown_only=False)
269+
270+
log_text = caplog.text
271+
# Check the actual log message format
272+
assert "Computer Vision not configured" in log_text
273+
assert "AZURE_COMPUTER_VISION_KEY" in log_text
274+
275+
276+
def test_computer_vision_config_error_message(tmp_path, caplog):
277+
"""Test Computer Vision configuration error message."""
278+
caplog.set_level("INFO")
279+
280+
with patch(
281+
"co_op_translator.core.vision.image_translator.ImageTranslator.create",
282+
side_effect=ValueError("CV error"),
283+
):
284+
with patch("co_op_translator.core.llm.text_translator.TextTranslator.create"):
285+
with patch(
286+
"co_op_translator.core.llm.markdown_translator.MarkdownTranslator.create"
287+
):
288+
translator = ProjectTranslator("ko", str(tmp_path), markdown_only=False)
289+
290+
assert translator.markdown_only is True
291+
log_text = caplog.text
292+
assert "Computer Vision not configured" in log_text
293+
assert "AZURE_COMPUTER_VISION_KEY" in log_text
294+
295+
296+
def test_markdown_only_mode_message(tmp_path, caplog):
297+
"""Test markdown-only mode initialization message."""
298+
caplog.set_level("INFO")
299+
300+
with patch("co_op_translator.core.llm.text_translator.TextTranslator.create"):
301+
with patch(
302+
"co_op_translator.core.llm.markdown_translator.MarkdownTranslator.create"
303+
):
304+
translator = ProjectTranslator("ko", str(tmp_path), markdown_only=True)
305+
306+
log_text = caplog.text
307+
assert "Running in markdown-only mode" in log_text
308+
assert "Image translation disabled" in log_text

0 commit comments

Comments
 (0)