◂ База знанийRYA.AETranscription Pipeline — транскрибация съёмочного дняобновлено 26 сен 2026
Транскрибация — фундамент этапов 3–5: каждый клип камеры и каждый TX-лав получает пословный транскрипт с таймкодами, и уже на нём стоят 3.10 Word Precision, 4.1 Word-Sync, 4.2 Fine Sync, 3.5 Transcript Document и 5.1 Assembly Brief. Мультикам синхронится по речи — по creation_time запрещено (кварц врёт на ±5–22 мин).
Быстрый старт. Штатная стадия — Phase 2 в run_pipeline.py (только с --all или --only transcribe). На Apple Silicon быстрый путь — mlx_whisper (Metal): 42-мин 4K → ~6 мин; офлайн-раннер держит ×11.5 реального времени. Один mlx-джоб за раз, длинное — фоном (nohup+caffeinate, лог в 00_Setup/logs/).
видео / WAV→аудио 16k mono→Whisper пословно→pyannote диаризация→роли / спикеры→JSON · SRT · Claude4_assembly
1Место в пайплайне2Движки3Команды4Язык5Диаризация6Роли слов7Zoom8Артефакты9Файлы

🧭3.6 · 1Место в пайплайне

  • Assembly brief читает {CODE}_Claude4_assembly.json с массивом words[] {w,s,e} на сегмент — из него берутся точные суб-сегменты: tc_in = first_word.s, tc_out = last_word.e + smart padding ≤0.3с.
  • Word-Sync — пословные транскрипты являются якорем синхронизации камер; часы устройств врут.
  • UXP-панель — Stage 6 стадии генерирует {CODE}_ingest.json в 00_Setup/01_Ingest/ для сборки проекта в Premiere.
  • Per-source EN-библиотека — каждый клип и TX-лав получает свой {stem}_en.json (mlx task=translate по аудио, НЕ LLM-перевод русского ASR) — строительные блоки для сборки.
  • Транскрипт таймлайна делается не проекцией слов из источников, а сборкой единого аудио таймлайна (лучшая дорожка на каждый момент) и его транскрибацией целиком — 100% покрытие, таймкоды сразу в timeline-времени.
Speaker ID (имена спикеров) — отдельный шаг вне пайплайна: python 03_speaker_id/00_process_all.py --project или Claude-проект.
внутри разбора съёмочного дня — своя расшифровка, до проекта

Когда день разбирается ночью (3.1 Shoot Day Ingest), расшифровка — стадия самого разбора, а не run_pipeline: по словам строятся часы, сцены и уроки, поэтому она нужна до раскладки. Выход — {work}/words/{akey}.words.json в формате, который ест wordsync: segments[].words[] = {w,s,e}, не {word,start,end} — иначе flatten_words() падает с KeyError.

выездной день · 0120_day_ingest/s3_transcribe.pyстудийный день · 0121_studio_day/asr.py
петличкиmlx-community/whisper-large-v3-mlx — это результат: по нему собирается монтажный текст и документ
звук камерmlx-community/whisper-large-v3-turbo — нужен только как n-граммы для графа часов, важна скорость
настройкаконстанты MODEL_MIC/MODEL_CAM в скрипте; запуск из run_night.py (гейт: транскрипт у каждой петлички и ≥ 20 000 слов)блок asr в day.json (язык, модели, уровни); asr.py --only mic|cam, --force; из night.py шагами asr_mic и asr_cam
  • condition_on_previous_text=False обязателен, no_speech_threshold=0.5: на начитке и пересказе дубли повторяются почти дословно, и whisper зацикливается между ними.
  • Отбраковка сегментов: no_speech_prob > 0.6 при avg_logprob < −1.0, compression_ratio > 2.4, повторы и коридор темпа, плюс фильтр галлюцинаций («Субтитры сделал…», «Продолжение следует»). В asr.py правила скопированы из s3_transcribe, а не импортированы: импорт потянул бы common_day с путями YTEVO03.
  • Файл без речи — это результат, а не дыра: в нём явное {"speech": false}, и гейт его принимает. s3_transcribe глухие файлы (mean ≤ −60 дБ) не расшифровывает вовсе; asr.py сверяет число петличных кусков с речью с expected.mic_chunks_with_speech из day.json.
  • Звук — рабочая копия 16 кГц из оригиналов, нормированная по RMS, не по пику (DJI пишет 32 bit float). verbose=None: False рисует прогресс-бар и раздувает лог ночи. Одна MLX-модель за раз, резюмируемо по файлам.
  • Скорость large-v3 на M-железе — ×8–10 реального времени.

