Обновить документацию под глобальную конфигурацию ИИ
ci / build-test (pull_request) Successful in 2m58s
ci / build-test (pull_request) Successful in 2m58s
ТЗ, api-map, техническая документация, инструкция пользователя и контракт операторских настроек: настройки ИИ-провайдера перенесены в консоль оператора, пользовательский POST /api/ai/check удалён.
This commit is contained in:
@@ -268,3 +268,73 @@
|
||||
> Примечание для вкладки Telegram у тенанта: `GET /api/tg/status` остаётся (подключение аккаунта),
|
||||
> поле `keysSet` отражает глобальные ключи; команды `start-phone`/`start-qr` без ключей отвечают
|
||||
> `400 { "detail": "Ключи Telegram не заданы оператором" }`.
|
||||
|
||||
---
|
||||
|
||||
## Операторские настройки: глобальная конфигурация ИИ
|
||||
|
||||
Провайдер, модель, адрес API и ключ ИИ задаёт оператор **глобально**, едины для всех тенантов
|
||||
(в настройках тенанта ключей `aiProvider`/`aiConfigs` больше нет). Хранилище — системная таблица
|
||||
`public.global_settings` (ключ `aiConfig`), `apiKey` хранится зашифрованным (`enc:`) и наружу
|
||||
не отдаётся. На эту конфигурацию работают все ИИ-вызовы всех тенантов: классификация, фильтр,
|
||||
ключи поиска, карточки (`AiProviderConfigBuilder`).
|
||||
|
||||
### GET /api/operator/settings/ai-config
|
||||
|
||||
Маскированный снимок конфигурации вместе с каталогом провайдеров для выбора.
|
||||
|
||||
**200**
|
||||
|
||||
```json
|
||||
{
|
||||
"providerId": "deepseek",
|
||||
"baseUrl": "https://api.deepseek.com",
|
||||
"model": "deepseek-v4-flash",
|
||||
"keySet": true,
|
||||
"keyMasked": "sk-o…-123",
|
||||
"providers": [
|
||||
{ "id": "deepseek", "name": "DeepSeek", "base": "https://api.deepseek.com", "local": false, "models": ["…"] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `providerId` — пусто, если конфигурацию ещё не задавали.
|
||||
- `baseUrl`/`model` — эффективные значения (адрес каталога, первая модель каталога), если не переопределены.
|
||||
- `keyMasked` — **маска** (пусто / `x…` / `1234…5678`); открытый ключ не возвращается никогда.
|
||||
- `providers` — каталог `AiProviders` (`id`/`name`/`base`/`local`/`models`); адрес каталогных облачных
|
||||
провайдеров фиксирован (SSRF-гейт), свой `baseUrl` задаётся только локальным и `custom`.
|
||||
|
||||
**Коды**: `200`, `401`.
|
||||
|
||||
### PUT /api/operator/settings/ai-config
|
||||
|
||||
Сохранение/смена. Поля можно передавать **по отдельности** (частичное обновление): непереданное поле
|
||||
(`null` или отсутствие в JSON) сохраняет текущее значение. Если конфигурации ещё нет, `providerId` обязателен.
|
||||
При смене провайдера `baseUrl`/`model`/`apiKey` не переносятся от старого (дефолты каталога); ключ
|
||||
меняется только при явной передаче (маска не принимается).
|
||||
|
||||
**Тело**
|
||||
|
||||
```json
|
||||
{ "providerId": "deepseek", "model": "deepseek-v4-pro", "apiKey": "sk-…" }
|
||||
```
|
||||
|
||||
**200** — маскированный снимок (форма как у GET).
|
||||
|
||||
**Ошибки**
|
||||
|
||||
- `400 { "detail": "Укажите хотя бы одно поле (providerId, baseUrl, model, apiKey)" }`
|
||||
- `400 { "detail": "Провайдер не из списка разрешённых" }`
|
||||
- `400 { "detail": "Конфигурация ИИ ещё не задана — укажите providerId" }`
|
||||
- `400 { "detail": "Укажите model — у выбранного провайдера нет моделей по умолчанию" }`
|
||||
- `400 { "detail": "API-ключ должен быть не короче 8 символов, без маски" }`
|
||||
- `401 { "detail": "Требуется вход оператора" }`
|
||||
|
||||
### POST /api/operator/settings/ai-config/check
|
||||
|
||||
Проверка связи с сохранённым провайдером (`200` — результат `AiCheckResultDto`). Локальный провайдер
|
||||
отвечает `ok: true` без HTTP; облачный — запрос к списку моделей (приватные адреса запрещены, SSRF-гейт).
|
||||
`400 { "detail": "Сначала сохраните конфигурацию ИИ" }` — конфигурации ещё нет.
|
||||
|
||||
**Аудит**: событие `ai_config_changed` (актор `operator`, `tenantId: null`, детали
|
||||
`{providerId, baseUrl, model, keySet}` — без ключа).
|
||||
|
||||
Reference in New Issue
Block a user