Почему локальный голосовой ассистент — это будущее?
Представьте себе голосового помощника, который работает полностью на вашем компьютере, не отправляет ваши данные в облако, работает без интернета и может быть настроен под ваши конкретные задачи. Это не фантастика — это реальность, которую можно собрать сегодня с помощью трёх ключевых технологий: LangChain для управления контекстом и цепочками, Ollama для запуска локальных языковых моделей и Whisper для преобразования речи в текст.
Главное преимущество локального решения — приватность. Ваши разговоры, вопросы и контекст никогда не покидают ваш компьютер. Это критически важно для бизнес-приложений, медицинских консультаций или просто личных бесед.
Архитектура решения: как всё работает вместе
Прежде чем переходить к коду, давайте разберёмся с архитектурой нашего голосового ассистента:
| Компонент | Роль | Альтернативы |
|---|---|---|
| Whisper (OpenAI) | Распознавание речи (STT) | Vosk, Silero |
| Ollama | Запуск LLM локально | LM Studio, llama.cpp |
| LangChain | Оркестрация и контекст | Semantic Kernel, Haystack |
| pyttsx3 / gTTS | Синтез речи (TTS) | Coqui TTS, Piper |
Рабочий процесс выглядит так: вы говорите → Whisper преобразует речь в текст → LangChain обрабатывает запрос с контекстом → Ollama генерирует ответ → система преобразует текст в речь.
1Подготовка окружения и установка зависимостей
Начнём с создания чистого Python-окружения и установки всех необходимых пакетов. Рекомендую использовать Python 3.10 или выше.
# Создаём виртуальное окружение
python -m venv voice_assistant_env
source voice_assistant_env/bin/activate # Linux/Mac
# или
voice_assistant_env\Scripts\activate # Windows
# Устанавливаем основные зависимости
pip install langchain langchain-community
pip install openai-whisper
pip install pyaudio # для захвата аудио с микрофона
pip install pyttsx3 # для синтеза речи (оффлайн)
# или pip install gtts # для онлайн синтеза через Google
pip install sounddevice soundfile # для работы с аудио
Внимание: установка pyaudio на некоторых системах может требовать дополнительных зависимостей. На Ubuntu/Debian: sudo apt-get install portaudio19-dev python3-pyaudio. На macOS: brew install portaudio.
2Установка и настройка Ollama
Ollama — это инструмент для запуска больших языковых моделей локально. Он поддерживает множество моделей, включая Llama 2, Mistral, CodeLlama и другие.
# Установка Ollama (Linux/Mac)
curl -fsSL https://ollama.com/install.sh | sh
# Запуск Ollama сервера
ollama serve &
# Скачиваем модель (например, Mistral 7B)
ollama pull mistral
# Проверяем работу
ollama run mistral "Привет! Как дела?"
Для Windows скачайте установщик с официального сайта. После установки модель будет доступна через локальный API на порту 11434.
3Создание базового голосового ассистента
Теперь соберём все компоненты в единый скрипт. Создадим файл voice_assistant.py:
import whisper
import pyttsx3
import sounddevice as sd
import soundfile as sf
import numpy as np
from langchain.llms import Ollama
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
import tempfile
import os
class VoiceAssistant:
def __init__(self, model_name="mistral"):
# Инициализация Whisper для распознавания речи
print("Загрузка модели Whisper...")
self.stt_model = whisper.load_model("base") # base, small, medium, large
# Инициализация синтеза речи
print("Инициализация TTS...")
self.tts_engine = pyttsx3.init()
self.tts_engine.setProperty('rate', 150) # Скорость речи
self.tts_engine.setProperty('volume', 0.9) # Громкость
# Инициализация LangChain с Ollama
print(f"Подключение к модели {model_name}...")
self.llm = Ollama(model=model_name, base_url="http://localhost:11434")
# Память для контекста диалога
self.memory = ConversationBufferMemory()
self.conversation = ConversationChain(
llm=self.llm,
memory=self.memory,
verbose=True
)
# Настройки аудио
self.sample_rate = 16000
self.duration = 5 # секунд записи
def record_audio(self):
"""Запись аудио с микрофона"""
print("Говорите сейчас...")
audio = sd.rec(
int(self.duration * self.sample_rate),
samplerate=self.sample_rate,
channels=1,
dtype='float32'
)
sd.wait()
print("Запись завершена")
return audio.flatten()
def speech_to_text(self, audio_data):
"""Преобразование речи в текст с помощью Whisper"""
# Сохраняем временный файл
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
sf.write(tmp_file.name, audio_data, self.sample_rate)
# Транскрибация
result = self.stt_model.transcribe(tmp_file.name, language="ru")
os.unlink(tmp_file.name)
return result["text"]
def process_query(self, text):
"""Обработка запроса через LangChain и Ollama"""
response = self.conversation.predict(input=text)
return response
def text_to_speech(self, text):
"""Преобразование текста в речь"""
self.tts_engine.say(text)
self.tts_engine.runAndWait()
def run(self):
"""Основной цикл ассистента"""
print("Голосовой ассистент запущен. Скажите 'стоп' для выхода.")
while True:
try:
# Шаг 1: Запись аудио
audio = self.record_audio()
# Шаг 2: Преобразование в текст
text = self.speech_to_text(audio)
print(f"Вы сказали: {text}")
if text.lower().strip() in ['стоп', 'stop', 'выход', 'exit']:
print("Завершение работы...")
break
if not text.strip():
print("Речь не распознана, попробуйте снова")
continue
# Шаг 3: Обработка запроса
print("Обработка запроса...")
response = self.process_query(text)
print(f"Ассистент: {response}")
# Шаг 4: Озвучивание ответа
self.text_to_speech(response)
except KeyboardInterrupt:
print("\nПрервано пользователем")
break
except Exception as e:
print(f"Ошибка: {e}")
continue
if __name__ == "__main__":
# Создаём ассистента с моделью mistral
assistant = VoiceAssistant(model_name="mistral")
assistant.run()
4Расширение функциональности: RAG и инструменты
Базовый ассистент уже работает, но его можно значительно улучшить. Добавим Retrieval-Augmented Generation (RAG) для работы с вашими документами и инструменты для выполнения действий.
from langchain.embeddings import OllamaEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import TextLoader, DirectoryLoader
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
class AdvancedVoiceAssistant(VoiceAssistant):
def __init__(self, model_name="mistral", docs_path="./docs"):
super().__init__(model_name)
# Загрузка и индексация документов для RAG
self.setup_rag(docs_path)
# Создание агента с инструментами
self.setup_agent()
def setup_rag(self, docs_path):
"""Настройка RAG системы"""
if os.path.exists(docs_path):
print("Загрузка документов для RAG...")
loader = DirectoryLoader(docs_path, glob="**/*.txt")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
texts = text_splitter.split_documents(documents)
# Создание векторной базы
embeddings = OllamaEmbeddings(
model=model_name,
base_url="http://localhost:11434"
)
self.vectorstore = Chroma.from_documents(
documents=texts,
embedding=embeddings
)
self.retriever = self.vectorstore.as_retriever()
def search_documents(self, query):
"""Поиск в документах"""
if hasattr(self, 'retriever'):
docs = self.retriever.get_relevant_documents(query)
return "\n".join([doc.page_content[:500] for doc in docs[:3]])
return "Документы не загружены"
def setup_agent(self):
"""Настройка агента с инструментами"""
tools = [
Tool(
name="Document Search",
func=self.search_documents,
description="Поиск информации в ваших документах"
),
Tool(
name="Calculator",
func=lambda x: str(eval(x)),
description="Выполнение математических вычислений"
)
]
self.agent = initialize_agent(
tools,
self.llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
memory=self.memory
)
def process_query(self, text):
"""Обработка запроса через агента"""
return self.agent.run(text)
Оптимизация и улучшение производительности
Локальный ассистент может работать медленно, особенно на слабом железе. Вот ключевые оптимизации:
- Используйте меньшие модели Whisper:
baseилиsmallвместоmedium/large - Квантование моделей Ollama:
ollama pull mistral:7b-q4_K_M— q4 версии в 2 раза меньше - Кэширование эмбеддингов: сохраняйте векторную базу на диск
- Асинхронная обработка: используйте asyncio для параллельной работы компонентов
Возможные ошибки и их решение
| Ошибка | Причина | Решение |
|---|---|---|
| CUDA out of memory | Не хватает видеопамяти | Используйте меньшую модель, увеличьте swap |
| Portaudio error | Проблемы с микрофоном | Проверьте доступность микрофона в системе |
| Ollama connection refused | Сервер Ollama не запущен | Запустите ollama serve в отдельном терминале |
| Whisper не распознаёт русский | Язык не указан | Добавьте параметр language="ru" в transcribe() |
Практические применения и развитие проекта
Ваш голосовой ассистент может стать основой для множества полезных приложений:
- Персональный секретарь: управление календарём, напоминаниями, заметками
- Образовательный помощник: объяснение сложных тем, проверка знаний
- Техническая поддержка: ответы на вопросы по документации, как в статье про Multi-modal RAG
- Голосовой интерфейс для DevOps: управление инфраструктурой голосом, как в DevOps для ИИ
Для дальнейшего развития рекомендую изучить бесплатный курс по AI-агентам, где подробно разбираются продвинутые техники.
Совет: начните с простой версии, убедитесь, что все компоненты работают, и только потом добавляйте сложные функции вроде RAG или интеграции с внешними API.
Заключение
Вы создали полностью локального голосового ассистента, который не уступает по функциональности облачным решениям, но при этом гарантирует приватность ваших данных. Комбинация LangChain, Ollama и Whisper открывает огромные возможности для создания специализированных голосовых интерфейсов — от персональных помощников до корпоративных экспертных систем.
Экспериментируйте с разными моделями, добавляйте свои инструменты, интегрируйте с другими системами. И помните: лучший ассистент — тот, который решает именно ваши задачи.