⚙️3.6 · 2Движки: штатный и быстрый

штатная стадияmlx-инструменты
чтоscripts/02_transcribe/020101_transcribe/transcribe_project.py (v3.0): openai-whisper large-v3 + pyannote 3.1, 6 стадий (audio → diar → whisper → map → generate → ingest)scripts/999_extra/: mlx_transcribe_review.py (одно видео), mlx_transcribe_folder.py (пачка per-source), wordrole_transcribe.py (слова+роли), ytch_ru_transcribe/ (офлайн-раннер с ctl.sh)
скоростьчасами — openai-whisper на Mac идёт на CPU FP32 (mps игнорируется); телл-тейл в логе: «FP16 is not supported on CPU»минуты — Metal/MLX, модель mlx-community/whisper-large-v3-mlx: 42-мин 4K → ~6 мин; wordrole 6 ч аудио → 41 мин
форматper-clip JSON/SRT + {CODE}_Claude4_assembly.jsonтот же JSON-schema {duration, segments:[{id,start,end,text,words[]}]} + SRT; words.json wordsync-совместим ({w,s,e} float-секунды)
⚠️ Один mlx-джоб за раз — два параллельных не помещаются в RAM → jetsam-kill. ⚠️ Шебанг .venv_transcribe/bin/pip сломан (venv переезжал) — работает .../bin/python. У mlx_transcribe_folder: condition_on_previous_text=False + no_speech_threshold=0.5 (меньше каскадных галлюцинаций); тихие клипы помечаются likely_silent, готовые {stem}.words.json скипаются (идемпотентно).

▶️3.6 · 3Команды

штатная стадия (run_pipeline форвардит -n / --language / -m и добавляет -y)
# окружение
source ~/YTAI/environment/.venv_transcribe/bin/activate
# только транскрибация (язык известен → флаг; смешанный EN+RU → БЕЗ флага)
python ~/YTAI/scripts/run_pipeline.py "$PROJECT" --only transcribe --language en --no-pause
# всё (prepare + transcribe) · статус фаз
python ~/YTAI/scripts/run_pipeline.py "$PROJECT" --all --language en --no-pause
python ~/YTAI/scripts/run_pipeline.py "$PROJECT" --list
mlx: одно видео · папка per-source
HF_HUB_OFFLINE=1 ~/YTAI/environment/.venv_transcribe/bin/python \
  ~/YTAI/scripts/999_extra/mlx_transcribe_review.py --video V.mp4 --output 05_Review/ --language ru
PY=~/YTAI/environment/.venv_transcribe/bin/python
$PY ~/YTAI/scripts/999_extra/mlx_transcribe_folder.py --folder ".../01_Source/Video/07_Scene" --language en
Полезные ключи стадии: -n/--speakers (число спикеров, авто если опущен) · --skip-done · --force · --resume · --stages 3,4,5 · --multicam. Офлайн-раннер YTCH: ctl.sh {start|pause|status|watch}, переживает ребут.

🌐3.6 · 4Язык: правило флага --language

  • Автоопределение = флаг ОПУСКАЕТСЯ. Значение форвардится прямо в Whisper, который валидирует ISO-код.
  • Один известный язык → --language en / --language ru; смешанный проект (EN+RU, как YTCR03) → без флага.
  • У mlx_transcribe_folder.py дефолт — en, не auto.
⚠️ НИКОГДА --language auto: строка «auto» — невалидный код → «Unsupported language: auto» → вся Phase 2 падает (реальный случай YTCR03). ⚠️ mlx task=translate ломает пословный синхрон (279 нативных слов → 236 переведённых) — перевод только в отдельное дерево {stem}_en.json.

