303 lines
9.7 KiB
Markdown
303 lines
9.7 KiB
Markdown
# API
|
||
|
||
Базовый URL: `http://<host>/api/v1`
|
||
|
||
Авторизация: `Authorization: Bearer <api_key>`
|
||
|
||
> Получить 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 <api-key>" \
|
||
-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 <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
|
||
|
||
```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=<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
|
||
|
||
```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"}
|
||
```
|
||
|
||
Не требует авторизации.
|