# DaSiWa API Guide Полное руководство по использованию DaSiWa I2V/FLF2V API для генерации видео через ComfyUI. --- ## 📋 Содержание 1. [Обзор](#обзор) 2. [Аутентификация](#аутентификация) 3. [Endpoints](#endpoints) 4. [Параметры генерации](#параметры-генерации) 5. [Примеры использования](#примеры-использования) 6. [Коды ошибок](#коды-ошибок) 7. [Best Practices](#best-practices) --- ## Обзор DaSiWa API — асинхронный REST API для генерации видео из изображений с использованием DaSiWa WAN 2.2 Lightspeed моделей через ComfyUI. **Архитектура:** Submit → Poll → Retrieve (как RunPod) **Base URL:** `http://:8080` **Аутентификация:** HMAC-SHA256 с timestamp и nonce --- ## Аутентификация Все endpoints (кроме `/health`) требуют HMAC подписи. ### Заголовки запроса ``` X-Client-Id: <ваш_client_id> X-Timestamp: X-Nonce: <случайная_строка_32_символа> X-Signature: ``` ### Алгоритм подписи ```python import hmac import hashlib import time import secrets timestamp = str(int(time.time())) nonce = secrets.token_hex(16) body = json.dumps(payload).encode('utf-8') message = f"{timestamp}.{nonce}.".encode() + body signature = hmac.new( secret_key.encode(), message, hashlib.sha256 ).hexdigest() ``` ### Защита от replay-атак - **Timestamp:** запросы старше 5 минут отклоняются - **Nonce:** каждый nonce можно использовать только один раз - **Signature:** уникальна для каждого запроса --- ## Endpoints ### `GET /health` Health check сервера. **Не требует аутентификации.** **Response:** ```json { "status": "ok", "comfyui": "ok", "queue": 0, "timestamp": 1234567890 } ``` **Поля:** - `status` — статус API сервера (`ok` / `error`) - `comfyui` — статус ComfyUI (`ok` / `unavailable`) - `queue` — количество задач в очереди - `timestamp` — текущее время сервера (unix) --- ### `POST /run` Поставить задачу на генерацию видео в очередь. **Request Body:** ```json { "image_base64": "base64_encoded_image_data", "prompt": "woman dancing gracefully", "negative_prompt": "blurry, low quality", "last_image_base64": "base64_encoded_last_frame", "width": 528, "height": 768, "length": 81, "steps": 4, "cfg": 1.0, "seed": -1, "fps": 16, "sampler_name": "euler", "scheduler": "linear_quadratic" } ``` **Обязательные поля:** - `image_base64` — первый кадр (base64) - `prompt` — текстовое описание **Опциональные поля:** - `last_image_base64` — последний кадр для FLF2V режима - `negative_prompt` — негативный промпт (default: встроенный) - `width` — ширина (default: 528, кратно 16) - `height` — высота (default: 768, кратно 16) - `length` — количество кадров (default: 81) - `steps` — шаги сэмплинга (default: 4) - `cfg` — CFG scale (default: 1.0) - `seed` — сид (-1 = random, default: -1) - `fps` — кадров в секунду (default: 16) - `sampler_name` — сэмплер (default: "euler") - `scheduler` — планировщик (default: "linear_quadratic") **Response:** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "status": "IN_QUEUE" } ``` **Коды ответа:** - `200` — задача принята - `400` — ошибка валидации (нет изображения) - `401` — ошибка аутентификации --- ### `GET /status/` Получить статус задачи. **Response (IN_QUEUE):** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "status": "IN_QUEUE" } ``` **Response (IN_PROGRESS):** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "status": "IN_PROGRESS" } ``` **Response (COMPLETED):** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "status": "COMPLETED", "output": { "video": "base64_encoded_video_data", "seed": 42, "mode": "I2V", "elapsed": 45.2 } } ``` **Response (FAILED):** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "status": "FAILED", "error": "Video generation failed — no output from ComfyUI" } ``` **Коды ответа:** - `200` — статус получен - `404` — задача не найдена - `401` — ошибка аутентификации --- ### `POST /purge/` Удалить завершённую задачу из памяти сервера (освободить RAM от base64 видео). **Response:** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "purged": true } ``` **Коды ответа:** - `200` — задача удалена - `400` — нельзя удалить активную задачу (IN_QUEUE / IN_PROGRESS) - `404` — задача не найдена - `401` — ошибка аутентификации --- ## Параметры генерации ### Режимы работы **I2V (Image to Video):** - Генерация видео из одного изображения - Передаётся только `image_base64` **FLF2V (First-Last Frame to Video):** - Генерация видео между двумя кадрами - Передаются `image_base64` + `last_image_base64` ### Рекомендуемые значения | Параметр | I2V | FLF2V | Описание | |----------|-----|-------|----------| | `width` | 528 | 528 | Ширина (кратно 16) | | `height` | 768 | 768 | Высота (кратно 16) | | `length` | 81 | 81 | Кол-во кадров (~5 сек при 16fps) | | `steps` | 4 | 4 | DaSiWa оптимизирован под 4 шага | | `cfg` | 1.0 | 1.0 | CFG scale (DaSiWa работает с 1.0) | | `fps` | 16 | 16 | Кадров в секунду | | `sampler_name` | euler | euler | Сэмплер | | `scheduler` | linear_quadratic | linear_quadratic | Планировщик | ### Ограничения - **Размеры:** должны быть кратны 16 - **Length:** рекомендуется кратно 8 + 1 (например: 81, 89, 97) - **Steps:** DaSiWa Lightspeed оптимизирован под 4 шага (можно больше, но медленнее) - **CFG:** значения > 2.0 могут давать артефакты --- ## Примеры использования ### Python (с библиотекой requests) ```python import requests import base64 import json import time from hmac_auth import sign_request # Загрузка ключей with open('keys.json') as f: keys = json.load(f) # Подготовка изображения with open('photo.png', 'rb') as f: image_b64 = base64.b64encode(f.read()).decode() # Payload payload = { "image_base64": image_b64, "prompt": "woman dancing gracefully", "width": 528, "height": 768, "length": 81, "steps": 4, "cfg": 1.0, "seed": -1, "fps": 16 } # 1. Submit job body = json.dumps(payload).encode('utf-8') auth_headers = sign_request(body, keys['secret_key'], keys['client_id']) headers = {'Content-Type': 'application/json', **auth_headers} response = requests.post( 'http://server:8080/run', data=body, headers=headers ) job_id = response.json()['id'] print(f"Job ID: {job_id}") # 2. Poll status while True: auth_headers = sign_request(b"", keys['secret_key'], keys['client_id']) response = requests.get( f'http://server:8080/status/{job_id}', headers=auth_headers ) data = response.json() if data['status'] == 'COMPLETED': video_b64 = data['output']['video'] video_bytes = base64.b64decode(video_b64) with open('output.mp4', 'wb') as f: f.write(video_bytes) print(f"Video saved! Seed: {data['output']['seed']}") break elif data['status'] == 'FAILED': print(f"Error: {data['error']}") break else: print(f"Status: {data['status']}") time.sleep(5) # 3. Purge job auth_headers = sign_request(b"{}", keys['secret_key'], keys['client_id']) requests.post( f'http://server:8080/purge/{job_id}', json={}, headers={'Content-Type': 'application/json', **auth_headers} ) ``` ### cURL ```bash # 1. Submit job curl -X POST http://server:8080/run \ -H "Content-Type: application/json" \ -H "X-Client-Id: your_client_id" \ -H "X-Timestamp: $(date +%s)" \ -H "X-Nonce: $(openssl rand -hex 16)" \ -H "X-Signature: " \ -d '{ "image_base64": "...", "prompt": "woman dancing" }' # Response: {"id": "abc-123", "status": "IN_QUEUE"} # 2. Check status curl http://server:8080/status/abc-123 \ -H "X-Client-Id: your_client_id" \ -H "X-Timestamp: $(date +%s)" \ -H "X-Nonce: $(openssl rand -hex 16)" \ -H "X-Signature: " # 3. Purge curl -X POST http://server:8080/purge/abc-123 \ -H "Content-Type: application/json" \ -H "X-Client-Id: your_client_id" \ -H "X-Timestamp: $(date +%s)" \ -H "X-Nonce: $(openssl rand -hex 16)" \ -H "X-Signature: " \ -d '{}' ``` --- ## Коды ошибок | Код | Описание | Решение | |-----|----------|---------| | `400` | Нет входного изображения | Передайте `image_base64` | | `401` | Invalid client ID | Проверьте `client_id` в `keys.json` | | `401` | Invalid timestamp | Синхронизируйте время на клиенте и сервере | | `401` | Nonce already used | Replay-атака или дублирующий запрос | | `401` | Invalid signature | Проверьте `secret_key` и алгоритм подписи | | `404` | Job not found | Job ID не существует или уже удалён | | `500` | Internal server error | Проверьте логи сервера (`journalctl -u dasiwa-api`) | --- ## Best Practices ### 1. Polling интервал - **Рекомендуется:** 5-10 секунд - **Не рекомендуется:** < 2 секунд (нагрузка на сервер) - Генерация обычно занимает 30-60 секунд ### 2. Timeout - Установите timeout на polling: 30 минут (1800 секунд) - Если задача не завершилась за это время — проверьте логи сервера ### 3. Purge после использования - Всегда вызывайте `/purge/` после получения видео - Base64 видео занимает ~10-50 MB RAM на сервере - Без purge память будет расти ### 4. Обработка ошибок ```python try: result = wait_for_completion(server, job_id, ...) except RuntimeError as e: if "Timeout" in str(e): # Задача зависла — проверьте сервер pass elif "Job failed" in str(e): # Ошибка генерации — проверьте параметры pass ``` ### 5. Retry логика - При `401` ошибках — не retry (проблема с ключами) - При `500` ошибках — retry с exponential backoff - При `404` на `/status` — задача потеряна, не retry ### 6. Размер изображений - Оптимально: 528x768 или 768x528 - Большие размеры → больше VRAM → медленнее - Маленькие размеры → хуже качество ### 7. Seed для воспроизводимости - Если нужен тот же результат — используйте тот же seed - Seed из ответа `output.seed` — сохраните для повтора ### 8. Мониторинг очереди ```python response = requests.get('http://server:8080/health') queue_size = response.json()['queue'] if queue_size > 5: print("Очередь большая, ожидайте дольше") ``` --- ## Лимиты и производительность ### Текущие лимиты - **Одновременные задачи:** 1 (1 GPU = 1 задача) - **Размер очереди:** не ограничен (но рекомендуется < 10) - **Размер изображения:** max 2048x2048 (теоретически) - **Длина видео:** max ~300 кадров (ограничено VRAM) ### Производительность | Параметры | Время генерации | VRAM | |-----------|-----------------|------| | 528x768, 81 frames, 4 steps | ~30-45s | ~18 GB | | 768x528, 81 frames, 4 steps | ~30-45s | ~18 GB | | 528x768, 161 frames, 4 steps | ~60-90s | ~24 GB | *Время указано для RTX 4090 / A100* --- ## Troubleshooting ### Задача зависла в IN_PROGRESS 1. Проверьте логи сервера: `journalctl -u dasiwa-api -f` 2. Проверьте ComfyUI: `curl http://localhost:8188` 3. Перезапустите сервис: `systemctl restart dasiwa-api` ### Ошибка "Video generation failed" - ComfyUI не запущен или недоступен - Недостаточно VRAM - Workflow файл повреждён ### Медленная генерация - Проверьте загрузку GPU: `nvidia-smi` - Убедитесь что модели загружены в VRAM (первый запрос медленнее) - Уменьшите `length` или размеры --- ## Changelog ### v2.0 (2026-03-07) - ✨ Асинхронный API (submit + poll) - ✨ Endpoints: `/run`, `/status`, `/purge` - ✨ Background worker thread - ✨ Queue management - 🔧 Обновлён на DaSiWa WAN 2.2 Lightspeed - 🔧 Упрощён workflow (14 нод вместо 50+) ### v1.0 (2026-03-06) - 🎉 Первый релиз - ✅ Синхронный `/generate` endpoint - ✅ HMAC аутентификация - ✅ I2V и FLF2V режимы