Локальный голосовой ассистент для терминала: Whisper + Claude Code CLI | AiManual
AiManual Logo Ai / Manual.
09 Фев 2026 Гайд

Терминал, который слушает: голосовой ассистент на Whisper и Claude Code CLI за 100 строк кода

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

Зачем вообще голосом управлять терминалом?

Руки на клавиатуре, глаза на мониторе. Стандартная поза разработчика. А что если освободить руки? Произнести "создай новую ветку для фичи авторизации" и увидеть, как терминал сам выполняет git checkout -b feature/auth.

Голосовое управление терминалом - не про лень. Это про фокус. Когда пишешь код, переключаться на терминал, печатать команды, возвращаться к редактору - это разрывает поток. Голос становится мостом между мыслью и действием.

Ключевое отличие от облачных ассистентов: ваши команды, пароли, пути к файлам никогда не покидают компьютер. Whisper работает локально, Claude Code CLI обрабатывает текст локально. Ноль отправок в облако.

Что у нас в арсенале на 2026 год

Технологии за последние два года сделали рывок. То, что было сложно в 2024, сейчас работает из коробки.

Компонент Версия (актуально на 09.02.2026) Зачем нужен
Whisper v4 (OpenAI выпустила крупное обновление в конце 2025) Распознавание речи → текст. Работает полностью локально
Claude Code CLI 3.7 (Anthropic обновили CLI в январе 2026) Преобразует естественную речь в команды терминала
SoundDevice 0.5.3 Захват аудио с микрофона в реальном времени
WebRTC VAD 2.0.12 Детектирование тишины - понимает, когда вы закончили говорить

Самое важное изменение в Whisper v4 - скорость. Модель tiny теперь работает в 3 раза быстрее при том же качестве. Для реального времени это критично.

Архитектура: как из звука получается команда

Не просто "записал - распознал - выполнил". Нужна система, которая понимает паузы, фильтрует шум и не запускает команды от случайного кашля.

  1. Микрофон слушает постоянно, но записывает только когда слышит речь (VAD)
  2. Когда вы замолкаете, аудио отправляется в Whisper
  3. Whisper возвращает текст: "создай папку проект и перейди в неё"
  4. Claude Code CLI преобразует это в: mkdir проект && cd проект
  5. Система спрашивает подтверждение (опционально) и выполняет
💡
VAD (Voice Activity Detection) - это не просто "громкость выше порога". Алгоритм WebRTC анализирует спектр звука, отличает речь от стука клавиш или фоновой музыки. Без него система будет запускаться от каждого случайного звука.

Установка: не пропустите эти пакеты

Первая ошибка новичков - пытаться установить всё через pip без системных зависимостей. Особенно на Linux.

# Для Ubuntu/Debian сначала это
sudo apt update
sudo apt install portaudio19-dev python3-dev ffmpeg

# Теперь Python-пакеты
pip install openai-whisper==4.0.0  # именно v4
pip install sounddevice
pip install webrtcvad
pip install numpy
pip install pydub

# Claude Code CLI - отдельная история
# Качаем с официального сайта Anthropic
# На 09.02.2026 актуальная версия 3.7
# Устанавливаем согласно инструкции для вашей ОС

Portaudio19-dev - обязателен для sounddevice на Linux. Без него получите ошибку "ALSA: Couldn't open audio device". На Windows обычно работает из коробки, на Mac может потребоваться brew install portaudio.

Код: 97 строк рабочего ассистента

Весь код в одном файле. Никаких сложных архитектур. Просто скопируйте, настройте два параметра и запускайте.

#!/usr/bin/env python3
"""
Голосовой ассистент для терминала
Требует: Whisper v4, Claude Code CLI, микрофон
"""

import sounddevice as sd
import numpy as np
import whisper
import wave
import os
import subprocess
import tempfile
from queue import Queue
import threading
import webrtcvad

