# Модели Два источника на data volume, они **складываются**, не заменяют друг друга: 1. **Civitai-seed** (ниже) — на пустой диск при bootstrap, если есть API-токен и манифест. 2. **Папка `Models/` в корне gpu-rent** — на каждом `up` выгрузить только изменившееся. `Wildcards/` и `CustomWorkflows/` — то же, см. [local-folders.md](local-folders.md). ## Быстрый старт моделей ```powershell copy models.example.yaml models.yaml # правь URL с modelVersionId=… # в .env: CIVITAI_API_TOKEN=… .\gpu-rent.ps1 up --yes ``` Или положи веса в `Models/Stable-Diffusion/` (и т.п.) — уедут на `up` / `gpu-rent push-models`. ### Capture с VM (ссылки only) Если на облачном диске уже есть модели (seed, UI Civitai, ручная заливка) — записать их обратно в локальный манифест **без скачивания весов**: ```powershell .\gpu-rent.ps1 capture models # merge Civitai url → models.yaml .\gpu-rent.ps1 capture models --kind lora .\gpu-rent.ps1 capture --dry-run # models + extensions, без записи .\gpu-rent.ps1 capture all ``` Берёт `{stem}.civitai.json` или SHA256 → Civitai `by-hash`. Дубли `modelVersionId` не дублируются. Перед записью — `models.yaml.bak`. Неизвестные файлы (нет в Civitai) — только в отчёте. Локальный SwarmUI на `7801` не зеркалируем. Только дерево `./Models` приложения. ## Локальная папка → сервер Каталог: `<корень приложения>/Models/` (или `LOCAL_MODELS_DIR`). Раскладка как у SwarmUI: `Stable-Diffusion/`, `Lora/`, `VAE/`, … Описание: [`Models/README.md`](../Models/README.md). Веса в git не коммитятся. Правило одно: | Локально | На `up` | | --- | --- | | Папки нет, или только `.gitkeep` / README | **Ничего не выгружаем**, тихий лог | | Появился файл весов (`.safetensors` / `.ckpt` / …) | Залить его **вместе с соседней метадатой** | | Веса уже на VM с тем же SHA256 | Пропуск (нет «обновления») | | Веса изменились | Залить веса заново и актуальную метадату | Метадата — файлы рядом с тем же stem: `.json`, `.civitai.json`, `.swarm.json`, превью (`.preview.png` / `.png` / `.webp`), если лежат в той же папке. Веса без sidecar тоже можно залить (предупреждение в лог: «метадаты нет»). Метадату без весов **не** шлём отдельно. С диска в облаке **ничего не удаляем**. Civitai-seed и то, чего нет в `./Models`, остаётся. Технически: SHA256 локального файла vs тот же относительный путь под `/mnt/swarm_data/Models/`. SFTP/paramiko, resume `.partial`. Preflight свободного места. Если залили и SwarmUI уже жив — refresh списка моделей. Повторный `up` при живой VM тоже смотрит папку (положил новую LoRA дома → следующий `up` её увезёт). Явно: `gpu-rent push-models` или `gpu-rent push` (все локальные деревья). Пока идёт аплоад, idle-killer на паузе. --- # Civitai: первый seed Срабатывает **один раз**: пустой data-диск + первый инстанс. Повторный `up` к уже засеянному диску строки манифеста с совпавшим SHA256 пропускает. ## Две ветки | Условие | Что происходит | | --- | --- | | В `.env` есть `CIVITAI_API_TOKEN` **и** в манифесте есть хотя бы одна запись | Скачать перечисленные модели с Civitai **на VM** (не через ноут). Рядом положить метаданные. **Не** качать дефолтный чекпоинт установщика SwarmUI | | Токена нет, или манифест пуст/отсутствует | Обычный первый запуск SwarmUI: пусть ставит свою стандартную модель. В лог — почему Civitai-seed пропущен | Токен без манифеста = предупреждение и ветка SwarmUI default, не «пустой диск без моделей». ComfyUI в `dlbackend` качается всегда. Речь только о **модели весов** установщика SwarmUI, не о backend. ## Когда в жизненном цикле Пока idle-killer ещё **не вооружён**: 1. Создать/примонтировать data volume, маркер FS. 2. Clone расширений из `extensions.yaml` ([extensions.md](extensions.md)). 3. Autocomplete word-list ([autocomplete.md](autocomplete.md)): скачать, если нет; иначе проверить GitHub sha. 4. Если ветка Civitai: залить на VM манифест (scp, не cloud-init — токен не должен светиться в Nova user_data). 5. Скачать файлы в `/mnt/swarm_data/Models/…`, проверить SHA256, записать sidecar. 6. Маркер `/mnt/swarm_data/.gpu-rent-models-seeded`. 7. **Push** из корневой `Models/` приложения (новые/изменённые, см. выше). 8. Первый старт SwarmUI (папки чекпоинтов уже не пустые → установщик не предлагает свой SD; Extensions и Autocompletions уже на месте). 9. Ждать backend Idle, затем вооружить idle-killer. Качание нескольких GB легко длиннее льготы 45 минут. Поэтому killer не живёт, пока не закончился seed. Позже тот же код: `gpu-rent seed-models` — докачать новые строки манифеста на уже живой диск (идемпотентно). ## Манифест Пример в репозитории: [`models.example.yaml`](../models.example.yaml). Рабочая копия: `models.yaml` в корне репо (или путь `MODELS_MANIFEST`). Идентификатор — **Civitai model version id**, не имя файла и не «последняя версия модели» (она плывёт). ```yaml # models.yaml — пример: Krea 2 + LoRA (см. models.example.yaml) checkpoint: - url: https://civitai.red/models/2786499/realism-by-stable-yogi-krea2?modelVersionId=3231611 lora: - url: https://civitai.red/models/2268008/realistic-snapshot-z-image-turbo-krea-2?modelVersionId=3084537 - url: https://civitai.red/models/2187487/cutifyier?modelVersionId=3107521 - url: https://civitai.red/models/1134895/2000s-analog-core?modelVersionId=3103914 ``` Допустимо вместо `url` поле `version_id` (число из `modelVersionId=`). Хосты `civitai.com`, `civitai.red`, `civitai.green` равнозначны (зелёный редиректит на `.com`). Несколько файлов у версии: берём `files[]` с `"primary": true`, иначе SafeTensor / fp16. Типы манифеста → каталоги SwarmUI (`ModelRoot` = `Models`): | Ключ yaml | Civitai `model.type` (ориентир) | Каталог на диске | | --- | --- | --- | | `checkpoint` | Checkpoint | `Models/Stable-Diffusion` | | `lora` | LORA, LoCon, DoRA | `Models/Lora` | | `vae` | VAE | `Models/VAE` | | `embedding` | TextualInversion | `Models/Embeddings` | | `controlnet` | Controlnet | `Models/controlnet` | | `upscaler` | Upscaler | `Models/upscale_models` | | `clip` | — | `Models/clip` | Тип в yaml задаёт **куда класть**, даже если Civitai назвал иначе. Если API-тип совсем другой — предупреждение, кладём по yaml. В git не коммитить рабочий манифест с личными чекпоинтами. В `models.example.yaml` — стартовый набор Krea 2 (чекпоинт + три LoRA); скопируй и дополни под себя. ## Civitai API (.com / .red) С апреля 2026 у Civitai два входа в **одну** базу ([анонс](https://civitai.com/articles/28369/two-front-doors-civitaicom-civitaired-and-whats-next)): | Домен | Что видно | | --- | --- | | `civitai.com` | SFW / PG (бывший green). NSFW-карточки с этого хоста часто **не находятся** (404) или без `files[]` | | `civitai.red` | Полный каталог, включая NSFW | | `civitai.green` | 301 на `.com` | REST не раздвоился: те же `/api/v1/...` на обоих хостах, один аккаунт, один API-токен. Официальная дока по-прежнему пишет base `https://civitai.com/api/v1/`, но там же: ответы с «зелёного» домена и из части регионов **молча режутся до SFW**. Нам нужны **любые** `version_id` из манифеста → **дефолтный API-хост `civitai.red`**. Клиент: 1. Доверять только `civitai.com`, `civitai.red` и их поддоменам. Токен на чужой хост (CDN после редиректа) **не** отправлять. 2. URL из yaml нормализовать: вытащить `modelVersionId` / `/models/{id}?modelVersionId=` с любого из трёх доменов. 3. Метаданные: `GET https://{CIVITAI_API_HOST}/api/v1/model-versions/{id}` с `Authorization: Bearer`. 4. Если 404, пустой `files[]` или нет `downloadUrl` — **один** повтор на второй хост (`.red` ↔ `.com`). Не крутить бесконечно. 5. Качать: `GET https://{хост_успешного_GET}/api/download/models/{id}` с Bearer, следовать редиректам на presigned S3. Имя — `Content-Disposition`. `downloadUrl` в JSON часто указывает на `.com` — для NSFW его переписать на хост, который отдал файлы. 6. Поле `nsfwLevel` / `model.nsfw` в sidecar сохранить как есть, фильтром не пользоваться. Без токена скачивание часто 401 даже на публичные веса. `requireAuth: true` в mini-endpoint — токен обязателен. После ответа version: 1. Primary file, `hashes.SHA256`, `sizeKB`. 2. Preflight места: сумма `sizeKB` × 1.2 < свободно на data volume. 3. Качать на VM. Прогресс в логах. 4. Сверить SHA256. Несовпадение — удалить файл, fail строки. Рядом с весами: | Файл | Содержимое | | --- | --- | | `{name}.safetensors` | веса | | `{name}.civitai.json` | сырой JSON version (+ при желании `GET /models/{modelId}` для автора/тегов) | | `{name}.swarm.json` | маппинг под SwarmUI: `name`, `title`, `description`, `trigger_phrase` из `trainedWords`, `author`, `license`, `tags` | Превью-картинки в base64 не обязательны в v1 (раздувают json). SwarmUI подтянет превью сам, если умеет по civitai id. Не класть API-токен в sidecar и не в Output. ## Пропуск дефолта SwarmUI Когда seed успешен (есть хотя бы один checkpoint **или** пользователь явно согласен на «только LoRA»): - первый старт SwarmUI — **после** появления файлов в `Models/`; - на spike проверить: установщик не качает Z-Image / SDXL Base, если `Stable-Diffusion` не пуст; - если всё же качает — выключить автозагрузку настройкой/LaunchArg (имя ключа зафиксировать на spike, не выдумывать сейчас). Если в манифесте нет ни одного `checkpoint` — предупреждение «без базовой модели генерация может не стартовать», не жёсткий fail. ## Сбой - 401 → «токен неверный или скачивание требует логина». - 404 на обоих хостах → версии нет / снята / не published. - Early access / 403 → строка fail, остальные можно продолжить; маркер seeded не ставить. - Обрыв сети — resume по `.partial` + повтор SHA256. ## Конфиг ```env CIVITAI_API_TOKEN= CIVITAI_API_HOST=civitai.red # полный каталог; civitai.com = только SFW MODELS_MANIFEST= # пусто = /models.yaml LOCAL_MODELS_DIR= # пусто = <корень приложения>/Models ```