/transcribe - Транскрибация видео и аудио

SkillFiles & storage

Transcribe video and audio files. Use when the user asks to transcribe, decode a recording, take meeting minutes, extract speech from video or audio, or convert speech to text. For audio (m4a/mp3/wav/ogg/flac/aac/wma) by default local faster-whisper + diarization with auto

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the /transcribe - Транскрибация видео и аудио skill

What this skill tells your AI

The instructions your AI receives, as published by desko77/cursor-1c-skills in skills/transcribe/SKILL.md and read by ahel’s review.

Два движка:

  • Локальный (default для аудио): faster-whisper (CUDA) + опц. диаризация. Движок диаризации выбирается сам: без --num-speakers - pyannote community-1 (GPU, корректный автодетект числа спикеров, RTF ~0.064); с явным --num-speakers N - sherpa-onnx GPU (pyannote-segmentation-3.0 + eres2net, RTF ~0.24, точное N). Опция --diarize-engine moss - MOSS-Transcribe-Diarize end-to-end: ASR+диаризация одной моделью (без whisper-шага), лучше текст на технических терминах, но ~2x медленнее (RTF ~0.34), требует venv-moss (env MOSS_PYTHON). Нет затрат, не уходит наружу. ВИДЕО тоже можно разобрать полностью локально - --engine local (разбор экрана локальной VLM + спикеры по голосу, см. ниже).
  • Gemini (default для видео и --analyze-ui): облачный API, ~$0.10/час. Нужен интернет и квота. Стартовая модель gemini-2.5-flash (пин конкретной версии, дешевая); при перегрузке (503/429) переходит на gemini-2.5-flash-lite. Дорогие 3.5/pro сознательно исключены.

Выбор движка по умолчанию

Тип файлаДвижокПричина
Аудио (m4a, mp3, wav, ogg, flac, aac, wma)localБыстро, бесплатно, диаризация
Видео (mp4, mkv, webm, avi, mov)geminiБыстро, облако. Приватный вариант - --engine local (см. ниже)
Видео + --engine locallocalРазбор экрана БЕЗ облака: whisper + локальная VLM (LM Studio) + спикеры по голосу
Любой + --analyze-uigeminiДетальный разбор интерфейсов в облаке
Любой + --engine geminigeminiЯвный override на облако
Аудио + --engine locallocalЯвный override (аудио)

При 503/429 Gemini-движок сначала сам перебирает пул моделей (см. раздел "Авто-fallback по моделям Gemini"). Если весь пул недоступен и это аудио - можно вручную переключиться на local (--engine local).

Режимы

Локальный (аудио + faster-whisper + опц. pyannote)

Выходные файлы:

  • <имя> - транскрипция.md - таймкоды + текст
  • <имя> - транскрипция.txt - plain text
  • <имя> - со спикерами.md - реплики с метками [SPEAKER_XX, MM:SS] (только при --diarize)

Gemini generic

Выходные файлы:

  • <имя> - транскрипция.md - речь с таймкодами + спикеры (если различимы)
  • <имя> - саммари.md - протокол встречи (с флагом --with-summary); строится из текста транскрипции в 2 прохода (экстрактор всех фактов -> протокол) для полноты задач/решений

Gemini analyze-ui (только видео)

Анализ видеозаписи с разбором экранного интерфейса + скриншоты. Детальный лог и транскрипция пишутся по частям сразу (инкрементально): сбой на поздней части длинного видео не теряет ранние. Саммари строится в конце из полной транскрипции (2 прохода) - это протокол задач/решений; разбор показанных интерфейсов - в детальном логе.

Выходные файлы:

  • <имя> - саммари.md
  • <имя> - детальный.md
  • <имя> - транскрипция.md
  • screenshots/ - PNG-кадры

Локальный разбор видео (--engine local, только видео)

Полностью локальный разбор экрана + речи БЕЗ облака (подробности в "Инструкция" ниже). Спикеры распознаются по голосу (голосовая база) и по репликам - см. "Спикеры и голосовая база".

