# API Базовый URL: `http://sovet.itoservice.ru/api/v1` Авторизация: `Authorization: Bearer ` > Получить API-ключ можно при регистрации через UI (отображается в настройках профиля). --- ## 1. Поиск по базе знаний `POST /api/v1/search` Поиск релевантных тикетов в коллекции с опциональной генерацией ответа. ### Request body ```json { "collection_id": "83f64913-9cb6-495e-984a-cbae31eacf54", "query": "не могу начать смену в приложении", "generate_answer": true } ``` | Поле | Тип | По умолчанию | Описание | |------------------|---------|--------------|------------------------------------| | `collection_id` | string | — | ID коллекции | | `query` | string | — | Поисковый запрос | | `generate_answer`| boolean | `true` | Сгенерировать ответ LLM или нет | ### Response ```json { "answer": "Проверьте подключение к интернету...", "sources": [ { "ticket_id": "12345", "score": 0.5885, "category": "техподдержка", "full_text": "Категория: техподдержка\nПроблема: ...\nРешение: ..." } ] } ``` | Поле | Тип | Описание | |----------|----------------------------|----------------------------------------| | `answer` | string или null | Сгенерированный ответ LLM или null | | `sources`| array of SourceItem | Найденные тикеты (от 0 до 5) | ### SourceItem | Поле | Тип | Описание | |------------|---------|-----------------------------| | `ticket_id`| string | ID тикета | | `score` | float | Релевантность (0..1) | | `category` | string | Категория тикета | | `full_text`| string | Полный текст решения | ### Пример (curl) ```bash curl -s -X POST http://sovet.itoservice.ru/api/v1/search \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "collection_id": "83f64913-9cb6-495e-984a-cbae31eacf54", "query": "не могу начать смену в приложении", "generate_answer": true }' ``` ### Пример (Python) ```python import requests resp = requests.post( "http://sovet.itoservice.ru/api/v1/search", headers={"Authorization": "Bearer "}, json={ "collection_id": "83f64913-9cb6-495e-984a-cbae31eacf54", "query": "не могу начать смену в приложении", "generate_answer": True, }, ) data = resp.json() print(data["answer"]) ``` --- ## 2. Загрузка тикетов `POST /api/v1/tickets?collection_id=` Загрузка массива тикетов в коллекцию. Дубликаты по `ticket_id` автоматически пропускаются. ### Request body ```json { "tickets": [ { "ticket_id": 12345, "category": "техподдержка", "description": "Не работает принтер", "client": "Иван", "messages": [ {"role": "user", "text": "У меня не печатает принтер"}, {"role": "assistant", "text": "Проверьте подключение кабеля USB к компьютеру..."} ] } ] } ``` | Поле | Тип | По умолчанию | Описание | |---------------|----------------------|--------------|-----------------------------| | `ticket_id` | int или string | — | Уникальный ID тикета | | `category` | string | `""` | Категория проблемы | | `description` | string | `""` | Краткое описание проблемы | | `client` | string | `""` | Имя клиента | | `messages` | array of Message | `[]` | Переписка (user + assistant)| ### Message ```json {"role": "user|assistant", "text": "текст сообщения"} ``` - `role` — `"user"` или `"assistant"`. Сообщения `"assistant"` используются как решение. - `text` — текст сообщения. Решение должно быть длиннее 100 символов и не заканчиваться вопросительным знаком. ### Response ```json { "processed": 1, "skipped": 0, "collection_ticket_count": 100 } ``` | Поле | Тип | Описание | |------------------------|-------|-----------------------------------| | `processed` | int | Количество обработанных тикетов | | `skipped` | int | Пропущено (дубликат или нет решения)| | `collection_ticket_count`| int | Всего тикетов в коллекции | ### Почему тикет может быть пропущен (skipped) 1. **Дубликат** — `ticket_id` уже существует в коллекции 2. **Нет решения** — в `messages` нет сообщения от `assistant` длиннее 100 символов 3. **Решение — вопрос** — последнее сообщение `assistant` заканчивается на `?` и короче 150 символов 4. **Решение — заглушка** — текст содержит фразы вроде «уточните», «приложите скрин», «позвоните нам» и т.п. ### Пример (curl) ```bash curl -s -X POST 'http://sovet.itoservice.ru/api/v1/tickets?collection_id=' \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"tickets": [{"ticket_id": 1, "description": "Проблема", "messages": [{"role": "user", "text": "вопрос"}, {"role": "assistant", "text": "Проверьте соединение и перезагрузите устройство, затем повторите попытку. Если не помогает – обратитесь к администратору системы."}]}]}' ``` --- ## 3. Список коллекций `GET /api/v1/collections` ### Response ```json [ { "id": "83f64913-9cb6-495e-984a-cbae31eacf54", "user_id": "30939310-e3a3-4993-b1ac-10c81b751843", "name": "OFRS", "ticket_count": 2898, "created_at": "2026-06-29T11:45:27.866413Z" } ] ``` --- ## 4. Профиль пользователя `GET /api/v1/me` ### Response ```json { "id": "30939310-e3a3-4993-b1ac-10c81b751843", "email": "user@example.com", "api_key": "abc123...", "plan": "pro", "created_at": "2026-06-29T11:45:27.866413Z" } ``` --- ## 5. Сброс API-ключа `PATCH /api/v1/me/api-key` ### Response ```json { "api_key": "новый-ключ-32-символа" } ``` --- ## 6. JWT-эндпоинты (для UI) Эти эндпоинты требуют JWT-токен (получается через `/api/login`), а не API-ключ. | Метод | Путь | Описание | |-------|-------------------------------|------------------------------| | POST | `/api/register` | Регистрация | | POST | `/api/login` | Вход (возвращает JWT) | | GET | `/api/me` | Профиль | | POST | `/api/collections` | Создать коллекцию | | GET | `/api/collections` | Список коллекций | | GET | `/api/collections/{id}` | Информация о коллекции | | DELETE| `/api/collections/{id}` | Удалить коллекцию | | POST | `/api/collections/{id}/tickets` | Загрузить тикеты (JSON)| | POST | `/api/collections/{id}/tickets/upload`| Загрузить тикеты (файл)| | POST | `/api/search` | Поиск | ### Регистрация ```json POST /api/register { "email": "user@example.com", "password": "secret123", "plan": "free" } → 201 {"access_token": "jwt...", "token_type": "bearer"} ``` ### Логин ```json POST /api/login { "email": "user@example.com", "password": "secret123" } → {"access_token": "jwt...", "token_type": "bearer"} ``` --- ## 7. Ошибки Все ошибки возвращают стандартный формат FastAPI: ```json { "detail": "Collection not found" } ``` HTTP-статусы: - `200` — успех - `201` — создано - `400` — неверный запрос - `401` — неавторизован - `404` — не найдено - `429` — превышен лимит запросов (30 req/min) - `500` — внутренняя ошибка сервера --- ## 8. Rate limiting 30 запросов в минуту на один IP-адрес. При превышении — `429 Too Many Requests`. Лимит действует на все эндпоинты, кроме `/api/health`. --- ## 9. Health check `GET /api/health` ```json {"status": "ok"} ``` Не требует авторизации.