9.7 KiB
9.7 KiB
API
Базовый URL: http://<host>/api/v1
Авторизация: Authorization: Bearer <api_key>
Получить API-ключ можно при регистрации через UI (отображается в настройках профиля).
1. Поиск по базе знаний
POST /api/v1/search
Поиск релевантных тикетов в коллекции с опциональной генерацией ответа.
Request body
{
"collection_id": "83f64913-9cb6-495e-984a-cbae31eacf54",
"query": "не могу начать смену в приложении",
"generate_answer": true
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
collection_id |
string | — | ID коллекции |
query |
string | — | Поисковый запрос |
generate_answer |
boolean | true |
Сгенерировать ответ LLM или нет |
Response
{
"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)
curl -s -X POST http://sovet.itoservice.ru/api/v1/search \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{
"collection_id": "83f64913-9cb6-495e-984a-cbae31eacf54",
"query": "не могу начать смену в приложении",
"generate_answer": true
}'
Пример (Python)
import requests
resp = requests.post(
"http://sovet.itoservice.ru/api/v1/search",
headers={"Authorization": "Bearer <api-key>"},
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=<uuid>
Загрузка массива тикетов в коллекцию. Дубликаты по ticket_id автоматически пропускаются.
Request body
{
"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
{"role": "user|assistant", "text": "текст сообщения"}
role—"user"или"assistant". Сообщения"assistant"используются как решение.text— текст сообщения. Решение должно быть длиннее 100 символов и не заканчиваться вопросительным знаком.
Response
{
"processed": 1,
"skipped": 0,
"collection_ticket_count": 100
}
| Поле | Тип | Описание |
|---|---|---|
processed |
int | Количество обработанных тикетов |
skipped |
int | Пропущено (дубликат или нет решения) |
collection_ticket_count |
int | Всего тикетов в коллекции |
Почему тикет может быть пропущен (skipped)
- Дубликат —
ticket_idуже существует в коллекции - Нет решения — в
messagesнет сообщения отassistantдлиннее 100 символов - Решение — вопрос — последнее сообщение
assistantзаканчивается на?и короче 150 символов - Решение — заглушка — текст содержит фразы вроде «уточните», «приложите скрин», «позвоните нам» и т.п.
Пример (curl)
curl -s -X POST 'http://sovet.itoservice.ru/api/v1/tickets?collection_id=<uuid>' \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{"tickets": [{"ticket_id": 1, "description": "Проблема", "messages": [{"role": "user", "text": "вопрос"}, {"role": "assistant", "text": "Проверьте соединение и перезагрузите устройство, затем повторите попытку. Если не помогает – обратитесь к администратору системы."}]}]}'
3. Список коллекций
GET /api/v1/collections
Response
[
{
"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
{
"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
{
"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 |
Поиск |
Регистрация
POST /api/register
{
"email": "user@example.com",
"password": "secret123",
"plan": "free"
}
→ 201 {"access_token": "jwt...", "token_type": "bearer"}
Логин
POST /api/login
{
"email": "user@example.com",
"password": "secret123"
}
→ {"access_token": "jwt...", "token_type": "bearer"}
7. Ошибки
Все ошибки возвращают стандартный формат FastAPI:
{
"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
{"status": "ok"}
Не требует авторизации.