Выходные файлы:

  • <имя> - транскрипция.md / .txt
  • <имя> - со спикерами.md (при --diarize)
  • <имя> - детальный.md - дословный лог: описание экрана по кадрам + реплики за интервал
  • <имя> - связный.md - связный нарратив экран+речь (если не --no-coherent)
  • <имя> - саммари.md - протокол задач/решений (если не --no-summary)
  • <имя>.voiceprints.json - отпечатки голоса кластеров
  • screenshots/ - ВСЕ scene-кадры

Аргументы

ПараметрОбязательныйПо умолчаниюОписание
FilePathда-Путь к аудио/видеофайлу
--output-dirнет<каталог>/Транскрипция/<имя>/Каталог результатов
--engineнетauto (local для аудио, gemini для видео)local или gemini
--diarizeнетвыклЛокальный движок: разделение по спикерам
--num-speakers Nнетавтодетект (pyannote community-1)Точное число спикеров; с ним движок переключается на sherpa-onnx (быстрее)
--min-speakers N / --max-speakers Nнет-Границы автодетекта (движок pyannote)
--diarize-engineнетавто: без N - pyannote, с N - sherpa-onnx; явно - moss (end-to-end)sherpa-onnx без --num-speakers пересегментирует (242 кластера на ~7 чел). moss - ASR+диаризация одной моделью (текст точнее на терминах, RTF ~0.34, требует venv-moss)
--analyze-uiнетвыклGemini: анализ интерфейсов (только видео)
--with-summaryнетвыклGemini: добавить саммари
--formatнетmdФормат: md или txt
--modelнетgemini-2.5-flashGemini: стартовая модель (или env GEMINI_MODEL)
--fallback-modelsнетвстроенный пулGemini: цепочка fallback через запятую (или env GEMINI_FALLBACK_MODELS)
--no-fallbackнетвыклGemini: только стартовая модель, без перебора
--project NAMEнет-local видео: пометить встречу в голосовой базе (провенанс)
--voiceprint-db PATHнетvoiceprints/db.json скиллаlocal видео: путь к голосовой базе
--no-voiceprintsнетвыклlocal видео: не использовать и не пополнять голосовую базу
--no-coherentнетвыклlocal видео: не строить связный лог (быстрее)
--no-summaryнетвыклlocal видео: не строить саммари
--speaker-model Mнетqwen2.5-32blocal видео: LLM для маппинга спикеров -> имена
--reuse-transcriptнетвыклlocal видео: не гонять whisper заново, если транскрипция уже есть
--no-vlmнетвыклlocal видео: не разбирать экран моделью зрения (кадры все равно нарезаются). Штатный способ получить речь+спикеров+саммари, когда зрение не нужно или сервер занят
--reuse-framesнетвыклlocal видео: взять готовые описания кадров из <имя>.status.json прошлого прогона и дораспознать только оставшиеся
--glossary PATHнетglossary.txt в корне скилаТермины и ослышки: правильные написания подсказываются распознавателю, ослышки правятся в готовом тексте (DAX вместо "ДАКС")
--no-glossaryнетвыклНе использовать глоссарий терминов

Поддерживаемые форматы

  • Видео: mp4, mkv, webm, avi, mov
  • Аудио: mp3, wav, ogg, m4a, flac, aac, wma

Зависимости

Локальный движок:

  • venv whisper (отдельный, изоляция CUDA-DLL): путь в env WHISPER_PYTHON; дефолт ~/.claude/skills/transcribe/venv-whisper (faster-whisper, ctranslate2-CUDA, ffmpeg)
  • Для --diarize БЕЗ --num-speakers (default): движок pyannote с чекпойнтом pyannote/speaker-diarization-community-1 - корректный автодетект числа спикеров (16.07.26: 8 при истине ~7, RTF 0.064). Нужны torch + pyannote.audio>=4 в whisper-venv, HF_TOKEN в .env (read-токен с принятыми условиями pyannote/speaker-diarization-community-1; для старых чекпойнтов также speaker-diarization-3.1, segmentation-3.0). Отпечатки голоса при этом считает venv-sherpa по готовым turns (diarize_sherpa.py --from-turns) - то же eres2net-пространство, что и голосовая база.
  • Для --diarize С --num-speakers N (default): движок sherpa-onnx GPU CUDA, ~/.claude/skills/transcribe/venv-sherpa с GPU-сборкой sherpa_onnx 1.13.0+cuda12.cudnn9 от k2-fsa maintainer (HuggingFace csukuangfj2/sherpa-onnx-wheels). pyannote-segmentation-3.0 + 3D-Speaker eres2net эмбеддинги в ONNX. RTF ~0.24, никаких HF gated моделей. ВНИМАНИЕ: пороговый автодетект sherpa (без N) СЛОМАН - пересегментирует (эксперимент 04.07: пороги 0.5-0.8 давали 21-45 спикеров при истине 4; прогон 16.07: 242 кластера на ~7 человек). Слабое звено - эмбеддер eres2net-zh-cn (EER 5.3 в бенчмарке Шмырева против 1.1-1.6 у топов).
  • CUDA GPU обязателен для обоих движков

