Часть 1/2.
✎
Как я построил голосовой AI-зеркало, которое вы можете запустить дома
Источник: Noted.lol
Написано автором проекта MirrorMate, который движим любопытством и креативностью.
Я хотел, чтобы помощник ощущался как присутствие. Что-то, что находится в том же физическом пространстве, что и я. Полузеркало оказалось идеальным интерфейсом для этого.
Демонстрация (видео)
Примечание: демонстрационное видео без звука. Прогулка с озвучиванием и более подробная информация доступны в README.
0:00
/0:22
1×
Демонстрация MirrorMate
Что вы получите из этого поста
- Почему MirrorMate является «голосовым» (и почему это важно для полузеркала)
- Два практических развертывания: легкий облачный режим против полностью локального режима
- Как работает конфигурируемый дизайн (провайдеры, RAG-память, плагины)
Введение
Я использовал умное зеркало в течение некоторого времени (в стиле MagicMirror), но «эра AI» наконец-то сделала взаимодействие настолько естественным, что я захотел перестроить его вокруг разговора: будильник → разговор → зеркало отвечает.
Это стало MirrorMate: личным помощником, который живет за полузеркалом.
Утром я просто говорю «Эй, Мира» во время чистки зубов.
Она говорит мне погоду на сегодня, мою первую встречу и стоит ли мне взять зонт.
С этого момента это перестало ощущаться как демонстрация и стало полезным.
Что такое MirrorMate (почему это весело)
MirrorMate — это личный помощник, который живет за полузеркалом.
Вы разговариваете с ним, и он отвечает — как разговор, встроенный в вашу повседневную жизнь.
С технической точки зрения, это саморазмещенное приложение, разработанное для полузеркала + дисплея.
Если вы когда-либо думали: «Я хочу свой собственный Alexa, но мой» или «дайте мне маленького JARVIS», то это то, что вам нужно.
Основные функции
- Голосовой интерфейс: будильник «Эй, Мира»
- Полностью локальный вариант: Ollama + VOICEVOX, облако не требуется
- RAG-память: извлекает и хранит личные факты, извлекает их по мере необходимости
- Многообразие провайдеров: OpenAI/Ollama, Web Speech/Whisper/faster-whisper, VOICEVOX/OpenAI TTS
- Система плагинов: добавляйте виджеты (часы и т. д.) без изменения ядра
- Предустановки локализации: меняйте язык и автоматически получайте региональные настройки
Если вы хотите самый быстрый путь к работающему зеркалу: начните с минимальной облачной настройки сначала, а затем переходите на полностью локальную после того, как UX станет правильным.
Модель стоимости (практический взгляд)
- Минимальная (Pi + OpenAI): низкие начальные затраты, но вы платите за использование
- Полностью локальная (Pi + сервер вывода): более высокие начальные затраты, но повторяющиеся затраты составляют примерно $0/месяц (исключая электричество)
Аппаратное обеспечение
MirrorMate — это программное обеспечение, но чтобы сделать его зеркалом, вам нужно стандартное оборудование для умного зеркала. Я не буду повторно объяснять все сборки (существует множество руководств по MagicMirror); вот детали, которые имели значение для меня.
Примерный список покупок
- Полузеркало (двустороннее зеркало)
- Дисплей (HDMI — самый простой)
- Raspberry Pi (для интерфейса киоска) + блок питания
- Микрофон + динамики (USB-аудио работает нормально)
- (Необязательно) Камера (для Vision Companion)
- Деревянная рамка / крепления / краска
Ссылочное видео (атмосфера сборки): https://youtu.be/LTuvAoSJZDY?si=Ylj8iAy0gJ90LU6T
Единственный совет, который я бы повторил: выберите дисплей первым, затем закажите полузеркало, чтобы оно соответствовало внешним размерам. Это делает конечный результат более «реальным».
Для справки, мой заказ на полузеркало (Япония, индивидуальный размер):
| Тип: Magic Mirror 3 мм (стекло) 10% пропускания
| Форма: Прямоугольник
| Размер: 255 мм (Ш) × 432 мм (В)
| Обработка краев: C-резка (с фаской)
| Цена единицы: ¥6,857
| Количество: 1
| Промежуточный итог: ¥6,857
|-------------------
| Доставка: ¥950
|-------------------
| Итого: ¥7,807
| Налог: ¥780
| ━━━━━━━━━━━
| Общая сумма: ¥8,587
| ━━━━━━━━━━━
Сейчас я использую Raspberry Pi 3 Model B+. В моей настройке Pi не запускает тяжелые AI-нагрузки — он в основном отвечает за интерфейс/аудио.
Фотографии (рама → краска → финал)
рама
краска
финал
Архитектура
Вот общая картина.
Два режима развертывания
MirrorMate поддерживает две распространенные настройки:
1) Минимальная (Raspberry Pi + OpenAI API)
* Запустите приложение на Pi
* Используйте OpenAI для LLM/TTS/STT
* Быстро начать, но основано на затратах на использование
2) Полностью локальная (Raspberry Pi + более мощная машина)
* Запустите тяжелые сервисы в другом месте (LLM/TTS/STT/встраивания)
* Используйте локальные Ollama, VOICEVOX, faster-whisper и т. д.
* Более высокие начальные затраты, но без зависимости от облака
Я использую полностью локальный вариант.
Ключевое дизайнерское решение - держать Raspberry Pi тонким.
Он отвечает только за интерфейс и аудио I/O — все тяжелое находится в другом месте.
Это делает зеркало отзывчивым, тихим и простым в обслуживании.
┌─────────────────────────────────────────────────────────────────────┐
│ Raspberry Pi │
│ ┌───────────────┐ ┌─────────────┐ ┌────────────────────────────┐ │
│ │ Браузер │ │ Next.js 15 │ │ SQLite + Drizzle ORM │ │
│ │ (Chromium) │◄─┤ Приложение │◄─┤ - воспоминания (RAG) │ │
│ │ + Микр./Кам │ │ Порт 3000 │ │ - сессии │ │
│ │ + MediaPipe │ │ │ │ - настройки пользователя │ │
│ └───────────────┘ └──────┬──────┘ └────────────────────────────┘ │
│ ▲ │ │
│ │ │ VPN Tailscale │
└─────────┼──────────────────┼────────────────────────────────────────┘
│ ▼
│ ┌───────────────────────────────────────────────────────┐
│ │ Сервер вывода │
│ │ ┌────────────┐ ┌───────────┐ ┌───────────────────┐ │
│ │ │ Ollama │ │ VOICEVOX │ │ faster-whisper │ │
│ │ │ - LLM │ │ TTS │ │ STT │ │
│ │ │ - VLM │ │ :50021 │ │ :8080 │ │
│ │ │ :11434 │ │ │ │ │ │
│ │ └────────────┘ └───────────┘ └───────────────────┘ │
│ │ ┌─────────────────────────────────────────────────┐ │
│ │ │ PLaMo-Embedding-1B (Сервер встраиваний):8000 │ │
│ │ └─────────────────────────────────────────────────┘ │
│ └───────────────────────────────────────────────────────┘
│
└── Полузеркало + Монитор
Если ваш Pi и сервер вывода находятся в разных сетях, что-то вроде Tailscale упрощает процесс — особенно если вы хотите сохранить все в частном режиме и не в публичном интернете.
Технологический стек
| Категория | Технология |
|---|---|
| Фронтенд | Next.js 15, React 19, Three.js |
| Бэкенд | Node.js, SQLite (Drizzle ORM) |
| LLM | Ollama (например, gpt-oss:20b), OpenAI |
| TTS | VOICEVOX (Япония), OpenAI TTS |
| STT | Web Speech API, OpenAI Whisper, faster-whisper |
| Встраивание | PLaMo-Embedding-1B (через Ollama) |
| VLM | Ollama (llava и т. д.) |
| Инфраструктура | Docker, Tailscale |
Примечания по программному обеспечению
Советы по интерфейсу для зеркала
Полупрозрачные зеркала лучше всего выглядят, когда вы «освещаете» только то, что важно. Я оставляю фон чисто черным (#000) и показываю только текст/значки. Для аватара я намеренно упростил его — слишком детализированные дизайны, как правило, выглядят ненадежно или ломаются в анимации.
┌────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ │
│ │ 10:30 AM │ ← Плагин часов (вверху слева) │
│ │ Jan 18 │ │
│ └──────────┘ │
│ │
│ ╭───╮ │
│ ( ◠‿◠ ) ← Аватар (в центре) │
│ ╰───╯ │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ "Доброе утро! Сегодня солнечно..." │ │
│ └────────────────────────────────────────────┘ │
│ ↑ Текст ответа (внизу) │
│ │
│ Фон: Чисто черный (#000000) │
└────────────────────────────────────────────────────┘
Поток анимации (упрощенный):
IDLE → LISTENING → THINKING → SPEAKING → LINGERING → IDLE
Конфигурация на основе YAML (почему это важно)
Я хотел поменять LLM, TTS и STT, как Lego — не трогая код приложения. MirrorMate основан на конфигурации. Вы можете менять провайдеров, не заходя в код.
config/app.yaml:
app:
locale: "ja" # или "en"
config/providers.yaml (пример):
providers:
llm:
provider: ollama # openai или ollama
ollama:
model: gpt-oss:20b
baseUrl: "http://studio:11434"
tts:
provider: voicevox # openai или voicevox
voicevox:
speaker: 2
baseUrl: "http://studio:50021"
stt:
provider: web # openai, local или web
embedding:
provider: ollama
ollama:
model: plamo-embedding-1b
Память на основе RAG («личная» часть)
Это функция, которая меня больше всего интересовала: ассистент должен помнить вещи (осторожно). Три типа памяти:
* Профиль : долговременные предпочтения/черты (например, «любит кофе», «ранняя птица»)
* Эпизод : недавние события (например, «вчера смотрел фильм», «командировка на следующей неделе»)
* Знания : фактические заметки (например, «Срок проекта X — конец января»)
Система извлекает память из разговоров, хранит встраивания и извлекает соответствующие элементы на следующем шаге.
providers:
memory:
enabled: true
rag:
topK: 8
threshold: 0.3
extraction:
autoExtract: true
minConfidence: 0.5
Предустановки локали
Изменение app.locale обновляет множество настроек одновременно.
Когда ja:
* Часовой пояс: Asia/Tokyo
* Место для прогноза погоды: Токио
* Формат времени: 24 часа
* Язык STT: ja-JP
Когда en:
* Часовой пояс: America/Los_Angeles
* Место для прогноза погоды: Сан-Франциско
* Формат времени: 12 часов
* Язык STT: en-US
Конфигурация персонажа
Личность ассистента также определяется в YAML:
character:
name: "Mira"
description: "Дружелюбный зеркальный ассистент"
personality:
- "Добрый и теплый"
- "Любопытный"
speech_style:
- "Непринужденный и доступный"
- "Сохранять ответы краткими"
background: |
Вы — ИИ-ассистент, живущий в зеркале.
Помогайте пользователю в повседневной жизни.
Движок правил
Вы можете определить рабочие процессы, срабатывающие по ключевым словам:
rules:
morning_greeting:
description: Подводить итоги дня при утреннем приветствии
triggers:
keywords:
- おはよう
- good morning
actions:
- module: time
- module: weather
- module: calendar
response_hint: |
Объясните следующее дружелюбно:
- Погода сегодня
- Расписание на сегодня
Плагины
Плагины позволяют вам расширять функционал, не перегружая основное приложение.
Плагин часов:
plugins:
clock:
source: github:orangekame3/mirrormate-clock-plugin
enabled: true
position: top-left
config:
showSeconds: false
showDate: true
Vision Companion (на основе камеры):
plugins:
vision-companion:
source: local:vision-companion
enabled: true
position: hidden
Встроенные интеграции
- Погода (Open-Meteo)
- Календарь (Google Calendar)
- Веб-поиск (Tavily)
- Напоминания (опрос)
- Дополнительное деление через Discord
По моему опыту, как только ассистент получает ваш «ежедневный контекст» (календарь, погода, напоминания), он перестает быть демонстрацией и начинает ощущаться как что-то, что вы действительно используете.
Настройка (быстрый путь)
Если вы просто хотите быстро увидеть, как это работает (Pi + OpenAI):
- Установите
llm/stt/ttsнаopenaiвconfig/providers.yaml - Добавьте свои API ключи в
.env - Упростите задачу для Pi: отображение интерфейса и работа с аудио
Клонировать
git clone https://github.com/orangekame3/mirrormate.git
cd mirrormate
Установить зависимости
bun install
Настроить окружение
cp .env.example .env
Запустить
bun dev
Docker:
docker compose up -d
Перейти на полностью локальный
- Запустите Ollama / VOICEVOX / faster-whisper / сервер встраивания на отдельной машине
- Укажите Pi на эти конечные точки через HTTP
- Если сети различаются, подключите через Tailscale (избегайте раскрытия служб публично)
Заключение
Создание MirrorMate заставило меня осознать, насколько иначе ощущается ассистент, когда он физически присутствует в вашем пространстве — не просто еще одно приложение или динамик. Если вам нравится строить вещи, которые живут в вашем окружении, а не только на вашем экране, вам может понравиться MirrorMate. Если это звучит интересно, взгляните на репозиторий:
https://github.com/orangekame3/mirrormate