Skip to content

Repository files navigation

lecture-transcript

Локальный пайплайн, который превращает запись лекции-вебинара (mp4) в transcript.md — текст для написания конспекта: речь сгруппирована по слайдам, содержимое слайдов распознано, формулы в LaTeX, у каждой секции таймкоды и картинка слайда.

Зачем видео, а не только звук: значимая часть лекции часто существует только на слайдах — формулы, схемы, определения, код, термины в правильном написании. Расшифровка одного аудио без слайдов неполна.

Всё работает локально, без внешних API.

Статус

MVP. Код, тесты и сквозная интеграция готовы; качество распознавания на целевой машине ещё не проверено.

Что Состояние
Весь пайплайн mp4 → transcript.md на 91-минутной записи ✅ проходит все стадии (сухой прогон: настоящие стадии, OCR/ASR — заглушки)
Извлечение аудио и кадров, детект слайдов, дедупликация, кэш, сборка транскрипта ✅ проверено на эталонной записи
Тесты ✅ 587 быстрых + 24 на эталонной записи
Качество OCR и распознавания речи, VRAM, время на GPU ⏳ нужна машина с NVIDIA GPU и весами моделей

Подробная хронология решений — DECISIONS.md, отложенное — TECH_DEBT.md.

Как это работает

audio  → vad ─────────────────────────────→ asr → punctuation ──┐
frames → slides → ocr → glossary ─────────────↑                  ├→ merge → transcript.md
                                                                 ┘
Стадия Что делает Модель по умолчанию
audio WAV 16 кГц моно ffmpeg
frames кадры 1 кадр/с ffmpeg (nvdec на GPU)
slides область демонстрации по временно́й дисперсии пикселей, дедупликация кадров по perceptual hash, PNG-кроп последнего кадра каждого слайда OpenCV, imagehash
ocr печатный текст и формулы слайда в Markdown + LaTeX; рукописное не распознаётся — вместо него ссылка на PNG PaddleOCR + pix2tex
glossary термины лекции со слайдов для подсказки ASR —
vad интервалы речи silero-vad
asr слова с таймкодами GigaAM-v2
punctuation пунктуация и регистр (только для ASR без своей пунктуации); таймкоды слов не меняются sbert_punc_case_ru
merge слияние речи и слайдов по времени, чистка филлеров, абзацы, рендер —

Стадии выполняются последовательно, модель выгружается перед следующей стадией — пик VRAM рассчитан ниже 8 ГБ. Результат каждой стадии кэшируется; ключ кэша учитывает входной файл, параметры и код стадии, поэтому правка шаблона вывода пересчитывает только merge.

Альтернативные бэкенды: Whisper large-v3 вместо GigaAM (лекции с англоязычными терминами), Qwen2.5-VL 4bit вместо PaddleOCR + pix2tex.

Пример результата

# Транскрипт лекции

- **Исходный файл:** lecture.mp4
- **Длительность:** 1:31:22
- **ASR-бэкенд:** gigaam-v2
- **OCR-бэкенд:** hybrid

## Слайд 35 — Пример 2. Решите уравнение — 1:09:58–1:10:25

> Пример 2. Решите уравнение
>
> $\sqrt{x^2-x} = -5$
>
> ![Слайд 35](slides/slide_035.png)

Итак, давайте посмотрим на второй пример. Под корнем у нас икс квадрат минус икс…

Соседние состояния одного слайда (лектор дописывает решение маркером) объединяются в одну секцию со ссылками на все различающиеся картинки. Короткие паузы демонстрации при смене слайда не рвут текст на отдельные секции.

Запуск на целевой машине

Требования: Docker с NVIDIA Container Toolkit и NVIDIA GPU с поддержкой CUDA 12. Бюджет памяти пайплайна рассчитан на 8 ГБ VRAM: модели загружаются по одной.

# 1. Собрать образ
docker compose -f docker/compose.yaml build

# 2. Проверить окружение: GPU виден, ffmpeg умеет nvdec, torch видит CUDA
docker compose -f docker/compose.yaml run --rm lecture-transcript verify_env.sh

# 3. Один раз скачать веса моделей в том model-cache (нужна сеть)
docker compose -f docker/compose.yaml run --rm lecture-transcript \
  python -m lecture_transcript.warmup

# 4. Положить запись в ./input и запустить
docker compose -f docker/compose.yaml run --rm lecture-transcript \
  python -m lecture_transcript.cli /data/input/lecture.mp4 -o /data/output/lecture