Gemini движок:

  • Python-пакеты: google-genai, python-dotenv
  • Системные: ffmpeg, ffprobe в PATH
  • API-ключ в ~/.claude/skills/transcribe/.env: GEMINI_API_KEY=...

Установка и настройка (для агента)

НЕ проверяй сервер/venv/модели вручную ПЕРЕД запуском. Скрипты сами читают .env и делают свой префлайт (печатают [0/5] проверка сервера ... + какие модели резолвятся). Просто ЗАПУСТИ нужный скрипт (см. "Инструкция") и читай ЕГО вывод.

Что где (скрипт берет из .env сам, тебе знать не обязательно, руками НЕ проверяй):

  • Локальный сервер VLM - из LOCAL_150_BASE в .env (может быть удаленный хост, НЕ обязательно localhost). НЕ проверяй localhost:1234.
  • Python для whisper - из WHISPER_PYTHON в .env (может быть внешний venv, НЕ обязательно skill-овый venv-whisper). НЕ проверяй skill-venv.

Ставить/чинить - ТОЛЬКО если скрипт при запуске сам сообщил, что сервер/модель/whisper недоступны:

  • установка: python ~/.claude/skills/transcribe/scripts/setup.py (ДОЛГО ~20-30 мин, фоном; флаги --skip-gemini/--skip-sherpa/--with-pyannote/--allow-cpu), проверка verify.py --full;
  • для --engine local (видео) нужен запущенный LM Studio (адрес из LOCAL_150_BASE) с моделями (VLM qwen3-vl-30b-a3b-instruct или qwen3-vl-8b, gemma-4-26b, qwen2.5-32b) + Pillow/numpy в python запуска. Пошагово - в README.

.env (~/.claude/skills/transcribe/.env, gitignore, НЕ коммить): GEMINI_API_KEY, HF_TOKEN (если pyannote), WHISPER_PYTHON, LOCAL_150_BASE, LOCAL_VLM_MODEL.

Инструкция

"Локально" / "без облака" = ТОЛЬКО локальный движок (--engine local / analyze_video_local.py). Если пользователь просит локально - НЕ запускай Gemini и НЕ старый analyze_video.py. Локаль-скрипт сам конфигурится из .env (сервер + whisper) - просто запусти его.

Недоступность сервера или модели больше НЕ повод останавливаться. Стадии деградируют поодиночке: нет модели зрения - будут речь, спикеры и саммари; нет сервера вовсе - будут речь и спикеры (whisper считает на своей машине, а голосовая база и проверка имен моделей не требуют). Запусти скрипт, прочитай <имя>.status.json и скажи пользователю, что именно осталось неразобранным. Останавливаться и ничего не отдавать - хуже, чем отдать неполный результат с честным перечнем дыр.

Gemini в локальном режиме запрещен ВСЕГДА (данные встреч конфиденциальны). А вот прочитать глазами непокрытые кадры - можно: это аварийный слой, ограничитель тут цена, а не приватность. Порядок такой: сперва дай скрипту отработать (при HTTP 400 по контексту он сам снижает параллельность, при выгруженной модели - сам ее поднимает), затем возьми из status.json список кадров со state не равным ok и посмотри ТОЛЬКО их файлы из screenshots/. Не читай все кадры подряд - в 24-минутной встрече их бывает под сотню.

  1. Определи FilePath и флаги. По расширению файла и флагам выбери движок (см. таблицу выше).

  2. Если расширение - аудио, и нет --engine gemini, и нет --analyze-ui → запускай локальный:

PYTHONUNBUFFERED=1 PYTHONIOENCODING=utf-8 \
 ~/.claude/skills/transcribe/venv-whisper/Scripts/python.exe \
 ~/.claude/skills/transcribe/scripts/transcribe_local.py \
 "<FilePath>" [--output-dir "<OutputDir>"] [--diarize] [--num-speakers N] [--min-speakers N] [--max-speakers N] [--glossary PATH] [--no-glossary]

Локальный пайплайн:

  • Транскрипция и диаризация запускаются в отдельных subprocess параллельно (изоляция CUDA-DLL ctranslate2 vs torch).
  • 27-мин аудио = ~10 мин общего времени (RTF ~0.4).
  • Часовое аудио = ~25 мин общего времени.
  • Диаризация - только при --diarize. Без нее ~1.5-2 мин на 27-мин файл.
  1. Если это ВИДЕО и указан --engine local → запускай ПОЛНОСТЬЮ ЛОКАЛЬНЫЙ разбор экрана (без облака):
PYTHONUNBUFFERED=1 PYTHONIOENCODING=utf-8 python ~/.claude/skills/transcribe/scripts/analyze_video_local.py "<FilePath>" [--output-dir "<OutputDir>"] [--diarize] [--num-speakers N] [--project NAME] [--voiceprint-db PATH] [--no-voiceprints] [--no-coherent] [--no-summary] [--no-vlm] [--reuse-transcript] [--reuse-frames] [--glossary PATH] [--no-glossary]