class TerminalVoiceAssistant:
    def __init__(self, model_size="tiny", sample_rate=16000):
        """
        model_size: tiny, base, small, medium, large
        tiny - самый быстрый, подходит для команд
        """
        print(f"Загружаем Whisper {model_size}...")
        self.model = whisper.load_model(model_size)
        self.sample_rate = sample_rate
        self.vad = webrtcvad.Vad(2)  # агрессивность 0-3
        self.audio_queue = Queue()
        
    def record_until_silence(self, silence_duration=1.0):
        """Записывает аудио, пока не наступит тишина"""
        print("Говорите... (пауза для окончания)")
        
        audio_buffer = []
        silence_frames = 0
        silence_threshold = int(silence_duration * self.sample_rate / 160)  # фреймы по 10мс
        
        def audio_callback(indata, frames, time, status):
            if status:
                print(f"Ошибка аудио: {status}")
            
            # Конвертируем в нужный формат для VAD
            audio_int16 = (indata * 32767).astype(np.int16)
            
            # VAD работает с фреймами по 10мс (160 samples при 16kHz)
            for i in range(0, len(audio_int16), 160):
                frame = audio_int16[i:i+160]
                if len(frame) < 160:
                    continue
                    
                is_speech = self.vad.is_speech(frame.tobytes(), self.sample_rate)
                
                if is_speech:
                    audio_buffer.extend(frame)
                    silence_frames = 0
                else:
                    if len(audio_buffer) > 0:
                        audio_buffer.extend(frame)
                        silence_frames += 1
                        
                        if silence_frames > silence_threshold:
                            raise sd.CallbackStop
            
        # Начинаем запись
        with sd.InputStream(callback=audio_callback,
                          channels=1,
                          samplerate=self.sample_rate,
                          dtype='float32'):
            try:
                sd.sleep(10000)  # максимум 10 секунд
            except sd.CallbackStop:
                pass
        
        if len(audio_buffer) == 0:
            return None
            
        return np.array(audio_buffer, dtype=np.int16)
    
    def transcribe_audio(self, audio_data):
        """Преобразует аудио в текст через Whisper"""
        if audio_data is None:
            return ""
            
        # Сохраняем во временный файл
        with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as f:
            with wave.open(f.name, 'wb') as wf:
                wf.setnchannels(1)
                wf.setsampwidth(2)  # 16-bit
                wf.setframerate(self.sample_rate)
                wf.writeframes(audio_data.tobytes())
            
            # Транскрибация
            result = self.model.transcribe(f.name, language='ru')
            
            os.unlink(f.name)
            return result['text'].strip()
    
    def text_to_command(self, text):
        """Преобразует естественный язык в команду терминала"""
        if not text:
            return None
            
        # Используем Claude Code CLI
        # Формируем промпт для преобразования
        prompt = f"""Преобразуй эту голосовую команду в одну команду терминала (bash).
Только команду, без объяснений.

Команда: {text}

Команда терминала:"""
        
        try:
            # Вызываем Claude Code CLI
            result = subprocess.run(
                ['claude', 'code', '--prompt', prompt],
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode == 0:
                command = result.stdout.strip()
                # Убираем возможные кавычки и лишние символы
                command = command.replace('`', '').strip()
                return command
            else:
                print(f"Ошибка Claude: {result.stderr}")
                return None
                
        except FileNotFoundError:
            print("Claude Code CLI не найден. Установите его с сайта Anthropic")
            return None
        except subprocess.TimeoutExpired:
            print("Claude не ответил за 10 секунд")
            return None
    
    def run(self):
        """Основной цикл"""
        print("Голосовой ассистент запущен. Скажите команду...")
        print("Для выхода нажмите Ctrl+C\n")
        
        while True:
            try:
                # 1. Запись
                audio = self.record_until_silence()
                
                # 2. Транскрибация
                if audio is not None:
                    text = self.transcribe_audio(audio)
                    print(f"Вы сказали: {text}")
                    
                    if text:
                        # 3. Преобразование в команду
                        command = self.text_to_command(text)
                        
                        if command:
                            print(f"Команда: {command}")
                            
                            # 4. Подтверждение и выполнение
                            confirm = input("Выполнить? (y/n): ").lower().strip()
                            if confirm == 'y':
                                os.system(command)
                                print("Готово!\n")
                            else:
                                print("Отменено\n")
                
            except KeyboardInterrupt:
                print("\nВыход")
                break
            except Exception as e:
                print(f"Ошибка: {e}")
                continue

if __name__ == "__main__":
    # Создаём ассистента с tiny моделью (самая быстрая)
    assistant = TerminalVoiceAssistant(model_size="tiny")
    assistant.run()

Настройка под себя: что менять в коде

Стандартные параметры работают, но можно улучшить.

1 Агрессивность VAD

В строке self.vad = webrtcvad.Vad(2) число от 0 до 3. 0 - ловит даже шёпот, 3 - только чёткую речь. Если ассистент пропускает команды - уменьшайте. Если срабатывает на стук клавиш - увеличивайте.

2 Длительность тишины для остановки

В record_until_silence(silence_duration=1.0) - секунды. Если вы делаете паузы в речи ("создай... папку... проект"), увеличьте до 1.5. Если говорите быстро - уменьшите до 0.7.

3 Модель Whisper

model_size="tiny" - самая быстрая, но может ошибаться в сложных командах. Для английского хватит tiny. Для русского лучше base или small. Но помните: large в 10 раз медленнее.

Типичные ошибки и как их исправить

Собрал список проблем, с которыми сталкивался сам и читатели моего блога.

Ошибка Причина Решение
"ALSA: Couldn't open audio device" Нет прав на микрофон или не установлен portaudio sudo apt install portaudio19-dev и перезапуск
Whisper не распознаёт русский По умолчанию ищет английский В коде уже стоит language='ru'. Если нет - добавьте
Claude возвращает не команду, а объяснение Неправильный промпт В промпте чётко: "Только команду, без объяснений"
Система срабатывает на фоновый шум Слишком низкий порог VAD Измените Vad(2) на Vad(3)
Долгая обработка после речи Whisper tiny всё равно требует 1-2 секунды Это нормально. Для реального времени нужны специализированные модели вроде Voxtral-Mini

Что делать, если Claude Code CLI не подходит

Claude Code CLI - не единственный вариант. Иногда нужна полностью open-source альтернатива.

  • Local LLM через Ollama: Установите ollama, скачайте модель типа codellama или deepseek-coder. Вместо вызова Claude используйте Ollama API. Подробности в нашем гайде по голосовым ассистентам.
  • Простые правила: Если команды стандартные ("создай папку", "перейди в"), можно обойтись регулярными выражениями. Но тогда теряется гибкость.
  • LangChain + локальная модель: Более мощное, но сложное решение. Описано в статье про архитектуру голосовых агентов.

Безопасность: что можно, что нельзя

Голосовое выполнение команд - это мощно и опасно. Одно неверное распознавание - и вместо rm temp.txt выполнится rm -rf /.

В коде выше есть подтверждение через input("Выполнить? (y/n)"). НИКОГДА не убирайте этот этап в продакшене. Лучше добавьте список запрещённых команд (rm -rf, dd, mkfs).

Мои рекомендации:

  1. Всегда подтверждение перед выполнением
  2. Вести лог всех распознанных команд и выполненных действий
  3. Не использовать для операций с sudo без дополнительной проверки
  4. Регулярно обновлять Whisper - в новых версиях улучшается точность

Куда развивать этот проект

Базовый вариант работает. Но если хочется большего...

  • Горячие клавиши: Добавьте глобальную горячую клавишу (Ctrl+Shift+Space) для активации вместо постоянного прослушивания
  • Контекст: Запоминайте предыдущие команды. "Повтори последнее" или "сделай то же самое в другой папке"
  • Мультимедиа: Интегрируйте AnyTTS для голосовых ответов
  • Визуальный интерфейс: Маленькое окошко с статусом (слушает/обрабатывает/выполняет)
  • Плагины: Отдельные обработчики для Git, Docker, k8s

Самый интересный путь - сделать систему, которая учится на ваших командах. Если вы часто говорите "разверни проект", а система каждый раз генерирует длинную команду с параметрами - можно запомнить шаблон и предлагать его.

Финальный совет: начинайте с простого

Не пытайтесь сразу сделать идеальную систему. Запустите базовый вариант. Скажите "создай файл test.txt". Посмотрите, как Whisper распознаёт, что Claude генерирует, как выполняется.

Потом добавьте VAD. Потом - горячую клавишу. Потом - логирование.

Через неделю использования вы поймёте главное: голосовой терминал меняет workflow. Вы меньше отвлекаетесь на механические действия. Больше остаётесь в потоке программирования.

И да, Whisper v4 на 09.02.2026 действительно работает в разы лучше, чем v3. Если пробовали раньше и разочаровались - попробуйте снова.