support-bot-saas/docs/API.md
ed0ss c0527c9bf6
Some checks failed
CI / lint-backend (push) Has been cancelled
CI / lint-frontend (push) Has been cancelled
CI / build-backend (push) Has been cancelled
CI / build-frontend (push) Has been cancelled
fix: включить прокси для embedding-клиента, исправить ошибку 500 на /api/search
2026-07-13 18:02:00 +03:00

9.7 KiB
Raw Permalink Blame History

API

Базовый URL: http://sovet.itoservice.ru/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)

  1. Дубликатticket_id уже существует в коллекции
  2. Нет решения — в messages нет сообщения от assistant длиннее 100 символов
  3. Решение — вопрос — последнее сообщение assistant заканчивается на ? и короче 150 символов
  4. Решение — заглушка — текст содержит фразы вроде «уточните», «приложите скрин», «позвоните нам» и т.п.

Пример (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"}

Не требует авторизации.