Spaces:
Running
Running
| """Phase 1.1 / 2.7 β translator service. | |
| Validates the glossary prompt-prefixing and the graceful "no LLM" path. | |
| Does NOT hit a real LLM β the client is mocked. | |
| """ | |
| import os | |
| os.environ.setdefault("OMNIVOICE_DISABLE_FILE_LOG", "1") | |
| from unittest.mock import MagicMock, patch | |
| import pytest | |
| from services import translator as tr | |
| # ββ Glossary preamble ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def test_glossary_text_empty_inputs(): | |
| assert tr._glossary_text(None) == "" | |
| assert tr._glossary_text([]) == "" | |
| assert tr._glossary_text([{"source": "", "target": "y"}]) == "" | |
| def test_glossary_text_includes_each_term(): | |
| out = tr._glossary_text([ | |
| {"source": "Marcus", "target": "Marcus", "note": "character name"}, | |
| {"source": "breakthrough", "target": "Durchbruch"}, | |
| ]) | |
| assert "Marcus β Marcus" in out | |
| assert "breakthrough β Durchbruch" in out | |
| assert "character name" in out | |
| # ββ No-LLM graceful path βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def test_cinematic_no_llm_returns_literal_with_marker(monkeypatch): | |
| monkeypatch.setattr(tr, "_llm_client", lambda: None) | |
| res = tr.cinematic_refine_sync( | |
| "Hello.", | |
| "Hola.", | |
| source_lang="en", | |
| target_lang="es", | |
| ) | |
| # With no LLM, "text" falls back to literal and an error marker is present. | |
| assert res["text"] == "Hola." | |
| assert res["literal"] == "Hola." | |
| assert res["critique"] == "" | |
| assert res.get("error") == "no-llm" | |
| def test_cinematic_empty_literal_is_passthrough(): | |
| res = tr.cinematic_refine_sync( | |
| "Source", | |
| "", | |
| source_lang="en", | |
| target_lang="es", | |
| ) | |
| assert res["text"] == "" | |
| assert res["literal"] == "" | |
| # No error when there's literally nothing to refine. | |
| assert "error" not in res | |
| # ββ Happy-path 3-step chain (mocked client) ββββββββββββββββββββββββββββββββ | |
| def test_cinematic_full_chain_with_mocked_llm(monkeypatch): | |
| calls = [] | |
| responses = iter([ | |
| "reads stiff; prefer idiomatic phrasing", # reflect | |
| "Hola, mundo.", # adapt | |
| ]) | |
| def fake_chat(client, *, system, user): | |
| calls.append({"system": system, "user": user}) | |
| return next(responses) | |
| mock_client = MagicMock() | |
| monkeypatch.setattr(tr, "_llm_client", lambda: mock_client) | |
| monkeypatch.setattr(tr, "_chat", fake_chat) | |
| res = tr.cinematic_refine_sync( | |
| "Hello, world.", | |
| "Hola mundo.", | |
| source_lang="en", | |
| target_lang="es", | |
| glossary=[{"source": "world", "target": "mundo"}], | |
| ) | |
| assert res["literal"] == "Hola mundo." | |
| assert res["text"] == "Hola, mundo." | |
| assert res["critique"] == "reads stiff; prefer idiomatic phrasing" | |
| assert len(calls) == 2 | |
| # Glossary prepended to both system prompts (reflect + adapt). | |
| assert "world β mundo" in calls[0]["system"] | |
| assert "world β mundo" in calls[1]["system"] | |
| def test_cinematic_reflect_failure_returns_literal(monkeypatch): | |
| mock_client = MagicMock() | |
| monkeypatch.setattr(tr, "_llm_client", lambda: mock_client) | |
| def boom(*a, **kw): | |
| raise RuntimeError("LLM down") | |
| monkeypatch.setattr(tr, "_chat", boom) | |
| res = tr.cinematic_refine_sync( | |
| "Hello", | |
| "Hola", | |
| source_lang="en", | |
| target_lang="es", | |
| ) | |
| assert res["text"] == "Hola" | |
| assert res["literal"] == "Hola" | |
| assert "reflect" in res.get("error", "") | |