add a retranslate chinese function

This commit is contained in:
2026-10-06 14:47:22 +08:00
parent 4fd0fd36a4
commit b28f809c46
11 changed files with 448 additions and 9 deletions

View File

@@ -4,7 +4,7 @@ import json
import re
import threading
from sentence_api.ai_tutor import AITutor, AITutorError, _parse_translation_payload
from sentence_api.ai_tutor import AITutor, AITutorError, _apply_translation_terms, _parse_translation_payload
class FakeResponse:
@@ -173,6 +173,38 @@ def test_ai_tutor_splits_invalid_windows_and_retries(monkeypatch):
assert calls["count"] >= 3
def test_ai_tutor_includes_name_terms_and_rewrites_output(monkeypatch):
requests_payloads = []
def fake_post(endpoint, headers, json, timeout):
requests_payloads.append(json)
return FakeResponse(
body={"choices": [{"message": {"content": '{"0":"哈达马托击败了 Harimoto。"}'}}]}
)
monkeypatch.setattr("sentence_api.ai_tutor.requests.post", fake_post)
tutor = AITutor("https://ai.test/v1", "secret", "test-model", 1)
translated = tutor.translate_sentences(
[(0, "Harimoto won.")],
course_title="Table tennis",
terms=[("Harimoto", "哈瑞么托"), ("哈达马托", "哈瑞么托")],
)
assert translated == {0: "哈瑞么托击败了 哈瑞么托。"}
user_prompt = requests_payloads[0]["messages"][1]["content"]
assert "Harimoto => 哈瑞么托" in user_prompt
assert "哈达马托 => 哈瑞么托" in user_prompt
def test_apply_translation_terms_replaces_english_and_wrong_chinese():
assert _apply_translation_terms(
"Harimoto won.",
"哈达马托击败了 Harimoto。",
[("Harimoto", "哈瑞么托"), ("哈达马托", "哈瑞么托")],
) == "哈瑞么托击败了 哈瑞么托。"
def test_parse_translation_payload_accepts_fenced_json_and_numbered_lines():
assert _parse_translation_payload('```json\n["一", "二"]\n```', 2) == {0: "一", 1: "二"}
assert _parse_translation_payload("1. 一\n2. 二", 2) == {0: "一", 1: "二"}

View File

@@ -391,6 +391,59 @@ def test_subtitle_translation_does_not_block_http_on_long_jobs(tmp_path, monkeyp
assert len(requested) == 1
def test_admin_can_retranslate_subtitles_with_name_terms(tmp_path, monkeypatch):
client = make_client(tmp_path)
_ready_video(client.app.state.video_repository)
requested = []
def translate_sentences(sentences, **kwargs):
requested.append((sentences, kwargs.get("terms")))
terms = dict(kwargs.get("terms") or [])
return {
index: terms.get("Harimoto", "哈达马托") + f":{text}"
for index, text in sentences
}
class StubAITutor:
available = True
stub = StubAITutor()
stub.translate_sentences = translate_sentences
monkeypatch.setattr(client.app.state, "ai_tutor", stub)
client.app.state.subtitle_translations.ai_tutor = stub
client.app.state.subtitle_translations.post_wait_seconds = 0.2
first = client.post(f"/api/v1/videos/{VIDEO_HASH}/subtitle-translation")
if not first.json().get("complete"):
first = wait_for_subtitle_translation(client, VIDEO_HASH)
assert first.json()["translations"] == [
{"index": 0, "zh_text": "哈达马托:Hello."},
{"index": 1, "zh_text": "哈达马托:Nice to meet you."},
]
response = client.post(
f"/api/v1/admin/videos/{VIDEO_HASH}/subtitle-translation",
json={"terms": [{"source": "Harimoto", "zh": "哈瑞么托"}]},
)
assert response.status_code == 200, response.text
if not response.json().get("complete"):
response = wait_for_subtitle_translation(client, VIDEO_HASH)
stored = client.get(f"/api/v1/admin/videos/{VIDEO_HASH}/subtitle-translation")
assert stored.status_code == 200
payload = stored.json()
else:
payload = response.json()
assert payload["translations"] == [
{"index": 0, "zh_text": "哈瑞么托:Hello."},
{"index": 1, "zh_text": "哈瑞么托:Nice to meet you."},
]
assert payload["terms"] == [{"source": "Harimoto", "zh": "哈瑞么托"}]
assert requested[-1][1] == [("Harimoto", "哈瑞么托")]
assert client.app.state.video_repository.get_translation_glossary(VIDEO_HASH) == [
("Harimoto", "哈瑞么托")
]
def test_oss_video_url_is_used_for_catalog_and_content(tmp_path):
index_path = tmp_path / "boundaries.json"
index_path.write_text("{}", encoding="utf-8")