Files
suno-mcp-server/NexusAI
OpenCode 8bd2e89907 feat: STT transcripts, model catalog+fuzzy resolve, UI audio player & auto-refresh
Core:
- ModelCatalog: periodic background sync of provider models + fuzzy resolve.
  Misspelled model ids map to the nearest match (cheapest on ties); no match
  raises ModelResolutionError with cheapest-first suggestions for the agent.

mcp-server:
- nexus_stt now writes the transcript to a Markdown file in the media dir so it
  appears in the gallery and is readable in the modal.
- media handler resolves model via catalog before generating; returns a note
  when substituting, or a BAD_REQUEST with available models when nothing fits.
- context wires a ModelCatalog per media provider with auto-sync.

admin:
- /media serves correct Content-Type (incl. text/markdown for transcripts).
- Gallery: audio play button on cards, dedicated audio player in modal,
  text/transcript tiles that fetch and render the .md in the modal.
- Header: auto-refresh toggle (5/10/30s) that refreshes the active tab
  without a full page reload; pauses while a modal is open.
2026-08-18 12:25:42 +07:00
..

NexusAI — универсальный MCP-сервис для агентов

Единый MCP-сервер (TypeScript, stdio), дающий агентам провайдер-абстрагированный доступ к:

  • TTS — озвучка текста
  • STT — распознавание речи (локально, faster-whisper)
  • Изображения — генерация и правка
  • Видео — text→video / image→video
  • Музыка — генерация треков
  • Веб-поиск — ответ с цитатами (search-augmented модели)

Первый провайдер — NordRouter. Архитектура расширяемая: RouterAI, GPTunnel, OpenRouter и облачные STT добавляются как новые адаптеры без изменения MCP-инструментов. Каждая операция логируется в SQLite (провайдер, модель, стоимость, статус, файл) — основа для будущей веб-админки.

Структура

NexusAI/
├── packages/
│   ├── core/          # провайдеры, media-storage, journal, ключи, типы, registry
│   ├── mcp-server/    # stdio MCP-сервер (10 инструментов)
│   └── admin/         # веб-админка (Fastify + лёгкий фронт)
├── sidecar/           # faster-whisper STT (PEP 723, запуск через uv)
├── .env.example
└── .opencode/opencode.json

Установка

cd NexusAI
npm install
npm run build

better-sqlite3 собирается нативно. Если сборка прервалась: npm rebuild better-sqlite3.

Для STT нужен uv и ffmpeg. Зависимости whisper uv ставит автоматически при первом запуске.

Подключение к opencode

.opencode/opencode.json:

{
  "mcp": {
    "nexusai": {
      "type": "local",
      "command": ["node", "/абс/путь/NexusAI/packages/mcp-server/dist/index.js"],
      "env": {
        "NORDROUTER_API_KEY": "sk-...",
        "NEXUS_MEDIA_DIR": "/абс/путь/NexusAI/media-output",
        "NEXUS_STT_MODEL": "small"
      }
    }
  }
}

Переменные окружения — см. .env.example.

Инструменты