🗣3.6 · 5Диаризация

  • Штатно: pyannote/speaker-diarization-3.1 поверх full_audio.wav на MPS/CUDA; num_speakers из -n, иначе авто.
  • Диаризация готового транскрипта (без перегона Whisper): ffmpeg → 16k mono WAV → pyannote → сегменту существующего mlx-транскрипта присваивается спикер по max-перекрытию. ~106 мин аудио → ~3.5 мин на MPS. Скрипт-образец: scripts/999_extra/civ_meeting_diarize.py.
  • Диаризация правит только «кто говорит» — текст остаётся с ASR-ошибками исходной расшифровки.
ffmpeg -i in.m4a -ac 1 -ar 16000 -vn out.wav
⚠️ pyannote 4.x: Pipeline.from_pretrained(..., token=tok) — НЕ use_auth_token=; нужен HF-токен с принятыми условиями модели (ищется в ~/.huggingface/token / HF_TOKEN). ⚠️ soundfile не читает m4a — сначала ffmpeg в WAV. ⚠️ Не для multitrack-Zoom — там mix+diar (ниже).

🎭3.6 · 6Роли слов — wordrole_transcribe

  • scripts/999_extra/wordrole_transcribe.py — дословная транскрибация на языке оригинала с пословными таймкодами и ролями: mlx large-v3 + pyannote, каждому слову спикер по max-перекрытию, подряд один спикер → блоки-реплики.
  • Выходы {base}.*: .words.json (мастер), .diarized.txt/.srt (по ролям), .words.srt/.csv (пословно), .review.html (тёмная тема, чипы ролей).
  • Чекпойнты в _wordrole_work/: --rebuild-only пересобирает выходы из кэша за секунды; --speaker-names "A,B" — имена по talk-time; --plain — режим интервью/подкастов.

💻3.6 · 7Zoom и sparse-speech

  • Zoom с раздельными дорожками → transcribe_zoom_multitrack.py --mode mix+diar (дефолт): транскрибируется общий микс, спикер назначается по RMS-огибающим персональных треков.
  • Причина: Whisper на длинных тишинах per-speaker трека сеедит каскад галлюцинаций — реальный кейс: 1602× «Спасибо за внимание!», реальных сегментов 0.2%.
  • Правило для любого sparse-speech (рация, интерком): транскрибировать continuous-speech версию. --mode per-speaker — только когда общего микса не существует.

🩹3.6 · 8Известные артефакты и вычитка

  • Повтор слова на стыке сегментов — регулярный артефакт Whisper (и mlx). Проверка за ~30с: вырезать окно ±6с в mono 16k WAV → mlx_whisper.transcribe(..., word_timestamps=True, temperature=0.0): одно слово в пословном выводе — дефекта нет.
  • subs_wordfix.py — вычитка МЕЖДУ транскрибацией и сборкой субтитров: правит плоский список слов до нарезки на реплики (чинит фразы, разорванные границей реплики); правки — JSON [{from,to,why}].
$PY subs_wordfix.py --transcript in.json --fixes fixes.json --out fixed.json
⚠️ Дефисные слова у mlx — два токена («что-то» = «что»+«-то») → в from писать «что то». ⚠️ Сегмент, из которого правка вынесла все слова, — выбрасывать. ⚠️ В while-read циклах ffmpeg съедает stdin — нужен ffmpeg -nostdin.

📁3.6 · 9Куда кладутся файлы

чтогде
главный транскрипт01_Source/Transcription/{CODE}_transcript.json + transcripts/*.srt + captions/*.srt (пословные) + per-clip по сценам {scene}/
для Assembly brief00_Setup/{CODE}_Claude4_assembly.json (стадия Generate)
для UXP00_Setup/01_Ingest/{CODE}_ingest.json + {CODE}_audio_map.json
per-source (mlx folder)01_Source/Transcription/<folder>/{stem}.words.json|.srt|.txt + сводные _folder_transcript.*
EN-библиотекакамеры → 01_Source/Transcription/{clip}_en.json; лавы → 99_Pipeline/DJI_Audio/transcripts/{tx}_en.json (translate_caption_sources.py)
логи00_Setup/logs/{project}_run_pipeline_{ts}.log
Транскрибация = фундамент: речь — якорь синхрона, слова — валюта монтажа. mlx — минуты вместо часов; один джоб за раз; --language auto не существует.