feat: Add transcription worker and state management

Introduce an `AppState` struct to hold shared application state,
including configuration and the transcription sender.
Modify `create_router` and `create_router_with_state` to use `AppState`.
Update `main.rs` to initialize the transcription worker and pass the
`AppState` to the router.
Implement the transcription worker logic in
`server/src/transcribe/worker.rs`, handling job queues, FFmpeg remuxing,
and Whisper transcription.
Update `server/src/auth.rs` to use `Arc<Config>` from the shared state.
Modify `server/src/routes/upload.rs` to enqueue transcription jobs and
handle potential errors.
Add `TranscribeJob` and channel types in `server/src/transcribe/mod.rs`.
This commit is contained in:
2026-04-13 16:45:24 +02:00
parent 84f8df2bf4
commit bcae4e5466
7 changed files with 158 additions and 19 deletions
+54
View File
@@ -0,0 +1,54 @@
use std::sync::Arc;
use std::time::Duration;
use tracing::{error, info, warn};
use super::{ffmpeg, whisper, TranscribeReceiver};
use crate::config::Config;
/// Consume transcription jobs sequentially. Whisper holds the GPU, so parallelism
/// here would only cause contention. One job in flight at a time.
pub async fn run(mut rx: TranscribeReceiver, config: Arc<Config>, client: reqwest::Client) {
info!("Transcription worker started");
let timeout = Duration::from_secs(config.whisper_timeout_seconds);
while let Some(job) = rx.recv().await {
let audio_path = job.audio_path;
let transcript_path = audio_path.with_extension("transcript.txt");
if transcript_path.exists() {
continue;
}
info!(audio = %audio_path.display(), "Transcribing");
let remuxed = match ffmpeg::remux_faststart(&audio_path).await {
Ok(f) => f,
Err(e) => {
error!(audio = %audio_path.display(), error = %e, "ffmpeg remux failed");
continue;
}
};
let text = match whisper::transcribe(&client, &config.whisper_url, remuxed.path(), timeout).await {
Ok(t) => t,
Err(e) => {
error!(audio = %audio_path.display(), error = %e, "whisper call failed");
continue;
}
};
if let Err(e) = tokio::fs::write(&transcript_path, &text).await {
error!(transcript = %transcript_path.display(), error = %e, "writing transcript failed");
continue;
}
info!(
audio = %audio_path.display(),
bytes = text.len(),
"Transcript written"
);
}
warn!("Transcription worker stopped (channel closed)");
}