Files
2026-06-12 23:53:39 +03:00

266 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Model Update Server
Минимальный backend-сервис на FastAPI для загрузки `.pt` моделей, их stub-конвертации в `.ort`, хранения метаданных в SQLite и выдачи последней модели устройствам.
## Что умеет
- `POST /models` - загрузка новой `.pt` модели с версией
- `GET /models/latest` - метаданные последней модели
- `GET /models/latest/download` - скачивание последней `.ort` модели
## API
Все API-запросы требуют заголовок авторизации:
```http
X-API-Key: <server-issued-key>
```
Ключи выпускаются вручную на сервере и задаются через переменную окружения `API_KEYS`.
Можно указать один ключ или несколько ключей через запятую.
### `POST /models`
Загружает новую модель и регистрирует её как актуальную.
Принимает:
- `Content-Type: multipart/form-data`
- поле `file` - файл модели в формате `.pt`
- поле `version` - строковая версия модели, например `1.0.3`
Возвращает:
- `201 Created` и JSON:
```json
{
"version": "1.0.3",
"created_at": "2026-05-12T10:00:00Z",
"filename": "model_v1.0.3.ort",
"is_latest": true
}
```
Ошибки:
- `400` - пустая версия или файл не `.pt`
- `409` - такая версия уже существует
- `500` - ошибка конвертации
### `GET /models/latest`
Возвращает метаданные последней доступной модели.
Принимает:
- ничего
Возвращает:
- `200 OK` и JSON:
```json
{
"version": "1.0.3",
"created_at": "2026-05-12T10:00:00Z",
"filename": "model_v1.0.3.ort"
}
```
Ошибки:
- `404` - если моделей ещё нет
### `GET /models/latest/download`
Возвращает файл последней `.ort` модели.
Принимает:
- query-параметр `version`
- query-параметр `filename`
Возвращает:
- `200 OK`
- бинарный файл `.ort`
- заголовок `Content-Disposition` для скачивания
Ошибки:
- `404` - если моделей нет, файл отсутствует на диске или `version`/`filename` не совпадают с актуальной моделью
## Требования
- Python 3.11+
## Локальный запуск
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload
```
Сервис будет доступен на `http://127.0.0.1:8000`.
Пример запуска с API-ключом:
```bash
API_KEYS="local-dev-key" uvicorn app.main:app --reload
```
Сгенерировать 10 API-ключей и экспортировать их в текущую shell:
```bash
source scripts/generate_api_keys.sh
uvicorn app.main:app --reload
```
Сгенерировать 10 API-ключей и сохранить их в env-файл:
```bash
scripts/generate_api_keys.sh --env-file .env
set -a
source .env
set +a
uvicorn app.main:app --reload
```
## Переменные окружения
- `MODELS_DIR` - директория хранения итоговых `.ort` моделей
- `TMP_DIR` - директория для временно загруженных `.pt`
- `DATABASE_URL` - URL подключения к SQLite, например `sqlite:///./db/app.db`
- `API_KEYS` - один или несколько API-ключей через запятую, например `key-1,key-2`
По умолчанию используются:
- `storage/models`
- `tmp`
- `sqlite:///db/app.db`
- пустой список API-ключей, при котором API-запросы будут отклоняться с `401`
## Архитектура
Проект разложен по слоям clean architecture:
- `app/domain` - сущности, интерфейсы репозиториев и доменные исключения
- `app/application` - use cases и DTO
- `app/infrastructure` - SQLite, файловое хранилище, stub-конвертер, bootstrap
- `app/presentation` - FastAPI routes, зависимости и response-схемы
Точка входа приложения: [app/main.py](/Users/tanexc/PyCharmMiscProject/convert-and-update-model-server/app/main.py).
## Поведение stub-конвертера
Stub-конвертер уже подключен к `POST /models`, но реальную конвертацию пока не делает. В текущей версии он копирует загруженный `.pt` файл в хранилище с расширением `.ort`, чтобы можно было проверить сценарий загрузки и скачивания end-to-end.
Точка расширения находится в [app/infrastructure/ModelConverterImpl.py](/Users/tanexc/PyCharmMiscProject/convert-and-update-model-server/app/infrastructure/ModelConverterImpl.py).
## Примеры запросов
Загрузка модели:
```bash
curl -X POST "http://127.0.0.1:8000/models" \
-H "X-API-Key: local-dev-key" \
-F "version=1.0.3" \
-F "file=@./example.pt"
```
Получение метаданных:
```bash
curl -H "X-API-Key: local-dev-key" \
"http://127.0.0.1:8000/models/latest"
```
Скачивание последней модели:
```bash
curl -OJ -H "X-API-Key: local-dev-key" \
"http://127.0.0.1:8000/models/latest/download?version=1.0.3&filename=model_v1.0.3.ort"
```
## Docker
Сборка:
```bash
docker build -t model-update-server .
```
Сгенерировать ключи в `.env`:
```bash
scripts/generate_api_keys.sh --env-file .env
```
Запуск через env-файл:
```bash
docker run --rm -p 8000:8000 \
--env-file .env \
-v "$(pwd)/storage/models:/app/storage/models" \
-v "$(pwd)/db:/app/db" \
model-update-server
```
Файл `.env` содержит реальные ключи и не должен попадать в репозиторий. Шаблон без секретов находится в `.env.example`.
## systemd
Пример unit-файла находится в `deploy/systemd/model-update-server.service`.
Он читает переменные окружения из `/etc/model-update-server/model-update-server.env`.
Установка env-файла с ключами:
```bash
sudo mkdir -p /etc/model-update-server
scripts/generate_api_keys.sh --env-file /tmp/model-update-server.env
sudo install -m 600 /tmp/model-update-server.env /etc/model-update-server/model-update-server.env
rm /tmp/model-update-server.env
```
Установка unit-файла:
```bash
sudo cp deploy/systemd/model-update-server.service /etc/systemd/system/model-update-server.service
sudo systemctl daemon-reload
sudo systemctl enable --now model-update-server
```
## CI
В CI храните `API_KEYS` как secret/protected variable и передавайте её в окружение сборки или деплоя.
Не генерируйте новые ключи при каждом деплое, если старые клиенты должны продолжать работать.
Пример для GitHub Actions:
```yaml
env:
API_KEYS: ${{ secrets.API_KEYS }}
```
Пример для GitLab CI:
```yaml
deploy:
script:
- docker run --env API_KEYS="$API_KEYS" model-update-server
```
## Структура данных
Таблица `models`:
- `id`
- `version`
- `filename`
- `file_path`
- `created_at`
- `is_latest`