Зачем платить за транскрибацию, если можно собрать свою систему за 17 тысяч рублей?
Помню тот день, когда получил счет от сервиса транскрибации: 2 часа аудио, 12 тысяч рублей. Это был последний раз. Сегодня моя система обрабатывает те же 2 часа за 4 минуты. И обошлась она мне в 17 тысяч рублей за видеокарту плюс пару дней настройки.
Секрет? Tesla V100 с AliExpress, Whisper от OpenAI и Pyannote для диаризации. Звучит как магия, но это просто инженерная задача, которую можно решить за выходные.
Результат: 2 часа аудио → 4 минуты обработки вместо 12 тысяч рублей за сервис. Окупаемость системы - меньше двух транскрибаций.
Ты точно хочешь покупать видеокарту с AliExpress?
Начну с главного страха. Tesla V100 за 17 тысяч рублей - это не новая карта. Это бывшее в употреблении оборудование из дата-центров. Риски есть, но их можно минимизировать.
1 Выбор и покупка Tesla V100
Идем на AliExpress и ищем "Tesla V100 16GB". Не 32GB - она дороже и для транскрибации не нужна. Сразу фильтруем по продавцам с рейтингом выше 97% и отзывами не меньше 100.
| Что проверяем | Как проверяем | Что делать, если проблема |
|---|---|---|
| Стресс-тест | FurMark + GPU-Z мониторинг температуры | Возврат, если выше 85°C |
| Память | memtest с CUDA | Возврат при ошибках |
| Вентиляторы | Тест на 100% скорости | Замена вентиляторов (дешево) |
Мой продавец назывался "GPU Server Store". Карта пришла в обычной коробке с пенопластом. Внешне - как новая. Внутри - отработала 3 года в дата-центре. Но для транскрибации это не проблема.
Важно: Tesla V100 - серверная карта. У нее нет видеовыходов. Не пытайся подключить к ней монитор. Это чисто для вычислений.
2 Подготовка системы: драйверы, CUDA и прочая магия
Вот где большинство спотыкается. Установка драйверов для Tesla - это не как для игровой карты. Делаем все по порядку.
# Удаляем все старые драйверы NVIDIA
sudo apt-get purge nvidia* cuda*
sudo apt-get autoremove
# Добавляем репозиторий
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
# Устанавливаем драйвер для Tesla V100
sudo apt-get update
sudo apt-get install -y nvidia-driver-535 nvidia-container-toolkit
Перезагружаемся и проверяем:
nvidia-smi
Должна появиться таблица с Tesla V100. Если видишь "NVIDIA-SMI has failed", значит драйвер не встал. Возвращаемся к удалению и пробуем версию 525.
3 Установка Whisper: не ту версию, что в документации
Официальная установка через pip install whisper работает, но медленно. Мы будем использовать оптимизированную версию.
# Создаем виртуальное окружение
python3 -m venv whisper_env
source whisper_env/bin/activate
# Ставим PyTorch с поддержкой CUDA 11.8 (важно для V100)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# Whisper с оптимизациями
pip install faster-whisper
Почему faster-whisper? Потому что он в 4 раза быстрее на длинных аудио. Использует CTranslate2 под капотом. Разница в качестве транскрипции незаметна для человеческого уха.
4 Pyannote для диаризации: кто сказал что
Whisper транскрибирует, но не различает говорящих. Для этого нужен Pyannote. Но есть нюанс: последние версии требуют Hugging Face токен.
pip install pyannote.audio
Теперь идем на Hugging Face, создаем аккаунт и получаем токен. Затем:
from pyannote.audio import Pipeline
pipeline = Pipeline.from_pretrained(
"pyannote/speaker-diarization-3.1",
use_auth_token="ВАШ_ТОКЕН_ЗДЕСЬ"
)
# Отправляем на GPU
pipeline.to(torch.device("cuda:0"))
Pyannote работает только с аудио в формате 16kHz mono. Если у тебя стерео или другая частота - конвертируй перед обработкой.
Собираем все вместе: Python скрипт, который работает
Теперь самое интересное - склеиваем Whisper и Pyannote в один пайплайн. Вот рабочий код:
import torch
from faster_whisper import WhisperModel
from pyannote.audio import Pipeline
import whisper
import subprocess
import tempfile
import os
class MeetingTranscriber:
def __init__(self, hf_token):
# Загружаем Whisper (используем medium - лучший баланс скорости/качества)
self.whisper_model = WhisperModel(
"medium",
device="cuda",
compute_type="float16", # Ускоряет в 2 раза с минимальной потерей точности
download_root="./models"
)
# Загружаем Pyannote
self.diarization_pipeline = Pipeline.from_pretrained(
"pyannote/speaker-diarization-3.1",
use_auth_token=hf_token
)
self.diarization_pipeline.to(torch.device("cuda:0"))
def convert_audio(self, input_path):
"""Конвертируем аудио в правильный формат для Pyannote"""
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
output_path = tmp.name
# Используем ffmpeg для конвертации
cmd = [
"ffmpeg", "-i", input_path,
"-ac", "1", # моно
"-ar", "16000", # 16kHz
"-acodec", "pcm_s16le", # 16-bit PCM
output_path, "-y"
]
subprocess.run(cmd, capture_output=True)
return output_path
def transcribe_meeting(self, audio_path):
"""Основная функция транскрибации"""
print("Конвертируем аудио...")
converted_audio = self.convert_audio(audio_path)
print("Диаризация...")
diarization = self.diarization_pipeline(converted_audio)
print("Транскрибация...")
segments, info = self.whisper_model.transcribe(
converted_audio,
language="ru",
beam_size=5, # Улучшает качество для русского
vad_filter=True # Убирает тишину
)
# Собираем результат
result = []
for segment in segments:
# Находим, кто говорил в это время
speaker = "UNKNOWN"
for turn, _, speaker_label in diarization.itertracks(yield_label=True):
if turn.start <= segment.start <= turn.end:
speaker = speaker_label
break
result.append({
"speaker": speaker,
"start": segment.start,
"end": segment.end,
"text": segment.text
})
# Убираем временный файл
os.unlink(converted_audio)
return result
Это базовая версия. В реальном проекте добавь обработку ошибок, логирование и кэширование моделей.
Оптимизация: как добиться 4 минут на 2 часа аудио
Из коробки система будет работать минут 15 на 2-часовом файле. Чтобы ускорить до 4 минут, нужно сделать три вещи:
- Batch processing: Обрабатывать аудио кусками по 30 секунд, а не целиком
- Async I/O: Пока Whisper работает с одним куском, Pyannote готовит следующий
- Кэширование моделей в памяти: Не загружать модели при каждом запросе
Вот оптимизированная версия обработки:
import asyncio
from concurrent.futures import ThreadPoolExecutor
class OptimizedTranscriber(MeetingTranscriber):
def __init__(self, hf_token):
super().__init__(hf_token)
self.executor = ThreadPoolExecutor(max_workers=2)
async def transcribe_chunk(self, chunk_path):
"""Асинхронная транскрибация одного куска"""
loop = asyncio.get_event_loop()
segments = await loop.run_in_executor(
self.executor,
lambda: self.whisper_model.transcribe(chunk_path, language="ru")[0]
)
return list(segments)
async def diarize_chunk(self, chunk_path):
"""Асинхронная диаризация одного куска"""
loop = asyncio.get_event_loop()
diarization = await loop.run_in_executor(
self.executor,
lambda: self.diarization_pipeline(chunk_path)
)
return diarization
Развёртывание: Docker, systemd или просто скрипт?
Зависит от того, кто будет пользоваться системой. Если только ты - хватит простого Python скрипта. Если команда - делаем веб-интерфейс. Вот минимальный Flask сервер:
from flask import Flask, request, jsonify
import os
app = Flask(__name__)
transcriber = None
@app.before_first_request
def load_model():
global transcriber
transcriber = MeetingTranscriber(os.getenv("HF_TOKEN"))
@app.route("/transcribe", methods=["POST"])
def transcribe():
if "audio" not in request.files:
return jsonify({"error": "No audio file"}), 400
audio = request.files["audio"]
temp_path = f"/tmp/{audio.filename}"
audio.save(temp_path)
try:
result = transcriber.transcribe_meeting(temp_path)
return jsonify({"transcription": result})
finally:
os.unlink(temp_path)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Запускаем через gunicorn для production:
HF_TOKEN=ваш_токен gunicorn -w 1 -k gevent --timeout 120 app:app
Что может пойти не так (и как это починить)
За два года эксплуатации системы я набил все возможные шишки. Вот главные проблемы:
- Out of memory на длинных файлах: Решение - резать аудио на куски по 10 минут
- Pyannote путает говорящих: Особенно если в записи эхо. Решение - использовать шумоподавление перед диаризацией
- Whisper не понимает акцент: Fine-tuning на 5-10 часах записей с акцентом решает проблему
- Карта перегревается: Tesla V100 не имеет активного охлаждения. Решение - поставить в корпус с хорошей вентиляцией
Альтернативы: может, не стоит покупать Tesla V100?
Если 17 тысяч рублей - все еще много, посмотри на RTX 2060. Медленнее в 3 раза, но стоит 8 тысяч. Или RTX 4070 Super - быстрее, но дороже.
Для совсем минималистов есть вариант с Whisper на CPU. 2 часа аудио будут обрабатываться 4 часа вместо 4 минут. Но зато бесплатно.
Итог: стоит ли игра свеч?
Да, если транскрибируешь больше 5 часов аудио в месяц. Нет, если это разовая задача.
Моя система окупилась за месяц. Теперь я транскрибирую все совещания автоматически, сохраняю в Notion и даже делаю краткие выжимки через локальную LLM.
Самое приятное - полный контроль над данными. Никаких соглашений о конфиденциальности, никаких утечек в интернет. Все работает в локальной сети.
И последний совет: не пытайся сделать идеальную систему с первого раза. Собери минимально рабочую версию, проверь на 10 записях, а потом оптимизируй. Whisper и Pyannote прощают много ошибок настройки.
Не забудь про лицензию Pyannote. Для коммерческого использования нужна отдельная лицензия от INRIA. Для личных проектов - бесплатно.
Теперь у тебя есть все, чтобы собрать свою систему. Карта - 17к, день на настройку, вечность бесплатной транскрибации. Выбор за тобой.