Результат: output/lecture/transcript.md и output/lecture/slides/*.png.

После прогрева пайплайн работает без сети: образ по умолчанию запускается с HF_HUB_OFFLINE=1. Каталоги входа и выхода меняются переменными LECTURE_INPUT_DIR и LECTURE_OUTPUT_DIR. Прогрев по умолчанию скачивает модели бэкендов из конфига; --all — все, кроме VLM; --with-vlm — добавить Qwen2.5-VL (~6 ГБ).

Подробности окружения и выбора версий — docker/README.md.

Использование

lecture-transcript lecture.mp4 -o out/
lecture-transcript lecture.mp4 -o out/ --asr-backend whisper-large-v3
lecture-transcript lecture.mp4 -o out/ --config my.yaml
lecture-transcript lecture.mp4 -o out/ --slide-region 64,60,1248,656   # если область слайда не определилась
lecture-transcript lecture.mp4 -o out/ --from-stage merge              # пересобрать только транскрипт из кэша

Основные параметры (lecture-transcript --help — полный список):

Параметр Назначение
--asr-backend gigaam-v2 (по умолчанию), whisper-large-v3
--ocr-backend hybrid (по умолчанию), paddle, vlm
--config YAML поверх default_config.yaml
--slide-region X,Y,W,H задать область демонстрации вручную
--hwaccel auto, cuda, videotoolbox, none
--from-stage, --only-stage запуск части стадий
--no-cache, --cache-dir управление кэшем (по умолчанию <out-dir>/.cache)

Файл без видеодорожки обрабатывается в аудио-режиме: транскрипт без слайдов и предупреждение о неполноте.

Конфигурация разбита по стадиям: media_ingest, slide_extraction, slide_ocr, speech_transcription, transcript_assembly, cache. Значения, подобранные на эталонной записи, прокомментированы прямо в YAML.

Разработка

Пайплайн без моделей (извлечение, слайды, кэш, сборка) запускается и тестируется на любой машине с ffmpeg:

uv venv --python 3.11
uv pip install -e ".[dev]"
.venv/bin/pytest -m "not gpu and not models and not slow"

Веса моделей и GPU-зависимости в pyproject.toml не входят — их набор с версиями живёт в docker/requirements*.txt.

Маркеры тестов:

Маркер Что нужно
reference эталонная запись, путь в LECTURE_REFERENCE_MP4
slow время — минуты
models скачанные веса моделей
gpu CUDA GPU

Короткие клипы для тестов нарезаются из эталонной записи: python tools/make_fixtures.py. Сами записи в репозиторий не кладутся.

Сухой прогон — весь пайплайн на реальной записи, где OCR, ASR и пунктуация заменены детерминированными заглушками. Проверяет стыки стадий, кэш и формат транскрипта без GPU:

python tools/dry_run.py --input lecture.mp4 --out-dir /tmp/dry_run

Структура

src/lecture_transcript/
  contracts.py            общие типы данных — стадии общаются только через них
  cli.py, config.py       оркестрация стадий и конфигурация
  cache.py                кэш промежуточных артефактов
  warmup.py               прогрев весов моделей
  media_ingest/           аудио и кадры
  slide_extraction/       область демонстрации, дедупликация, PNG слайдов
  slide_ocr/              OCR-бэкенды, роутинг формул, глоссарий
  speech_transcription/   VAD, ASR-бэкенды, пунктуация
  transcript_assembly/    слияние, чистка, абзацы, рендер
docker/                   образ CUDA + ffmpeg nvdec, зависимости, самопроверка
openspec/                 спецификация: proposal, design, specs, tasks
tools/                    нарезка фикстур, сухой прогон

Ограничения

  • Рукописные пометки маркером не распознаются — транскрипт ссылается на PNG слайда. Это осознанный выбор: картинка полезнее выдуманной моделью формулы.
  • Разделения речи по спикерам нет.
  • GigaAM не принимает глоссарий как подсказки (hotwords); с ним пайплайн работает без глоссария и предупреждает об этом. Whisper глоссарий получает.
  • Детект слайдов и пороги подобраны на одной платформе вебинаров; на другой может понадобиться --slide-region и перепроверка порогов.
  • Генерация самого конспекта в скоуп не входит — пайплайн заканчивается на transcript.md.

Лицензия

MIT. Лицензия распространяется на код этого репозитория. Модели, которые пайплайн скачивает, распространяются под собственными лицензиями.

About

Локальный пайплайн: запись лекции (mp4) → transcript.md со слайдами, формулами и таймкодами

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages