#!/usr/bin/env -S uv run --script # /// script # dependencies = ["httpx"] # /// import argparse import base64 import functools import logging import os import re import subprocess import tempfile import textwrap import time from collections.abc import Callable from dataclasses import dataclass from pathlib import Path import httpx RETRY_STATUS_CODES = {429, 500, 502, 503, 504, 524, 529} MAX_ATTEMPTS = 5 MIN_SPLIT_DURATION = 1.0 MIN_CHUNK_DURATION = 0.1 DIALOGUE_LINE_LENGTH = 42 MAX_DIALOGUE_GAP = 1.0 MAX_DIALOGUE_DURATION = 7.0 LINE_LENGTH = 42 MAX_LINES = 2 # lowercase tokens (en, tr) whose trailing period does not end a sentence ABBREVIATIONS = {"mr", "mrs", "ms", "dr", "prof", "e.g", "i.e", "vs", "etc", "doç", "av", "sn", "vb", "bkz"} # Finds candidate sentence boundaries: end punctuation, optional closers, then whitespace. # Matches in "He left. Then" -> ". " and in 'He said "no." Then' -> '." '. SENTENCE_END = re.compile( r""" [.!?…]+ # one or more end marks: "." "?!" "..." or the ellipsis character [\"'”’)\]]* # closing quotes or brackets that belong to the finished sentence \s+ # whitespace after it; one or more, so double spaces work too """, re.VERBOSE, ) logger = logging.getLogger(__name__) @dataclass class Segment: """A timed piece of transcript; times are in seconds, speaker is a diarization index if known.""" start: float end: float text: str speaker: int | None = None def parse_args() -> argparse.Namespace: """Parse command-line arguments.""" parser = argparse.ArgumentParser( description="Transcribe a video into an SRT file using an OpenRouter speech-to-text model.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser.add_argument("video", type=Path, help="Input video (or audio) file") parser.add_argument("--output", "-o", type=Path, help="Output SRT path (default: