feat(cmf): integrate CMF as a managed local model server
Run models in the CMF (.cmf) format locally, via the native `cortiq` CLI from crates.io — no Python and no external model server. - cmf_runtime: install/update `cortiq-cli` from crates.io, spawn and health-check `cortiq serve` as a managed local backend. - import: model-import jobs shell out to the native `cortiq convert` (HF repo -> .cmf, quant mapped Q8_2F->q8_2f / Q8_ROW->q8 / Q4->q4); the Python converter is used only for advanced/exotic options. - pipeline: local-first routing — serve from the local CMF model when the router is disabled/unreachable, with a "local only" hard switch. - registry/state: register the local CMF server as an OpenAI provider and track local candidates. - config: data-dir resolution + CmfCfg (auto-install/update, managed server, host/port/model) and relaxed validation for the managed model. - admin + settings UI (en/ru): "Local models (CMF)" settings card.
This commit is contained in:
Vendored
+73
@@ -28,12 +28,14 @@ export default {
|
||||
// nav
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.models": "Models",
|
||||
"nav.import": "Import model",
|
||||
"nav.routing": "Routing",
|
||||
"nav.protocols": "Protocols",
|
||||
"nav.keys": "API keys",
|
||||
"nav.playground": "Playground",
|
||||
"nav.settings": "Settings",
|
||||
"nav.foot": "Gateway · v{v}",
|
||||
"nav.billing": "Router key & billing",
|
||||
|
||||
// topbar / status
|
||||
"status.router": "Router",
|
||||
@@ -41,6 +43,7 @@ export default {
|
||||
"status.online": "online",
|
||||
"status.offline": "offline",
|
||||
"status.checking": "checking…",
|
||||
"status.noKey": "no key",
|
||||
"theme.toggle": "Theme",
|
||||
"logout": "Log out",
|
||||
|
||||
@@ -89,6 +92,7 @@ export default {
|
||||
"dash.health.title": "Health",
|
||||
"dash.health.reachable": "reachable",
|
||||
"dash.health.unreachable": "unreachable",
|
||||
"dash.health.getKey": "Get a router key",
|
||||
|
||||
// models
|
||||
"models.title": "Models",
|
||||
@@ -225,7 +229,34 @@ export default {
|
||||
"settings.router.keyEnv": "Router key env name",
|
||||
"settings.router.timeout": "Timeout (ms)",
|
||||
"settings.router.verifyTls": "Verify TLS certificate",
|
||||
"settings.router.enabled": "Use the router (off = local models only)",
|
||||
"settings.cmf": "Local models (CMF)",
|
||||
"settings.cmf.localOnly": "Use only local models",
|
||||
"settings.cmf.manage": "Run a local model server",
|
||||
"settings.cmf.autoInstall": "Auto-install cortiq (crates.io)",
|
||||
"settings.cmf.autoUpdate": "Auto-update cortiq",
|
||||
"settings.cmf.model": "Local .cmf model path",
|
||||
"settings.cmf.port": "Local server port",
|
||||
"settings.cmf.modelId": "Model id in the pool",
|
||||
"settings.cmf.note": "Serves a local .cmf via cortiq (github.com/infosave2007/cmf). Works even when the router is unavailable.",
|
||||
"settings.router.taxonomy": "Taxonomy id",
|
||||
"settings.router.getKey": "Get or top up a router key at",
|
||||
"settings.router.secret": "Router key (value)",
|
||||
"settings.router.saveKey": "Save key",
|
||||
"settings.router.keySaved": "Router key saved",
|
||||
"settings.router.keyEmpty": "Paste the key first",
|
||||
"settings.router.secretHelp": "Paste the key from your api.allaigate.com email, then Save key. This is NOT a “Keys” value — those are for clients calling your gateway.",
|
||||
"settings.router.keyStoredMask": "•••••••••••• — key saved (paste again to replace)",
|
||||
"settings.router.test": "Test router",
|
||||
"router.probe.ok": "Router OK ({ms} ms)",
|
||||
"router.probe.noKey": "Router key is not set",
|
||||
"router.probe.auth": "Key rejected — invalid or revoked",
|
||||
"router.probe.payment": "Payment required — plan expired or quota exhausted",
|
||||
"router.probe.quota": "Rate limit exceeded",
|
||||
"router.probe.timeout": "Router timed out",
|
||||
"router.probe.unreachable": "Router unreachable",
|
||||
"router.probe.error": "Router error",
|
||||
"router.usage": "Usage",
|
||||
"settings.route": "Routing input",
|
||||
"settings.route.strategy": "Text strategy",
|
||||
"settings.route.maxChars": "Max chars",
|
||||
@@ -266,4 +297,46 @@ export default {
|
||||
"settings.cache.ttl": "Entry TTL",
|
||||
"settings.cache.embed": "Embedding model",
|
||||
"settings.cache.note": "Cache settings take effect after a restart.",
|
||||
|
||||
// import (HuggingFace → CMF)
|
||||
"import.subtitle": "Search HuggingFace, convert to a local .cmf, and serve it.",
|
||||
"import.searchPlaceholder": "Search HuggingFace models (e.g. qwen3, llama)…",
|
||||
"import.searching": "Searching…",
|
||||
"import.noResults": "No models found.",
|
||||
"import.configure": "Configure conversion",
|
||||
"import.outName": "Output name",
|
||||
"import.outNameHint": "The .cmf file name (letters, digits, - and _).",
|
||||
"import.quant": "Quantization",
|
||||
"import.convert": "Convert & load",
|
||||
"import.converting": "Converting",
|
||||
"import.started": "Conversion started",
|
||||
"import.failed": "Conversion failed — see the log.",
|
||||
"import.register": "Register as local model",
|
||||
"import.registered": "Registered as '{id}'. Run cortiq-server to serve it.",
|
||||
"import.jobs": "Conversions",
|
||||
"import.cancel": "Cancel",
|
||||
"import.cancelling": "Cancelling — cleaning up partial output…",
|
||||
"import.delete": "Delete",
|
||||
"import.deleteConfirm": "Delete this model and its converted .cmf file from disk?",
|
||||
"import.deleted": "Deleted with its files",
|
||||
"import.state.running": "running",
|
||||
"import.state.done": "done",
|
||||
"import.state.error": "error",
|
||||
"import.state.cancelled": "cancelled",
|
||||
"import.q.q8_2f": "8-bit two-field (𝒲×θ) — recommended: best quality/size.",
|
||||
"import.q.q8_row": "8-bit per-row — simple, robust.",
|
||||
"import.q.q4": "4-bit block — smallest, lower quality.",
|
||||
"import.q.vbit": "Variable 3–8 bit — per-expert bit budgets.",
|
||||
"import.q.f16": "16-bit — no quantization.",
|
||||
"import.q.f32": "32-bit — full precision (large file).",
|
||||
"import.adv.title": "Advanced settings",
|
||||
"import.adv.auto": "auto",
|
||||
"import.adv.linearCore": "Linear core",
|
||||
"import.adv.linearHint": "How linear-attention layers are carried/folded.",
|
||||
"import.adv.nphase": "vmf_phase phases/head",
|
||||
"import.adv.vbitShape": "VBIT budget shape",
|
||||
"import.adv.meanBits": "VBIT mean bits",
|
||||
"import.adv.shard": "Shard max (GB)",
|
||||
"import.adv.noShard": "no sharding",
|
||||
"import.adv.skipMtp": "skip MTP head",
|
||||
};
|
||||
|
||||
Vendored
+73
@@ -27,12 +27,14 @@ export default {
|
||||
// nav
|
||||
"nav.dashboard": "Дашборд",
|
||||
"nav.models": "Модели",
|
||||
"nav.import": "Импорт модели",
|
||||
"nav.routing": "Роутинг",
|
||||
"nav.protocols": "Протоколы",
|
||||
"nav.keys": "API-ключи",
|
||||
"nav.playground": "Playground",
|
||||
"nav.settings": "Настройки",
|
||||
"nav.foot": "Шлюз · v{v}",
|
||||
"nav.billing": "Ключ роутера и оплата",
|
||||
|
||||
// topbar / status
|
||||
"status.router": "Роутер",
|
||||
@@ -40,6 +42,7 @@ export default {
|
||||
"status.online": "в сети",
|
||||
"status.offline": "недоступен",
|
||||
"status.checking": "проверка…",
|
||||
"status.noKey": "нет ключа",
|
||||
"theme.toggle": "Тема",
|
||||
"logout": "Выйти",
|
||||
|
||||
@@ -88,6 +91,7 @@ export default {
|
||||
"dash.health.title": "Состояние",
|
||||
"dash.health.reachable": "доступен",
|
||||
"dash.health.unreachable": "недоступен",
|
||||
"dash.health.getKey": "Получить ключ роутера",
|
||||
|
||||
// models
|
||||
"models.title": "Модели",
|
||||
@@ -224,7 +228,34 @@ export default {
|
||||
"settings.router.keyEnv": "Имя env-переменной с ключом роутера",
|
||||
"settings.router.timeout": "Таймаут (мс)",
|
||||
"settings.router.verifyTls": "Проверять TLS-сертификат",
|
||||
"settings.router.enabled": "Использовать роутер (выкл = только локальные модели)",
|
||||
"settings.cmf": "Локальные модели (CMF)",
|
||||
"settings.cmf.localOnly": "Использовать только локальные модели",
|
||||
"settings.cmf.manage": "Запускать локальный сервер моделей",
|
||||
"settings.cmf.autoInstall": "Автоустановка cortiq (crates.io)",
|
||||
"settings.cmf.autoUpdate": "Автообновление cortiq",
|
||||
"settings.cmf.model": "Путь к локальной .cmf-модели",
|
||||
"settings.cmf.port": "Порт локального сервера",
|
||||
"settings.cmf.modelId": "ID модели в пуле",
|
||||
"settings.cmf.note": "Обслуживает локальный .cmf через cortiq (github.com/infosave2007/cmf). Работает даже когда роутер недоступен.",
|
||||
"settings.router.taxonomy": "ID таксономии",
|
||||
"settings.router.getKey": "Получить или пополнить ключ роутера:",
|
||||
"settings.router.secret": "Ключ роутера (значение)",
|
||||
"settings.router.saveKey": "Сохранить ключ",
|
||||
"settings.router.keySaved": "Ключ роутера сохранён",
|
||||
"settings.router.keyEmpty": "Сначала вставьте ключ",
|
||||
"settings.router.secretHelp": "Вставьте ключ из письма с api.allaigate.com и нажмите «Сохранить ключ». Это НЕ ключ из раздела «Ключи» — те выдаются клиентам для доступа к вашему шлюзу.",
|
||||
"settings.router.keyStoredMask": "•••••••••••• — ключ сохранён (вставьте снова, чтобы заменить)",
|
||||
"settings.router.test": "Проверить роутер",
|
||||
"router.probe.ok": "Роутер работает ({ms} мс)",
|
||||
"router.probe.noKey": "Ключ роутера не задан",
|
||||
"router.probe.auth": "Ключ отклонён — недействителен или отозван",
|
||||
"router.probe.payment": "Требуется оплата — тариф истёк или квота исчерпана",
|
||||
"router.probe.quota": "Превышен лимит запросов",
|
||||
"router.probe.timeout": "Роутер не ответил вовремя",
|
||||
"router.probe.unreachable": "Роутер недоступен",
|
||||
"router.probe.error": "Ошибка роутера",
|
||||
"router.usage": "Использование",
|
||||
"settings.route": "Входные данные роутинга",
|
||||
"settings.route.strategy": "Стратегия текста",
|
||||
"settings.route.maxChars": "Макс. символов",
|
||||
@@ -265,4 +296,46 @@ export default {
|
||||
"settings.cache.ttl": "TTL записи",
|
||||
"settings.cache.embed": "Модель эмбеддингов",
|
||||
"settings.cache.note": "Настройки кэша применяются после перезапуска.",
|
||||
|
||||
// импорт (HuggingFace → CMF)
|
||||
"import.subtitle": "Найдите модель на HuggingFace, сконвертируйте в локальный .cmf и подключите.",
|
||||
"import.searchPlaceholder": "Поиск моделей на HuggingFace (напр. qwen3, llama)…",
|
||||
"import.searching": "Ищу…",
|
||||
"import.noResults": "Модели не найдены.",
|
||||
"import.configure": "Настройка конвертации",
|
||||
"import.outName": "Имя файла",
|
||||
"import.outNameHint": "Имя .cmf (буквы, цифры, - и _).",
|
||||
"import.quant": "Квантизация",
|
||||
"import.convert": "Сконвертировать и загрузить",
|
||||
"import.converting": "Конвертация",
|
||||
"import.started": "Конвертация запущена",
|
||||
"import.failed": "Конвертация не удалась — смотрите лог.",
|
||||
"import.register": "Подключить как локальную модель",
|
||||
"import.registered": "Подключено как '{id}'. Запустите cortiq-server для обслуживания.",
|
||||
"import.jobs": "Конвертации",
|
||||
"import.cancel": "Отменить",
|
||||
"import.cancelling": "Отмена — удаляю недописанный файл…",
|
||||
"import.delete": "Удалить",
|
||||
"import.deleteConfirm": "Удалить эту модель и сконвертированный .cmf-файл с диска?",
|
||||
"import.deleted": "Удалено вместе с файлами",
|
||||
"import.state.running": "идёт",
|
||||
"import.state.done": "готово",
|
||||
"import.state.error": "ошибка",
|
||||
"import.state.cancelled": "отменено",
|
||||
"import.q.q8_2f": "8-бит двухполевой (𝒲×θ) — рекомендуется: лучшее качество/размер.",
|
||||
"import.q.q8_row": "8-бит построчно — просто, надёжно.",
|
||||
"import.q.q4": "4-бит блочно — компактнее, ниже качество.",
|
||||
"import.q.vbit": "Переменная 3–8 бит — per-expert бюджеты.",
|
||||
"import.q.f16": "16-бит — без квантования.",
|
||||
"import.q.f32": "32-бит — полная точность (большой файл).",
|
||||
"import.adv.title": "Расширенные настройки",
|
||||
"import.adv.auto": "авто",
|
||||
"import.adv.linearCore": "Линейное ядро",
|
||||
"import.adv.linearHint": "Как переносятся/сворачиваются линейные слои внимания.",
|
||||
"import.adv.nphase": "vmf_phase фаз/голову",
|
||||
"import.adv.vbitShape": "Форма бюджета VBIT",
|
||||
"import.adv.meanBits": "VBIT средних бит",
|
||||
"import.adv.shard": "Шард макс (ГБ)",
|
||||
"import.adv.noShard": "без шардинга",
|
||||
"import.adv.skipMtp": "пропустить MTP-голову",
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user