diff --git a/moss_transcribe_diarize/app/jobs.py b/moss_transcribe_diarize/app/jobs.py index ef977fb..ee3ce5e 100644 --- a/moss_transcribe_diarize/app/jobs.py +++ b/moss_transcribe_diarize/app/jobs.py @@ -316,9 +316,10 @@ def render(self, job_id: str, style_payload: dict[str, Any] | None = None) -> Jo raise RuntimeError("ffmpeg and ffprobe are not available on PATH.") if not job.segments_path.exists(): raise RuntimeError("No subtitle segments are available for this job.") + resolved_style = job.subtitle_style if style_payload is None else style_payload threading.Thread( target=self._render_job, - args=(job.id, SubtitleStyle.from_dict(style_payload)), + args=(job.id, SubtitleStyle.from_dict(resolved_style)), name=f"mtd-render-{job.id}", daemon=True, ).start() diff --git a/tests/test_app_api.py b/tests/test_app_api.py index 7db6610..0778c47 100644 --- a/tests/test_app_api.py +++ b/tests/test_app_api.py @@ -213,6 +213,73 @@ def test_running_job_exposes_live_token_progress(self): self.assertEqual(finished["status"], "waiting_review") self.assertEqual(finished["usage"]["generated_tokens"], 5) + def test_render_reuses_saved_style_unless_explicitly_overridden(self): + from fastapi.testclient import TestClient + from moss_transcribe_diarize.app.server import create_app + + with tempfile.TemporaryDirectory() as tmpdir: + app = create_app(model_path="fake-model", runs_dir=tmpdir) + app.state.manager.model_runner = FakeRunner() + client = TestClient(app) + + created = client.post( + "/api/jobs", + files={"file": ("sample.wav", b"audio", "audio/wav")}, + ) + self.assertEqual(created.status_code, 200) + job_id = created.json()["id"] + + job = {} + for _ in range(40): + job = client.get(f"/api/jobs/{job_id}").json() + if job["status"] == "waiting_review": + break + time.sleep(0.05) + self.assertEqual(job["status"], "waiting_review") + + segments = client.get(f"/api/jobs/{job_id}/segments").json()["segments"] + updated = client.put( + f"/api/jobs/{job_id}/segments", + json={ + "segments": segments, + "style": { + "font_size": 42, + "margin_v": 80, + "speaker_names": {"S01": "Alice"}, + }, + }, + ) + self.assertEqual(updated.status_code, 200) + + class Available: + available = True + + with patch("moss_transcribe_diarize.app.jobs.detect_ffmpeg", return_value=Available()), patch( + "moss_transcribe_diarize.app.jobs.threading.Thread" + ) as thread_cls: + rendered = client.post(f"/api/jobs/{job_id}/render") + self.assertEqual(rendered.status_code, 200) + saved_style = thread_cls.call_args.kwargs["args"][1] + self.assertEqual(saved_style.font_size, 42) + self.assertEqual(saved_style.margin_v, 80) + self.assertEqual(saved_style.speaker_names, {"S01": "Alice"}) + + overridden = client.post( + f"/api/jobs/{job_id}/render", + json={ + "style": { + "font_size": 60, + "margin_v": 96, + "speaker_names": {"S01": "Bob"}, + } + }, + ) + self.assertEqual(overridden.status_code, 200) + explicit_style = thread_cls.call_args.kwargs["args"][1] + self.assertEqual(explicit_style.font_size, 60) + self.assertEqual(explicit_style.margin_v, 96) + self.assertEqual(explicit_style.speaker_names, {"S01": "Bob"}) + if __name__ == "__main__": unittest.main()