digest: translate variants once per active non-en language
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d318039ad5
commit
924f37548b
2 changed files with 152 additions and 8 deletions
|
|
@ -250,3 +250,85 @@ async def test_analyse_no_clause_when_lang_is_en(tmp_path, monkeypatch):
|
|||
await pa.analyse(session, req)
|
||||
system = next(m["content"] for m in captured["messages"] if m["role"] == "system")
|
||||
assert "Respond in" not in system
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_digest_translates_variants_per_active_lang(monkeypatch):
|
||||
"""After English variants are built, the job translates each to every
|
||||
active non-en lang. The result is an in-memory mapping the send loop
|
||||
consults."""
|
||||
from unittest.mock import MagicMock
|
||||
from app.jobs import email_digest_job as ed
|
||||
from app.services.openrouter import LogResult
|
||||
|
||||
english_variants = {
|
||||
"NOVICE": "**Today.** Markets calmer.",
|
||||
"INTERMEDIATE": "**Today.** Indices slightly down.",
|
||||
"PRO": "**Today.** Risk-off rotation, breadth weak.",
|
||||
}
|
||||
|
||||
translate_calls: list[tuple[str, str]] = []
|
||||
|
||||
async def _fake_translate(client, text, target_lang):
|
||||
translate_calls.append((text, target_lang))
|
||||
return f"[IT] {text}", LogResult(
|
||||
content=f"[IT] {text}", model="m",
|
||||
prompt_tokens=10, completion_tokens=10, cost_usd=0.0,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(ed, "translate", _fake_translate)
|
||||
|
||||
client = MagicMock()
|
||||
table = await ed._translate_variants_for_active_langs(
|
||||
client, english_variants, ["it"],
|
||||
)
|
||||
|
||||
# Three tones × one non-en lang = three translation calls.
|
||||
assert len(translate_calls) == 3
|
||||
assert {lang for _, lang in translate_calls} == {"it"}
|
||||
|
||||
# English entries are present unchanged.
|
||||
assert table[("NOVICE", "en")] == english_variants["NOVICE"]
|
||||
assert table[("PRO", "en")] == english_variants["PRO"]
|
||||
# Italian entries are populated.
|
||||
assert table[("INTERMEDIATE", "it")].startswith("[IT] ")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_digest_translation_failure_falls_back_to_english(monkeypatch):
|
||||
"""When translate() fails for a (tone, lang) cell, the table entry
|
||||
for that cell is the English variant of the same tone — the user
|
||||
still gets a digest, just in English that day."""
|
||||
from unittest.mock import MagicMock
|
||||
from app.jobs import email_digest_job as ed
|
||||
|
||||
english_variants = {"INTERMEDIATE": "**Today.** Indices down."}
|
||||
|
||||
async def _fake_translate(client, text, target_lang):
|
||||
raise RuntimeError("upstream down")
|
||||
monkeypatch.setattr(ed, "translate", _fake_translate)
|
||||
|
||||
client = MagicMock()
|
||||
table = await ed._translate_variants_for_active_langs(
|
||||
client, english_variants, ["it"],
|
||||
)
|
||||
|
||||
assert table[("INTERMEDIATE", "it")] == english_variants["INTERMEDIATE"]
|
||||
|
||||
|
||||
def test_digest_pick_variant_uses_user_lang():
|
||||
"""The variant-picker helper consults user.digest_tone + user.lang."""
|
||||
from app.jobs import email_digest_job as ed
|
||||
|
||||
table = {
|
||||
("NOVICE", "en"): "novice en",
|
||||
("NOVICE", "it"): "novice it",
|
||||
("INTERMEDIATE", "en"): "intermediate en",
|
||||
("INTERMEDIATE", "it"): "intermediate it",
|
||||
}
|
||||
assert ed._pick_variant(table, tone="NOVICE", lang="it") == "novice it"
|
||||
assert ed._pick_variant(table, tone="INTERMEDIATE", lang="en") == "intermediate en"
|
||||
# Missing lang → fallback to English variant of the same tone.
|
||||
assert ed._pick_variant(table, tone="NOVICE", lang="de") == "novice en"
|
||||
# Missing tone → fallback to INTERMEDIATE/en (the safe default).
|
||||
assert ed._pick_variant(table, tone="UNKNOWN", lang="en") == "intermediate en"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue