fix: preserve upload recovery and harden speech indexing
This commit is contained in:
+49
-24
@@ -29,22 +29,44 @@ def arguments() -> argparse.Namespace:
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def worker_run(data_dir: Path, wav: Path, window: dict, combination: tuple[str, ...]) -> dict:
|
||||
def _write_window_batch(source: Path, destination: Path, windows: list[dict]) -> int:
|
||||
"""Concatenate equal-sized diagnostic windows without reloading Whisper."""
|
||||
with wave.open(str(source), "rb") as handle:
|
||||
params = handle.getparams()
|
||||
sample_rate = handle.getframerate()
|
||||
frame_count = handle.getnframes()
|
||||
durations = {int(item["end_ms"]) - int(item["start_ms"]) for item in windows}
|
||||
if len(durations) != 1:
|
||||
raise ValueError("all diagnostic windows for one media item must have equal duration")
|
||||
duration_ms = durations.pop()
|
||||
frames_per_window = duration_ms * sample_rate // 1000
|
||||
with wave.open(str(destination), "wb") as output:
|
||||
output.setparams(params)
|
||||
for item in windows:
|
||||
start_frame = int(item["start_ms"]) * sample_rate // 1000
|
||||
handle.setpos(min(start_frame, frame_count))
|
||||
raw = handle.readframes(frames_per_window)
|
||||
expected = frames_per_window * params.nchannels * params.sampwidth
|
||||
if len(raw) < expected:
|
||||
raw += b"\0" * (expected - len(raw))
|
||||
output.writeframesraw(raw)
|
||||
return duration_ms
|
||||
|
||||
|
||||
def worker_run(data_dir: Path, wav: Path, windows: list[dict], combination: tuple[str, ...]) -> list[dict]:
|
||||
name, model, device, segmentation = combination
|
||||
with wave.open(str(wav), "rb") as handle:
|
||||
sample_rate = handle.getframerate()
|
||||
start_ms = int(window["start_ms"])
|
||||
duration_ms = int(window["end_ms"]) - start_ms
|
||||
duration_ms = round(handle.getnframes() / handle.getframerate() * 1000 / len(windows))
|
||||
command = [
|
||||
sys.executable, "-m", "imagefind.audio_worker",
|
||||
"--data-dir", str(data_dir), "--wav", str(wav),
|
||||
"--device", device, "--model-variant", model,
|
||||
"--segmentation", segmentation, "--quality-profile", "accuracy",
|
||||
"--language-policy", str(window.get("language_policy", "zh_priority")),
|
||||
"--language-policy", str(windows[0].get("language_policy", "zh_priority")),
|
||||
"--chunk-seconds", str(max(15, min(30, (duration_ms + 999) // 1000))),
|
||||
"--overlap-seconds", "0",
|
||||
"--start-frame", str(start_ms * sample_rate // 1000),
|
||||
"--max-chunks", "1", "--cpu-threads", "2",
|
||||
"--start-frame", "0",
|
||||
"--max-chunks", str(len(windows)), "--cpu-threads", "2",
|
||||
]
|
||||
started = time.monotonic()
|
||||
process = subprocess.run(command, text=True, capture_output=True, encoding="utf-8", errors="replace")
|
||||
@@ -55,19 +77,21 @@ def worker_run(data_dir: Path, wav: Path, window: dict, combination: tuple[str,
|
||||
events.append(json.loads(line))
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return {
|
||||
"combination": name,
|
||||
"model": model,
|
||||
"device": device,
|
||||
"beam": 1 if device == "GPU" else 5,
|
||||
"segmentation": segmentation,
|
||||
"elapsed_seconds": round(elapsed, 3),
|
||||
"window_seconds": round(duration_ms / 1000, 3),
|
||||
"rtf": round(elapsed / max(0.001, duration_ms / 1000), 3),
|
||||
"exit_code": process.returncode,
|
||||
"events": events,
|
||||
"stderr_tail": process.stderr[-2000:],
|
||||
}
|
||||
results = []
|
||||
for index, window in enumerate(windows, 1):
|
||||
selected = [event for event in events if event.get("chunk_index") == index]
|
||||
if index == len(windows):
|
||||
selected.extend(event for event in events if event.get("event") in {"complete", "error"})
|
||||
results.append({
|
||||
"combination": name, "model": model, "device": device,
|
||||
"beam": 1 if device == "GPU" else 5, "segmentation": segmentation,
|
||||
"elapsed_seconds": round(elapsed, 3), "window_seconds": round(duration_ms / 1000, 3),
|
||||
"batch_window_count": len(windows),
|
||||
"batch_rtf": round(elapsed / max(0.001, duration_ms * len(windows) / 1000), 3),
|
||||
"exit_code": process.returncode, "events": selected,
|
||||
"stderr_tail": process.stderr[-2000:] if process.returncode else "", "window": window,
|
||||
})
|
||||
return results
|
||||
|
||||
|
||||
def main() -> int:
|
||||
@@ -95,10 +119,11 @@ def main() -> int:
|
||||
selected = windows.get(media.name)
|
||||
if not isinstance(selected, list) or len(selected) != 8:
|
||||
raise SystemExit(f"{media.name}: windows JSON must contain exactly 8 labelled windows")
|
||||
for window in selected:
|
||||
for combination in COMBINATIONS:
|
||||
result = worker_run(args.data_dir, wav, window, combination)
|
||||
result.update({"media": media.name, "window": window})
|
||||
batched_wav = Path(work) / f"{media.stem}-windows.wav"
|
||||
_write_window_batch(wav, batched_wav, selected)
|
||||
for combination in COMBINATIONS:
|
||||
for result in worker_run(args.data_dir, batched_wav, selected, combination):
|
||||
result["media"] = media.name
|
||||
artifact["runs"].append(result)
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(json.dumps(artifact, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
|
||||
Reference in New Issue
Block a user