Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed9a7b4b11 | ||
|
|
32a73b02f5 | ||
|
|
7d79e626a5 | ||
|
|
d756ea1d0e | ||
|
|
79bbf669e2 | ||
|
|
5e4348ebc1 | ||
|
|
1b8a798c31 | ||
|
|
d95b81dde5 | ||
|
|
ec08eb5d31 | ||
|
|
2c1c3a7ed7 | ||
|
|
ee36caccd6 | ||
|
|
e226548471 | ||
|
|
b9196ef5f5 | ||
|
|
a38915b354 | ||
|
|
da55b0889b | ||
|
|
9b143e65b1 | ||
|
|
27d2a70867 | ||
|
|
3c828a170f | ||
|
|
ae7ba961c1 | ||
|
|
0b8802deb5 | ||
| 0d7d4d404f | |||
|
|
615c400024 | ||
| bb65486995 | |||
|
|
8487b177b4 | ||
| 116941673e | |||
|
|
467c90594c | ||
| a4a21051a5 | |||
|
|
c0e6cff7b7 | ||
| 369c92e3ea | |||
|
|
5aede18ad5 |
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
venv/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
instance/
|
||||||
|
flask_session/
|
||||||
|
static/uploads/
|
||||||
|
tools/
|
||||||
|
.git/
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -31,3 +31,6 @@ Thumbs.db
|
|||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
# Tools (cloned at runtime — not tracked in this repo)
|
||||||
|
tools/
|
||||||
|
|||||||
219
API_GUIDE.md
Normal file
219
API_GUIDE.md
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
# GAZE REST API Guide
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Open **Settings** in the GAZE web UI
|
||||||
|
2. Scroll to **REST API Key** and click **Regenerate**
|
||||||
|
3. Copy the key — you'll need it for all API requests
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Every request must include your API key via one of:
|
||||||
|
|
||||||
|
- **Header (recommended):** `X-API-Key: <your-key>`
|
||||||
|
- **Query parameter:** `?api_key=<your-key>`
|
||||||
|
|
||||||
|
Responses for auth failures:
|
||||||
|
|
||||||
|
| Status | Meaning |
|
||||||
|
|--------|---------|
|
||||||
|
| `401` | Missing API key |
|
||||||
|
| `403` | Invalid API key |
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### List Presets
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/presets
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns all available presets.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
{
|
||||||
|
"preset_id": "example_01",
|
||||||
|
"slug": "example_01",
|
||||||
|
"name": "Example Preset",
|
||||||
|
"has_cover": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Image
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/v1/generate/<preset_slug>
|
||||||
|
```
|
||||||
|
|
||||||
|
Queue one or more image generations using a preset's configuration. All body parameters are optional — when omitted, the preset's own settings are used.
|
||||||
|
|
||||||
|
**Request body (JSON):**
|
||||||
|
|
||||||
|
| Field | Type | Default | Description |
|
||||||
|
|-------|------|---------|-------------|
|
||||||
|
| `count` | int | `1` | Number of images to generate (1–20) |
|
||||||
|
| `checkpoint` | string | — | Override checkpoint path (e.g. `"Illustrious/model.safetensors"`) |
|
||||||
|
| `extra_positive` | string | `""` | Additional positive prompt tags appended to the generated prompt |
|
||||||
|
| `extra_negative` | string | `""` | Additional negative prompt tags |
|
||||||
|
| `seed` | int | random | Fixed seed for reproducible generation |
|
||||||
|
| `width` | int | — | Output width in pixels (must provide both width and height) |
|
||||||
|
| `height` | int | — | Output height in pixels (must provide both width and height) |
|
||||||
|
|
||||||
|
**Response (202):**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"jobs": [
|
||||||
|
{ "job_id": "783f0268-ba85-4426-8ca2-6393c844c887", "status": "queued" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
|
||||||
|
| Status | Cause |
|
||||||
|
|--------|-------|
|
||||||
|
| `400` | Invalid parameters (bad count, seed, or mismatched width/height) |
|
||||||
|
| `404` | Preset slug not found |
|
||||||
|
| `500` | Internal generation error |
|
||||||
|
|
||||||
|
### Check Job Status
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/job/<job_id>
|
||||||
|
```
|
||||||
|
|
||||||
|
Poll this endpoint to track generation progress.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "783f0268-ba85-4426-8ca2-6393c844c887",
|
||||||
|
"label": "Preset: Example Preset – preview",
|
||||||
|
"status": "done",
|
||||||
|
"error": null,
|
||||||
|
"result": {
|
||||||
|
"image_url": "/static/uploads/presets/example_01/gen_1773601346.png",
|
||||||
|
"relative_path": "presets/example_01/gen_1773601346.png",
|
||||||
|
"seed": 927640517599332
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Job statuses:**
|
||||||
|
|
||||||
|
| Status | Meaning |
|
||||||
|
|--------|---------|
|
||||||
|
| `pending` | Waiting in queue |
|
||||||
|
| `processing` | Currently generating |
|
||||||
|
| `done` | Complete — `result` contains image info |
|
||||||
|
| `failed` | Error occurred — check `error` field |
|
||||||
|
|
||||||
|
The `result` object is only present when status is `done`. Use `seed` from the result to reproduce the exact same image later.
|
||||||
|
|
||||||
|
**Retrieving the image:** The `image_url` is a path relative to the server root. Fetch it directly:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET http://<host>:5782/static/uploads/presets/example_01/gen_1773601346.png
|
||||||
|
```
|
||||||
|
|
||||||
|
Image retrieval does not require authentication.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Generate a single image and wait for it
|
||||||
|
|
||||||
|
```bash
|
||||||
|
API_KEY="your-key-here"
|
||||||
|
HOST="http://localhost:5782"
|
||||||
|
|
||||||
|
# Queue generation
|
||||||
|
JOB_ID=$(curl -s -X POST \
|
||||||
|
-H "X-API-Key: $API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{}' \
|
||||||
|
"$HOST/api/v1/generate/example_01" | python3 -c "import sys,json; print(json.load(sys.stdin)['jobs'][0]['job_id'])")
|
||||||
|
|
||||||
|
echo "Job: $JOB_ID"
|
||||||
|
|
||||||
|
# Poll until done
|
||||||
|
while true; do
|
||||||
|
RESULT=$(curl -s -H "X-API-Key: $API_KEY" "$HOST/api/v1/job/$JOB_ID")
|
||||||
|
STATUS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
|
||||||
|
echo "Status: $STATUS"
|
||||||
|
if [ "$STATUS" = "done" ] || [ "$STATUS" = "failed" ]; then
|
||||||
|
echo "$RESULT" | python3 -m json.tool
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate 3 images with extra prompts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST \
|
||||||
|
-H "X-API-Key: $API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"count": 3,
|
||||||
|
"extra_positive": "smiling, outdoors",
|
||||||
|
"extra_negative": "blurry"
|
||||||
|
}' \
|
||||||
|
"$HOST/api/v1/generate/example_01"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reproduce a specific image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST \
|
||||||
|
-H "X-API-Key: $API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"seed": 927640517599332}' \
|
||||||
|
"$HOST/api/v1/generate/example_01"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Python example
|
||||||
|
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
HOST = "http://localhost:5782"
|
||||||
|
API_KEY = "your-key-here"
|
||||||
|
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
|
||||||
|
|
||||||
|
# List presets
|
||||||
|
presets = requests.get(f"{HOST}/api/v1/presets", headers=HEADERS).json()
|
||||||
|
print(f"Available presets: {[p['name'] for p in presets['presets']]}")
|
||||||
|
|
||||||
|
# Generate
|
||||||
|
resp = requests.post(
|
||||||
|
f"{HOST}/api/v1/generate/{presets['presets'][0]['slug']}",
|
||||||
|
headers=HEADERS,
|
||||||
|
json={"count": 1},
|
||||||
|
).json()
|
||||||
|
|
||||||
|
job_id = resp["jobs"][0]["job_id"]
|
||||||
|
print(f"Queued job: {job_id}")
|
||||||
|
|
||||||
|
# Poll
|
||||||
|
while True:
|
||||||
|
status = requests.get(f"{HOST}/api/v1/job/{job_id}", headers=HEADERS).json()
|
||||||
|
print(f"Status: {status['status']}")
|
||||||
|
if status["status"] in ("done", "failed"):
|
||||||
|
break
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
if status["status"] == "done":
|
||||||
|
image_url = f"{HOST}{status['result']['image_url']}"
|
||||||
|
print(f"Image: {image_url}")
|
||||||
|
print(f"Seed: {status['result']['seed']}")
|
||||||
|
```
|
||||||
598
CLAUDE.md
Normal file
598
CLAUDE.md
Normal file
@@ -0,0 +1,598 @@
|
|||||||
|
# GAZE — Character Browser: LLM Development Guide
|
||||||
|
|
||||||
|
## What This Project Is
|
||||||
|
|
||||||
|
GAZE is a Flask web app for managing AI image generation assets and generating images via ComfyUI. It is a **personal creative tool** for organizing characters, outfits, actions, styles, scenes, and detailers — all of which map to Stable Diffusion LoRAs and prompt fragments — and generating images by wiring those assets into a ComfyUI workflow at runtime.
|
||||||
|
|
||||||
|
The app is deployed locally, connects to a local ComfyUI instance at `http://127.0.0.1:8188`, and uses SQLite for persistence. LoRA and model files live on `/mnt/alexander/AITools/Image Models/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
app.py # ~186 lines: Flask init, config, logging, route registration, startup/migrations
|
||||||
|
models.py # SQLAlchemy models only
|
||||||
|
comfy_workflow.json # ComfyUI workflow template with placeholder strings
|
||||||
|
utils.py # Pure constants + helpers (no Flask/DB deps)
|
||||||
|
services/
|
||||||
|
__init__.py
|
||||||
|
comfyui.py # ComfyUI HTTP client (queue_prompt, get_history, get_image)
|
||||||
|
workflow.py # Workflow building (_prepare_workflow, _apply_checkpoint_settings)
|
||||||
|
prompts.py # Prompt building + dedup (build_prompt, build_extras_prompt)
|
||||||
|
llm.py # LLM integration + MCP tool calls (call_llm, load_prompt)
|
||||||
|
mcp.py # MCP/Docker server lifecycle (ensure_mcp_server_running)
|
||||||
|
sync.py # All sync_*() functions + preset resolution helpers
|
||||||
|
job_queue.py # Background job queue (_enqueue_job, _make_finalize, worker thread)
|
||||||
|
file_io.py # LoRA/checkpoint scanning, file helpers
|
||||||
|
generation.py # Shared generation logic (generate_from_preset)
|
||||||
|
routes/
|
||||||
|
__init__.py # register_routes(app) — imports and calls all route modules
|
||||||
|
characters.py # Character CRUD + generation + outfit management
|
||||||
|
outfits.py # Outfit routes
|
||||||
|
actions.py # Action routes
|
||||||
|
styles.py # Style routes
|
||||||
|
scenes.py # Scene routes
|
||||||
|
detailers.py # Detailer routes
|
||||||
|
checkpoints.py # Checkpoint routes
|
||||||
|
looks.py # Look routes
|
||||||
|
presets.py # Preset routes
|
||||||
|
generator.py # Generator mix-and-match page
|
||||||
|
gallery.py # Gallery browsing + image/resource deletion
|
||||||
|
settings.py # Settings page + status APIs + context processors
|
||||||
|
strengths.py # Strengths gallery system
|
||||||
|
transfer.py # Resource transfer system
|
||||||
|
queue_api.py # /api/queue/* endpoints
|
||||||
|
api.py # REST API v1 (preset generation, auth)
|
||||||
|
regenerate.py # Tag regeneration (single + bulk, via LLM queue)
|
||||||
|
search.py # Global search across resources and gallery images
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependency Graph
|
||||||
|
|
||||||
|
```
|
||||||
|
app.py
|
||||||
|
├── models.py (unchanged)
|
||||||
|
├── utils.py (no deps except stdlib)
|
||||||
|
├── services/
|
||||||
|
│ ├── comfyui.py ← utils (for config)
|
||||||
|
│ ├── prompts.py ← utils, models
|
||||||
|
│ ├── workflow.py ← prompts, utils, models
|
||||||
|
│ ├── llm.py ← mcp (for tool calls)
|
||||||
|
│ ├── mcp.py ← (stdlib only: subprocess, os)
|
||||||
|
│ ├── sync.py ← models, utils
|
||||||
|
│ ├── job_queue.py ← comfyui, models
|
||||||
|
│ ├── file_io.py ← models, utils
|
||||||
|
│ └── generation.py ← prompts, workflow, job_queue, sync, models
|
||||||
|
└── routes/
|
||||||
|
├── All route modules ← services/*, utils, models
|
||||||
|
└── (routes never import from other routes)
|
||||||
|
```
|
||||||
|
|
||||||
|
**No circular imports**: routes → services → utils/models. Services never import routes. Utils never imports services.
|
||||||
|
|
||||||
|
### Route Registration Pattern
|
||||||
|
|
||||||
|
Routes use a `register_routes(app)` closure pattern — each route module defines a function that receives the Flask `app` object and registers routes via `@app.route()` closures. This preserves all existing `url_for()` endpoint names without requiring Blueprint prefixes. Helper functions used only by routes in that module are defined inside `register_routes()` before the routes that reference them.
|
||||||
|
|
||||||
|
### Database
|
||||||
|
SQLite at `instance/database.db`, managed by Flask-SQLAlchemy. The DB is a cache of the JSON files on disk — the JSON files are the source of truth.
|
||||||
|
|
||||||
|
**Models**: `Character`, `Look`, `Outfit`, `Action`, `Style`, `Scene`, `Detailer`, `Checkpoint`, `Settings`
|
||||||
|
|
||||||
|
The `Settings` model stores LLM provider config, LoRA/checkpoint directory paths, default checkpoint, and `api_key` for REST API authentication.
|
||||||
|
|
||||||
|
All category models (except Settings and Checkpoint) share this pattern:
|
||||||
|
- `{entity}_id` — canonical ID (from JSON, often matches filename without extension)
|
||||||
|
- `slug` — URL-safe version of the ID (alphanumeric + underscores only, via `re.sub(r'[^a-zA-Z0-9_]', '', id)`)
|
||||||
|
- `name` — display name
|
||||||
|
- `filename` — original JSON filename
|
||||||
|
- `data` — full JSON blob (SQLAlchemy JSON column)
|
||||||
|
- `default_fields` — list of `section::key` strings saved as the user's preferred prompt fields
|
||||||
|
- `image_path` — relative path under `static/uploads/`
|
||||||
|
- `is_favourite` — boolean (DB-only, not in JSON; toggled from detail pages)
|
||||||
|
- `is_nsfw` — boolean (mirrored in both DB column and JSON `tags.nsfw`; synced on rescan)
|
||||||
|
|
||||||
|
### Data Flow: JSON → DB → Prompt → ComfyUI
|
||||||
|
|
||||||
|
1. **JSON files** in `data/{characters,clothing,actions,styles,scenes,detailers,looks}/` are loaded by `sync_*()` functions into SQLite.
|
||||||
|
2. At generation time, `build_prompt(data, selected_fields, default_fields, active_outfit)` converts the character JSON blob into `{"main": ..., "face": ..., "hand": ...}` prompt strings.
|
||||||
|
3. `_prepare_workflow(workflow, character, prompts, ...)` wires prompts and LoRAs into the loaded `comfy_workflow.json`.
|
||||||
|
4. `queue_prompt(workflow, client_id)` POSTs the workflow to ComfyUI's `/prompt` endpoint.
|
||||||
|
5. The app polls `get_history(prompt_id)` and retrieves the image via `get_image(filename, subfolder, type)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ComfyUI Workflow Node Map
|
||||||
|
|
||||||
|
The workflow (`comfy_workflow.json`) uses string node IDs. These are the critical nodes:
|
||||||
|
|
||||||
|
| Node | Role |
|
||||||
|
|------|------|
|
||||||
|
| `3` | Main KSampler |
|
||||||
|
| `4` | Checkpoint loader |
|
||||||
|
| `5` | Empty latent (width/height) |
|
||||||
|
| `6` | Positive prompt — contains `{{POSITIVE_PROMPT}}` placeholder |
|
||||||
|
| `7` | Negative prompt |
|
||||||
|
| `8` | VAE decode |
|
||||||
|
| `9` | Save image |
|
||||||
|
| `11` | Face ADetailer |
|
||||||
|
| `13` | Hand ADetailer |
|
||||||
|
| `14` | Face detailer prompt — contains `{{FACE_PROMPT}}` placeholder |
|
||||||
|
| `15` | Hand detailer prompt — contains `{{HAND_PROMPT}}` placeholder |
|
||||||
|
| `16` | Character LoRA (or Look LoRA when a Look is active) |
|
||||||
|
| `17` | Outfit LoRA |
|
||||||
|
| `18` | Action LoRA |
|
||||||
|
| `19` | Style / Detailer / Scene LoRA (priority: style > detailer > scene) |
|
||||||
|
|
||||||
|
LoRA nodes chain: `4 → 16 → 17 → 18 → 19`. Unused LoRA nodes are bypassed by pointing `model_source`/`clip_source` directly to the prior node. All model/clip consumers (nodes 3, 6, 7, 11, 13, 14, 15) are wired to the final `model_source`/`clip_source` at the end of `_prepare_workflow`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Functions by Module
|
||||||
|
|
||||||
|
### `utils.py` — Constants and Pure Helpers
|
||||||
|
|
||||||
|
- **`_IDENTITY_KEYS` / `_WARDROBE_KEYS`** — Lists of canonical field names for the `identity` and `wardrobe` sections. Used by `_ensure_character_fields()`.
|
||||||
|
- **`ALLOWED_EXTENSIONS`** — Permitted upload file extensions.
|
||||||
|
- **`_LORA_DEFAULTS`** — Default LoRA directory paths per category.
|
||||||
|
- **`parse_orientation(orientation_str)`** — Converts orientation codes (`1F`, `2F`, `1M1F`, etc.) into Danbooru tags.
|
||||||
|
- **`_resolve_lora_weight(lora_data)`** — Extracts and validates LoRA weight from a lora data dict.
|
||||||
|
- **`allowed_file(filename)`** — Checks file extension against `ALLOWED_EXTENSIONS`.
|
||||||
|
|
||||||
|
### `services/prompts.py` — Prompt Building
|
||||||
|
|
||||||
|
- **`build_prompt(data, selected_fields, default_fields, active_outfit)`** — Converts a character (or combined) data dict into `{"main", "face", "hand"}` prompt strings. Field selection priority: `selected_fields` → `default_fields` → select all (fallback). Fields are addressed as `"section::key"` strings (e.g. `"identity::hair"`, `"wardrobe::top"`). Characters support a **nested** wardrobe format where `wardrobe` is a dict of outfit names → outfit dicts.
|
||||||
|
- **`build_extras_prompt(actions, outfits, scenes, styles, detailers)`** — Used by the Generator page. Combines prompt text from all checked items across categories into a single string.
|
||||||
|
- **`_cross_dedup_prompts(positive, negative)`** — Cross-deduplicates tags between positive and negative prompt strings. Equal counts cancel completely; excess on one side is retained.
|
||||||
|
- **`_resolve_character(character_slug)`** — Returns a `Character` ORM object for a given slug string. Handles `"__random__"` sentinel.
|
||||||
|
- **`_ensure_character_fields(character, selected_fields, ...)`** — Mutates `selected_fields` in place, appending populated identity/wardrobe keys. Called in every secondary-category generate route after `_resolve_character()`.
|
||||||
|
- **`_append_background(prompts, character=None)`** — Appends `"<primary_color> simple background"` tag to `prompts['main']`.
|
||||||
|
|
||||||
|
### `services/workflow.py` — Workflow Wiring
|
||||||
|
|
||||||
|
- **`_prepare_workflow(workflow, character, prompts, ...)`** — Core workflow wiring function. Replaces prompt placeholders, chains LoRA nodes dynamically, randomises seeds, applies checkpoint settings, runs cross-dedup as the final step.
|
||||||
|
- **`_apply_checkpoint_settings(workflow, ckpt_data)`** — Applies checkpoint-specific sampler/prompt/VAE settings.
|
||||||
|
- **`_get_default_checkpoint()`** — Returns `(checkpoint_path, checkpoint_data)` from session, database Settings, or workflow file fallback.
|
||||||
|
- **`_log_workflow_prompts(label, workflow)`** — Logs the fully assembled workflow prompts in a readable block.
|
||||||
|
|
||||||
|
### `services/job_queue.py` — Background Job Queue
|
||||||
|
|
||||||
|
Two independent queues with separate worker threads:
|
||||||
|
|
||||||
|
- **ComfyUI queue** (`_job_queue` + `_queue_worker`): Image generation jobs.
|
||||||
|
- **`_enqueue_job(label, workflow, finalize_fn)`** — Adds a generation job to the queue.
|
||||||
|
- **`_make_finalize(category, slug, db_model_class=None, action=None)`** — Factory returning a callback that retrieves the generated image from ComfyUI, saves it, and optionally updates the DB cover image.
|
||||||
|
- **LLM queue** (`_llm_queue` + `_llm_queue_worker`): LLM task jobs (tag regeneration, bulk create with overwrite).
|
||||||
|
- **`_enqueue_task(label, task_fn)`** — Adds an LLM task job. `task_fn` receives the job dict and runs inside `app.app_context()`.
|
||||||
|
- **Shared**: Both queues share `_job_history` (for status lookup by job ID) and `_job_queue_lock`.
|
||||||
|
- **`_prune_job_history(max_age_seconds=3600)`** — Removes old terminal-state jobs from memory.
|
||||||
|
- **`init_queue_worker(flask_app)`** — Stores the app reference and starts both worker threads.
|
||||||
|
|
||||||
|
### `services/comfyui.py` — ComfyUI HTTP Client
|
||||||
|
|
||||||
|
- **`queue_prompt(prompt_workflow, client_id)`** — POSTs workflow to ComfyUI's `/prompt` endpoint.
|
||||||
|
- **`get_history(prompt_id)`** — Polls ComfyUI for job completion.
|
||||||
|
- **`get_image(filename, subfolder, folder_type)`** — Retrieves generated image bytes.
|
||||||
|
- **`_ensure_checkpoint_loaded(checkpoint_path)`** — Forces ComfyUI to load a specific checkpoint.
|
||||||
|
|
||||||
|
### `services/llm.py` — LLM Integration
|
||||||
|
|
||||||
|
- **`call_llm(prompt, system_prompt)`** — OpenAI-compatible chat completion supporting OpenRouter (cloud) and Ollama/LMStudio (local). Implements a tool-calling loop (up to 10 turns) using `DANBOORU_TOOLS` via MCP Docker container. Safe to call from background threads (uses `has_request_context()` fallback for OpenRouter HTTP-Referer header).
|
||||||
|
- **`load_prompt(filename)`** — Loads system prompt text from `data/prompts/`.
|
||||||
|
- **`call_mcp_tool()`** — Synchronous wrapper for MCP tool calls.
|
||||||
|
|
||||||
|
### `services/sync.py` — Data Synchronization
|
||||||
|
|
||||||
|
- **`sync_characters()`, `sync_outfits()`, `sync_actions()`, etc.** — Load JSON files from `data/` directories into SQLite. One function per category.
|
||||||
|
- **`_sync_nsfw_from_tags(entity, data)`** — Reads `data['tags']['nsfw']` and sets `entity.is_nsfw`. Called in every sync function on both create and update paths.
|
||||||
|
- **`_resolve_preset_entity(type, id)`** / **`_resolve_preset_fields(preset_data)`** — Preset resolution helpers.
|
||||||
|
|
||||||
|
### `services/file_io.py` — File & DB Helpers
|
||||||
|
|
||||||
|
- **`get_available_loras(category)`** — Scans filesystem for available LoRA files in a category.
|
||||||
|
- **`get_available_checkpoints()`** — Scans checkpoint directories.
|
||||||
|
- **`_count_look_assignments()`** / **`_count_outfit_lora_assignments()`** — DB aggregate queries.
|
||||||
|
|
||||||
|
### `services/generation.py` — Shared Generation Logic
|
||||||
|
|
||||||
|
- **`generate_from_preset(preset, overrides=None)`** — Core preset generation function used by both the web route and the REST API. Resolves entities, builds prompts, wires the workflow, and enqueues the job. The `overrides` dict accepts: `action`, `checkpoint`, `extra_positive`, `extra_negative`, `seed`, `width`, `height`. Has no `request` or `session` dependencies.
|
||||||
|
|
||||||
|
### `services/mcp.py` — MCP/Docker Lifecycle
|
||||||
|
|
||||||
|
- **`ensure_mcp_server_running()`** — Ensures the danbooru-mcp Docker container is running.
|
||||||
|
- **`ensure_character_mcp_server_running()`** — Ensures the character-mcp Docker container is running.
|
||||||
|
|
||||||
|
### Route-local Helpers
|
||||||
|
|
||||||
|
Some helpers are defined inside a route module's `register_routes()` since they're only used by routes in that file:
|
||||||
|
- `routes/scenes.py`: `_queue_scene_generation()` — scene-specific workflow builder
|
||||||
|
- `routes/detailers.py`: `_queue_detailer_generation()` — detailer-specific generation helper
|
||||||
|
- `routes/styles.py`: `_build_style_workflow()` — style-specific workflow builder
|
||||||
|
- `routes/checkpoints.py`: `_build_checkpoint_workflow()` — checkpoint-specific workflow builder
|
||||||
|
- `routes/strengths.py`: `_build_strengths_prompts()`, `_prepare_strengths_workflow()` — strengths gallery helpers
|
||||||
|
- `routes/transfer.py`: `_create_minimal_template()` — transfer template builder
|
||||||
|
- `routes/gallery.py`: `_scan_gallery_images()`, `_enrich_with_names()`, `_parse_comfy_png_metadata()`, `_write_sidecar()` — gallery image sidecar JSON I/O
|
||||||
|
- `routes/regenerate.py`: Tag regeneration routes (single + category bulk + all), tag migration
|
||||||
|
- `routes/search.py`: `_search_resources()`, `_search_images()` — global search across resources and gallery
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JSON Data Schemas
|
||||||
|
|
||||||
|
### Character (`data/characters/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"character_id": "tifa_lockhart",
|
||||||
|
"character_name": "Tifa Lockhart",
|
||||||
|
"identity": { "base_specs": "", "hair": "", "eyes": "", "hands": "", "arms": "", "torso": "", "pelvis": "", "legs": "", "feet": "", "extra": "" },
|
||||||
|
"defaults": { "expression": "", "pose": "", "scene": "" },
|
||||||
|
"wardrobe": {
|
||||||
|
"default": { "full_body": "", "headwear": "", "top": "", "bottom": "", "legwear": "", "footwear": "", "hands": "", "gloves": "", "accessories": "" }
|
||||||
|
},
|
||||||
|
"styles": { "aesthetic": "", "primary_color": "", "secondary_color": "", "tertiary_color": "" },
|
||||||
|
"lora": { "lora_name": "Illustrious/Looks/tifa.safetensors", "lora_weight": 0.8, "lora_triggers": "" },
|
||||||
|
"tags": { "origin_series": "Final Fantasy VII", "origin_type": "game", "nsfw": false },
|
||||||
|
"participants": { "orientation": "1F", "solo_focus": "true" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`participants` is optional; when absent, `(solo:1.2)` is injected. `orientation` is parsed by `parse_orientation()` into Danbooru tags (`1girl`, `hetero`, etc.).
|
||||||
|
|
||||||
|
### Outfit (`data/clothing/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"outfit_id": "french_maid_01",
|
||||||
|
"outfit_name": "French Maid",
|
||||||
|
"wardrobe": { "full_body": "", "headwear": "", "top": "", "bottom": "", "legwear": "", "footwear": "", "hands": "", "accessories": "" },
|
||||||
|
"lora": { "lora_name": "Illustrious/Clothing/maid.safetensors", "lora_weight": 0.8, "lora_triggers": "" },
|
||||||
|
"tags": { "outfit_type": "Uniform", "nsfw": false }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Action (`data/actions/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"action_id": "sitting",
|
||||||
|
"action_name": "Sitting",
|
||||||
|
"action": { "full_body": "", "additional": "", "head": "", "eyes": "", "arms": "", "hands": "" },
|
||||||
|
"lora": { "lora_name": "", "lora_weight": 1.0, "lora_triggers": "" },
|
||||||
|
"tags": { "participants": "1girl", "nsfw": false }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scene (`data/scenes/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scene_id": "beach",
|
||||||
|
"scene_name": "Beach",
|
||||||
|
"scene": { "background": "", "foreground": "", "furniture": "", "colors": "", "lighting": "", "theme": "" },
|
||||||
|
"lora": { "lora_name": "", "lora_weight": 1.0, "lora_triggers": "" },
|
||||||
|
"tags": { "scene_type": "Outdoor", "nsfw": false }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Style (`data/styles/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"style_id": "watercolor",
|
||||||
|
"style_name": "Watercolor",
|
||||||
|
"style": { "artist_name": "", "artistic_style": "" },
|
||||||
|
"lora": { "lora_name": "", "lora_weight": 1.0, "lora_triggers": "" },
|
||||||
|
"tags": { "style_type": "Watercolor", "nsfw": false }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Detailer (`data/detailers/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"detailer_id": "detailed_skin",
|
||||||
|
"detailer_name": "Detailed Skin",
|
||||||
|
"prompt": ["detailed skin", "pores"],
|
||||||
|
"focus": { "face": true, "hands": true },
|
||||||
|
"lora": { "lora_name": "", "lora_weight": 1.0, "lora_triggers": "" },
|
||||||
|
"tags": { "associated_resource": "skin", "adetailer_targets": ["face", "hands"], "nsfw": false }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Look (`data/looks/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"look_id": "tifa_casual",
|
||||||
|
"look_name": "Tifa Casual",
|
||||||
|
"character_id": "tifa_lockhart",
|
||||||
|
"positive": "casual clothes, jeans",
|
||||||
|
"negative": "revealing",
|
||||||
|
"lora": { "lora_name": "Illustrious/Looks/tifa_casual.safetensors", "lora_weight": 0.85, "lora_triggers": "" },
|
||||||
|
"tags": { "origin_series": "Final Fantasy VII", "origin_type": "game", "nsfw": false }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Looks occupy LoRA node 16, overriding the character's own LoRA. The Look's `negative` is prepended to the workflow's negative prompt.
|
||||||
|
|
||||||
|
### Checkpoint (`data/checkpoints/*.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"checkpoint_path": "Illustrious/model.safetensors",
|
||||||
|
"checkpoint_name": "Model Display Name",
|
||||||
|
"base_positive": "anime",
|
||||||
|
"base_negative": "text, logo",
|
||||||
|
"steps": 25,
|
||||||
|
"cfg": 5,
|
||||||
|
"sampler_name": "euler_ancestral",
|
||||||
|
"scheduler": "normal",
|
||||||
|
"vae": "integrated"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Checkpoint JSONs are keyed by `checkpoint_path`. If no JSON exists for a discovered model file, `_default_checkpoint_data()` provides defaults.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## URL Routes
|
||||||
|
|
||||||
|
### Characters
|
||||||
|
- `GET /` — character gallery (index)
|
||||||
|
- `GET /character/<slug>` — character detail with generation UI
|
||||||
|
- `POST /character/<slug>/generate` — queue generation (AJAX or form); returns `{"job_id": ...}`
|
||||||
|
- `POST /character/<slug>/replace_cover_from_preview` — promote preview to cover
|
||||||
|
- `GET/POST /character/<slug>/edit` — edit character data
|
||||||
|
- `POST /character/<slug>/upload` — upload cover image
|
||||||
|
- `POST /character/<slug>/save_defaults` — save default field selection
|
||||||
|
- `POST /character/<slug>/outfit/switch|add|delete|rename` — manage per-character wardrobe outfits
|
||||||
|
- `GET/POST /create` — create new character (blank or LLM-generated)
|
||||||
|
- `POST /rescan` — sync DB from JSON files
|
||||||
|
|
||||||
|
### Category Pattern (Outfits, Actions, Styles, Scenes, Detailers)
|
||||||
|
Each category follows the same URL pattern:
|
||||||
|
- `GET /<category>/` — library with favourite/NSFW filter controls
|
||||||
|
- `GET /<category>/<slug>` — detail + generation UI
|
||||||
|
- `POST /<category>/<slug>/generate` — queue generation; returns `{"job_id": ...}`
|
||||||
|
- `POST /<category>/<slug>/replace_cover_from_preview`
|
||||||
|
- `GET/POST /<category>/<slug>/edit`
|
||||||
|
- `POST /<category>/<slug>/upload`
|
||||||
|
- `POST /<category>/<slug>/save_defaults`
|
||||||
|
- `POST /<category>/<slug>/favourite` — toggle `is_favourite` (AJAX)
|
||||||
|
- `POST /<category>/<slug>/clone` — duplicate entry
|
||||||
|
- `POST /<category>/<slug>/save_json` — save raw JSON (from modal editor)
|
||||||
|
- `POST /<category>/rescan`
|
||||||
|
- `POST /<category>/bulk_create` — LLM-generate entries from LoRA files on disk
|
||||||
|
|
||||||
|
### Looks
|
||||||
|
- `GET /looks` — gallery
|
||||||
|
- `GET /look/<slug>` — detail
|
||||||
|
- `GET/POST /look/<slug>/edit`
|
||||||
|
- `POST /look/<slug>/generate` — queue generation; returns `{"job_id": ...}`
|
||||||
|
- `POST /look/<slug>/replace_cover_from_preview`
|
||||||
|
- `GET/POST /look/create`
|
||||||
|
- `POST /looks/rescan`
|
||||||
|
|
||||||
|
### Generator (Mix & Match)
|
||||||
|
- `GET/POST /generator` — freeform generator with multi-select accordion UI
|
||||||
|
- `POST /generator/preview_prompt` — AJAX: preview composed prompt without generating
|
||||||
|
|
||||||
|
### Checkpoints
|
||||||
|
- `GET /checkpoints` — gallery
|
||||||
|
- `GET /checkpoint/<slug>` — detail + generation settings editor
|
||||||
|
- `POST /checkpoint/<slug>/save_json`
|
||||||
|
- `POST /checkpoints/rescan`
|
||||||
|
|
||||||
|
### REST API (`/api/v1/`)
|
||||||
|
Authenticated via `X-API-Key` header (or `api_key` query param). Key is stored in `Settings.api_key` and managed from the Settings page.
|
||||||
|
- `GET /api/v1/presets` — list all presets (id, slug, name, has_cover)
|
||||||
|
- `POST /api/v1/generate/<preset_slug>` — queue generation from a preset; accepts JSON body with optional `checkpoint`, `extra_positive`, `extra_negative`, `seed`, `width`, `height`, `count` (1–20); returns `{"jobs": [{"job_id": ..., "status": "queued"}]}`
|
||||||
|
- `GET /api/v1/job/<job_id>` — poll job status; returns `{"id", "label", "status", "error", "result"}`
|
||||||
|
- `POST /api/key/regenerate` — generate a new API key (Settings page)
|
||||||
|
|
||||||
|
See `API_GUIDE.md` for full usage examples.
|
||||||
|
|
||||||
|
### Job Queue API
|
||||||
|
All generation routes use the background job queue. Frontend polls:
|
||||||
|
- `GET /api/queue/<job_id>/status` — returns `{"status": "pending"|"running"|"done"|"failed", "result": {...}}`
|
||||||
|
|
||||||
|
Image retrieval is handled server-side by the `_make_finalize()` callback; there are no separate client-facing finalize routes.
|
||||||
|
|
||||||
|
### Search
|
||||||
|
- `GET /search` — global search page; query params: `q` (search term), `category` (all/characters/outfits/etc.), `nsfw` (all/sfw/nsfw), `type` (all/resources/images)
|
||||||
|
|
||||||
|
### Tag Regeneration
|
||||||
|
- `POST /api/<category>/<slug>/regenerate_tags` — single entity tag regeneration via LLM queue
|
||||||
|
- `POST /admin/bulk_regenerate_tags/<category>` — queue LLM tag regeneration for all entities in a category
|
||||||
|
- `POST /admin/bulk_regenerate_tags` — queue LLM tag regeneration for all resources across all categories
|
||||||
|
- `POST /admin/migrate_tags` — convert old list-format tags to new dict format
|
||||||
|
|
||||||
|
### Gallery Image Metadata
|
||||||
|
- `POST /gallery/image/favourite` — toggle favourite on a gallery image (writes sidecar JSON)
|
||||||
|
- `POST /gallery/image/nsfw` — toggle NSFW on a gallery image (writes sidecar JSON)
|
||||||
|
|
||||||
|
### Utilities
|
||||||
|
- `POST /set_default_checkpoint` — save default checkpoint to session and persist to `comfy_workflow.json`
|
||||||
|
- `GET /get_missing_{characters,outfits,actions,scenes,styles,detailers,looks,checkpoints}` — AJAX: list items without cover images (sorted by display name)
|
||||||
|
- `POST /generate_missing` — batch generate covers for all characters missing one (uses job queue)
|
||||||
|
- `POST /clear_all_covers` / `clear_all_{outfit,action,scene,style,detailer,look,checkpoint}_covers`
|
||||||
|
- `GET /gallery` — global image gallery browsing `static/uploads/`
|
||||||
|
- `GET/POST /settings` — LLM provider configuration
|
||||||
|
- `POST /resource/<category>/<slug>/delete` — soft (JSON only) or hard (JSON + safetensors) delete
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
- Bootstrap 5.3 (CDN). Custom styles in `static/style.css`.
|
||||||
|
- All templates extend `templates/layout.html`. The base layout provides:
|
||||||
|
- `{% block content %}` — main page content
|
||||||
|
- `{% block scripts %}` — additional JS at end of body
|
||||||
|
- Navbar with links to all sections
|
||||||
|
- Global default checkpoint selector (saves to session via AJAX)
|
||||||
|
- Resource delete modal (soft/hard) shared across gallery pages
|
||||||
|
- `initJsonEditor(saveUrl)` — shared JSON editor modal (simple form + raw textarea tabs)
|
||||||
|
- Context processors inject `all_checkpoints`, `default_checkpoint_path`, and `COMFYUI_WS_URL` into every template. The `random_gen_image(category, slug)` template global returns a random image path from `static/uploads/<category>/<slug>/` for use as a fallback cover when `image_path` is not set.
|
||||||
|
- **No `{% block head %}` exists** in layout.html — do not try to use it.
|
||||||
|
- Generation is async: JS submits the form via AJAX (`X-Requested-With: XMLHttpRequest`), receives a `{"job_id": ...}` response, then polls `/api/queue/<job_id>/status` every ~1.5 seconds until `status == "done"`. The server-side worker handles all ComfyUI polling and image saving via the `_make_finalize()` callback. There are no client-facing finalize HTTP routes.
|
||||||
|
- **Batch generation** (library pages): Uses a two-phase pattern:
|
||||||
|
1. **Queue phase**: All jobs are submitted upfront via sequential fetch calls, collecting job IDs
|
||||||
|
2. **Poll phase**: All jobs are polled concurrently via `Promise.all()`, updating UI as each completes
|
||||||
|
3. **Progress tracking**: Displays currently processing items in real-time using a `Set` to track active jobs
|
||||||
|
4. **Sorting**: All batch operations sort items by display `name` (not `filename`) for better UX
|
||||||
|
- **Fallback covers** (library pages): When a resource has no assigned `image_path` but has generated images in its upload folder, a random image is shown at 50% opacity (CSS class `fallback-cover`). The image changes on each page load. Resources with no generations show "No Image".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LLM Integration
|
||||||
|
|
||||||
|
### System Prompts
|
||||||
|
Text files in `data/prompts/` define JSON output schemas for LLM-generated entries:
|
||||||
|
- `character_system.txt` — character JSON schema
|
||||||
|
- `outfit_system.txt` — outfit JSON schema
|
||||||
|
- `action_system.txt`, `scene_system.txt`, `style_system.txt`, `detailer_system.txt`, `look_system.txt`, `checkpoint_system.txt`
|
||||||
|
- `preset_system.txt` — preset JSON schema
|
||||||
|
- `regenerate_tags_system.txt` — tag regeneration schema (all per-category tag structures)
|
||||||
|
|
||||||
|
Used by: character/outfit/action/scene/style create forms, bulk_create routes, and tag regeneration. All system prompts include NSFW awareness preamble.
|
||||||
|
|
||||||
|
### Danbooru MCP Tools
|
||||||
|
The LLM loop in `call_llm()` provides three tools via a Docker-based MCP server (`danbooru-mcp:latest`):
|
||||||
|
- `search_tags(query, limit, category)` — prefix search
|
||||||
|
- `validate_tags(tags)` — exact-match validation
|
||||||
|
- `suggest_tags(partial, limit, category)` — autocomplete
|
||||||
|
|
||||||
|
The LLM uses these to verify and discover correct Danbooru-compatible tags for prompts.
|
||||||
|
|
||||||
|
All system prompts (`character_system.txt`, `outfit_system.txt`, `action_system.txt`, `scene_system.txt`, `style_system.txt`, `detailer_system.txt`, `look_system.txt`, `checkpoint_system.txt`) instruct the LLM to use these tools before finalising any tag values. `checkpoint_system.txt` applies them specifically to the `base_positive` and `base_negative` fields.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tagging System
|
||||||
|
|
||||||
|
Tags are **semantic metadata** for organizing and filtering resources. They are **not injected into generation prompts** — tags are purely for the UI (search, filtering, categorization).
|
||||||
|
|
||||||
|
### Tag Schema Per Category
|
||||||
|
|
||||||
|
| Category | Tag fields | Example |
|
||||||
|
|----------|-----------|---------|
|
||||||
|
| Character | `origin_series`, `origin_type`, `nsfw` | `{"origin_series": "Final Fantasy VII", "origin_type": "game", "nsfw": false}` |
|
||||||
|
| Look | `origin_series`, `origin_type`, `nsfw` | same as Character |
|
||||||
|
| Outfit | `outfit_type`, `nsfw` | `{"outfit_type": "Uniform", "nsfw": false}` |
|
||||||
|
| Action | `participants`, `nsfw` | `{"participants": "1girl, 1boy", "nsfw": true}` |
|
||||||
|
| Style | `style_type`, `nsfw` | `{"style_type": "Anime", "nsfw": false}` |
|
||||||
|
| Scene | `scene_type`, `nsfw` | `{"scene_type": "Indoor", "nsfw": false}` |
|
||||||
|
| Detailer | `associated_resource`, `adetailer_targets`, `nsfw` | `{"associated_resource": "skin", "adetailer_targets": ["face", "hands"], "nsfw": false}` |
|
||||||
|
| Checkpoint | `art_style`, `base_model`, `nsfw` | `{"art_style": "anime", "base_model": "Illustrious", "nsfw": false}` |
|
||||||
|
|
||||||
|
### Favourite / NSFW Columns
|
||||||
|
|
||||||
|
- `is_favourite` — DB-only boolean. Toggled via `POST /<category>/<slug>/favourite`. Not stored in JSON (user preference, not asset metadata).
|
||||||
|
- `is_nsfw` — DB column **and** `tags.nsfw` in JSON. Synced from JSON on rescan via `_sync_nsfw_from_tags()`. Editable from edit pages.
|
||||||
|
|
||||||
|
### Library Filtering
|
||||||
|
|
||||||
|
All library index pages support query params:
|
||||||
|
- `?favourite=on` — show only favourites
|
||||||
|
- `?nsfw=sfw|nsfw|all` — filter by NSFW status
|
||||||
|
- Results are ordered by `is_favourite DESC, name ASC` (favourites sort first).
|
||||||
|
|
||||||
|
### Gallery Image Sidecar Files
|
||||||
|
|
||||||
|
Gallery images can have per-image favourite/NSFW metadata stored in sidecar JSON files at `{image_path}.json` (e.g. `static/uploads/characters/tifa/gen_123.png.json`). Sidecar schema: `{"is_favourite": bool, "is_nsfw": bool}`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LoRA File Paths
|
||||||
|
|
||||||
|
LoRA filenames in JSON are stored as paths relative to ComfyUI's `models/lora/` root:
|
||||||
|
|
||||||
|
| Category | Path prefix | Example |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| Character / Look | `Illustrious/Looks/` | `Illustrious/Looks/tifa_v2.safetensors` |
|
||||||
|
| Outfit | `Illustrious/Clothing/` | `Illustrious/Clothing/maid.safetensors` |
|
||||||
|
| Action | `Illustrious/Poses/` | `Illustrious/Poses/sitting.safetensors` |
|
||||||
|
| Style | `Illustrious/Styles/` | `Illustrious/Styles/watercolor.safetensors` |
|
||||||
|
| Detailer | `Illustrious/Detailers/` | `Illustrious/Detailers/skin.safetensors` |
|
||||||
|
| Scene | `Illustrious/Backgrounds/` | `Illustrious/Backgrounds/beach.safetensors` |
|
||||||
|
|
||||||
|
Checkpoint paths: `Illustrious/<filename>.safetensors` or `Noob/<filename>.safetensors`.
|
||||||
|
|
||||||
|
Absolute paths on disk:
|
||||||
|
- Checkpoints: `/mnt/alexander/AITools/Image Models/Stable-diffusion/{Illustrious,Noob}/`
|
||||||
|
- LoRAs: `/mnt/alexander/AITools/Image Models/lora/Illustrious/{Looks,Clothing,Poses,Styles,Detailers,Backgrounds}/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a New Category
|
||||||
|
|
||||||
|
To add a new content category (e.g. "Poses" as a separate concept from Actions), the pattern is:
|
||||||
|
|
||||||
|
1. **Model** (`models.py`): Add a new SQLAlchemy model with the standard fields.
|
||||||
|
2. **Sync function** (`services/sync.py`): Add `sync_newcategory()` following the pattern of `sync_outfits()`.
|
||||||
|
3. **Data directory** (`app.py`): Add `app.config['NEWCATEGORY_DIR'] = 'data/newcategory'`.
|
||||||
|
4. **Routes** (`routes/newcategory.py`): Create a new route module with a `register_routes(app)` function. Implement index, detail, edit, generate, replace_cover_from_preview, upload, save_defaults, clone, rescan routes. Follow `routes/outfits.py` or `routes/scenes.py` exactly.
|
||||||
|
5. **Route registration** (`routes/__init__.py`): Import and call `newcategory.register_routes(app)`.
|
||||||
|
6. **Templates**: Create `templates/newcategory/{index,detail,edit,create}.html` extending `layout.html`.
|
||||||
|
7. **Nav**: Add link to navbar in `templates/layout.html`.
|
||||||
|
8. **Startup** (`app.py`): Import and call `sync_newcategory()` in the `with app.app_context()` block.
|
||||||
|
9. **Generator page**: Add to `routes/generator.py`, `services/prompts.py` `build_extras_prompt()`, and `templates/generator.html` accordion.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Session Keys
|
||||||
|
|
||||||
|
The Flask filesystem session stores:
|
||||||
|
- `default_checkpoint` — checkpoint_path string for the global default
|
||||||
|
- `prefs_{slug}` — selected_fields list for character detail page
|
||||||
|
- `preview_{slug}` — relative image path of last character preview
|
||||||
|
- `prefs_outfit_{slug}`, `preview_outfit_{slug}`, `char_outfit_{slug}` — outfit detail state
|
||||||
|
- `prefs_action_{slug}`, `preview_action_{slug}`, `char_action_{slug}` — action detail state
|
||||||
|
- `prefs_scene_{slug}`, `preview_scene_{slug}`, `char_scene_{slug}` — scene detail state
|
||||||
|
- `prefs_detailer_{slug}`, `preview_detailer_{slug}`, `char_detailer_{slug}`, `action_detailer_{slug}`, `extra_pos_detailer_{slug}`, `extra_neg_detailer_{slug}` — detailer detail state (selected fields, preview image, character, action LoRA, extra positive prompt, extra negative prompt)
|
||||||
|
- `prefs_style_{slug}`, `preview_style_{slug}`, `char_style_{slug}` — style detail state
|
||||||
|
- `prefs_look_{slug}`, `preview_look_{slug}` — look detail state
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the App
|
||||||
|
|
||||||
|
### Directly (development)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /mnt/alexander/Projects/character-browser
|
||||||
|
source venv/bin/activate
|
||||||
|
python app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The app runs in debug mode on port 5000 by default. ComfyUI must be running at `http://127.0.0.1:8188`.
|
||||||
|
|
||||||
|
The DB is initialised and all sync functions are called inside `with app.app_context():` at the bottom of `app.py` before `app.run()`.
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
The compose file (`docker-compose.yml`) runs two services:
|
||||||
|
- **`danbooru-mcp`** — built from `https://git.liveaodh.com/aodhan/danbooru-mcp.git`; the MCP tag-search container used by `call_llm()`.
|
||||||
|
- **`app`** — the Flask app, exposed on host port **5782** → container port 5000.
|
||||||
|
|
||||||
|
Key environment variables set by compose:
|
||||||
|
- `COMFYUI_URL=http://10.0.0.200:8188` — points at ComfyUI on the Docker host network.
|
||||||
|
- `SKIP_MCP_AUTOSTART=true` — disables the app's built-in danbooru-mcp launch logic (compose manages it).
|
||||||
|
|
||||||
|
Volumes mounted into the app container:
|
||||||
|
- `./data`, `./static/uploads`, `./instance`, `./flask_session` — persistent app data.
|
||||||
|
- `/Volumes/ImageModels:/ImageModels:ro` — model files for checkpoint/LoRA scanning (**requires Docker Desktop file sharing enabled for `/Volumes/ImageModels`**).
|
||||||
|
- `/var/run/docker.sock` — Docker socket so the app can exec danbooru-mcp tool containers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Pitfalls
|
||||||
|
|
||||||
|
- **SQLAlchemy JSON mutation**: After modifying a JSON column dict in place, always call `flag_modified(obj, "data")` or the change won't be detected.
|
||||||
|
- **Dual write**: Every edit route writes back to both the DB (`db.session.commit()`) and the JSON file on disk. Both must be kept in sync.
|
||||||
|
- **Slug generation**: `re.sub(r'[^a-zA-Z0-9_]', '', id)` — note this removes hyphens and dots, not just replaces them. Character IDs like `yuna_(ff10)` become slug `yunaffx10`. This is intentional.
|
||||||
|
- **Checkpoint slugs use underscore replacement**: `re.sub(r'[^a-zA-Z0-9_]', '_', ...)` (replaces with `_`, not removes) to preserve readability in paths.
|
||||||
|
- **LoRA chaining**: If a LoRA node has no LoRA (name is empty/None), the node is skipped and `model_source`/`clip_source` pass through unchanged. Do not set the node inputs for skipped nodes.
|
||||||
|
- **AJAX detection**: `request.headers.get('X-Requested-With') == 'XMLHttpRequest'` determines whether to return JSON or redirect.
|
||||||
|
- **Session must be marked modified for JSON responses**: After setting session values in AJAX-responding routes, set `session.modified = True`.
|
||||||
|
- **Detailer `prompt` is a list**: The `prompt` field in detailer JSON is stored as a list of strings (e.g. `["detailed skin", "pores"]`), not a plain string. In generate routes, the detailer prompt is injected directly into `prompts['main']` after `build_prompt()` returns (not via tags or `build_prompt` itself).
|
||||||
|
- **`_make_finalize` action semantics**: Pass `action=None` when the route should always update the DB cover (e.g. batch generate, checkpoint generate). Pass `action=request.form.get('action')` for routes that support both "preview" (no DB update) and "replace" (update DB). The factory skips the DB write when `action` is truthy and not `"replace"`.
|
||||||
|
- **LLM queue runs without request context**: `_enqueue_task()` callbacks execute in a background thread with only `app.app_context()`. Do not access `flask.request`, `flask.session`, or other request-scoped objects inside `task_fn`. Use `has_request_context()` guard if code is shared between HTTP handlers and background tasks.
|
||||||
|
- **Tags are metadata only**: Tags (`data['tags']`) are never injected into generation prompts. They are purely for UI filtering and search. The old pattern of `parts.extend(data.get('tags', []))` in prompt building has been removed.
|
||||||
29
Dockerfile
Normal file
29
Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
# Install system deps: git (for danbooru-mcp repo clone) + docker CLI
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
&& install -m 0755 -d /etc/apt/keyrings \
|
||||||
|
&& curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc \
|
||||||
|
&& chmod a+r /etc/apt/keyrings/docker.asc \
|
||||||
|
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
||||||
|
> /etc/apt/sources.list.d/docker.list \
|
||||||
|
&& apt-get update && apt-get install -y --no-install-recommends docker-ce-cli docker-compose-plugin \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Writable dirs that will typically be bind-mounted at runtime
|
||||||
|
RUN mkdir -p static/uploads instance flask_session data/characters data/clothing \
|
||||||
|
data/actions data/styles data/scenes data/detailers data/checkpoints data/looks
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
CMD ["python", "app.py"]
|
||||||
61
README.md
61
README.md
@@ -5,16 +5,25 @@ A local web-based GUI for managing character profiles (JSON) and generating cons
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Character Gallery**: Automatically scans your `characters/` folder and builds a searchable, sortable database.
|
- **Character Gallery**: Automatically scans your `characters/` folder and builds a searchable, sortable database.
|
||||||
- **Granular Prompt Control**: Every field in your character JSON (Identity, Wardrobe, Styles) has a checkbox. You decide exactly what is sent to the AI.
|
- **Outfit Gallery**: Manage reusable outfit presets that can be applied to any character.
|
||||||
|
- **Actions Gallery**: A library of reusable poses and actions (e.g., "Belly Dancing", "Sword Fighting") that can be previewed on any character model.
|
||||||
|
- **Styles Gallery**: Manage art style / artist LoRA presets with AI-assisted bulk creation from your styles LoRA folder.
|
||||||
|
- **Scenes Gallery**: Background and environment LoRA presets, previewable with any character.
|
||||||
|
- **Detailers Gallery**: Detail enhancement LoRA presets for fine-tuning face, hands, and other features.
|
||||||
|
- **Checkpoints Gallery**: Browse all your installed SDXL checkpoints (Illustrious & Noob families). Stores per-checkpoint generation settings (steps, CFG, sampler, VAE, base prompts) via JSON files in `data/checkpoints/`. Supports AI-assisted metadata generation from accompanying HTML files.
|
||||||
|
- **AI-Powered Creation**: Create and populate gallery entries using AI to generate profiles from descriptions or LoRA HTML files, or manually create blank templates.
|
||||||
|
- **Character-Integrated Previews**: Standalone items (Outfits/Actions/Styles/Scenes/Detailers/Checkpoints) can be previewed directly on a specific character's model.
|
||||||
|
- **Granular Prompt Control**: Every field in your JSON models (Identity, Wardrobe, Styles, Action details) has a checkbox. You decide exactly what is sent to the AI.
|
||||||
- **ComfyUI Integration**:
|
- **ComfyUI Integration**:
|
||||||
- **SDXL Optimized**: Designed for high-quality SDXL workflows.
|
- **SDXL Optimized**: Designed for high-quality SDXL/Illustrious workflows.
|
||||||
- **Localized ADetailer**: Automated Face and Hand detailing with focused prompts (e.g., only eye color and expression are sent to the face detailer).
|
- **Localized ADetailer**: Automated Face and Hand detailing with focused prompts (e.g., only eye color and expression are sent to the face detailer).
|
||||||
- **LoRA Support**: Automatically detects and applies LoRAs specified in your character sheets.
|
- **Quad LoRA Chaining**: Chains up to four distinct LoRAs (Character + Outfit + Action + Style/Detailer/Scene) sequentially in the generation workflow.
|
||||||
|
- **Per-Checkpoint Settings**: Steps, CFG, sampler name, VAE, and base prompts are applied automatically from each checkpoint's JSON profile.
|
||||||
- **Real-time Progress**: Live progress bars and queue status via WebSockets (with a reliable polling fallback).
|
- **Real-time Progress**: Live progress bars and queue status via WebSockets (with a reliable polling fallback).
|
||||||
- **Batch Processing**:
|
- **Batch Processing**:
|
||||||
- **Fill Missing**: Generate covers for every character missing one with a single click.
|
- **Fill Missing**: Generate covers for every item missing one with a single click, across all galleries.
|
||||||
- **Refresh All**: Unassign all current covers and generate a fresh set for the whole collection.
|
- **Bulk Create from LoRAs/Checkpoints**: Auto-generate JSON metadata for entire directories using an LLM.
|
||||||
- **Advanced Generator**: A dedicated page to mix-and-match characters with different checkpoints (Illustrious/Noob support) and custom prompt additions.
|
- **Advanced Generator**: A dedicated mix-and-match page combining any character, outfit, action, style, scene, and detailer in a single generation.
|
||||||
- **Smart URLs**: Sanitized, human-readable URLs (slugs) that handle special characters and slashes gracefully.
|
- **Smart URLs**: Sanitized, human-readable URLs (slugs) that handle special characters and slashes gracefully.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
@@ -30,6 +39,20 @@ A local web-based GUI for managing character profiles (JSON) and generating cons
|
|||||||
|
|
||||||
## Setup & Installation
|
## Setup & Installation
|
||||||
|
|
||||||
|
### Option A — Docker (recommended)
|
||||||
|
|
||||||
|
1. **Clone the repository.**
|
||||||
|
2. Edit `docker-compose.yml` if needed:
|
||||||
|
- Set `COMFYUI_URL` to your ComfyUI host/port.
|
||||||
|
- Adjust the `/Volumes/ImageModels` volume path to your model directory. If you're on Docker Desktop, add the path under **Settings → Resources → File Sharing** first.
|
||||||
|
3. **Start services:**
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
The app will be available at `http://localhost:5782`.
|
||||||
|
|
||||||
|
### Option B — Local (development)
|
||||||
|
|
||||||
1. **Clone the repository** to your local machine.
|
1. **Clone the repository** to your local machine.
|
||||||
2. **Configure Paths**: Open `app.py` and update the following variables to match your system:
|
2. **Configure Paths**: Open `app.py` and update the following variables to match your system:
|
||||||
```python
|
```python
|
||||||
@@ -45,13 +68,18 @@ A local web-based GUI for managing character profiles (JSON) and generating cons
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
### Creating Content
|
||||||
|
- **AI Generation**: Toggle "Use AI to generate profile from description" on, then describe your character, outfit, or action. The AI will generate a complete profile with appropriate tags.
|
||||||
|
- **Manual Creation**: Toggle AI generation off to create a blank template you can edit yourself.
|
||||||
|
- **Auto-naming**: Leave the filename field empty to auto-generate one from the name. If a file already exists, a number will be appended automatically.
|
||||||
|
|
||||||
### Gallery Management
|
### Gallery Management
|
||||||
- **Rescan**: Use the "Rescan Character Files" button if you've added new JSON files or manually edited them.
|
- **Rescan**: Use the "Rescan" buttons if you've added new JSON files or manually edited them.
|
||||||
- **Save Defaults**: On a character page, select your favorite prompt combination and click "Save as Default Selection" to remember it for future quick generations.
|
- **Save Defaults**: On any detail page, select your favorite prompt combination and click "Save as Default Selection" to remember it for future generations.
|
||||||
|
|
||||||
### Generation
|
### Generation
|
||||||
- **Preview**: Generates an image and shows it to you without replacing your current cover.
|
- **Preview**: Generates an image and shows it to you without replacing your current cover.
|
||||||
- **Replace**: Generates an image and sets it as the character's official gallery cover.
|
- **Replace**: Generates an image and sets it as the item's official gallery cover.
|
||||||
- **Clean Start**: If you want to wipe the database and all generated images to start fresh:
|
- **Clean Start**: If you want to wipe the database and all generated images to start fresh:
|
||||||
```bash
|
```bash
|
||||||
./launch.sh --clean
|
./launch.sh --clean
|
||||||
@@ -59,9 +87,16 @@ A local web-based GUI for managing character profiles (JSON) and generating cons
|
|||||||
|
|
||||||
## File Structure
|
## File Structure
|
||||||
|
|
||||||
- `/characters`: Your character JSON files.
|
- `/data/characters`: Character JSON files.
|
||||||
- `/static/uploads`: Generated images (organized by character subfolders).
|
- `/data/clothing`: Outfit preset JSON files.
|
||||||
- `/templates`: HTML UI using Bootstrap 5.
|
- `/data/actions`: Action/Pose preset JSON files.
|
||||||
|
- `/data/styles`: Art style / artist LoRA JSON files.
|
||||||
|
- `/data/scenes`: Scene/background LoRA JSON files.
|
||||||
|
- `/data/detailers`: Detailer LoRA JSON files.
|
||||||
|
- `/data/checkpoints`: Per-checkpoint metadata JSON files (steps, CFG, sampler, VAE, base prompts).
|
||||||
|
- `/data/prompts`: LLM system prompts used by the AI-assisted bulk creation features.
|
||||||
|
- `/static/uploads`: Generated images (organized by subfolders).
|
||||||
- `app.py`: Flask backend and prompt-building logic.
|
- `app.py`: Flask backend and prompt-building logic.
|
||||||
- `comfy_workflow.json`: The API-format workflow used for generations.
|
- `comfy_workflow.json`: The API-format workflow used for generations.
|
||||||
- `models.py`: SQLite database schema.
|
- `models.py`: SQLAlchemy database models.
|
||||||
|
- `DEVELOPMENT_GUIDE.md`: Architectural patterns for extending the browser.
|
||||||
|
|||||||
711
app.py
711
app.py
@@ -1,544 +1,201 @@
|
|||||||
import os
|
import os
|
||||||
import json
|
import logging
|
||||||
import time
|
from flask import Flask
|
||||||
import re
|
from flask_session import Session
|
||||||
import requests
|
from models import db, Settings, Look
|
||||||
import random
|
|
||||||
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
|
||||||
from werkzeug.utils import secure_filename
|
|
||||||
from models import db, Character
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
|
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
app.config['UPLOAD_FOLDER'] = 'static/uploads'
|
app.config['UPLOAD_FOLDER'] = 'static/uploads'
|
||||||
app.config['SECRET_KEY'] = 'dev-key-123'
|
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev-key-123')
|
||||||
app.config['CHARACTERS_DIR'] = 'characters'
|
app.config['CHARACTERS_DIR'] = 'data/characters'
|
||||||
app.config['COMFYUI_URL'] = 'http://127.0.0.1:8188'
|
app.config['CLOTHING_DIR'] = 'data/clothing'
|
||||||
app.config['ILLUSTRIOUS_MODELS_DIR'] = '/mnt/alexander/AITools/Image Models/Stable-diffusion/Illustrious/'
|
app.config['ACTIONS_DIR'] = 'data/actions'
|
||||||
app.config['NOOB_MODELS_DIR'] = '/mnt/alexander/AITools/Image Models/Stable-diffusion/Noob/'
|
app.config['STYLES_DIR'] = 'data/styles'
|
||||||
|
app.config['SCENES_DIR'] = 'data/scenes'
|
||||||
|
app.config['DETAILERS_DIR'] = 'data/detailers'
|
||||||
|
app.config['CHECKPOINTS_DIR'] = 'data/checkpoints'
|
||||||
|
app.config['LOOKS_DIR'] = 'data/looks'
|
||||||
|
app.config['PRESETS_DIR'] = 'data/presets'
|
||||||
|
app.config['COMFYUI_URL'] = os.environ.get('COMFYUI_URL', 'http://127.0.0.1:8188')
|
||||||
|
app.config['ILLUSTRIOUS_MODELS_DIR'] = '/ImageModels/Stable-diffusion/Illustrious/'
|
||||||
|
app.config['NOOB_MODELS_DIR'] = '/ImageModels/Stable-diffusion/Noob/'
|
||||||
|
app.config['LORA_DIR'] = '/ImageModels/lora/Illustrious/Looks/'
|
||||||
|
|
||||||
|
# Server-side session configuration to avoid cookie size limits
|
||||||
|
app.config['SESSION_TYPE'] = 'filesystem'
|
||||||
|
app.config['SESSION_FILE_DIR'] = os.path.join(app.config['UPLOAD_FOLDER'], '../flask_session')
|
||||||
|
app.config['SESSION_PERMANENT'] = False
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
Session(app)
|
||||||
|
|
||||||
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp'}
|
# ---------------------------------------------------------------------------
|
||||||
|
# Logging
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
log_level_str = os.environ.get('LOG_LEVEL', 'INFO').upper()
|
||||||
|
log_level = getattr(logging, log_level_str, logging.INFO)
|
||||||
|
|
||||||
def get_available_checkpoints():
|
logging.basicConfig(
|
||||||
checkpoints = []
|
level=log_level,
|
||||||
|
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
|
||||||
# Scan Illustrious
|
datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
if os.path.exists(app.config['ILLUSTRIOUS_MODELS_DIR']):
|
)
|
||||||
for f in os.listdir(app.config['ILLUSTRIOUS_MODELS_DIR']):
|
logger = logging.getLogger('gaze')
|
||||||
if f.endswith('.safetensors') or f.endswith('.ckpt'):
|
logger.setLevel(log_level)
|
||||||
checkpoints.append(f"Illustrious/{f}")
|
|
||||||
|
|
||||||
# Scan Noob
|
|
||||||
if os.path.exists(app.config['NOOB_MODELS_DIR']):
|
|
||||||
for f in os.listdir(app.config['NOOB_MODELS_DIR']):
|
|
||||||
if f.endswith('.safetensors') or f.endswith('.ckpt'):
|
|
||||||
checkpoints.append(f"Noob/{f}")
|
|
||||||
|
|
||||||
return sorted(checkpoints)
|
|
||||||
|
|
||||||
def allowed_file(filename):
|
# ---------------------------------------------------------------------------
|
||||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
# Register all routes
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
def build_prompt(data, selected_fields=None, default_fields=None):
|
from routes import register_routes
|
||||||
def is_selected(section, key):
|
register_routes(app)
|
||||||
# Priority:
|
|
||||||
# 1. Manual selection from form (if list is not empty)
|
|
||||||
# 2. Database defaults (if they exist)
|
|
||||||
# 3. Select all (default behavior)
|
|
||||||
if selected_fields:
|
|
||||||
return f"{section}::{key}" in selected_fields
|
|
||||||
if default_fields:
|
|
||||||
return f"{section}::{key}" in default_fields
|
|
||||||
return True
|
|
||||||
|
|
||||||
identity = data.get('identity', {})
|
|
||||||
wardrobe = data.get('wardrobe', {})
|
|
||||||
|
|
||||||
# Pre-calculate Hand/Glove priority
|
|
||||||
hand_val = ""
|
|
||||||
if wardrobe.get('gloves') and is_selected('wardrobe', 'gloves'):
|
|
||||||
hand_val = wardrobe.get('gloves')
|
|
||||||
elif identity.get('hands') and is_selected('identity', 'hands'):
|
|
||||||
hand_val = identity.get('hands')
|
|
||||||
|
|
||||||
# 1. Main Prompt
|
|
||||||
parts = ["(solo:1.2)"]
|
|
||||||
# Use character_id (underscores to spaces) for tags compatibility
|
|
||||||
char_tag = data.get('character_id', '').replace('_', ' ')
|
|
||||||
if char_tag and is_selected('special', 'name'):
|
|
||||||
parts.append(char_tag)
|
|
||||||
|
|
||||||
for key in ['base_specs', 'hair', 'eyes', 'expression', 'distinguishing_marks']:
|
|
||||||
val = identity.get(key)
|
|
||||||
if val and is_selected('identity', key):
|
|
||||||
parts.append(val)
|
|
||||||
|
|
||||||
# Add hand priority value to main prompt
|
|
||||||
if hand_val:
|
|
||||||
parts.append(hand_val)
|
|
||||||
|
|
||||||
for key in ['outer_layer', 'inner_layer', 'lower_body', 'footwear', 'accessories']:
|
|
||||||
val = wardrobe.get(key)
|
|
||||||
if val and is_selected('wardrobe', key):
|
|
||||||
parts.append(val)
|
|
||||||
|
|
||||||
style = data.get('styles', {}).get('aesthetic')
|
|
||||||
if style and is_selected('styles', 'aesthetic'):
|
|
||||||
parts.append(f"{style} style")
|
|
||||||
|
|
||||||
tags = data.get('tags', [])
|
|
||||||
if tags and is_selected('special', 'tags'):
|
|
||||||
parts.extend(tags)
|
|
||||||
|
|
||||||
lora = data.get('lora', {})
|
|
||||||
if lora.get('lora_triggers') and is_selected('lora', 'lora_triggers'):
|
|
||||||
parts.append(lora.get('lora_triggers'))
|
|
||||||
|
|
||||||
# 2. Face Prompt: Tag, Eyes, Expression
|
|
||||||
face_parts = []
|
|
||||||
if char_tag and is_selected('special', 'name'): face_parts.append(char_tag)
|
|
||||||
if identity.get('eyes') and is_selected('identity', 'eyes'): face_parts.append(identity.get('eyes'))
|
|
||||||
if identity.get('expression') and is_selected('identity', 'expression'): face_parts.append(identity.get('expression'))
|
|
||||||
|
|
||||||
# 3. Hand Prompt: Hand value (Gloves or Hands)
|
|
||||||
hand_parts = [hand_val] if hand_val else []
|
|
||||||
|
|
||||||
return {
|
|
||||||
"main": ", ".join(parts),
|
|
||||||
"face": ", ".join(face_parts),
|
|
||||||
"hand": ", ".join(hand_parts)
|
|
||||||
}
|
|
||||||
|
|
||||||
def queue_prompt(prompt_workflow, client_id=None):
|
|
||||||
p = {"prompt": prompt_workflow}
|
|
||||||
if client_id:
|
|
||||||
p["client_id"] = client_id
|
|
||||||
data = json.dumps(p).encode('utf-8')
|
|
||||||
response = requests.post(f"{app.config['COMFYUI_URL']}/prompt", data=data)
|
|
||||||
return response.json()
|
|
||||||
|
|
||||||
def get_history(prompt_id):
|
|
||||||
response = requests.get(f"{app.config['COMFYUI_URL']}/history/{prompt_id}")
|
|
||||||
return response.json()
|
|
||||||
|
|
||||||
def get_image(filename, subfolder, folder_type):
|
|
||||||
data = {"filename": filename, "subfolder": subfolder, "type": folder_type}
|
|
||||||
response = requests.get(f"{app.config['COMFYUI_URL']}/view", params=data)
|
|
||||||
return response.content
|
|
||||||
|
|
||||||
from sqlalchemy.orm.attributes import flag_modified
|
|
||||||
|
|
||||||
def sync_characters():
|
|
||||||
if not os.path.exists(app.config['CHARACTERS_DIR']):
|
|
||||||
return
|
|
||||||
|
|
||||||
current_ids = []
|
|
||||||
|
|
||||||
for filename in os.listdir(app.config['CHARACTERS_DIR']):
|
|
||||||
if filename.endswith('.json'):
|
|
||||||
file_path = os.path.join(app.config['CHARACTERS_DIR'], filename)
|
|
||||||
try:
|
|
||||||
with open(file_path, 'r') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
char_id = data.get('character_id')
|
|
||||||
if not char_id:
|
|
||||||
continue
|
|
||||||
|
|
||||||
current_ids.append(char_id)
|
|
||||||
|
|
||||||
# Generate URL-safe slug: remove special characters from character_id
|
|
||||||
slug = re.sub(r'[^a-zA-Z0-9_]', '', char_id)
|
|
||||||
|
|
||||||
# Check if character already exists
|
|
||||||
character = Character.query.filter_by(character_id=char_id).first()
|
|
||||||
name = data.get('character_name', char_id.replace('_', ' ').title())
|
|
||||||
|
|
||||||
if character:
|
|
||||||
character.data = data
|
|
||||||
character.name = name
|
|
||||||
character.slug = slug
|
|
||||||
|
|
||||||
# Check if cover image still exists
|
|
||||||
if character.image_path:
|
|
||||||
full_img_path = os.path.join(app.config['UPLOAD_FOLDER'], character.image_path)
|
|
||||||
if not os.path.exists(full_img_path):
|
|
||||||
print(f"Image missing for {character.name}, clearing path.")
|
|
||||||
character.image_path = None
|
|
||||||
|
|
||||||
# Explicitly tell SQLAlchemy the JSON field was modified
|
|
||||||
flag_modified(character, "data")
|
|
||||||
else:
|
|
||||||
new_char = Character(
|
|
||||||
character_id=char_id,
|
|
||||||
slug=slug,
|
|
||||||
name=name,
|
|
||||||
data=data
|
|
||||||
)
|
|
||||||
db.session.add(new_char)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error importing {filename}: {e}")
|
|
||||||
|
|
||||||
# Remove characters that are no longer in the folder
|
|
||||||
all_characters = Character.query.all()
|
|
||||||
for char in all_characters:
|
|
||||||
if char.character_id not in current_ids:
|
|
||||||
db.session.delete(char)
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def index():
|
|
||||||
characters = Character.query.order_by(Character.name).all()
|
|
||||||
return render_template('index.html', characters=characters)
|
|
||||||
|
|
||||||
@app.route('/rescan', methods=['POST'])
|
|
||||||
def rescan():
|
|
||||||
sync_characters()
|
|
||||||
flash('Database synced with character files.')
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
@app.route('/generator', methods=['GET', 'POST'])
|
|
||||||
def generator():
|
|
||||||
characters = Character.query.order_by(Character.name).all()
|
|
||||||
checkpoints = get_available_checkpoints()
|
|
||||||
|
|
||||||
if not checkpoints:
|
|
||||||
checkpoints = ["Noob/oneObsession_v19Atypical.safetensors"]
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
char_slug = request.form.get('character')
|
|
||||||
checkpoint = request.form.get('checkpoint')
|
|
||||||
custom_positive = request.form.get('positive_prompt', '')
|
|
||||||
custom_negative = request.form.get('negative_prompt', '')
|
|
||||||
|
|
||||||
character = Character.query.filter_by(slug=char_slug).first_or_404()
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open('comfy_workflow.json', 'r') as f:
|
|
||||||
workflow = json.load(f)
|
|
||||||
|
|
||||||
# Build base prompts from character defaults
|
|
||||||
prompts = build_prompt(character.data, default_fields=character.default_fields)
|
|
||||||
|
|
||||||
# Append custom additions to the "main" prompt
|
|
||||||
if custom_positive:
|
|
||||||
prompts["main"] = f"{prompts['main']}, {custom_positive}"
|
|
||||||
|
|
||||||
# Prepare workflow with custom checkpoint and negative prompt
|
|
||||||
workflow = _prepare_workflow(workflow, character, prompts, checkpoint, custom_negative)
|
|
||||||
|
|
||||||
print(f"Queueing generator prompt for {character.character_id}")
|
|
||||||
prompt_response = queue_prompt(workflow)
|
|
||||||
|
|
||||||
if 'prompt_id' not in prompt_response:
|
|
||||||
raise Exception(f"ComfyUI failed: {prompt_response.get('error', 'Unknown error')}")
|
|
||||||
|
|
||||||
prompt_id = prompt_response['prompt_id']
|
|
||||||
flash("Generation started...")
|
|
||||||
|
|
||||||
max_retries = 120
|
|
||||||
while max_retries > 0:
|
|
||||||
history = get_history(prompt_id)
|
|
||||||
if prompt_id in history:
|
|
||||||
outputs = history[prompt_id]['outputs']
|
|
||||||
for node_id in outputs:
|
|
||||||
if 'images' in outputs[node_id]:
|
|
||||||
image_info = outputs[node_id]['images'][0]
|
|
||||||
image_data = get_image(image_info['filename'], image_info['subfolder'], image_info['type'])
|
|
||||||
|
|
||||||
char_folder = os.path.join(app.config['UPLOAD_FOLDER'], character.slug)
|
|
||||||
os.makedirs(char_folder, exist_ok=True)
|
|
||||||
filename = f"gen_{int(time.time())}.png"
|
|
||||||
file_path = os.path.join(char_folder, filename)
|
|
||||||
with open(file_path, 'wb') as f:
|
|
||||||
f.write(image_data)
|
|
||||||
|
|
||||||
relative_path = f"{character.slug}/{filename}"
|
|
||||||
return render_template('generator.html', characters=characters, checkpoints=checkpoints,
|
|
||||||
generated_image=relative_path, selected_char=char_slug, selected_ckpt=checkpoint)
|
|
||||||
time.sleep(2)
|
|
||||||
max_retries -= 1
|
|
||||||
flash("Generation timed out.")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Generator error: {e}")
|
|
||||||
flash(f"Error: {str(e)}")
|
|
||||||
|
|
||||||
return render_template('generator.html', characters=characters, checkpoints=checkpoints)
|
|
||||||
|
|
||||||
@app.route('/character/<path:slug>')
|
|
||||||
def detail(slug):
|
|
||||||
character = Character.query.filter_by(slug=slug).first_or_404()
|
|
||||||
|
|
||||||
# Load state from session
|
|
||||||
preferences = session.get(f'prefs_{slug}')
|
|
||||||
preview_image = session.get(f'preview_{slug}')
|
|
||||||
|
|
||||||
return render_template('detail.html', character=character, preferences=preferences, preview_image=preview_image)
|
|
||||||
|
|
||||||
@app.route('/character/<path:slug>/upload', methods=['POST'])
|
|
||||||
def upload_image(slug):
|
|
||||||
character = Character.query.filter_by(slug=slug).first_or_404()
|
|
||||||
|
|
||||||
if 'image' not in request.files:
|
|
||||||
flash('No file part')
|
|
||||||
return redirect(request.url)
|
|
||||||
|
|
||||||
file = request.files['image']
|
|
||||||
if file.filename == '':
|
|
||||||
flash('No selected file')
|
|
||||||
return redirect(request.url)
|
|
||||||
|
|
||||||
if file and allowed_file(file.filename):
|
|
||||||
# Create character subfolder
|
|
||||||
char_folder = os.path.join(app.config['UPLOAD_FOLDER'], slug)
|
|
||||||
os.makedirs(char_folder, exist_ok=True)
|
|
||||||
|
|
||||||
filename = secure_filename(file.filename)
|
|
||||||
file_path = os.path.join(char_folder, filename)
|
|
||||||
file.save(file_path)
|
|
||||||
|
|
||||||
# Store relative path in DB
|
|
||||||
character.image_path = f"{slug}/{filename}"
|
|
||||||
db.session.commit()
|
|
||||||
flash('Image uploaded successfully!')
|
|
||||||
|
|
||||||
return redirect(url_for('detail', slug=slug))
|
|
||||||
|
|
||||||
@app.route('/character/<path:slug>/finalize_generation/<prompt_id>', methods=['POST'])
|
|
||||||
def finalize_generation(slug, prompt_id):
|
|
||||||
character = Character.query.filter_by(slug=slug).first_or_404()
|
|
||||||
action = request.form.get('action', 'preview')
|
|
||||||
|
|
||||||
try:
|
|
||||||
history = get_history(prompt_id)
|
|
||||||
if prompt_id not in history:
|
|
||||||
return {'error': 'History not found'}, 404
|
|
||||||
|
|
||||||
outputs = history[prompt_id]['outputs']
|
|
||||||
for node_id in outputs:
|
|
||||||
if 'images' in outputs[node_id]:
|
|
||||||
image_info = outputs[node_id]['images'][0]
|
|
||||||
image_data = get_image(image_info['filename'], image_info['subfolder'], image_info['type'])
|
|
||||||
|
|
||||||
# Create character subfolder
|
|
||||||
char_folder = os.path.join(app.config['UPLOAD_FOLDER'], slug)
|
|
||||||
os.makedirs(char_folder, exist_ok=True)
|
|
||||||
|
|
||||||
filename = f"gen_{int(time.time())}.png"
|
|
||||||
file_path = os.path.join(char_folder, filename)
|
|
||||||
with open(file_path, 'wb') as f:
|
|
||||||
f.write(image_data)
|
|
||||||
|
|
||||||
print(f"Image saved to: {os.path.abspath(file_path)}")
|
|
||||||
|
|
||||||
# Handle actions
|
|
||||||
relative_path = f"{slug}/{filename}"
|
|
||||||
|
|
||||||
if action == 'replace':
|
|
||||||
character.image_path = relative_path
|
|
||||||
db.session.commit()
|
|
||||||
flash('Cover image updated!')
|
|
||||||
else:
|
|
||||||
# Preview mode
|
|
||||||
session[f'preview_{slug}'] = relative_path
|
|
||||||
|
|
||||||
return {'success': True, 'image_url': url_for('static', filename=f'uploads/{relative_path}')}
|
|
||||||
|
|
||||||
return {'error': 'No image found in output'}, 404
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Finalize error: {e}")
|
|
||||||
return {'error': str(e)}, 500
|
|
||||||
|
|
||||||
def _prepare_workflow(workflow, character, prompts, checkpoint=None, custom_negative=None):
|
|
||||||
# 1. Update prompts using replacement to preserve embeddings
|
|
||||||
workflow["6"]["inputs"]["text"] = workflow["6"]["inputs"]["text"].replace("{{POSITIVE_PROMPT}}", prompts["main"])
|
|
||||||
|
|
||||||
if custom_negative:
|
|
||||||
workflow["7"]["inputs"]["text"] = f"{workflow['7']['inputs']['text']}, {custom_negative}"
|
|
||||||
|
|
||||||
if "14" in workflow:
|
|
||||||
workflow["14"]["inputs"]["text"] = workflow["14"]["inputs"]["text"].replace("{{FACE_PROMPT}}", prompts["face"])
|
|
||||||
if "15" in workflow:
|
|
||||||
workflow["15"]["inputs"]["text"] = workflow["15"]["inputs"]["text"].replace("{{HAND_PROMPT}}", prompts["hand"])
|
|
||||||
|
|
||||||
print("--- DEBUG: COMFYUI PROMPTS ---")
|
|
||||||
print(f"Main Positive (6): {workflow['6']['inputs']['text']}")
|
|
||||||
print(f"Main Negative (7): {workflow['7']['inputs']['text']}")
|
|
||||||
if "14" in workflow:
|
|
||||||
print(f"Face Detailer (14): {workflow['14']['inputs']['text']}")
|
|
||||||
if "15" in workflow:
|
|
||||||
print(f"Hand Detailer (15): {workflow['15']['inputs']['text']}")
|
|
||||||
print("-------------------------------")
|
|
||||||
|
|
||||||
# 2. Update Checkpoint
|
|
||||||
if checkpoint:
|
|
||||||
workflow["4"]["inputs"]["ckpt_name"] = checkpoint
|
|
||||||
|
|
||||||
# 3. Handle LoRA
|
|
||||||
lora_data = character.data.get('lora', {})
|
|
||||||
lora_name = lora_data.get('lora_name')
|
|
||||||
|
|
||||||
model_source = ["4", 0]
|
|
||||||
clip_source = ["4", 1]
|
|
||||||
|
|
||||||
if lora_name and "16" in workflow:
|
|
||||||
workflow["16"]["inputs"]["lora_name"] = lora_name
|
|
||||||
workflow["16"]["inputs"]["strength_model"] = lora_data.get('lora_weight', 1.0)
|
|
||||||
workflow["16"]["inputs"]["strength_clip"] = lora_data.get('lora_weight', 1.0)
|
|
||||||
model_source = ["16", 0]
|
|
||||||
clip_source = ["16", 1]
|
|
||||||
|
|
||||||
# Apply connections to all model/clip consumers
|
|
||||||
workflow["3"]["inputs"]["model"] = model_source
|
|
||||||
workflow["11"]["inputs"]["model"] = model_source
|
|
||||||
workflow["13"]["inputs"]["model"] = model_source
|
|
||||||
|
|
||||||
workflow["6"]["inputs"]["clip"] = clip_source
|
|
||||||
workflow["7"]["inputs"]["clip"] = clip_source
|
|
||||||
workflow["11"]["inputs"]["clip"] = clip_source
|
|
||||||
workflow["13"]["inputs"]["clip"] = clip_source
|
|
||||||
workflow["14"]["inputs"]["clip"] = clip_source
|
|
||||||
workflow["15"]["inputs"]["clip"] = clip_source
|
|
||||||
|
|
||||||
# 4. Randomize seeds
|
|
||||||
gen_seed = random.randint(1, 10**15)
|
|
||||||
workflow["3"]["inputs"]["seed"] = gen_seed
|
|
||||||
if "11" in workflow: workflow["11"]["inputs"]["seed"] = gen_seed
|
|
||||||
if "13" in workflow: workflow["13"]["inputs"]["seed"] = gen_seed
|
|
||||||
|
|
||||||
return workflow
|
|
||||||
|
|
||||||
def _queue_generation(character, action='preview', selected_fields=None, client_id=None):
|
|
||||||
# 1. Load workflow
|
|
||||||
with open('comfy_workflow.json', 'r') as f:
|
|
||||||
workflow = json.load(f)
|
|
||||||
|
|
||||||
# 2. Build prompts
|
|
||||||
prompts = build_prompt(character.data, selected_fields, character.default_fields)
|
|
||||||
|
|
||||||
# 3. Prepare workflow
|
|
||||||
workflow = _prepare_workflow(workflow, character, prompts)
|
|
||||||
|
|
||||||
return queue_prompt(workflow, client_id=client_id)
|
|
||||||
@app.route('/get_missing_characters')
|
|
||||||
def get_missing_characters():
|
|
||||||
missing = Character.query.filter((Character.image_path == None) | (Character.image_path == '')).all()
|
|
||||||
return {'missing': [{'slug': c.slug, 'name': c.name} for c in missing]}
|
|
||||||
|
|
||||||
@app.route('/clear_all_covers', methods=['POST'])
|
|
||||||
def clear_all_covers():
|
|
||||||
characters = Character.query.all()
|
|
||||||
for char in characters:
|
|
||||||
char.image_path = None
|
|
||||||
db.session.commit()
|
|
||||||
return {'success': True}
|
|
||||||
|
|
||||||
@app.route('/generate_missing', methods=['POST'])
|
|
||||||
def generate_missing():
|
|
||||||
missing = Character.query.filter((Character.image_path == None) | (Character.image_path == '')).all()
|
|
||||||
if not missing:
|
|
||||||
flash("No characters missing cover images.")
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
success_count = 0
|
|
||||||
for character in missing:
|
|
||||||
try:
|
|
||||||
print(f"Batch generating for: {character.name}")
|
|
||||||
prompt_response = _queue_generation(character, action='replace')
|
|
||||||
prompt_id = prompt_response['prompt_id']
|
|
||||||
|
|
||||||
# Simple synchronous wait for each
|
|
||||||
max_retries = 120
|
|
||||||
while max_retries > 0:
|
|
||||||
history = get_history(prompt_id)
|
|
||||||
if prompt_id in history:
|
|
||||||
outputs = history[prompt_id]['outputs']
|
|
||||||
for node_id in outputs:
|
|
||||||
if 'images' in outputs[node_id]:
|
|
||||||
image_info = outputs[node_id]['images'][0]
|
|
||||||
image_data = get_image(image_info['filename'], image_info['subfolder'], image_info['type'])
|
|
||||||
|
|
||||||
char_folder = os.path.join(app.config['UPLOAD_FOLDER'], character.slug)
|
|
||||||
os.makedirs(char_folder, exist_ok=True)
|
|
||||||
filename = f"gen_{int(time.time())}.png"
|
|
||||||
file_path = os.path.join(char_folder, filename)
|
|
||||||
with open(file_path, 'wb') as f:
|
|
||||||
f.write(image_data)
|
|
||||||
|
|
||||||
character.image_path = f"{character.slug}/{filename}"
|
|
||||||
db.session.commit()
|
|
||||||
success_count += 1
|
|
||||||
break
|
|
||||||
break
|
|
||||||
time.sleep(2)
|
|
||||||
max_retries -= 1
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error generating for {character.name}: {e}")
|
|
||||||
|
|
||||||
flash(f"Batch generation complete. Generated {success_count} images.")
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
@app.route('/check_status/<prompt_id>')
|
|
||||||
def check_status(prompt_id):
|
|
||||||
try:
|
|
||||||
history = get_history(prompt_id)
|
|
||||||
if prompt_id in history:
|
|
||||||
return {'status': 'finished'}
|
|
||||||
return {'status': 'pending'}
|
|
||||||
except Exception:
|
|
||||||
return {'status': 'error'}, 500
|
|
||||||
|
|
||||||
@app.route('/character/<path:slug>/generate', methods=['POST'])
|
|
||||||
def generate_image(slug):
|
|
||||||
character = Character.query.filter_by(slug=slug).first_or_404()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Get action type
|
|
||||||
action = request.form.get('action', 'preview')
|
|
||||||
client_id = request.form.get('client_id')
|
|
||||||
|
|
||||||
# Get selected fields
|
|
||||||
selected_fields = request.form.getlist('include_field')
|
|
||||||
|
|
||||||
# Save preferences
|
|
||||||
session[f'prefs_{slug}'] = selected_fields
|
|
||||||
|
|
||||||
# Queue generation using helper
|
|
||||||
prompt_response = _queue_generation(character, action, selected_fields, client_id=client_id)
|
|
||||||
|
|
||||||
if 'prompt_id' not in prompt_response:
|
|
||||||
raise Exception(f"ComfyUI failed: {prompt_response.get('error', 'Unknown error')}")
|
|
||||||
|
|
||||||
prompt_id = prompt_response['prompt_id']
|
|
||||||
|
|
||||||
# Return JSON if AJAX request
|
|
||||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
|
||||||
return {'status': 'queued', 'prompt_id': prompt_id}
|
|
||||||
|
|
||||||
return redirect(url_for('detail', slug=slug))
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Generation error: {e}")
|
|
||||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
|
||||||
return {'error': str(e)}, 500
|
|
||||||
flash(f"Error during generation: {str(e)}")
|
|
||||||
return redirect(url_for('detail', slug=slug))
|
|
||||||
|
|
||||||
@app.route('/character/<path:slug>/save_defaults', methods=['POST'])
|
|
||||||
def save_defaults(slug):
|
|
||||||
character = Character.query.filter_by(slug=slug).first_or_404()
|
|
||||||
selected_fields = request.form.getlist('include_field')
|
|
||||||
character.default_fields = selected_fields
|
|
||||||
db.session.commit()
|
|
||||||
flash('Default prompt selection saved for this character!')
|
|
||||||
return redirect(url_for('detail', slug=slug))
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Startup
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
from services.mcp import ensure_mcp_server_running, ensure_character_mcp_server_running
|
||||||
|
from services.job_queue import init_queue_worker
|
||||||
|
from services.sync import (
|
||||||
|
sync_characters, sync_outfits, sync_actions, sync_styles,
|
||||||
|
sync_detailers, sync_scenes, sync_looks, sync_checkpoints, sync_presets,
|
||||||
|
)
|
||||||
|
|
||||||
|
ensure_mcp_server_running()
|
||||||
|
ensure_character_mcp_server_running()
|
||||||
|
init_queue_worker(app)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
||||||
|
# Migration: Add active_outfit column if it doesn't exist
|
||||||
|
try:
|
||||||
|
from sqlalchemy import text
|
||||||
|
db.session.execute(text('ALTER TABLE character ADD COLUMN active_outfit VARCHAR(100) DEFAULT \'default\''))
|
||||||
|
db.session.commit()
|
||||||
|
print("Added active_outfit column to character table")
|
||||||
|
except Exception as e:
|
||||||
|
if 'duplicate column name' in str(e).lower() or 'already exists' in str(e).lower():
|
||||||
|
print("active_outfit column already exists")
|
||||||
|
else:
|
||||||
|
print(f"Migration note: {e}")
|
||||||
|
|
||||||
|
# Migration: Add default_fields column to action table if it doesn't exist
|
||||||
|
try:
|
||||||
|
from sqlalchemy import text
|
||||||
|
db.session.execute(text('ALTER TABLE action ADD COLUMN default_fields JSON'))
|
||||||
|
db.session.commit()
|
||||||
|
print("Added default_fields column to action table")
|
||||||
|
except Exception as e:
|
||||||
|
if 'duplicate column name' in str(e).lower() or 'already exists' in str(e).lower():
|
||||||
|
print("default_fields column already exists in action table")
|
||||||
|
else:
|
||||||
|
print(f"Migration action note: {e}")
|
||||||
|
|
||||||
|
# Migration: Add new columns to settings table
|
||||||
|
columns_to_add = [
|
||||||
|
('llm_provider', "VARCHAR(50) DEFAULT 'openrouter'"),
|
||||||
|
('local_base_url', "VARCHAR(255)"),
|
||||||
|
('local_model', "VARCHAR(100)"),
|
||||||
|
('lora_dir_characters', "VARCHAR(500) DEFAULT '/ImageModels/lora/Illustrious/Looks'"),
|
||||||
|
('lora_dir_outfits', "VARCHAR(500) DEFAULT '/ImageModels/lora/Illustrious/Clothing'"),
|
||||||
|
('lora_dir_actions', "VARCHAR(500) DEFAULT '/ImageModels/lora/Illustrious/Poses'"),
|
||||||
|
('lora_dir_styles', "VARCHAR(500) DEFAULT '/ImageModels/lora/Illustrious/Styles'"),
|
||||||
|
('lora_dir_scenes', "VARCHAR(500) DEFAULT '/ImageModels/lora/Illustrious/Backgrounds'"),
|
||||||
|
('lora_dir_detailers', "VARCHAR(500) DEFAULT '/ImageModels/lora/Illustrious/Detailers'"),
|
||||||
|
('checkpoint_dirs', "VARCHAR(1000) DEFAULT '/ImageModels/Stable-diffusion/Illustrious,/ImageModels/Stable-diffusion/Noob'"),
|
||||||
|
('default_checkpoint', "VARCHAR(500)"),
|
||||||
|
('api_key', "VARCHAR(255)"),
|
||||||
|
]
|
||||||
|
for col_name, col_type in columns_to_add:
|
||||||
|
try:
|
||||||
|
db.session.execute(text(f'ALTER TABLE settings ADD COLUMN {col_name} {col_type}'))
|
||||||
|
db.session.commit()
|
||||||
|
print(f"Added {col_name} column to settings table")
|
||||||
|
except Exception as e:
|
||||||
|
if 'duplicate column name' in str(e).lower() or 'already exists' in str(e).lower():
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print(f"Migration settings note ({col_name}): {e}")
|
||||||
|
|
||||||
|
# Migration: Add is_favourite and is_nsfw columns to all resource tables
|
||||||
|
_tag_tables = ['character', 'look', 'outfit', 'action', 'style', 'scene', 'detailer', 'checkpoint']
|
||||||
|
for _tbl in _tag_tables:
|
||||||
|
for _col, _type in [('is_favourite', 'BOOLEAN DEFAULT 0'), ('is_nsfw', 'BOOLEAN DEFAULT 0')]:
|
||||||
|
try:
|
||||||
|
db.session.execute(text(f'ALTER TABLE {_tbl} ADD COLUMN {_col} {_type}'))
|
||||||
|
db.session.commit()
|
||||||
|
print(f"Added {_col} column to {_tbl} table")
|
||||||
|
except Exception as e:
|
||||||
|
if 'duplicate column name' in str(e).lower() or 'already exists' in str(e).lower():
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print(f"Migration note ({_tbl}.{_col}): {e}")
|
||||||
|
|
||||||
|
# Ensure settings exist
|
||||||
|
if not Settings.query.first():
|
||||||
|
db.session.add(Settings())
|
||||||
|
db.session.commit()
|
||||||
|
print("Created default settings")
|
||||||
|
|
||||||
|
# Log the default checkpoint on startup
|
||||||
|
settings = Settings.query.first()
|
||||||
|
if settings and settings.default_checkpoint:
|
||||||
|
logger.info("=" * 80)
|
||||||
|
logger.info("DEFAULT CHECKPOINT loaded from database: %s", settings.default_checkpoint)
|
||||||
|
logger.info("=" * 80)
|
||||||
|
else:
|
||||||
|
logger.info("No default checkpoint set in database")
|
||||||
|
|
||||||
sync_characters()
|
sync_characters()
|
||||||
app.run(debug=True, port=5000)
|
sync_outfits()
|
||||||
|
sync_actions()
|
||||||
|
# Migration: Add data column to checkpoint table
|
||||||
|
try:
|
||||||
|
db.session.execute(text('ALTER TABLE checkpoint ADD COLUMN data JSON'))
|
||||||
|
db.session.commit()
|
||||||
|
print("Added data column to checkpoint table")
|
||||||
|
except Exception as e:
|
||||||
|
if 'duplicate column name' in str(e).lower() or 'already exists' in str(e).lower():
|
||||||
|
print("data column already exists in checkpoint table")
|
||||||
|
else:
|
||||||
|
print(f"Migration checkpoint note: {e}")
|
||||||
|
|
||||||
|
sync_styles()
|
||||||
|
sync_detailers()
|
||||||
|
sync_scenes()
|
||||||
|
sync_looks()
|
||||||
|
sync_checkpoints()
|
||||||
|
sync_presets()
|
||||||
|
|
||||||
|
# Migration: Convert look.character_id to look.character_ids
|
||||||
|
try:
|
||||||
|
from sqlalchemy import text
|
||||||
|
# First ensure the column exists
|
||||||
|
db.session.execute(text("ALTER TABLE look ADD COLUMN character_ids JSON"))
|
||||||
|
db.session.commit()
|
||||||
|
print("Added character_ids column to look table")
|
||||||
|
except Exception as e:
|
||||||
|
if 'duplicate column name' in str(e).lower() or 'already exists' in str(e).lower():
|
||||||
|
pass # Column already exists
|
||||||
|
else:
|
||||||
|
print(f"Migration note (character_ids column): {e}")
|
||||||
|
|
||||||
|
# Migrate existing character_id to character_ids list
|
||||||
|
try:
|
||||||
|
looks_with_old_field = Look.query.filter(Look.character_id.isnot(None)).all()
|
||||||
|
migrated_count = 0
|
||||||
|
for look in looks_with_old_field:
|
||||||
|
if not look.character_ids:
|
||||||
|
look.character_ids = []
|
||||||
|
if look.character_id and look.character_id not in look.character_ids:
|
||||||
|
look.character_ids.append(look.character_id)
|
||||||
|
migrated_count += 1
|
||||||
|
if migrated_count > 0:
|
||||||
|
db.session.commit()
|
||||||
|
print(f"Migrated {migrated_count} looks from character_id to character_ids")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Migration note (character_ids data): {e}")
|
||||||
|
|
||||||
|
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "aerith_gainsborough",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "long brown hair, braided, pink ribbon",
|
|
||||||
"eyes": "green eyes",
|
|
||||||
"expression": "cheerful expression",
|
|
||||||
"hands": "pink nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "pink dress, red bolero jacket",
|
|
||||||
"lower_body": "long skirt",
|
|
||||||
"footwear": "brown boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "gold bracelets, flower basket"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "floral, gentle, final fantasy style",
|
|
||||||
"primary_color": "pink",
|
|
||||||
"secondary_color": "red",
|
|
||||||
"tertiary_color": "brown"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Final Fantasy VII"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "android_18",
|
|
||||||
"character_name": "Android 18",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "shoulder-length blonde hair, tucked behind one ear",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "cool, indifferent expression",
|
|
||||||
"hands": "blue nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "gold hoop earrings"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black short-sleeved shirt",
|
|
||||||
"outer_layer": "blue denim vest, 'RR' text on back",
|
|
||||||
"lower_body": "blue denim skirt, black leggings",
|
|
||||||
"footwear": "brown boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": ""
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "90s casual, anime, dragon ball style",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "white"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Dragon Ball Z"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "anya_(spy_x_family)",
|
|
||||||
"character_name": "Anya Forger",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, small build, loli, fair skin",
|
|
||||||
"hair": "short pink hair, two small horns (hair ornaments)",
|
|
||||||
"eyes": "green eyes",
|
|
||||||
"expression": "smirk",
|
|
||||||
"hands": "pink nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "flat chest",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "black Eden Academy uniform, gold trim",
|
|
||||||
"lower_body": "uniform skirt",
|
|
||||||
"footwear": "black shoes, white socks",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "black and gold hair cones"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "cute, academic, spy x family style",
|
|
||||||
"primary_color": "pink",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Spy x Family"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "biwa_hayahide_(Umamusume)",
|
|
||||||
"character_name": "Biwa Hayahide",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, horse ears, horse tail, tall",
|
|
||||||
"hair": "long grey hair, wild hair",
|
|
||||||
"eyes": "purple eyes, red framed glasses",
|
|
||||||
"expression": "thinking",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white shirt",
|
|
||||||
"outer_layer": "tracen school uniform",
|
|
||||||
"lower_body": "pleated skirt",
|
|
||||||
"footwear": "heeled shoes",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": ""
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "intellectual, cool",
|
|
||||||
"primary_color": "maroon",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "grey"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Umamusume"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "bulma",
|
|
||||||
"character_name": "Bulma Briefs",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "turquoise hair, ponytail",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "energetic smile",
|
|
||||||
"hands": "turquoise nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "black playboy bunny",
|
|
||||||
"lower_body": "pantyhose",
|
|
||||||
"footwear": "red high heels",
|
|
||||||
"gloves": "detatched cuffs",
|
|
||||||
"accessories": "red hair ribbon, dragon radar"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "retro-futuristic, anime, dragon ball style",
|
|
||||||
"primary_color": "pink",
|
|
||||||
"secondary_color": "turquoise",
|
|
||||||
"tertiary_color": "purple"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Dragon Ball"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "camilla_(fire_emblem)",
|
|
||||||
"character_name": "Camilla Nohr",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, curvaceous build, fair skin",
|
|
||||||
"hair": "long wavy lavender hair, hair covering one eye",
|
|
||||||
"eyes": "purple eyes",
|
|
||||||
"expression": "seductive smile",
|
|
||||||
"hands": "purple nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "black headband with horns"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "black armor, cleavage",
|
|
||||||
"lower_body": "black leggings, armored plates",
|
|
||||||
"footwear": "black armored boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "purple cape, large axe"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "dark fantasy, gothic, fire emblem style",
|
|
||||||
"primary_color": "black",
|
|
||||||
"secondary_color": "gold",
|
|
||||||
"tertiary_color": "purple"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Fire Emblem"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "cammy",
|
|
||||||
"character_name": "Cammy White",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, muscular build, fair skin",
|
|
||||||
"hair": "long blonde hair, twin braids",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "serious look",
|
|
||||||
"hands": "green nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "scar on left cheek, green camouflage paint on legs"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "green high-leg leotard",
|
|
||||||
"lower_body": "bare legs",
|
|
||||||
"footwear": "black combat boots, green socks",
|
|
||||||
"gloves": "red gauntlets",
|
|
||||||
"accessories": "red beret"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "military, athletic, street fighter style",
|
|
||||||
"primary_color": "green",
|
|
||||||
"secondary_color": "red",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Street Fighter"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "chun_li",
|
|
||||||
"character_name": "Chun-Li",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, muscular build, fair skin, asian",
|
|
||||||
"hair": "black hair, hair buns",
|
|
||||||
"eyes": "brown eyes",
|
|
||||||
"expression": "determined smile",
|
|
||||||
"hands": "blue nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "thick thighs",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "blue qipao, gold embroidery, white accents",
|
|
||||||
"lower_body": "brown tights",
|
|
||||||
"footwear": "white combat boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "white hair ribbons, spiked bracelets"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "chinese style",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Street Fighter"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "ciri",
|
|
||||||
"character_name": "Ciri",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, athletic build",
|
|
||||||
"hair": "ashen grey hair, messy bun",
|
|
||||||
"eyes": "emerald green eyes, mascara",
|
|
||||||
"expression": "determined look",
|
|
||||||
"hands": "green nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "scar over eye"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white blouse",
|
|
||||||
"outer_layer": "",
|
|
||||||
"lower_body": "brown leather trousers",
|
|
||||||
"footwear": "brown leather boots",
|
|
||||||
"gloves": "brown leather gloves",
|
|
||||||
"accessories": "silver sword on back, witcher medallion"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "gritty, fantasy, witcher style",
|
|
||||||
"primary_color": "white",
|
|
||||||
"secondary_color": "brown",
|
|
||||||
"tertiary_color": "silver"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"The Witcher 3"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "delinquent_mother_flim13",
|
|
||||||
"character_name": "Delinquent Mother",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, milf, gyaru, tall",
|
|
||||||
"hair": "blonde hair, long hair",
|
|
||||||
"eyes": "sharp eyes",
|
|
||||||
"expression": "smirk, sharp teeth",
|
|
||||||
"hands": "painted nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "very large breasts",
|
|
||||||
"pelvis": "wide hips",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "biege sweater, cleavage",
|
|
||||||
"outer_layer": "",
|
|
||||||
"lower_body": "pencil skirt",
|
|
||||||
"footwear": "high heels",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "necklace, rings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "gyaru, milf, pink leopard print",
|
|
||||||
"primary_color": "pink",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/Gyaru_mom_Flim13_IL_V1.safetensors",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Original","flim13"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "gold_city_(Umamusume)",
|
|
||||||
"character_name": "Gold City",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, horse ears, horse tail, tall",
|
|
||||||
"hair": "blonde hair, wavy hair",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "confident expression",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white shirt",
|
|
||||||
"outer_layer": "tracen school uniform",
|
|
||||||
"lower_body": "pleated skirt",
|
|
||||||
"footwear": "heeled shoes",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "choker, earrings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "fashionable, model",
|
|
||||||
"primary_color": "gold",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Umamusume"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "gold_ship_(Umamusume)",
|
|
||||||
"character_name": "Gold Ship",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, horse ears, horse tail, tall",
|
|
||||||
"hair": "grey hair, short hair",
|
|
||||||
"eyes": "red eyes",
|
|
||||||
"expression": "crazy expression, grin",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white shirt",
|
|
||||||
"outer_layer": "tracen school uniform",
|
|
||||||
"lower_body": "pleated skirt",
|
|
||||||
"footwear": "heeled shoes",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "ear covers, hat"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "energetic, sporty",
|
|
||||||
"primary_color": "red",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Umamusume"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "hatsune_miku",
|
|
||||||
"character_name": "Hatsune Miku",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "long turquoise hair, twin tails, floor-length",
|
|
||||||
"eyes": "turquoise eyes",
|
|
||||||
"expression": "cheerful smile",
|
|
||||||
"hands": "turquoise nails",
|
|
||||||
"arms": "01 tattoo on left shoulder",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "grey sleeveless shirt, turquoise tie",
|
|
||||||
"lower_body": "grey miniskirt, turquoise trim",
|
|
||||||
"footwear": "black thigh-high boots, turquoise trim",
|
|
||||||
"gloves": "black arm warmers, turquoise trim",
|
|
||||||
"accessories": "hair ornament, headset"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "vocaloid, futuristic, anime style",
|
|
||||||
"primary_color": "teal",
|
|
||||||
"secondary_color": "grey",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Vocaloid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "jessica_rabbit",
|
|
||||||
"character_name": "Jessica Rabbit",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, voluptuous build, tall,",
|
|
||||||
"hair": "long red hair, side part, hair over one eye",
|
|
||||||
"eyes": "green eyes, heavy makeup, purple eyeshadow",
|
|
||||||
"expression": "seductive smile",
|
|
||||||
"hands": "purple elbow gloves",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "narrow waist",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "red lips"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "red sequin dress, strapless, high slit, backless",
|
|
||||||
"lower_body": "side_slit,",
|
|
||||||
"footwear": "red high heels",
|
|
||||||
"gloves": "purple opera gloves",
|
|
||||||
"accessories": "gold earrings, glitter"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "noir, cartoon, glamorous",
|
|
||||||
"primary_color": "red",
|
|
||||||
"secondary_color": "purple",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Who Framed Roger Rabbit"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "jessie_(pokemon)",
|
|
||||||
"character_name": "Jessie",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "long magenta hair, curved back",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "arrogant smirk",
|
|
||||||
"hands": "white nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "green earrings"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black crop top",
|
|
||||||
"outer_layer": "white Team Rocket uniform jacket, bare stomach, red R logo",
|
|
||||||
"lower_body": "white miniskirt",
|
|
||||||
"footwear": "black thigh-high boots",
|
|
||||||
"gloves": "black elbow gloves",
|
|
||||||
"accessories": "green earrings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "villainous, anime, pokemon style",
|
|
||||||
"primary_color": "white",
|
|
||||||
"secondary_color": "magenta",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Pokemon"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "jinx_(league_of_legends)",
|
|
||||||
"character_name": "Jinx",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, pale skin,",
|
|
||||||
"hair": "long aqua hair, twin braids, very long hair, bangs",
|
|
||||||
"eyes": "pink eyes, ",
|
|
||||||
"expression": "crazy eyes, crazy smile",
|
|
||||||
"hands": "black and pink nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "flat chest,",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "cloud tattoo,"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "pink and black bikini, asymmetrical_bikini ",
|
|
||||||
"lower_body": "pink shorts, single pink stocking",
|
|
||||||
"footwear": "combat boots",
|
|
||||||
"gloves": "black fingerless gloves, fishnet elbow gloves,",
|
|
||||||
"accessories": "ammo belts, choker, bullet necklace,"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "punk, chaotic,",
|
|
||||||
"primary_color": "pink",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "aqua"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/jinx_default_lol-000021.safetensors",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"League of Legends"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "kagamine_rin",
|
|
||||||
"character_name": "Kagamine Rin",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, petite",
|
|
||||||
"hair": "blonde hair, short hair, hair bow",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "smile, energetic",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "detached sleeves",
|
|
||||||
"torso": "flat chest",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "leg warmers",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white shirt, sailor collar",
|
|
||||||
"outer_layer": "",
|
|
||||||
"lower_body": "black shorts, yellow belt",
|
|
||||||
"footwear": "white shoes",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "headset, hair bow"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "vocaloid, cyber",
|
|
||||||
"primary_color": "yellow",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Vocaloid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "kagari_atsuko",
|
|
||||||
"character_name": "Kagari Atsuko",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "long brown hair, half-ponytail, bangs",
|
|
||||||
"eyes": "red eyes",
|
|
||||||
"expression": "determined smile",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white shirt",
|
|
||||||
"outer_layer": "dark blue witch robes",
|
|
||||||
"lower_body": "dark blue skirt",
|
|
||||||
"footwear": "brown boots, white socks",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "pointed witch hat, brown belt, magic wand"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "fantasy, magical girl, little witch academia style",
|
|
||||||
"primary_color": "dark blue",
|
|
||||||
"secondary_color": "brown",
|
|
||||||
"tertiary_color": "red"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Little Witch Academia"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "k/da_all_out_ahri",
|
|
||||||
"character_name": "Ahri",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin, fox ears",
|
|
||||||
"hair": "long blonde hair, flowing",
|
|
||||||
"eyes": "yellow eyes",
|
|
||||||
"expression": "charming smile",
|
|
||||||
"hands": "silver nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "whisker markings on cheeks, crystal tails"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "silver crop top",
|
|
||||||
"outer_layer": "white and silver jacket",
|
|
||||||
"lower_body": "black leather shorts",
|
|
||||||
"footwear": "black thigh-high boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "crystal heart, silver jewelry"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "pop star, mystical, k/da style",
|
|
||||||
"primary_color": "silver",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "blue"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/KDA AhriIlluLoRA.safetensors",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"League of Legends", "K/DA", "KDA", "K-Pop"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "k/da_all_out_akali",
|
|
||||||
"character_name": "Akali",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, athletic build, fair skin",
|
|
||||||
"hair": "long dark blue hair, blonde streaks, high ponytail",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "cool, rebellious look",
|
|
||||||
"hands": "blue nails",
|
|
||||||
"arms": "tattoos on arms",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black crop top",
|
|
||||||
"outer_layer": "blue and silver motorcycle jacket",
|
|
||||||
"lower_body": "black leather pants",
|
|
||||||
"footwear": "blue sneakers",
|
|
||||||
"gloves": "black fingerless gloves",
|
|
||||||
"accessories": "kama and kunai"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "pop star, street, k/da style",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "purple",
|
|
||||||
"tertiary_color": "silver"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/KDAAkaliIlluLoRA.safetensors",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"League of Legends", "K/DA", "KDA", "K-Pop"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "k/da_all_out_evelynn",
|
|
||||||
"character_name": "Evelynn",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, curvaceous build, fair skin",
|
|
||||||
"hair": "light blue hair,",
|
|
||||||
"eyes": "yellow glowing eyes, slit pupils",
|
|
||||||
"expression": "seductive, confident look",
|
|
||||||
"hands": "metal claws",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "two long lashers (shadow tendrils)"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black leather bra",
|
|
||||||
"outer_layer": "iridescent blue jacket, fur collar",
|
|
||||||
"lower_body": "black leather skirt",
|
|
||||||
"footwear": "black high-heeled boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "diamond earrings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "pop star, glamorous, k/da style",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "purple",
|
|
||||||
"tertiary_color": "silver"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/KDA EvelynnIlluLoRA.safetensors",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"League of Legends", "K/DA", "KDA", "K-Pop"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "k/da_all_out_kai'sa",
|
|
||||||
"character_name": "Kai'Sa",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, athletic build, fair skin",
|
|
||||||
"hair": "long hair, purple hair, hair ornament, ponytail, green highlights",
|
|
||||||
"eyes": "purple eyes",
|
|
||||||
"expression": "focused expression",
|
|
||||||
"hands": "silver nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "silver bodysuit",
|
|
||||||
"outer_layer": "white and silver jacket",
|
|
||||||
"lower_body": "silver leggings",
|
|
||||||
"footwear": "silver high-heeled boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "crystal shoulder pods"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "pop star, futuristic, k/da style",
|
|
||||||
"primary_color": "silver",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "purple"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/KDA KaisaIlluLoRA.safetensors",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"League of Legends", "K/DA", "KDA", "K-Pop"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "komi_shouko",
|
|
||||||
"character_name": "Komi Shouko",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, pale skin, asian",
|
|
||||||
"hair": "long dark purple hair, hime cut,",
|
|
||||||
"eyes": "dark purple eyes,",
|
|
||||||
"expression": "neutral expression, stoic, cat ears",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "black pantyhose",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white shirt",
|
|
||||||
"outer_layer": "itan private high school uniform, blazer, striped bow tie",
|
|
||||||
"lower_body": "plaid skirt",
|
|
||||||
"footwear": "loafers",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": ""
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "anime, manga, clean lines",
|
|
||||||
"primary_color": "purple",
|
|
||||||
"secondary_color": "magenta",
|
|
||||||
"tertiary_color": "white"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": "komi shouko, itan private high school uniform"
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Komi Can't Communicate"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "lara_croft_classic",
|
|
||||||
"character_name": "Lara Croft",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, athletic build,",
|
|
||||||
"hair": "long brown hair, single braid",
|
|
||||||
"eyes": "brown eyes",
|
|
||||||
"expression": "light smile, raised eyebrow",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "teal tank top,",
|
|
||||||
"lower_body": "brown shorts",
|
|
||||||
"footwear": "brown combat boots, red laces",
|
|
||||||
"gloves": "black fingerless gloves",
|
|
||||||
"accessories": "dual thigh pistol holsters, brown leatherbackpack, red circular sunglasses"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "adventure, retro, 90s style",
|
|
||||||
"primary_color": "teal",
|
|
||||||
"secondary_color": "brown",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/LaraCroft_ClassicV2_Illu_Dwnsty.safetensors",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Tomb Raider"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "lisa_(genshin_impact)",
|
|
||||||
"character_name": "Lisa Minci",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, tall, mature female",
|
|
||||||
"hair": "brown hair, wavy hair, side ponytail",
|
|
||||||
"eyes": "green eyes",
|
|
||||||
"expression": "seductive smile",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "detached sleeves",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "wide hips",
|
|
||||||
"legs": "black pantyhose",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "beauty mark"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "purple dress, corset",
|
|
||||||
"outer_layer": "purple shawl",
|
|
||||||
"lower_body": "slit skirt",
|
|
||||||
"footwear": "black heels",
|
|
||||||
"gloves": "purple gloves",
|
|
||||||
"accessories": "witch hat, rose, necklace"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "genshin impact, witch, librarian",
|
|
||||||
"primary_color": "purple",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Genshin Impact"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "lulu (ff10)",
|
|
||||||
"character_name": "Lulu",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, curvaceous build, fair skin",
|
|
||||||
"hair": "long black hair, complex braids, hairpins",
|
|
||||||
"eyes": "red eyes",
|
|
||||||
"expression": "thinking, raised eyebrow",
|
|
||||||
"hands": "black nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "dark purple lipstick"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black corset",
|
|
||||||
"outer_layer": "black fur-trimmed dress, many belts on front",
|
|
||||||
"lower_body": "long skirt made of belts",
|
|
||||||
"footwear": "black boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "moogle doll, silver jewelry"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "gothic, ornate, final fantasy x style",
|
|
||||||
"primary_color": "black",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "purple"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/Lulu DG illuLoRA_1337272.safetensors",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Final Fantasy X"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "majin_android_21",
|
|
||||||
"character_name": "Majin Android 21",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, curvaceous build, pink skin",
|
|
||||||
"hair": "long voluminous white hair",
|
|
||||||
"eyes": "red eyes, black sclera",
|
|
||||||
"expression": "evil smile",
|
|
||||||
"hands": "black claws, pink nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "pink skin, long tail, pointy ears"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black tube top",
|
|
||||||
"outer_layer": "",
|
|
||||||
"lower_body": "white harem pants",
|
|
||||||
"footwear": "black and yellow boots",
|
|
||||||
"gloves": "black sleeves",
|
|
||||||
"accessories": "gold bracelets, gold neck ring, hoop earrings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "supernatural, anime, dragon ball style",
|
|
||||||
"primary_color": "pink",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Dragon Ball FighterZ"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "marin_kitagawa",
|
|
||||||
"character_name": "Marin Kitagawa",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin, asian",
|
|
||||||
"hair": "long blonde hair, pink tips",
|
|
||||||
"eyes": "pink eyes (contacts)",
|
|
||||||
"expression": "excited smile",
|
|
||||||
"hands": "long pink nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "piercings"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "white school shirt, loosely tied blue tie",
|
|
||||||
"lower_body": "blue plaid miniskirt",
|
|
||||||
"footwear": "black loafers, black socks",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "choker, various bracelets"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "gyaru, modern, anime style",
|
|
||||||
"primary_color": "white",
|
|
||||||
"secondary_color": "blue",
|
|
||||||
"tertiary_color": "pink"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"My Dress-Up Darling"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "megurine_luka",
|
|
||||||
"character_name": "Megurine Luka",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, tall, mature female",
|
|
||||||
"hair": "pink hair, long hair",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "light smile",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "crop top, detached sleeves, gold trim",
|
|
||||||
"lower_body": "side slit, lace-up skirt",
|
|
||||||
"footwear": "thinghighs, lace-up boots, gold boots, gold armlet",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "headset"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "vocaloid, elegant",
|
|
||||||
"primary_color": "black",
|
|
||||||
"secondary_color": "gold",
|
|
||||||
"tertiary_color": "pink"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Vocaloid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "meiko",
|
|
||||||
"character_name": "Meiko",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, mature female",
|
|
||||||
"hair": "brown hair, short hair",
|
|
||||||
"eyes": "brown eyes",
|
|
||||||
"expression": "smile, confident",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "red crop top, sleeveless",
|
|
||||||
"outer_layer": "",
|
|
||||||
"lower_body": "red skirt, mini skirt",
|
|
||||||
"footwear": "brown boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "choker"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "vocaloid, casual",
|
|
||||||
"primary_color": "red",
|
|
||||||
"secondary_color": "brown",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Vocaloid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "nessa",
|
|
||||||
"character_name": "Nessa",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, athletic build, dark skin",
|
|
||||||
"hair": "long hair, light blue highlights",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "confident smile",
|
|
||||||
"hands": "blue nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "blue earrings"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white and blue bikini top",
|
|
||||||
"outer_layer": "gym uniform, number 049",
|
|
||||||
"lower_body": "white and blue shorts",
|
|
||||||
"footwear": "blue and white sandals",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "wristband, life buoy, pokeball"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "sporty, aquatic, pokemon style",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "orange"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Pokemon"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "olivier_mira_armstrong",
|
|
||||||
"character_name": "Olivier Mira Armstrong",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, tall, mature female",
|
|
||||||
"hair": "blonde hair, long hair, hair over one eye",
|
|
||||||
"eyes": "blue eyes, sharp eyes",
|
|
||||||
"expression": "serious",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "thick lips"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black shirt",
|
|
||||||
"outer_layer": "blue military coat, fur collar",
|
|
||||||
"lower_body": "black pants",
|
|
||||||
"footwear": "black boots",
|
|
||||||
"gloves": "black gloves",
|
|
||||||
"accessories": "sword"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "military, amestris uniform",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Fullmetal Alchemist"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "princess_peach",
|
|
||||||
"character_name": "Princess Peach",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "long blonde hair, voluminous, crown",
|
|
||||||
"eyes": "blue eyes, long eyelashes",
|
|
||||||
"expression": "gentle smile",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "pink lips, blue earrings"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white petticoat",
|
|
||||||
"outer_layer": "pink floor-length ball gown, puffy sleeves, dark pink panniers",
|
|
||||||
"lower_body": "long skirt",
|
|
||||||
"footwear": "red high heels",
|
|
||||||
"gloves": "white opera gloves",
|
|
||||||
"accessories": "gold crown with red and blue jewels, blue brooch"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "royal, whimsical, nintendo style",
|
|
||||||
"primary_color": "pink",
|
|
||||||
"secondary_color": "gold",
|
|
||||||
"tertiary_color": "blue"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/Princess_Peach_Shiny_Style_V4.0_Illustrious_1652958.safetensors",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": "princess peach, crown, pink dress, shiny skin, royal elegance"
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Super Mario"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "princess_zelda_botw",
|
|
||||||
"character_name": "Princess Zelda",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin, pointed ears",
|
|
||||||
"hair": "long blonde hair, braided, gold hair clips",
|
|
||||||
"eyes": "green eyes",
|
|
||||||
"expression": "curious",
|
|
||||||
"hands": "gold nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "tri-force symbol, elf ears"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "blue tunic",
|
|
||||||
"outer_layer": "blue champion's tunic, brown leather belts",
|
|
||||||
"lower_body": "tan trousers",
|
|
||||||
"footwear": "brown leather boots",
|
|
||||||
"gloves": "brown fingerless gloves",
|
|
||||||
"accessories": "sheikah slate, gold jewelry"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "fantasy, adventurous, zelda style",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "gold",
|
|
||||||
"tertiary_color": "brown"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"The Legend of Zelda"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "rice_shower_(Umamusume)",
|
|
||||||
"character_name": "Rice Shower",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, petite, horse ears, horse tail",
|
|
||||||
"hair": "long dark brown hair, bangs, hair over one eye",
|
|
||||||
"eyes": "purple eyes",
|
|
||||||
"expression": "shy expression",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white shirt",
|
|
||||||
"outer_layer": "tracen school uniform",
|
|
||||||
"lower_body": "pleated skirt",
|
|
||||||
"footwear": "heeled shoes",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "blue rose, hair flower, small hat, dagger"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "gothic lolita, elegant",
|
|
||||||
"primary_color": "purple",
|
|
||||||
"secondary_color": "blue",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Umamusume"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "riju",
|
|
||||||
"character_name": "Riju",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, young, dark skin, gerudo",
|
|
||||||
"hair": "short red hair, braided ponytail, gold hair ornament",
|
|
||||||
"eyes": "green eyes",
|
|
||||||
"expression": "serious",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "darkblue lipstick,"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "black top, blue sash",
|
|
||||||
"lower_body": "black skirt, pelvic curtain,",
|
|
||||||
"footwear": "gold high heels",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "gold jewelry, earrings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "fantasy, desert, gerudo style",
|
|
||||||
"primary_color": "gold",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "red"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"The Legend of Zelda"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "rosalina",
|
|
||||||
"character_name": "Rosalina",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, tall, slender build, fair skin",
|
|
||||||
"hair": "long platinum blonde hair, side-swept bangs covering one eye",
|
|
||||||
"eyes": "light blue eyes",
|
|
||||||
"expression": "serene expression",
|
|
||||||
"hands": "turquoise nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "star-shaped earrings"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "turquoise off-the-shoulder gown, silver trim",
|
|
||||||
"lower_body": "long skirt",
|
|
||||||
"footwear": "silver high heels",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "silver crown with blue jewels, star wand, luma"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "celestial, elegant, nintendo style",
|
|
||||||
"primary_color": "turquoise",
|
|
||||||
"secondary_color": "silver",
|
|
||||||
"tertiary_color": "yellow"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Super Mario"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "rouge_the_bat",
|
|
||||||
"character_name": "Rouge the Bat",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, anthro, bat girl, white fur",
|
|
||||||
"hair": "short white hair",
|
|
||||||
"eyes": "teal eyes",
|
|
||||||
"expression": "sly smirk",
|
|
||||||
"hands": "white gloves",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "bat wings, eyeshadow"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "black skin-tight jumpsuit, pink heart-shaped chest plate, bare shoulders, cleavage",
|
|
||||||
"lower_body": "jumpsuit",
|
|
||||||
"footwear": "white boots, pink heart motifs",
|
|
||||||
"gloves": "white gloves, pink cuffs",
|
|
||||||
"accessories": "blue eyeshadow"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "jewels, museum,sleek, spy, sonic style",
|
|
||||||
"primary_color": "white",
|
|
||||||
"secondary_color": "pink",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "Illustrious/Looks/Rouge_the_bat_v2.safetensors",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Sonic the Hedgehog"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "ryouko_(tenchi_muyou!)",
|
|
||||||
"character_name": "Ryouko Hakubi",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slim build,",
|
|
||||||
"hair": "long teal hair, spiky, voluminous",
|
|
||||||
"eyes": "golden eyes, cat-like pupils",
|
|
||||||
"expression": "confident smirk",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "red gem on forehead,"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "long white dress, plunging neckline, black belt",
|
|
||||||
"outer_layer": "black and orange long sleeve jacket with purple trim,",
|
|
||||||
"lower_body": "side_slit,, red trousers",
|
|
||||||
"footwear": "",
|
|
||||||
"gloves": "red gloves",
|
|
||||||
"accessories": "red gems, wristbands"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "90s anime, sci-fi",
|
|
||||||
"primary_color": "teal",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "red"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": "ryouko hakubi, space pirate"
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Tenchi Muyou!", "Tenchi Muyo!"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "samus_aran",
|
|
||||||
"character_name": "Samus Aran",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, athletic build, fair skin",
|
|
||||||
"hair": "long blonde hair, ponytail",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "serious expression",
|
|
||||||
"hands": "blue nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "beauty mark on chin"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "blue skin-tight bodysuit, pink symbols",
|
|
||||||
"lower_body": "bodysuit",
|
|
||||||
"footwear": "blue high-heeled boots",
|
|
||||||
"gloves": "zero suit",
|
|
||||||
"accessories": "paralyzer pistol"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "sci-fi, sleek, metroid style",
|
|
||||||
"primary_color": "blue",
|
|
||||||
"secondary_color": "pink",
|
|
||||||
"tertiary_color": "yellow"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Metroid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "sarah_miller_(the_last_of_us)",
|
|
||||||
"character_name": "Sarah Miller",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, loli, small build",
|
|
||||||
"hair": "blonde hair, short hair",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "smile",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "flat chest",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "grey t-shirt, white shirt",
|
|
||||||
"outer_layer": "",
|
|
||||||
"lower_body": "blue jeans",
|
|
||||||
"footwear": "sneakers",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "wristwatch"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "casual, 2013 fashion",
|
|
||||||
"primary_color": "grey",
|
|
||||||
"secondary_color": "blue",
|
|
||||||
"tertiary_color": "white"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"The Last of Us"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "shantae",
|
|
||||||
"character_name": "Shantae",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, dark skin, pointy ears",
|
|
||||||
"hair": "purple hair, very long hair, ponytail",
|
|
||||||
"eyes": "blue eyes",
|
|
||||||
"expression": "smile, energetic",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "gold bracelets",
|
|
||||||
"torso": "small breasts, perky breasts",
|
|
||||||
"pelvis": "wide hips",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "red bikini top, red harem pants, gold trim",
|
|
||||||
"lower_body": "",
|
|
||||||
"footwear": "gold shoes",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "gold tiara, hoop earrings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "genie, dancer, arabian",
|
|
||||||
"primary_color": "red",
|
|
||||||
"secondary_color": "gold",
|
|
||||||
"tertiary_color": "purple"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Shantae"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "sucy_manbavaran",
|
|
||||||
"character_name": "Sucy Manbavaran",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, lanky build, pale skin",
|
|
||||||
"hair": "light purple hair, hair covering one eye",
|
|
||||||
"eyes": "red eyes",
|
|
||||||
"expression": "deadpan expression",
|
|
||||||
"hands": "black nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "narrow waist",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "dark circles under eyes"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "dark purple witch robes",
|
|
||||||
"lower_body": "long skirt with frayed edges",
|
|
||||||
"footwear": "brown boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "pointed witch hat, potion bottle"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "gothic, whimsical, little witch academia style",
|
|
||||||
"primary_color": "purple",
|
|
||||||
"secondary_color": "mauve",
|
|
||||||
"tertiary_color": "green"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Little Witch Academia"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "tifa_lockhart",
|
|
||||||
"character_name": "Tifa Lockhart",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, athletic build, fair skin",
|
|
||||||
"hair": "long black hair, tied end",
|
|
||||||
"eyes": "red eyes",
|
|
||||||
"expression": "kind smile",
|
|
||||||
"hands": "dark red nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "black sports bra",
|
|
||||||
"outer_layer": "white tank top, black suspenders",
|
|
||||||
"lower_body": "black miniskirt",
|
|
||||||
"footwear": "red boots, black socks",
|
|
||||||
"gloves": "red fingerless gloves",
|
|
||||||
"accessories": "silver earrings"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "urban, martial arts, final fantasy style",
|
|
||||||
"primary_color": "white",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "red"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Final Fantasy VII"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "tracer",
|
|
||||||
"character_name": "Tracer",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "short spiky brown hair",
|
|
||||||
"eyes": "brown eyes",
|
|
||||||
"expression": "energetic smile",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "freckles"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "orange leggings",
|
|
||||||
"outer_layer": "brown flight jacket, yellow vest",
|
|
||||||
"lower_body": "orange leggings",
|
|
||||||
"footwear": "white and orange sneakers",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "chronal accelerator, yellow goggles"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "sci-fi, pilot, overwatch style",
|
|
||||||
"primary_color": "orange",
|
|
||||||
"secondary_color": "brown",
|
|
||||||
"tertiary_color": "white"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Overwatch"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "urbosa",
|
|
||||||
"character_name": "Urbosa",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, tall, muscular, dark skin, gerudo",
|
|
||||||
"hair": "long red hair, wild hair",
|
|
||||||
"eyes": "green eyes",
|
|
||||||
"expression": "confident",
|
|
||||||
"hands": "gold nails",
|
|
||||||
"arms": "muscular arms",
|
|
||||||
"torso": "abs, mediumS breasts",
|
|
||||||
"pelvis": "wide hips",
|
|
||||||
"legs": "muscular legs",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "dark blue lipstick, gerudo markings"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "blue top, blue champion's skirt, green sash, green shoulder guards,",
|
|
||||||
"lower_body": "blue skirt",
|
|
||||||
"footwear": "gold heels",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "gold jewelry, scimitar"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "fantasy, warrior, gerudo style",
|
|
||||||
"primary_color": "gold",
|
|
||||||
"secondary_color": "blue",
|
|
||||||
"tertiary_color": "red"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"The Legend of Zelda"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "widowmaker",
|
|
||||||
"character_name": "Widowmaker",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, blue skin",
|
|
||||||
"hair": "long purple hair, ponytail",
|
|
||||||
"eyes": "yellow eyes",
|
|
||||||
"expression": "cold expression",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "spider tattoo on arm",
|
|
||||||
"torso": "large breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "blue skin"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "purple tactical bodysuit, plunging neckline",
|
|
||||||
"lower_body": "bodysuit",
|
|
||||||
"footwear": "purple high-heeled boots",
|
|
||||||
"gloves": "purple gauntlets",
|
|
||||||
"accessories": "sniper visor, grappling hook"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "sci-fi, assassin, overwatch style",
|
|
||||||
"primary_color": "purple",
|
|
||||||
"secondary_color": "black",
|
|
||||||
"tertiary_color": "pink"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Overwatch"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "yor_briar",
|
|
||||||
"character_name": "Yor Briar",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "long black hair, styled with gold headband",
|
|
||||||
"eyes": "red eyes",
|
|
||||||
"expression": "gentle yet mysterious smile",
|
|
||||||
"hands": "black nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "medium breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "black backless halter dress, red rose pattern inside",
|
|
||||||
"lower_body": "black thigh-high boots",
|
|
||||||
"footwear": "black boots",
|
|
||||||
"gloves": "black fingerless gloves",
|
|
||||||
"accessories": "gold rose-themed headband, gold needle weapons"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "elegant, assassin, spy x family style",
|
|
||||||
"primary_color": "black",
|
|
||||||
"secondary_color": "red",
|
|
||||||
"tertiary_color": "gold"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Spy x Family"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "y'shtola_rhul",
|
|
||||||
"character_name": "Y'shtola Rhul",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, miqo'te, slender build, fair skin, cat ears",
|
|
||||||
"hair": "short white hair, bangs",
|
|
||||||
"eyes": "blind, white eyes",
|
|
||||||
"expression": "stoic expression",
|
|
||||||
"hands": "black nails",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "facial markings, cat tail"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "black sorceress robes, fur trim",
|
|
||||||
"lower_body": "long skirt",
|
|
||||||
"footwear": "black boots",
|
|
||||||
"gloves": "",
|
|
||||||
"accessories": "wooden staff"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "magical, scholarly, final fantasy xiv style",
|
|
||||||
"primary_color": "black",
|
|
||||||
"secondary_color": "white",
|
|
||||||
"tertiary_color": "purple"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Final Fantasy XIV"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "yuffie_kisaragi",
|
|
||||||
"character_name": "Yuffie Kisaragi",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender build, fair skin",
|
|
||||||
"hair": "short black hair, bob cut",
|
|
||||||
"eyes": "brown eyes",
|
|
||||||
"expression": "playful grin",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "black sleeve on one arm",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": "headband"
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "",
|
|
||||||
"outer_layer": "green turtleneck sweater vest, midriff",
|
|
||||||
"lower_body": "beige shorts",
|
|
||||||
"footwear": "boots, socks",
|
|
||||||
"gloves": "fingerless glove on one hand, large gauntlet on one arm",
|
|
||||||
"accessories": "shuriken"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "ninja, adventurer, final fantasy style",
|
|
||||||
"primary_color": "green",
|
|
||||||
"secondary_color": "beige",
|
|
||||||
"tertiary_color": "black"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 1.0,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Final Fantasy VII"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"character_id": "yuna_(ff10)",
|
|
||||||
"character_name": "Yuna",
|
|
||||||
"identity": {
|
|
||||||
"base_specs": "1girl, slender, fair skin",
|
|
||||||
"hair": "short brown hair, bob cut",
|
|
||||||
"eyes": "heterochromia, blue eye, green eye",
|
|
||||||
"expression": "gentle",
|
|
||||||
"hands": "",
|
|
||||||
"arms": "",
|
|
||||||
"torso": "small breasts",
|
|
||||||
"pelvis": "",
|
|
||||||
"legs": "",
|
|
||||||
"feet": "",
|
|
||||||
"distinguishing_marks": ""
|
|
||||||
},
|
|
||||||
"wardrobe": {
|
|
||||||
"inner_layer": "white kimono top, yellow obi",
|
|
||||||
"outer_layer": "",
|
|
||||||
"lower_body": "long blue skirt, floral pattern",
|
|
||||||
"footwear": "boots",
|
|
||||||
"gloves": "detached sleeves",
|
|
||||||
"accessories": "summoner staff, necklace"
|
|
||||||
},
|
|
||||||
"styles": {
|
|
||||||
"aesthetic": "fantasy, final fantasy x style",
|
|
||||||
"primary_color": "white",
|
|
||||||
"secondary_color": "blue",
|
|
||||||
"tertiary_color": "yellow"
|
|
||||||
},
|
|
||||||
"lora": {
|
|
||||||
"lora_name": "",
|
|
||||||
"lora_weight": 0.8,
|
|
||||||
"lora_triggers": ""
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Final Fantasy X"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"ckpt_name": "Noob/oneObsession_v19Atypical.safetensors"
|
"ckpt_name": ""
|
||||||
},
|
},
|
||||||
"class_type": "CheckpointLoaderSimple"
|
"class_type": "CheckpointLoaderSimple"
|
||||||
},
|
},
|
||||||
@@ -169,5 +169,45 @@
|
|||||||
"clip": ["4", 1]
|
"clip": ["4", 1]
|
||||||
},
|
},
|
||||||
"class_type": "LoraLoader"
|
"class_type": "LoraLoader"
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"inputs": {
|
||||||
|
"lora_name": "",
|
||||||
|
"strength_model": 0.8,
|
||||||
|
"strength_clip": 0.8,
|
||||||
|
"model": ["16", 0],
|
||||||
|
"clip": ["16", 1]
|
||||||
|
},
|
||||||
|
"class_type": "LoraLoader"
|
||||||
|
},
|
||||||
|
"18": {
|
||||||
|
"inputs": {
|
||||||
|
"lora_name": "",
|
||||||
|
"strength_model": 1.0,
|
||||||
|
"strength_clip": 1.0,
|
||||||
|
"model": ["17", 0],
|
||||||
|
"clip": ["17", 1]
|
||||||
|
},
|
||||||
|
"class_type": "LoraLoader"
|
||||||
|
},
|
||||||
|
"19": {
|
||||||
|
"inputs": {
|
||||||
|
"lora_name": "",
|
||||||
|
"strength_model": 1.0,
|
||||||
|
"strength_clip": 1.0,
|
||||||
|
"model": ["18", 0],
|
||||||
|
"clip": ["18", 1]
|
||||||
|
},
|
||||||
|
"class_type": "LoraLoader"
|
||||||
|
},
|
||||||
|
"20": {
|
||||||
|
"inputs": {
|
||||||
|
"lora_name": "",
|
||||||
|
"strength_model": 1.0,
|
||||||
|
"strength_clip": 1.0,
|
||||||
|
"model": ["19", 0],
|
||||||
|
"clip": ["19", 1]
|
||||||
|
},
|
||||||
|
"class_type": "LoraLoader"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
data/actions/3p_sex_000037.json
Normal file
24
data/actions/3p_sex_000037.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "3p_sex_000037",
|
||||||
|
"action_name": "3P Sex 000037",
|
||||||
|
"action": {
|
||||||
|
"base": "threesome, group_sex, 3_people",
|
||||||
|
"head": "blush, half-closed_eyes, sweat",
|
||||||
|
"upper_body": "nude, reaching",
|
||||||
|
"lower_body": "sex, spread_legs, intercourse",
|
||||||
|
"hands": "groping",
|
||||||
|
"feet": "toes_curled",
|
||||||
|
"additional": "panting, orgasm, sweat"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/3P_SEX-000037.safetensors",
|
||||||
|
"lora_weight": 0.8,
|
||||||
|
"lora_triggers": "threesome, group_sex",
|
||||||
|
"lora_weight_min": 0.8,
|
||||||
|
"lora_weight_max": 0.8
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "threesome",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/4p_sex.json
Normal file
24
data/actions/4p_sex.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "4p_sex",
|
||||||
|
"action_name": "4P Sex",
|
||||||
|
"action": {
|
||||||
|
"base": "group_sex, foursome, 4p, multiple_partners, sexual_act",
|
||||||
|
"head": "moaning, open_mouth, closed_eyes, ahegao, heart_eyes, heavy_breathing, flushed_face, sweat",
|
||||||
|
"upper_body": "nude, arching_back, standing_on_all_fours, breasts_press, breast_grab, fingers_in_mouth",
|
||||||
|
"lower_body": "vaginal_intercourse, anal_intercourse, double_penetration, legs_apart, kneeing, missionary_position",
|
||||||
|
"hands": "breast_fondling, clutching_sheets, on_partner, touching_self",
|
||||||
|
"feet": "toes_curled, barefoot",
|
||||||
|
"additional": "bodily_fluids, semen, sweat, messy, erotic, intimate"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/4P_sex.safetensors",
|
||||||
|
"lora_weight": 0.6,
|
||||||
|
"lora_triggers": "4P_sexV1",
|
||||||
|
"lora_weight_min": 0.6,
|
||||||
|
"lora_weight_max": 0.6
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "4people",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "_malebolgia__oral_sex_tounge_afterimage_concept_2_0_illustrious",
|
||||||
|
"action_name": "Malebolgia Oral Sex Tounge Afterimage Concept 2 0 Illustrious",
|
||||||
|
"action": {
|
||||||
|
"base": "kneeling, leaning_forward, oral_sex",
|
||||||
|
"head": "looking_up, mouth_open, intense_expression, half-closed_eyes",
|
||||||
|
"upper_body": "forward_bend, reaching_forward",
|
||||||
|
"lower_body": "kneeling, legs_spread",
|
||||||
|
"hands": "grabbing_partner, hand_on_thigh",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "afterimage, motion_blur, multiple_tongues, speed_lines, saliva_drool"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/[Malebolgia] Oral Sex Tounge Afterimage Concept 2.0 Illustrious.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "[Malebolgia] Oral Sex Tounge Afterimage Concept 2.0 Illustrious",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "actually_reliable_penis_kissing_3_variants_illustrious",
|
||||||
|
"action_name": "Actually Reliable Penis Kissing 3 Variants Illustrious",
|
||||||
|
"action": {
|
||||||
|
"base": "kneeling, fellatio, oral sex, kissing penis",
|
||||||
|
"head": "eyes closed, half-closed eyes, looking up, kissing, tongue",
|
||||||
|
"upper_body": "arched back, leaning forward",
|
||||||
|
"lower_body": "kneeling",
|
||||||
|
"hands": "holding penis, hand on thigh",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "saliva, slime, connection"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/Actually_Reliable_Penis_Kissing_3_Variants_Illustrious.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "Actually_Reliable_Penis_Kissing_3_Variants_Illustrious",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "after_sex_fellatio_illustriousxl_lora_nochekaiser_r1",
|
||||||
|
"action_name": "After Sex Fellatio Illustriousxl Lora Nochekaiser R1",
|
||||||
|
"action": {
|
||||||
|
"base": "1girl, 1boy, completely_nude, lying, on_back, spread_legs",
|
||||||
|
"head": "looking_at_viewer, tongue, open_mouth, blush, disheveled_hair, half-closed_eyes",
|
||||||
|
"upper_body": "on_bed, large_breasts, nipples, sweat",
|
||||||
|
"lower_body": "pussy, cum_in_pussy, leaking_cum, knees_up, thighs_apart",
|
||||||
|
"hands": "on_bed",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "after_sex, fellatio, penis, cum, cum_drip, messy_body, sweat, bed_sheet"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/after-sex-fellatio-illustriousxl-lora-nochekaiser_r1.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "after sex fellatio",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/afterfellatio_ill.json
Normal file
24
data/actions/afterfellatio_ill.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "afterfellatio_ill",
|
||||||
|
"action_name": "Afterfellatio Ill",
|
||||||
|
"action": {
|
||||||
|
"base": "kneeling, leaning_forward, pov",
|
||||||
|
"head": "looking_at_viewer, blush, tilted_head, cum_on_face, half-closed_eyes, tears, messy_makeup",
|
||||||
|
"upper_body": "arms_down, reaching_towards_viewer",
|
||||||
|
"lower_body": "kneeling",
|
||||||
|
"hands": "hands_on_penis",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "cum, cum_string, cum_in_mouth, closed_mouth, stringy_cum"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/afterfellatio_ill.safetensors",
|
||||||
|
"lora_weight": 0.8,
|
||||||
|
"lora_triggers": "after fellatio, cum in mouth, closed mouth, cum string",
|
||||||
|
"lora_weight_min": 0.8,
|
||||||
|
"lora_weight_max": 0.8
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/afteroral.json
Normal file
24
data/actions/afteroral.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "afteroral",
|
||||||
|
"action_name": "Afteroral",
|
||||||
|
"action": {
|
||||||
|
"base": "after_fellatio, post-coital, flushed_face, messy_appearance",
|
||||||
|
"head": "messy_hair, panting, heavy_breathing, half-closed_eyes, dazed, pupil_dilated, flushed, sweat",
|
||||||
|
"upper_body": "smeared_lipstick, runny_makeup, saliva, saliva_trail, cum_on_face, cum_on_mouth, excessive_cum",
|
||||||
|
"lower_body": "",
|
||||||
|
"hands": "hands_near_face, curled_fingers",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "after_fellatio, cum_drip, mess"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/afteroral.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "after oral, after deepthroat",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/afterpaizuri.json
Normal file
28
data/actions/afterpaizuri.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "afterpaizuri",
|
||||||
|
"action_name": "Afterpaizuri",
|
||||||
|
"action": {
|
||||||
|
"base": "kneeling, sitting, exhausted, post-coital, afterpaizuri",
|
||||||
|
"head": "flushed, messy_hair, panting, mouth_open, tongue_out, half-closed_eyes, dazed, looking_at_viewer",
|
||||||
|
"upper_body": "bare_shoulders, cleavage, semen_on_breasts, disheveled_clothes, bra_removed_under_clothes",
|
||||||
|
"lower_body": "kneeling, thighs_together, buttocks_on_heels",
|
||||||
|
"hands": "hands_on_lap",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "semen_on_face, heavy_breathing, sweat, moisture, viscous_liquid, creamy_fluid"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "F"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/afterpaizuri.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "afterpaizuri",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/aftersexbreakv2.json
Normal file
24
data/actions/aftersexbreakv2.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "aftersexbreakv2",
|
||||||
|
"action_name": "Aftersexbreakv2",
|
||||||
|
"action": {
|
||||||
|
"base": "lying, on_back, on_bed, bowlegged_pose, spread_legs, twisted_torso",
|
||||||
|
"head": "messy_hair, head_back, sweaty, rolling_eyes, half-closed_eyes, ahegao",
|
||||||
|
"upper_body": "arms_spread, arms_above_head, sweat, naked, collarbone, heavy_breathing",
|
||||||
|
"lower_body": "hips, navel, female_pubic_hair, spread_legs, legs_up, bent_legs",
|
||||||
|
"hands": "relaxed_hands",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "condom_wrapper, used_tissue, stained_sheets, cum_on_bed, sweat_bead"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/AfterSexBreakV2.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "aftersexbreak, after sex, male sitting",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/against_glass_bs.json
Normal file
28
data/actions/against_glass_bs.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "against_glass_bs",
|
||||||
|
"action_name": "Against Glass Bs",
|
||||||
|
"action": {
|
||||||
|
"base": "against_glass, leaning_forward, pressed_against_surface, glass_surface",
|
||||||
|
"head": "face_pressed, cheek_press, breath_on_glass, looking_at_viewer, intimate_gaze",
|
||||||
|
"upper_body": "chest_pressed_against_glass, leaning_into_glass",
|
||||||
|
"lower_body": "hips_pushed_forward, standing",
|
||||||
|
"hands": "hands_on_glass, palms_on_glass, fingers_spread",
|
||||||
|
"feet": "standing",
|
||||||
|
"additional": "condensation, translucent_surface, distortion"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/Against_glass_bs.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "Against_glass_bs",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/amateur_pov_filming.json
Normal file
24
data/actions/amateur_pov_filming.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "amateur_pov_filming",
|
||||||
|
"action_name": "Amateur Pov Filming",
|
||||||
|
"action": {
|
||||||
|
"base": "pov, selfie, solo, indoors, recording, smartphone, holding_phone",
|
||||||
|
"head": "looking_at_viewer, blush, open_mouth",
|
||||||
|
"upper_body": "upper_body, breasts, nipples",
|
||||||
|
"lower_body": "hips",
|
||||||
|
"hands": "holding_phone, holding_id_card",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "mirror_selfie, amateur_aesthetic"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/Amateur_POV_Filming.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "Homemade_PornV1, recording, pov, prostitution",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/arch_back_sex_v1_1_illustriousxl.json
Normal file
24
data/actions/arch_back_sex_v1_1_illustriousxl.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "arch_back_sex_v1_1_illustriousxl",
|
||||||
|
"action_name": "Arch Back Sex V1 1 Illustriousxl",
|
||||||
|
"action": {
|
||||||
|
"base": "doggystyle, sex_from_behind, all_fours",
|
||||||
|
"head": "head_back, looking_back, closed_eyes, blush",
|
||||||
|
"upper_body": "arms_support, arched_back",
|
||||||
|
"lower_body": "lifted_hip, kneeling, spread_legs",
|
||||||
|
"hands": "grabbing_butt",
|
||||||
|
"feet": "toes",
|
||||||
|
"additional": "kiss, sweat, saliva, intense_pleasure"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/arch-back-sex-v1.1-illustriousxl.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "kiss, arched_back, sex_from_behind",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/arm_grab_missionary_ill_10.json
Normal file
24
data/actions/arm_grab_missionary_ill_10.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "arm_grab_missionary_ill_10",
|
||||||
|
"action_name": "Arm Grab Missionary Ill 10",
|
||||||
|
"action": {
|
||||||
|
"base": "missionary, lying, on_back, sex, vaginal_sex",
|
||||||
|
"head": "blushing, open_mouth, one_eye_closed, looking_at_viewer, dilated_pupils",
|
||||||
|
"upper_body": "arms_above_head, pinned, restrained, grabbed_wrists, breasts, nipples, medium_breasts",
|
||||||
|
"lower_body": "legs_spread, lifted_pelvis, spread_legs, legs_up, knees_up",
|
||||||
|
"hands": "interlocked_fingers, holding_hands",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "faceless_male, sweat, motion_lines"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/arm_grab_missionary_ill-10.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "arm_grab_missionary",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/ballsdeep_il_v2_2_s.json
Normal file
24
data/actions/ballsdeep_il_v2_2_s.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "ballsdeep_il_v2_2_s",
|
||||||
|
"action_name": "Ballsdeep Il V2 2 S",
|
||||||
|
"action": {
|
||||||
|
"base": "sexual_intercourse, deep_penetration, thrusting, mating_press, from_behind, doggy_style, missionary, cowgirl_position",
|
||||||
|
"head": "eyes_rolled_back, closed_eyes, open_mouth, flushed_face, sweat, expressionless, intense_expression",
|
||||||
|
"upper_body": "arched_back, hands_on_own_body, grabbing, fingers_clenched, sweating",
|
||||||
|
"lower_body": "joined_genitals, spread_legs, wrap_legs, hips_thrusting, stomach_bulge, testicles_pressed",
|
||||||
|
"hands": "finger_clutch, gripping",
|
||||||
|
"feet": "curled_toes",
|
||||||
|
"additional": "intense, deep_pen, skin_on_skin"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/BallsDeep-IL-V2.2-S.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "deep penetration",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/bathingtogether.json
Normal file
24
data/actions/bathingtogether.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "bathingtogether",
|
||||||
|
"action_name": "Bathingtogether",
|
||||||
|
"action": {
|
||||||
|
"base": "bathing, sitting, partially_submerged, bathtub",
|
||||||
|
"head": "looking_at_viewer, eye_contact",
|
||||||
|
"upper_body": "bare_shoulders, skin_to_skin, arms_around_each_other",
|
||||||
|
"lower_body": "underwater, knees_up",
|
||||||
|
"hands": "hands_on_body",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "bubbles, water, steam, wet, wet_hair, mirror_reflection"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/bathingtogether.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "bathing together",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "2girls",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/before_after_1230829.json
Normal file
24
data/actions/before_after_1230829.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action": {
|
||||||
|
"base": "2koma, side-by-side, comparison",
|
||||||
|
"head": "facial, cum_on_face, messy_face, eyes_closed, mouth_open, orgasm",
|
||||||
|
"upper_body": "semi-nude, messy, cum_on_breasts",
|
||||||
|
"lower_body": "",
|
||||||
|
"hands": "hands_on_head",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "cum, close-up, ejaculation"
|
||||||
|
},
|
||||||
|
"action_id": "before_after_1230829",
|
||||||
|
"action_name": "Before After 1230829",
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/before_after_1230829.safetensors",
|
||||||
|
"lora_triggers": "before_after",
|
||||||
|
"lora_weight": 0.9,
|
||||||
|
"lora_weight_max": 0.7,
|
||||||
|
"lora_weight_min": 0.6
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/belly_dancing.json
Normal file
28
data/actions/belly_dancing.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "belly_dancing",
|
||||||
|
"action_name": "Belly Dancing",
|
||||||
|
"action": {
|
||||||
|
"base": "belly_dancing, dancing, standing",
|
||||||
|
"head": "",
|
||||||
|
"upper_body": "arms_up",
|
||||||
|
"lower_body": "swaying",
|
||||||
|
"hands": "own_hands_together",
|
||||||
|
"feet": "",
|
||||||
|
"additional": ""
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "false",
|
||||||
|
"orientation": "F"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/bentback.json
Normal file
24
data/actions/bentback.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "bentback",
|
||||||
|
"action_name": "Bentback",
|
||||||
|
"action": {
|
||||||
|
"base": "bent_over, from_behind, arched_back",
|
||||||
|
"head": "looking_back, looking_at_viewer",
|
||||||
|
"upper_body": "twisted_torso, arms_at_sides",
|
||||||
|
"lower_body": "ass_focus, kneepits, spread_legs",
|
||||||
|
"hands": "hands_on_legs",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "leaning_forward"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/BentBack.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "bentback, kneepits",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/blowjobcomicpart2.json
Normal file
24
data/actions/blowjobcomicpart2.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "blowjobcomicpart2",
|
||||||
|
"action_name": "Blowjobcomicpart2",
|
||||||
|
"action": {
|
||||||
|
"base": "3koma, comic_strip, sequence, vertical_strip",
|
||||||
|
"head": "tongue_out, open_mouth, saliva, empty_eyes, rolled_eyes",
|
||||||
|
"upper_body": "arms_at_sides, torso, standing_on_knees",
|
||||||
|
"lower_body": "sexual_activity, kneeling",
|
||||||
|
"hands": "hands_on_penis, grasping",
|
||||||
|
"feet": "out_of_frame",
|
||||||
|
"additional": "fellatio, irrumatio, licking, ejaculation, cum_in_mouth, excessive_cum"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/BlowjobComicPart2.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "bjmcut",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/bodybengirl.json
Normal file
24
data/actions/bodybengirl.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "bodybengirl",
|
||||||
|
"action_name": "Bodybengirl",
|
||||||
|
"action": {
|
||||||
|
"base": "suspended_congress, lifted_by_torso, torso_grab",
|
||||||
|
"head": "",
|
||||||
|
"upper_body": "arms_up, bent_over",
|
||||||
|
"lower_body": "legs_up",
|
||||||
|
"hands": "",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "1boy, 1girl, size_difference, loli"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/BodyBenGirl.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "bentstand-behind",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1boy 1girl",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/bodybengirlpart2.json
Normal file
24
data/actions/bodybengirlpart2.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "bodybengirlpart2",
|
||||||
|
"action_name": "Bodybengirlpart2",
|
||||||
|
"action": {
|
||||||
|
"base": "suspended, from_side, bent_over, torso_grab",
|
||||||
|
"head": "embarrassed, sweating, scared, mouth_open, looking_away, downcast",
|
||||||
|
"upper_body": "arms_at_sides, limp_arms",
|
||||||
|
"lower_body": "legs_dangling, knees_together, bare_feet, feet_dangling",
|
||||||
|
"hands": "open_hands, limp_hands",
|
||||||
|
"feet": "bare_feet, dangling",
|
||||||
|
"additional": "motion_lines, sweat_drops"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/BodyBenGirlPart2.safetensors",
|
||||||
|
"lora_weight": 0.9,
|
||||||
|
"lora_triggers": "bentstand-behind, dangling legs, dangling arms, from_side, arms hanging down, torso_grab, suspended",
|
||||||
|
"lora_weight_min": 0.9,
|
||||||
|
"lora_weight_max": 0.9
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/bored_retrain_000115_1336316.json
Normal file
28
data/actions/bored_retrain_000115_1336316.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "bored_retrain_000115_1336316",
|
||||||
|
"action_name": "Bored Retrain 000115 1336316",
|
||||||
|
"action": {
|
||||||
|
"base": "bored, slouching, leaning_forward, ennui, uninterested",
|
||||||
|
"head": "head_on_hand, blank_stare, half-lidded_eyes",
|
||||||
|
"upper_body": "slumped, leaning_forward, sitting, arms_crossed",
|
||||||
|
"lower_body": "sitting, legs_crossed",
|
||||||
|
"hands": "hand_on_cheek, hand_on_chin",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "sighing, waiting"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/Bored_Retrain-000115_1336316.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "Bored_Retrain-000115_1336316",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/breast_pressh.json
Normal file
24
data/actions/breast_pressh.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "breast_pressh",
|
||||||
|
"action_name": "Breast Pressh",
|
||||||
|
"action": {
|
||||||
|
"base": "1boy, 2girls, sandwiched, standing, height_difference, size_difference",
|
||||||
|
"head": "head_between_breasts, face_between_breasts, cheek_squash",
|
||||||
|
"upper_body": "breast_press, hugging, arms_around_waist, chest_to_chest",
|
||||||
|
"lower_body": "hips_touching, legs_apart",
|
||||||
|
"hands": "hands_on_back",
|
||||||
|
"feet": "barefoot",
|
||||||
|
"additional": "hetero, multiple_girls"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/breast_pressH.safetensors",
|
||||||
|
"lora_weight": 0.6,
|
||||||
|
"lora_triggers": "breast_pressH",
|
||||||
|
"lora_weight_min": 0.6,
|
||||||
|
"lora_weight_max": 0.6
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1boy 2girls",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "breast_smother_illustriousxl_lora_nochekaiser",
|
||||||
|
"action_name": "Breast Smother Illustriousxl Lora Nochekaiser",
|
||||||
|
"action": {
|
||||||
|
"base": "breast_smother, face_in_cleavage, intimate, (POV:1.2), side_view",
|
||||||
|
"head": "looking_down, half-closed_eyes, affectionate, dominant",
|
||||||
|
"upper_body": "large_breasts, cleavage, squished_breasts, hugging, embracing, chest_press",
|
||||||
|
"lower_body": "close_contact, standing",
|
||||||
|
"hands": "cradling_head, fingers_in_hair, pressing_head_to_breasts",
|
||||||
|
"feet": "barefoot, feet_on_ground",
|
||||||
|
"additional": "skin_compression, soft_lighting, motorboating"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/breast-smother-illustriousxl-lora-nochekaiser.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "breast-smother-illustriousxl-lora-nochekaiser",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "breast_sucking_fingering_illustriousxl_lora_nochekaiser",
|
||||||
|
"action_name": "Breast Sucking Fingering Illustriousxl Lora Nochekaiser",
|
||||||
|
"action": {
|
||||||
|
"base": "duo, sex, sexual_intercourse, close-up, breast_sucking, fingering, intimate_embrace",
|
||||||
|
"head": "face_buried_in_breasts, sucking_nipple, nipples_suck, saliva, eyes_closed, heavy_breathing, blush, expression_of_bliss",
|
||||||
|
"upper_body": "reaching_down, holding_partner, arm_around_waist, large_breasts, exposed_breasts, nude_torso, pressing_bodies",
|
||||||
|
"lower_body": "legs_spread, pussy_exposed, vaginal_fingering, m_legs, intertwined_legs",
|
||||||
|
"hands": "fingering, fingers_inside, clitoris_rubbing, squeezing_breasts, groping",
|
||||||
|
"feet": "toes_curled, relaxed_feet",
|
||||||
|
"additional": "saliva_trail, sweat, sweat_drop, uncensored"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/breast-sucking-fingering-illustriousxl-lora-nochekaiser.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "breast-sucking-fingering-illustriousxl-lora-nochekaiser",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/brokenglass_illusxl_incrs_v1.json
Normal file
28
data/actions/brokenglass_illusxl_incrs_v1.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "brokenglass_illusxl_incrs_v1",
|
||||||
|
"action_name": "Brokenglass Illusxl Incrs V1",
|
||||||
|
"action": {
|
||||||
|
"base": "breaking_through_barrier, dynamic_pose, impact_frame, dynamic_angle",
|
||||||
|
"head": "intense_expression, facial_focus, visible_through_glass",
|
||||||
|
"upper_body": "reaching_towards_viewer, twisted_torso, arms_extended",
|
||||||
|
"lower_body": "dynamic_pose, movement",
|
||||||
|
"hands": "hands_up, touching_glass, debris_interaction",
|
||||||
|
"feet": "grounded, dynamic",
|
||||||
|
"additional": "broken_glass, glass_shards, shattered, spiderweb_cracks, cinematic_lighting, refraction, debris, explosive_impact"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "F"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/BrokenGlass_illusXL_Incrs_v1.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "BrokenGlass_illusXL_Incrs_v1",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/butt_smother_ag_000043.json
Normal file
28
data/actions/butt_smother_ag_000043.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "butt_smother_ag_000043",
|
||||||
|
"action_name": "Butt Smother Ag 000043",
|
||||||
|
"action": {
|
||||||
|
"base": "1girl, 1boy, facesitting, pov, first-person_view, dominant_woman, submissive_man",
|
||||||
|
"head": "looking_down, looking_away, half-closed_eyes, seductive_expression, facial_expression",
|
||||||
|
"upper_body": "arms_behind_back, arched_back, upper_body_lean",
|
||||||
|
"lower_body": "buttocks, ass_focus, heavy_buttocks, spread_legs, kneeling, thighs_straddling",
|
||||||
|
"hands": "hands_on_thighs, hands_on_head",
|
||||||
|
"feet": "feet_together, curled_toes",
|
||||||
|
"additional": "extreme_close-up, squashed, muffling, soft_lighting, skin_texture"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/Butt_smother_ag-000043.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "Butt_smother_ag-000043",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/buttjob.json
Normal file
28
data/actions/buttjob.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "buttjob",
|
||||||
|
"action_name": "Buttjob",
|
||||||
|
"action": {
|
||||||
|
"base": "buttjob, intercrural_sex, sex_positions",
|
||||||
|
"head": "",
|
||||||
|
"upper_body": "bent_over",
|
||||||
|
"lower_body": "buttjob, genitals_between_buttocks",
|
||||||
|
"hands": "hands_on_own_thighs",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "missionary_position"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "MF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/buttjob.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "buttjob",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/carwashv2.json
Normal file
24
data/actions/carwashv2.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "carwashv2",
|
||||||
|
"action_name": "Carwashv2",
|
||||||
|
"action": {
|
||||||
|
"base": "washing_vehicle, bending_over, suggestive_pose",
|
||||||
|
"head": "wet_hair",
|
||||||
|
"upper_body": "wet_clothes, breast_press, cleavage, breasts_on_glass",
|
||||||
|
"lower_body": "",
|
||||||
|
"hands": "holding_sponge, holding_hose",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "car, motor_vehicle, soap_bubbles, wet, water_splashing"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/CarWashV2.safetensors",
|
||||||
|
"lora_weight": 0.8,
|
||||||
|
"lora_triggers": "w4sh1n, w4sh0ut",
|
||||||
|
"lora_weight_min": 0.8,
|
||||||
|
"lora_weight_max": 0.8
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/cat_stretchill.json
Normal file
24
data/actions/cat_stretchill.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "cat_stretchill",
|
||||||
|
"action_name": "Cat Stretchill",
|
||||||
|
"action": {
|
||||||
|
"base": "cat_stretch, pose, all_fours",
|
||||||
|
"head": "head_down, looking_at_viewer, closed_eyes",
|
||||||
|
"upper_body": "arched_back, outstretched_arms, chest_support, hands_on_ground",
|
||||||
|
"lower_body": "hips_up, buttocks_up, kneeling, knees_on_ground",
|
||||||
|
"hands": "palms_down",
|
||||||
|
"feet": "feet_up",
|
||||||
|
"additional": "trembling, cat_tail, cat_ears"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/cat_stretchILL.safetensors",
|
||||||
|
"lora_weight": 0.7,
|
||||||
|
"lora_triggers": "stretching, cat stretch, downward dog, trembling",
|
||||||
|
"lora_weight_min": 0.7,
|
||||||
|
"lora_weight_max": 0.7
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/charm_person_magic.json
Normal file
24
data/actions/charm_person_magic.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "charm_person_magic",
|
||||||
|
"action_name": "Charm Person Magic",
|
||||||
|
"action": {
|
||||||
|
"base": "casting_spell, magic_circle, spell_casting",
|
||||||
|
"head": "smile, confident_expression, glowing_eyes, looking_at_viewer",
|
||||||
|
"upper_body": "outstretched_hand, reaching_towards_viewer, arms_up, upper_body",
|
||||||
|
"lower_body": "",
|
||||||
|
"hands": "open_hand, hand_gesture",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "aura, light_particles, glittering, magical_energy"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/charm_person_magic.safetensors",
|
||||||
|
"lora_weight": 0.7,
|
||||||
|
"lora_triggers": "charm_person_(magic), cham_aura",
|
||||||
|
"lora_weight_min": 0.7,
|
||||||
|
"lora_weight_max": 0.7
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/cheekbulge.json
Normal file
24
data/actions/cheekbulge.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "cheekbulge",
|
||||||
|
"action_name": "Cheekbulge",
|
||||||
|
"action": {
|
||||||
|
"base": "fellatio",
|
||||||
|
"head": "cheek_bulge, head_tilt, saliva, penis_in_mouth, fellatio, looking_up, mouth_fill",
|
||||||
|
"upper_body": "arms_behind_back, upper_body",
|
||||||
|
"lower_body": "kneeling, kneeling_position",
|
||||||
|
"hands": "hands_on_head",
|
||||||
|
"feet": "plantar_flexion",
|
||||||
|
"additional": "deepthroat, pov, penis, male_focus"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/cheekbulge.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "cheek bulge, male pov",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/chokehold.json
Normal file
24
data/actions/chokehold.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "chokehold",
|
||||||
|
"action_name": "Chokehold",
|
||||||
|
"action": {
|
||||||
|
"base": "rear_naked_choke, from_behind, struggling, kneeling",
|
||||||
|
"head": "head_back, open_mouth, rolling_eyes, teardrops, veins, suffocation, air_hunger",
|
||||||
|
"upper_body": "arm_around_neck, struggling, grabbing_arm, posture_leaned_forward, arched_back",
|
||||||
|
"lower_body": "kneeling, bent_over, spread_legs",
|
||||||
|
"hands": "clenched_hands, struggling",
|
||||||
|
"feet": "barefoot, toes_curled",
|
||||||
|
"additional": "distress, blushing, drooling, saliva, sweat"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/chokehold.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "choke hold",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/cleavageteasedwnsty_000008.json
Normal file
24
data/actions/cleavageteasedwnsty_000008.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "cleavageteasedwnsty_000008",
|
||||||
|
"action_name": "Cleavageteasedwnsty 000008",
|
||||||
|
"action": {
|
||||||
|
"base": "leaning_forward, sexually_suggestive",
|
||||||
|
"head": "looking_at_viewer, smile, blush, one_eye_closed, blue_eyes",
|
||||||
|
"upper_body": "arms_bent_at_elbows, cleavage, breasts_squeezed_together, areola_slip, bare_shoulders, collarbone",
|
||||||
|
"lower_body": "",
|
||||||
|
"hands": "hands_on_own_chest, pulling_down_clothes, adjusting_clothes",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "teasing, undressing"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/CleavageTeaseDwnsty-000008.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "pulling down own clothes, teasing",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/closeup_facial_illus.json
Normal file
24
data/actions/closeup_facial_illus.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action": {
|
||||||
|
"base": "close-up, portrait, face_focus",
|
||||||
|
"head": "open_mouth, tongue, saliva, blush, looking_at_viewer, eyes_visible",
|
||||||
|
"upper_body": "",
|
||||||
|
"lower_body": "",
|
||||||
|
"hands": "",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "cum, messy, fluids"
|
||||||
|
},
|
||||||
|
"action_id": "closeup_facial_illus",
|
||||||
|
"action_name": "Closeup Facial Illus",
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/Closeup_Facial_iLLus.safetensors",
|
||||||
|
"lora_triggers": "Closeup Facial",
|
||||||
|
"lora_weight": 1,
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/cof.json
Normal file
28
data/actions/cof.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "cof",
|
||||||
|
"action_name": "Cum on Figure",
|
||||||
|
"action": {
|
||||||
|
"base": "faux_figurine, miniature, cum_on_body",
|
||||||
|
"head": "cum_on_face",
|
||||||
|
"upper_body": "",
|
||||||
|
"lower_body": "",
|
||||||
|
"hands": "",
|
||||||
|
"feet": "",
|
||||||
|
"additional": "cum, excessive_cum"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "true",
|
||||||
|
"orientation": "F"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/cof.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "cof",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
28
data/actions/cooperative_grinding.json
Normal file
28
data/actions/cooperative_grinding.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "cooperative_grinding",
|
||||||
|
"action_name": "Cooperative Grinding",
|
||||||
|
"action": {
|
||||||
|
"base": "duo, standing, lift_and_carry, straddling, legs_wrapped_around_waist, physical_contact",
|
||||||
|
"head": "head_thrown_back, blushing, panting, eyes_closed, half-closed_eyes, rolled_back_eyes, expressionless_pleasure",
|
||||||
|
"upper_body": "arms_around_neck, holding_buttocks, supporting_thighs, chest_to_chest, close_embrace",
|
||||||
|
"lower_body": "hips_touching, grinding, mating_press, pelvic_curtain, thighs_spread, lifted_legs",
|
||||||
|
"hands": "grabbing, gripping_back, squeezing",
|
||||||
|
"feet": "arched_toes, dangling_feet",
|
||||||
|
"additional": "sweat, motion_lines, intimate, sexual_intercourse, erotic"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "false",
|
||||||
|
"orientation": "MFF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/cooperative_grinding.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "cooperative_grinding",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1boy 2girls",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/cooperativepaizuri.json
Normal file
24
data/actions/cooperativepaizuri.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "cooperativepaizuri",
|
||||||
|
"action_name": "Cooperativepaizuri",
|
||||||
|
"action": {
|
||||||
|
"base": "cooperative_paizuri, 2girls, 1boy, sexual_activity, sex_position",
|
||||||
|
"head": "smile, open_mouth, facial, looking_at_partner, eyes_closed, flushed",
|
||||||
|
"upper_body": "arms_around_neck, breasts_between_breasts, large_breasts, cleavage, nipple_tweaking",
|
||||||
|
"lower_body": "penis, glans, erection, kneeling, straddling, cowgirl_position",
|
||||||
|
"hands": "holding_penis, touching_partner, reaching_for_partner",
|
||||||
|
"feet": "barefoot, toes_curled",
|
||||||
|
"additional": "pov, cum_on_body, fluids, (multiple_girls:1.2), erotic, masterpiece"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/cooperativepaizuri.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "cooperative paizuri",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "2girls 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/covering_privates_illustrious_v1_0.json
Normal file
24
data/actions/covering_privates_illustrious_v1_0.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "covering_privates_illustrious_v1_0",
|
||||||
|
"action_name": "Covering Privates Illustrious V1 0",
|
||||||
|
"action": {
|
||||||
|
"base": "covering_genitals, covering_breasts",
|
||||||
|
"head": "blush, embarrassed, looking_at_viewer",
|
||||||
|
"upper_body": "arms_crossed, covering_breasts, upper_body",
|
||||||
|
"lower_body": "legs_together, hips",
|
||||||
|
"hands": "covering_crotch",
|
||||||
|
"feet": "standing",
|
||||||
|
"additional": "modesty"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/covering privates_illustrious_V1.0.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "covering privates, covering crotch, covering breasts",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
data/actions/coveringownmouth_ill_v1.json
Normal file
24
data/actions/coveringownmouth_ill_v1.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"action_id": "coveringownmouth_ill_v1",
|
||||||
|
"action_name": "Coveringownmouth Ill V1",
|
||||||
|
"action": {
|
||||||
|
"base": "covering_own_mouth, solo",
|
||||||
|
"head": "hand_over_mouth",
|
||||||
|
"upper_body": "arm_raised",
|
||||||
|
"lower_body": "variable",
|
||||||
|
"hands": "palm_inward",
|
||||||
|
"feet": "variable",
|
||||||
|
"additional": "pensive, shy, embarrassed, surprise"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/CoveringOwnMouth_Ill_V1.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "covering_own_mouth",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "solo",
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"action_id": "cowgirl_position_breast_press_illustriousxl_lora_nochekaiser",
|
||||||
|
"action_name": "Cowgirl Position Breast Press Illustriousxl Lora Nochekaiser",
|
||||||
|
"action": {
|
||||||
|
"base": "straddling, pov, on_top, leaning_forward",
|
||||||
|
"head": "looking_at_viewer, intense_gaze, half-closed_eyes",
|
||||||
|
"upper_body": "arms_extended, breasts_pressed_against_viewer, breast_squish, cleavage",
|
||||||
|
"lower_body": "spread_legs, knees_up, straddling_partner",
|
||||||
|
"hands": "on_man's_chest, hand_on_partner",
|
||||||
|
"feet": "out_of_frame",
|
||||||
|
"additional": "breast_deformation, intimate, close-up, first-person_view"
|
||||||
|
},
|
||||||
|
"participants": {
|
||||||
|
"solo_focus": "false",
|
||||||
|
"orientation": "MFF"
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"lora_name": "Illustrious/Poses/cowgirl-position-breast-press-illustriousxl-lora-nochekaiser.safetensors",
|
||||||
|
"lora_weight": 1.0,
|
||||||
|
"lora_triggers": "cowgirl-position-breast-press-illustriousxl-lora-nochekaiser",
|
||||||
|
"lora_weight_min": 1.0,
|
||||||
|
"lora_weight_max": 1.0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"participants": "1girl 1boy",
|
||||||
|
"nsfw": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user