Инструмент Назначение
nexus_tts текст → речь (audio/elevenlabs-tts, audio/gemini-3.1-flash-tts, …)
nexus_image генерация/правка изображений (image/*)
nexus_video видео из текста/фото (video/*)
nexus_music музыка (music/*)
nexus_stt речь → текст (локально)
nexus_web_search веб-поиск с цитатами (perplexity/sonar*, search/*)
nexus_media_models список моделей провайдера (id, тип, цена)
nexus_media_estimate оценка стоимости до запуска
nexus_media_upload загрузка исходника (фото/аудио/видео)
nexus_usage_stats траты и история из журнала

Единый формат вызова

{
  "provider": "nordrouter",
  "model": "audio/elevenlabs-tts",
  "input": { "text": "Привет, мир", "voice": "James · Husky, Engaging and Bold" },
  "output": { "save": true, "embed": false }
}
  • provider опционален (default из NEXUS_DEFAULT_PROVIDER).
  • input пропускает любые модель-специфичные поля (aspect_ratio, resolution, duration, sound, …).
  • output.save — сохранять файл локально (по умолчанию да).
  • output.embed — встроить image/audio прямо в ответ MCP (с лимитом размера).

Единый формат ответа

{
  "provider": "nordrouter",
  "capability": "tts",
  "model": "audio/elevenlabs-tts",
  "status": "done",
  "file_path": "/.../media-output/audio-...wav",
  "mime_type": "audio/wav",
  "result_url": "https://nordrouter.com/media/file/...",
  "result_url_2": null,
  "cost_usd": 0.0049
}

result_url_2 заполняется для музыкальных моделей, отдающих два трека (Suno).

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

  • Media асинхронно: POST /media/generate → polling GET /media/job/:id → скачивание result_url в NEXUS_MEDIA_DIR. Таймаут зависит от типа (картинки — быстро, видео/музыка — до минут).
  • Web search через OpenAI-совместимый /v1/chat/completions с sonar/search/*; цитаты берутся из message.annotations[].url_citation.
  • STT локально: TS запускает uv run sidecar/stt_server.py; faster-whisper декодирует аудио (mp3/wav/ogg/m4a/webm) и возвращает {text, language, segments}.
  • Журнал SQLite (nexus.sqlite в media-dir) пишет каждую операцию; nexus_usage_stats агрегирует траты.
  • MCP работает по stdio — все логи идут в stderr.

Ключи провайдеров

Ключи можно задавать двумя способами, с приоритетом env → БД:

  1. Env (приоритет)NORDROUTER_API_KEY<NAME>_API_KEY для других провайдеров). Просто для CI и локального запуска.
  2. Зашифрованная БД — управляется из будущей админки. Ключи хранятся в SQLite, зашифрованные AES-256-GCM на мастер-ключе NEXUS_MASTER_KEY (сам мастер-ключ — только в env, в БД его нет).

Свойства слоя:

  • В git/логи/БД сырой ключ не попадает; в UI показывается только маска sk-…last4.
  • Бэкап БД не раскрывает ключи (нужен мастер-ключ).
  • Ротация NEXUS_MASTER_KEY инвалидирует зашифрованные ключи — их нужно ввести заново.
  • Без NEXUS_MASTER_KEY работают только env-ключи (сервер предупреждает в stderr).

Программное управление (пока до админки) — через @nexusai/core:

import { KeyCipher, ProvidersStore } from '@nexusai/core';
const cipher = new KeyCipher(process.env.NEXUS_MASTER_KEY);
const store = new ProvidersStore('./media-output/nexus.sqlite', cipher);
store.upsert({ name: 'nordrouter', type: 'nordrouter', apiKey: 'sk-...', isDefault: true });
store.setEnabled('nordrouter', true);
store.listViews(); // masked view for UI

Генерация мастер-ключа: openssl rand -hex 32.

STT в ограниченных сетях

faster-whisper скачивает модель с HuggingFace. Если huggingface.co недоступен:

  • задать зеркало: HF_ENDPOINT=https://hf-mirror.com
  • либо предзагрузить модель и указать путь: NEXUS_STT_MODEL=/abs/model-dir + NEXUS_STT_LOCAL_ONLY=1
  • либо кэш-директорию: NEXUS_STT_DOWNLOAD_ROOT=./models

Веб-админка

Отдельный пакет @nexusai/admin (Fastify + одностраничный фронт) на общем core. Читает тот же SQLite и media-каталог.

npm run build
NEXUS_MASTER_KEY=$(openssl rand -hex 32) \
NEXUS_MEDIA_DIR=./media-output \
npm run admin
# → http://127.0.0.1:4123

Возможности:

  • Тема — переключатель светлая/тёмная (сохраняется в localStorage).
  • Потребление — дашборд трат: суммарно, по провайдерам, по возможностям, по дням (из журнала).
  • Галерея — просмотр сгенерированного контента (изображения/аудио/видео), фильтр по возможности, пагинация 50/100/150/200, модальное окно на весь экран, удаление контента (файл + запись).
  • Провайдеры — добавить/включить/выключить, назначить default, ввести ключ (шифруется), проверить ключ реальным вызовом, типы nordrouter и openai. Ключи показываются только маской.

Переменные: NEXUS_ADMIN_HOST (default 127.0.0.1), NEXUS_ADMIN_PORT (default 4123), NEXUS_MASTER_KEY (для ключей).

Важно: изменения провайдеров/ключей в админке подхватываются MCP-сервером при рестарте (hot-reload — в планах). По умолчанию админка слушает только localhost.

Расширение: новый провайдер

  1. Реализовать MediaProvider / SearchProvider / SttProvider из @nexusai/core.
  2. Зарегистрировать в packages/mcp-server/src/context.ts.

Инструменты и схемы менять не нужно — они провайдер-агностичны.

Roadmap

  • Фаза 2: веб-админка (отдельный пакет admin, Hono/Fastify + лёгкий фронт) на общем core: галерея контента, дашборд трат, управление провайдерами.
  • Доп. провайдеры: RouterAI, GPTunnel, OpenRouter; облачный STT.