Save the transcript as subtitles too, not just as text

whisper-1's verbose response carries a start and an end for every segment,
and the file tab was reading only the start, to build the [mm:ss] prefix.
Keeping the end as well is all an SRT needs.

The text stays the authority on wording and the segments on timing; they
meet at that prefix, which the cleanup model is already told to leave alone.
So a transcript that went through cleanup still turns into properly timed
subtitles. A line whose stamp matches no segment runs until the next line
starts, a line with no stamp at all joins the cue above it, and an end that
would run into the next cue is trimmed back.

The button is dead until a timestamped run finishes, because without
timestamps there are no segments to time anything with.
This commit is contained in:
yusufipk
2026-07-26 22:33:32 +07:00
parent c3f22f0794
commit 37e360743d
6 changed files with 114 additions and 20 deletions
+5 -3
View File
@@ -151,7 +151,7 @@ def transcribe(target, wav_path, language="", prompt="", timeout=300):
def transcribe_segments(target, wav_path, language="", prompt="", timeout=300):
"""[(start_seconds, text)] using whisper-1's verbose response."""
"""[(start_seconds, end_seconds, text)] using whisper-1's verbose response."""
data = _transcribe_request(
target._replace(model=timestamp_model(target.provider)),
wav_path, language, prompt, "verbose_json",
@@ -162,12 +162,14 @@ def transcribe_segments(target, wav_path, language="", prompt="", timeout=300):
for seg in segments:
text = (seg.get("text") or "").strip()
if text:
out.append((float(seg.get("start") or 0.0), text))
start = float(seg.get("start") or 0.0)
end = float(seg.get("end") or 0.0)
out.append((start, max(end, start), text))
if not out:
text = (data.get("text") or "").strip()
if not text:
raise ApiError(t("Transcript came back empty."))
out = [(0.0, text)]
out = [(0.0, 0.0, text)]
return out