add chinese subtitles
This commit is contained in:
@@ -71,3 +71,34 @@ def test_ai_tutor_rejects_unexpected_response(monkeypatch):
|
||||
|
||||
with pytest.raises(AITutorError):
|
||||
tutor.explain("Hello.")
|
||||
|
||||
|
||||
from sentence_api.ai_tutor import _parse_translation_payload
|
||||
|
||||
|
||||
def test_ai_tutor_translates_full_document(monkeypatch):
|
||||
requests_payloads = []
|
||||
|
||||
def fake_post(endpoint, headers, json, timeout):
|
||||
requests_payloads.append((endpoint, headers, json, timeout))
|
||||
return FakeResponse(body={"choices": [{"message": {"content": '["你好。", "见到你很高兴。"]'}}]})
|
||||
|
||||
monkeypatch.setattr("sentence_api.ai_tutor.requests.post", fake_post)
|
||||
tutor = AITutor("https://ai.test/v1", "secret", "test-model", 1.5)
|
||||
|
||||
translated = tutor.translate_sentences(
|
||||
[(0, "Hello."), (1, "Nice to meet you.")],
|
||||
course_title="Greetings",
|
||||
)
|
||||
|
||||
assert translated == {0: "你好。", 1: "见到你很高兴。"}
|
||||
_endpoint, _headers, payload, timeout = requests_payloads[0]
|
||||
user_prompt = payload["messages"][1]["content"]
|
||||
assert "Hello." in user_prompt
|
||||
assert "Nice to meet you." in user_prompt
|
||||
assert timeout == 90.0
|
||||
|
||||
|
||||
def test_parse_translation_payload_accepts_fenced_json_and_numbered_lines():
|
||||
assert _parse_translation_payload('```json\n["一", "二"]\n```', 2) == ["一", "二"]
|
||||
assert _parse_translation_payload("1. 一\n2. 二", 2) == ["一", "二"]
|
||||
|
||||
@@ -202,6 +202,72 @@ def test_sentence_explanation_uses_server_side_ai_client(tmp_path, monkeypatch):
|
||||
]
|
||||
|
||||
|
||||
|
||||
def _ready_video(repository):
|
||||
repository.upsert_upload(
|
||||
video_hash=VIDEO_HASH,
|
||||
title="Greetings",
|
||||
filename="lesson.mp4",
|
||||
stored_filename=f"{VIDEO_HASH}.mp4",
|
||||
content_type="video/mp4",
|
||||
size_bytes=5,
|
||||
language="en",
|
||||
)
|
||||
repository.save_processing_result(
|
||||
SentenceBoundaryDocument(
|
||||
video_hash=VIDEO_HASH,
|
||||
duration_ms=9000,
|
||||
algorithm_version="test",
|
||||
sentences=[
|
||||
SentenceBoundary(index=0, start_ms=0, end_ms=4000, text="Hello.", language="en", reference_speech_duration_ms=3000),
|
||||
SentenceBoundary(index=1, start_ms=4000, end_ms=9000, text="Nice to meet you.", language="en", reference_speech_duration_ms=4000),
|
||||
],
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
def test_subtitle_translation_requires_login(tmp_path):
|
||||
client = make_client(tmp_path)
|
||||
client.headers.clear()
|
||||
response = client.post(f"/api/v1/videos/{VIDEO_HASH}/subtitle-translation")
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_subtitle_translation_uses_full_document_and_is_cached(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))
|
||||
return {index: f"中文{index}" for index, _text in sentences}
|
||||
|
||||
class StubAITutor:
|
||||
pass
|
||||
|
||||
stub = StubAITutor()
|
||||
stub.translate_sentences = translate_sentences
|
||||
monkeypatch.setattr(client.app.state, "ai_tutor", stub)
|
||||
|
||||
response = client.post(f"/api/v1/videos/{VIDEO_HASH}/subtitle-translation")
|
||||
assert response.status_code == 200, response.text
|
||||
payload = response.json()
|
||||
assert payload["video_hash"] == VIDEO_HASH
|
||||
assert payload["translations"] == [
|
||||
{"index": 0, "zh_text": "中文0"},
|
||||
{"index": 1, "zh_text": "中文1"},
|
||||
]
|
||||
document = client.app.state.video_repository.get_document(VIDEO_HASH)
|
||||
assert [sentence.zh_text for sentence in document.sentences] == ["中文0", "中文1"]
|
||||
|
||||
second = client.post(f"/api/v1/videos/{VIDEO_HASH}/subtitle-translation")
|
||||
assert second.status_code == 200
|
||||
assert second.json() == payload
|
||||
assert len(requested) == 1
|
||||
assert requested[0][0] == [(0, "Hello."), (1, "Nice to meet you.")]
|
||||
|
||||
|
||||
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")
|
||||
|
||||
Reference in New Issue
Block a user