Files
suno-mcp-server/NexusAI/README.md
T
OpenCode 679e56424b Add admin web UI (Phase 2): spend dashboard, media gallery, provider management
Fastify + single-page frontend on shared @nexusai/core. Reads the same SQLite
journal and media dir. Features: usage stats (by provider/capability/day),
content gallery (image/audio/video with local file serving + path-traversal
guard), provider CRUD with encrypted keys (masked in UI), enable/disable,
set-default, and real key validation via zero-cost /media/models call.
Adds Journal.getById and NordRouterMediaProvider.checkKey to core.
2026-08-17 17:22:07 +07:00

184 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```
## Установка
```bash
cd NexusAI
npm install
npm run build
```
> `better-sqlite3` собирается нативно. Если сборка прервалась: `npm rebuild better-sqlite3`.
Для STT нужен [`uv`](https://docs.astral.sh/uv/) и `ffmpeg`. Зависимости whisper `uv` ставит автоматически при первом запуске.
## Подключение к opencode
`.opencode/opencode.json`:
```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` | траты и история из журнала |
### Единый формат вызова
```json
{
"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 (с лимитом размера).
### Единый формат ответа
```json
{
"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`:
```ts
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-каталог.
```bash
npm run build
NEXUS_MASTER_KEY=$(openssl rand -hex 32) \
NEXUS_MEDIA_DIR=./media-output \
npm run admin
# → http://127.0.0.1:4123
```
Возможности:
- **Потребление** — дашборд трат: суммарно, по провайдерам, по возможностям, по дням (из журнала).
- **Галерея** — просмотр сгенерированного контента (изображения/аудио/видео), фильтр по возможности.
- **Провайдеры** — добавить/включить/выключить, назначить default, ввести ключ (шифруется), **проверить ключ** реальным вызовом. Ключи показываются только маской.
Переменные: `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.