Фоновые задачи: плейлисты, длинные лекции, вкладка настроек
- таблица jobs + очередь с воркером: POST /jobs сразу отвечает, элементы
плейлиста обрабатываются последовательно, есть отмена и живой прогресс
(скачивание %, минуты распознанного Vosk-аудио)
- expand_url: плейлист раскрывается в список видео
- keep_video=false теперь качает только аудио (для 4-5ч лекций)
- настройки (LLM-ключ, модель, длина выжимки, хранение видео, путь Vosk)
хранятся в Postgres: переживают перезапуск и перезагрузку страницы
- длина выжимки прокидывается в LLM-промпт ({n} предложений)
- UI: вкладки «Главная»/«Настройки», карточка задач с автообновлением
каждые 3 сек, прогресс-бар, отмена, библиотека обновляется по мере
готовности элементов
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -53,8 +53,16 @@ class VoskModelManager:
|
||||
t.join(timeout=2)
|
||||
|
||||
|
||||
def transcribe_via_ffmpeg(media_path: Path, model_path: Path, sample_rate: int = 16000) -> str:
|
||||
"""Decode the source media to PCM s16le mono via ffmpeg and feed it to Vosk in chunks."""
|
||||
def transcribe_via_ffmpeg(
|
||||
media_path: Path,
|
||||
model_path: Path,
|
||||
sample_rate: int = 16000,
|
||||
on_progress=None,
|
||||
) -> str:
|
||||
"""Decode the source media to PCM s16le mono via ffmpeg and feed it to Vosk in chunks.
|
||||
|
||||
on_progress: callback(minutes: int) — вызывается каждые ~5 минут распознанного аудио.
|
||||
"""
|
||||
if Model is None or KaldiRecognizer is None:
|
||||
raise RuntimeError("vosk is not installed in runtime")
|
||||
if shutil.which("ffmpeg") is None:
|
||||
@@ -103,10 +111,16 @@ def transcribe_via_ffmpeg(media_path: Path, model_path: Path, sample_rate: int =
|
||||
break
|
||||
recognizer.AcceptWaveform(chunk)
|
||||
bytes_read += len(chunk)
|
||||
mb = bytes_read // (1024 * 1024)
|
||||
if mb >= last_logged_mb + 5:
|
||||
last_logged_mb = mb
|
||||
logger.info("Transcribed %d MB of audio so far", mb)
|
||||
# PCM s16le mono: sample_rate * 2 байта в секунду
|
||||
minutes = bytes_read // (sample_rate * 2 * 60)
|
||||
if minutes >= last_logged_mb + 5:
|
||||
last_logged_mb = minutes
|
||||
logger.info("Transcribed %d minutes of audio so far", minutes)
|
||||
if on_progress is not None:
|
||||
try:
|
||||
on_progress(minutes)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
result = json.loads(recognizer.FinalResult())
|
||||
text = result.get("text", "")
|
||||
|
||||
Reference in New Issue
Block a user