Речь - локальный whisper; разбор экрана - qwen3-vl-8b-instruct на локальном сервере LM Studio; связный лог и саммари - google/gemma-4-26b-a4b; маппинг спикеров по репликам - qwen2.5-32b. Кадры обрабатываются параллельно (число слотов выводится из контекста VLM под unified KV cache). Клиентские кадры НЕ уходят в облако. Спикеры распознаются слоями: по ГОЛОСУ (голосовая база, узнает людей между встречами) и по репликам - см. "Спикеры и голосовая база". Предусловия: сервер LM Studio доступен (по умолчанию http://localhost:1234, env LOCAL_150_BASE), модели qwen3-vl-8b-instruct + google/gemma-4-26b-a4b + qwen2.5-32b-instruct загружены (скрипт проверяет и внятно сообщает, если модели нет). Выход: транскрипция / со спикерами / детальный / связный / саммари / voiceprints.json / screenshots/ (ВСЕ scene-кадры). ВНИМАНИЕ: локальное зрение НЕ гарантирует посимвольную точность (в отличие от облака) - финансовые цифры сверять с экраном. Env-переопределения: LOCAL_150_BASE, LOCAL_VLM_MODEL, LOCAL_SUMMARY_MODEL, LOCAL_SPEAKER_MODEL, SCENE_THRESHOLD, FRAME_FLOOR_SEC, FRAME_CAP, WHISPER_PYTHON.

  1. Иначе (видео без --engine local, или явный --engine gemini, или --analyze-ui) - запускай Gemini:
PYTHONUNBUFFERED=1 python ~/.claude/skills/transcribe/scripts/transcribe.py "<FilePath>" [--output-dir "<OutputDir>"] [--analyze-ui] [--with-summary] [--format md|txt] [--model MODEL] [--fallback-models "m1,m2"] [--no-fallback]

Скрипт долгий (5-15 мин), файлы >1 ч разбиваются автоматически.

  1. Fallback при перегрузке Gemini (503 / 429): скрипт сам перебирает пул моделей (см. "Авто-fallback по моделям Gemini"), доп. действий не требуется. Если весь пул недоступен и это аудио - крайний случай: локальный движок (см. шаг 2).

  2. После завершения покажи пользователю пути к файлам и прочитай начало транскрипции / саммари.

ВАЖНО: PYTHONUNBUFFERED=1 обязательно для прогресса.

Спикеры и голосовая база

В локальном разборе видео (--engine local) имена спикеров определяются ТРЕМЯ слоями (голос приоритетнее текста, проверка идет последней):

  1. По голосу (голосовая база). Диаризация считает отпечаток голоса каждого спикера (eres2net-эмбеддинг). Отпечаток сверяется с накопительной базой voiceprints/db.json по косинусной близости - так узнаются даже неназванные люди и ОДИН человек между разными встречами. Это больше, чем делает облако (оно вяжет имена только внутри одной записи).
  2. По репликам (текст). LLM (qwen2.5-32b) читает транскрипт и вяжет имена по обращениям ("Иван, что скажешь?"), самопредставлениям, ссылкам. Ответ запрашивается строгим JSON по схеме - формат гарантирует сервер, а не послушание модели.
  3. Программная проверка (speaker_validator.py). Обязательная, работает без всяких моделей. Отдельно от разбора обращений она снимает имена, которые в записи НЕ ЗВУЧАЛИ НИ РАЗУ: на встрече, где никого не назвали, модель уверенно выдает правдоподобный набор ("Роман", "Станислав"), и такое имя раньше проходило насквозь - порог улик к предложениям модели по замыслу не применяется, а других улик у выдумки нет. Пустая метка честнее выдуманного имени. Имя, подтвержденное голосовой базой, эта проверка не трогает. Причина остальных правок: ВСЕ проверенные модели (qwen2.5-32b, qwen3-vl-30b, qwen3.6 в том числе с размышлениями) систематически вешают имя на того, кто его ПРОИЗНОСИТ, хотя произносящий обращается к другому - на эталонной встрече три модели дали три разных ответа, совпав на одной метке из шести. Правило в промпте это не лечит. Проверка: имя из звательной позиции ("Марина, логика та же", "Да, Леш?") вешается на того, кто ОТВЕЧАЕТ, а не на говорящего; упоминание в третьем лице (косвенный падеж, имя с фамилией, "как Алексей просил") кандидатом не считается; усеченные формы сводятся к полной (Леш -> Алексей); роли и заглушки ("Модератор", "неизвестно") отбрасываются; род говорящего проверяется по форме глаголов ("я сделал" против "я сделала"); одно имя не висит на двух метках. Имена, подтвержденные голосом, проверка не пересматривает.

Проверку можно запустить отдельно на готовом транскрипте - она покажет все найденные обращения и оценки:

python ~/.claude/skills/transcribe/scripts/speaker_validator.py "<файл - со спикерами.md>"

Авто-пополнение (бутстрап): если человек назван текстом, но в базе его еще нет - его отпечаток заносится в базу, и на будущих встречах он узнается уже по голосу. Заносятся только имена, прошедшие проверку (она же гарантирует, что одно имя не висит на нескольких метках - иначе в одну запись базы попали бы голоса разных людей).

Провенанс: --project NAME помечает, в каком проекте/встрече встречался человек (полезно при пересечении людей между проектами).

Управление: --no-voiceprints (не трогать базу), --voiceprint-db PATH (своя база), --speaker-model (модель текстового слоя). Голоса - чувствительные данные: база хранится ЛОКАЛЬНО и не коммитится.

Просмотр / ручной enroll базы:

python ~/.claude/skills/transcribe/scripts/voiceprints.py list
python ~/.claude/skills/transcribe/scripts/voiceprints.py match --prints "<имя>.voiceprints.json"

Термины и ослышки (глоссарий)

Распознаватель уверенно ослышивается на англицизмах и жаргоне, и молча: DAX -> "ДАКС", JSON -> "G-Splone", PROD -> "Прот", гашения -> "базаты". Дальше по конвейеру ошибку никто не ловит - текстовая модель принимает ослышку за факт и тащит ее в связный лог и в саммари.

Лечится файлом glossary.txt в корне скила (UTF-8):

DAX = ДАКС, дэкс, ДАХ # слева правильное написание, справа ослышки
JSON = джейсон, G-Splone
регламентное задание # строка без "=" - только подсказка распознавателю

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

  • Подсказка (hotwords). Правильные написания уходят в промпт КАЖДОГО окна распознавания - модель чаще выбирает знакомую форму. Профилактика, не гарантия: список режется по лимиту промпта.
  • Правка по факту. Ослышки заменяются в готовом тексте - и в обычной транскрипции, и в файле со спикерами (он собирается заново из слов, поэтому правится отдельно). Дальше по конвейеру идет уже верный текст.
  • Регистр не важен (ДАКС ловит и дакс), границы слов соблюдаются (Протокол не превращается в PRODокол), ослышки короче 3 символов игнорируются.
  • Формы пишутся ЛИТЕРАЛЬНО, какими вышли из распознавателя: морфологии здесь нет, поэтому и слева форма под стать ослышке (гашения = базаты).

Дополняй файл по итогам своих встреч - увидел ослышку, добавь строку. Проверить разбор и замены:

python ~/.claude/skills/transcribe/scripts/glossary.py "текст с ослышкой"

Управление: --glossary PATH (свой файл), --no-glossary (выключить), env TRANSCRIBE_GLOSSARY.

Проверка связного лога на выдумку

Связный лог собирается текстовой моделью из описаний кадров, и модель там сочиняет: на реальном прогоне 08.2026 в нарративе оказались восемь сумм, кодов счетов и годов, которых в описаниях кадров не было (4,800.00, 90.01.1, ОКС0100222, диапазоны "от 2009 до 2019"). Запрет в промпте это не держит.

Поэтому после сборки каждое число и код нарратива сверяются с исходным материалом. Не подтвержденные выносятся сноской в конец файла <имя> - связный.md:

> **Не подтверждено кадрами.** Эти числа и коды есть в нарративе, но их нет в описаниях экрана...

Вырезать их автоматически нельзя - порвется фраза, поэтому решение за человеком: проверить по скриншотам в screenshots/. Промпты зрения и связного лога дополнительно требуют помечать нечитаемое как "не читается" и не обобщать перечисления в диапазоны.

Авто-fallback по моделям Gemini

При 503 (перегрузка серверов Google) или 429 (лимит) скрипт автоматически переходит к следующей модели из пула, пока одна не ответит. Ретрай одной модели делает SDK, смену модели - скрипт.

Дефолтная цепочка (только дешевые модели 2.5): gemini-2.5-flash -> gemini-2.5-flash-lite.

Дорогие модели (gemini-3.5-flash, *-pro, плавающие *-latest) сознательно НЕ в цепочке: плавающий gemini-flash-latest дрейфовал в gemini-3.5-flash и дал 96% счета за июнь 2026 (видео-вход в 5x дороже 2.5-flash). Нужна максимальная надежность любой ценой - добавить их через --fallback-models.

Управление:

  • --model MODEL - стартовая модель (или env GEMINI_MODEL).
  • --fallback-models "m1,m2,..." - переопределить цепочку (или env GEMINI_FALLBACK_MODELS).
  • --no-fallback - только стартовая модель, без перебора.

503 - серверная перегрузка Gemini, она НЕ зависит от тарифа (платный тариф не помогает). Перебор моделей - официально рекомендованный обход. По умолчанию перебор идет только по дешевым 2.5-моделям.

Стоимость

  • Локальный движок: бесплатно (только электричество).
  • Gemini: flash-класс ~$0.10-0.30 за 1 час записи. По умолчанию перебор только по дешевым 2.5-моделям (дорогие 3.5/pro исключены).

Ограничения

  • Локальный АУДИО-движок (whisper) сам по себе не делает анализ интерфейсов. Для локального разбора ЭКРАНА видео есть отдельный путь --engine local (analyze_video_local.py: whisper + локальная VLM на LM Studio + спикеры по голосу) - требует доступный сервер LM Studio и загруженные модели; посимвольная точность зрения не гарантирована.
  • Локальный движок требует CUDA GPU.
  • Pyannote 4.x (диаризация) - модели gated, нужны принятые условия + HF-токен.
  • Кириллические имена файлов: скриптом обрабатываются.
  • Точность таймкодов +/- несколько секунд.
  • --analyze-ui с аудиофайлом → fallback на Gemini generic + саммари.

Signals

GitHub stars
57
Forks
13
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
transcribe-2
Source
github.com/desko77/cursor-1c-skills