Updated generation pages.
This commit is contained in:
@@ -12,6 +12,8 @@ def register_routes(app):
|
||||
from routes import looks
|
||||
from routes import presets
|
||||
from routes import generator
|
||||
from routes import quick
|
||||
from routes import multi_char
|
||||
from routes import gallery
|
||||
from routes import strengths
|
||||
from routes import transfer
|
||||
@@ -28,6 +30,8 @@ def register_routes(app):
|
||||
looks.register_routes(app)
|
||||
presets.register_routes(app)
|
||||
generator.register_routes(app)
|
||||
quick.register_routes(app)
|
||||
multi_char.register_routes(app)
|
||||
gallery.register_routes(app)
|
||||
strengths.register_routes(app)
|
||||
transfer.register_routes(app)
|
||||
|
||||
@@ -213,11 +213,12 @@ def register_routes(app):
|
||||
combined_data['participants'] = action_obj.data.get('participants', {}) # Add participants
|
||||
|
||||
# Aggregate pose-related fields into 'pose'
|
||||
pose_fields = ['full_body', 'arms', 'hands', 'torso', 'pelvis', 'legs', 'feet']
|
||||
pose_fields = ['base', 'upper_body', 'lower_body', 'hands', 'feet']
|
||||
pose_parts = [action_data.get(k) for k in pose_fields if action_data.get(k)]
|
||||
|
||||
# Aggregate expression-related fields into 'expression'
|
||||
expression_parts = [action_data.get(k) for k in ['head', 'eyes'] if action_data.get(k)]
|
||||
expression_parts = [action_data.get('head', '')]
|
||||
expression_parts = [p for p in expression_parts if p]
|
||||
|
||||
combined_data['defaults'] = {
|
||||
'pose': ", ".join(pose_parts),
|
||||
@@ -245,12 +246,13 @@ def register_routes(app):
|
||||
# Fallback to sensible defaults if still empty (no checkboxes and no action defaults)
|
||||
selected_fields = ['special::name', 'defaults::pose', 'defaults::expression']
|
||||
# Add identity fields
|
||||
for key in ['base_specs', 'hair', 'eyes']:
|
||||
for key in ['base', 'head']:
|
||||
if character.data.get('identity', {}).get(key):
|
||||
selected_fields.append(f'identity::{key}')
|
||||
# Add wardrobe fields
|
||||
from utils import _WARDROBE_KEYS
|
||||
wardrobe = character.get_active_wardrobe()
|
||||
for key in ['full_body', 'headwear', 'top', 'bottom', 'legwear', 'footwear', 'hands', 'gloves', 'accessories']:
|
||||
for key in _WARDROBE_KEYS:
|
||||
if wardrobe.get(key):
|
||||
selected_fields.append(f'wardrobe::{key}')
|
||||
|
||||
@@ -261,11 +263,12 @@ def register_routes(app):
|
||||
action_data = action_obj.data.get('action', {})
|
||||
|
||||
# Aggregate pose-related fields into 'pose'
|
||||
pose_fields = ['full_body', 'arms', 'hands', 'torso', 'pelvis', 'legs', 'feet']
|
||||
pose_fields = ['base', 'upper_body', 'lower_body', 'hands', 'feet']
|
||||
pose_parts = [action_data.get(k) for k in pose_fields if action_data.get(k)]
|
||||
|
||||
# Aggregate expression-related fields into 'expression'
|
||||
expression_parts = [action_data.get(k) for k in ['head', 'eyes'] if action_data.get(k)]
|
||||
expression_parts = [action_data.get('head', '')]
|
||||
expression_parts = [p for p in expression_parts if p]
|
||||
|
||||
combined_data = {
|
||||
'character_id': action_obj.action_id,
|
||||
@@ -312,7 +315,7 @@ def register_routes(app):
|
||||
|
||||
# Identity
|
||||
ident = extra_char.data.get('identity', {})
|
||||
for key in ['base_specs', 'hair', 'eyes', 'extra']:
|
||||
for key in ['base', 'head', 'additional']:
|
||||
val = ident.get(key)
|
||||
if val:
|
||||
# Remove 1girl/solo
|
||||
@@ -320,8 +323,9 @@ def register_routes(app):
|
||||
extra_parts.append(val)
|
||||
|
||||
# Wardrobe (active outfit)
|
||||
from utils import _WARDROBE_KEYS
|
||||
wardrobe = extra_char.get_active_wardrobe()
|
||||
for key in ['top', 'headwear', 'legwear', 'footwear', 'accessories']:
|
||||
for key in _WARDROBE_KEYS:
|
||||
val = wardrobe.get(key)
|
||||
if val:
|
||||
extra_parts.append(val)
|
||||
@@ -531,8 +535,8 @@ def register_routes(app):
|
||||
"action_id": safe_slug,
|
||||
"action_name": name,
|
||||
"action": {
|
||||
"full_body": "", "head": "", "eyes": "", "arms": "", "hands": "",
|
||||
"torso": "", "pelvis": "", "legs": "", "feet": "", "additional": ""
|
||||
"base": "", "head": "", "upper_body": "", "lower_body": "",
|
||||
"hands": "", "feet": "", "additional": ""
|
||||
},
|
||||
"lora": {"lora_name": "", "lora_weight": 1.0, "lora_triggers": ""},
|
||||
"tags": []
|
||||
|
||||
@@ -295,14 +295,13 @@ Create an outfit JSON with wardrobe fields appropriate for this character."""
|
||||
# Ensure required fields
|
||||
if 'wardrobe' not in outfit_data:
|
||||
outfit_data['wardrobe'] = {
|
||||
"full_body": "",
|
||||
"headwear": "",
|
||||
"top": "",
|
||||
"bottom": "",
|
||||
"legwear": "",
|
||||
"footwear": "",
|
||||
"base": "",
|
||||
"head": "",
|
||||
"upper_body": "",
|
||||
"lower_body": "",
|
||||
"hands": "",
|
||||
"accessories": ""
|
||||
"feet": "",
|
||||
"additional": ""
|
||||
}
|
||||
if 'lora' not in outfit_data:
|
||||
outfit_data['lora'] = {
|
||||
@@ -392,16 +391,13 @@ Do NOT include a wardrobe section - the outfit is handled separately."""
|
||||
"character_id": safe_slug,
|
||||
"character_name": name,
|
||||
"identity": {
|
||||
"base_specs": prompt,
|
||||
"hair": "",
|
||||
"eyes": "",
|
||||
"base": prompt,
|
||||
"head": "",
|
||||
"upper_body": "",
|
||||
"lower_body": "",
|
||||
"hands": "",
|
||||
"arms": "",
|
||||
"torso": "",
|
||||
"pelvis": "",
|
||||
"legs": "",
|
||||
"feet": "",
|
||||
"extra": ""
|
||||
"additional": ""
|
||||
},
|
||||
"defaults": {
|
||||
"expression": "",
|
||||
@@ -631,8 +627,8 @@ Do NOT include a wardrobe section - the outfit is handled separately."""
|
||||
|
||||
# Create new outfit (copy from default as template)
|
||||
default_outfit = wardrobe.get('default', {
|
||||
'headwear': '', 'top': '', 'legwear': '',
|
||||
'footwear': '', 'hands': '', 'accessories': ''
|
||||
'base': '', 'head': '', 'upper_body': '', 'lower_body': '',
|
||||
'hands': '', 'feet': '', 'additional': ''
|
||||
})
|
||||
wardrobe[safe_name] = default_outfit.copy()
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ def register_routes(app):
|
||||
combined_data = character.data.copy()
|
||||
combined_data['character_id'] = character.character_id
|
||||
selected_fields = []
|
||||
for key in ['base_specs', 'hair', 'eyes']:
|
||||
for key in ['base', 'head']:
|
||||
if character.data.get('identity', {}).get(key):
|
||||
selected_fields.append(f'identity::{key}')
|
||||
selected_fields.append('special::name')
|
||||
wardrobe = character.get_active_wardrobe()
|
||||
for key in ['full_body', 'top', 'bottom']:
|
||||
for key in ['base', 'upper_body', 'lower_body']:
|
||||
if wardrobe.get(key):
|
||||
selected_fields.append(f'wardrobe::{key}')
|
||||
prompts = build_prompt(combined_data, selected_fields, None, active_outfit=character.active_outfit)
|
||||
|
||||
@@ -45,7 +45,7 @@ def register_routes(app):
|
||||
else:
|
||||
# Auto-include essential character fields (minimal set for batch/default generation)
|
||||
selected_fields = []
|
||||
for key in ['base_specs', 'hair', 'eyes']:
|
||||
for key in ['base', 'head']:
|
||||
if character.data.get('identity', {}).get(key):
|
||||
selected_fields.append(f'identity::{key}')
|
||||
selected_fields.append('special::name')
|
||||
|
||||
@@ -6,6 +6,7 @@ from services.prompts import build_prompt, build_extras_prompt
|
||||
from services.workflow import _prepare_workflow, _get_default_checkpoint
|
||||
from services.job_queue import _enqueue_job, _make_finalize
|
||||
from services.file_io import get_available_checkpoints
|
||||
from services.comfyui import get_loaded_checkpoint
|
||||
|
||||
logger = logging.getLogger('gaze')
|
||||
|
||||
@@ -25,6 +26,12 @@ def register_routes(app):
|
||||
if not checkpoints:
|
||||
checkpoints = ["Noob/oneObsession_v19Atypical.safetensors"]
|
||||
|
||||
# Default to whatever is currently loaded in ComfyUI, then settings default
|
||||
selected_ckpt = get_loaded_checkpoint()
|
||||
if not selected_ckpt:
|
||||
default_path, _ = _get_default_checkpoint()
|
||||
selected_ckpt = default_path
|
||||
|
||||
if request.method == 'POST':
|
||||
char_slug = request.form.get('character')
|
||||
checkpoint = request.form.get('checkpoint')
|
||||
@@ -63,9 +70,17 @@ def register_routes(app):
|
||||
if extras:
|
||||
combined = f"{combined}, {extras}"
|
||||
if custom_positive:
|
||||
combined = f"{combined}, {custom_positive}"
|
||||
combined = f"{custom_positive}, {combined}"
|
||||
prompts["main"] = combined
|
||||
|
||||
# Apply face/hand prompt overrides if provided
|
||||
override_face = request.form.get('override_face_prompt', '').strip()
|
||||
override_hand = request.form.get('override_hand_prompt', '').strip()
|
||||
if override_face:
|
||||
prompts["face"] = override_face
|
||||
if override_hand:
|
||||
prompts["hand"] = override_hand
|
||||
|
||||
# Parse optional seed
|
||||
seed_val = request.form.get('seed', '').strip()
|
||||
fixed_seed = int(seed_val) if seed_val else None
|
||||
@@ -103,7 +118,7 @@ def register_routes(app):
|
||||
|
||||
return render_template('generator.html', characters=characters, checkpoints=checkpoints,
|
||||
actions=actions, outfits=outfits, scenes=scenes,
|
||||
styles=styles, detailers=detailers)
|
||||
styles=styles, detailers=detailers, selected_ckpt=selected_ckpt)
|
||||
|
||||
@app.route('/generator/preview_prompt', methods=['POST'])
|
||||
def generator_preview_prompt():
|
||||
@@ -134,6 +149,6 @@ def register_routes(app):
|
||||
if extras:
|
||||
combined = f"{combined}, {extras}"
|
||||
if custom_positive:
|
||||
combined = f"{combined}, {custom_positive}"
|
||||
combined = f"{custom_positive}, {combined}"
|
||||
|
||||
return {'prompt': combined}
|
||||
return {'prompt': combined, 'face': prompts['face'], 'hand': prompts['hand']}
|
||||
|
||||
@@ -356,16 +356,13 @@ Character ID: {character_slug}"""
|
||||
"character_id": character_slug,
|
||||
"character_name": character_name,
|
||||
"identity": {
|
||||
"base_specs": lora_data.get('lora_triggers', ''),
|
||||
"hair": "",
|
||||
"eyes": "",
|
||||
"base": lora_data.get('lora_triggers', ''),
|
||||
"head": "",
|
||||
"upper_body": "",
|
||||
"lower_body": "",
|
||||
"hands": "",
|
||||
"arms": "",
|
||||
"torso": "",
|
||||
"pelvis": "",
|
||||
"legs": "",
|
||||
"feet": "",
|
||||
"extra": ""
|
||||
"additional": ""
|
||||
},
|
||||
"defaults": {
|
||||
"expression": "",
|
||||
@@ -373,14 +370,13 @@ Character ID: {character_slug}"""
|
||||
"scene": ""
|
||||
},
|
||||
"wardrobe": {
|
||||
"full_body": "",
|
||||
"headwear": "",
|
||||
"top": "",
|
||||
"bottom": "",
|
||||
"legwear": "",
|
||||
"footwear": "",
|
||||
"base": "",
|
||||
"head": "",
|
||||
"upper_body": "",
|
||||
"lower_body": "",
|
||||
"hands": "",
|
||||
"accessories": ""
|
||||
"feet": "",
|
||||
"additional": ""
|
||||
},
|
||||
"styles": {
|
||||
"aesthetic": "",
|
||||
|
||||
153
routes/multi_char.py
Normal file
153
routes/multi_char.py
Normal file
@@ -0,0 +1,153 @@
|
||||
import json
|
||||
import logging
|
||||
from flask import render_template, request, session
|
||||
from models import Character, Action, Style, Scene, Detailer, Checkpoint
|
||||
from services.prompts import build_multi_prompt, build_extras_prompt, _resolve_character
|
||||
from services.workflow import _prepare_workflow
|
||||
from services.job_queue import _enqueue_job, _make_finalize
|
||||
from services.file_io import get_available_checkpoints
|
||||
|
||||
logger = logging.getLogger('gaze')
|
||||
|
||||
|
||||
def register_routes(app):
|
||||
|
||||
@app.route('/multi', methods=['GET', 'POST'])
|
||||
def multi_char():
|
||||
characters = Character.query.order_by(Character.name).all()
|
||||
checkpoints = get_available_checkpoints()
|
||||
actions = Action.query.order_by(Action.name).all()
|
||||
scenes = Scene.query.order_by(Scene.name).all()
|
||||
styles = Style.query.order_by(Style.name).all()
|
||||
detailers = Detailer.query.order_by(Detailer.name).all()
|
||||
|
||||
if not checkpoints:
|
||||
checkpoints = ["Noob/oneObsession_v19Atypical.safetensors"]
|
||||
|
||||
if request.method == 'POST':
|
||||
char_a_slug = request.form.get('char_a')
|
||||
char_b_slug = request.form.get('char_b')
|
||||
checkpoint = request.form.get('checkpoint')
|
||||
custom_positive = request.form.get('positive_prompt', '')
|
||||
custom_negative = request.form.get('negative_prompt', '')
|
||||
|
||||
action_slugs = request.form.getlist('action_slugs')
|
||||
scene_slugs = request.form.getlist('scene_slugs')
|
||||
style_slugs = request.form.getlist('style_slugs')
|
||||
detailer_slugs = request.form.getlist('detailer_slugs')
|
||||
width = request.form.get('width') or 1024
|
||||
height = request.form.get('height') or 1024
|
||||
|
||||
char_a = _resolve_character(char_a_slug)
|
||||
char_b = _resolve_character(char_b_slug)
|
||||
|
||||
if not char_a or not char_b:
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
return {'error': 'Both characters must be selected'}, 400
|
||||
return render_template('multi_char.html', characters=characters, checkpoints=checkpoints,
|
||||
actions=actions, scenes=scenes, styles=styles, detailers=detailers)
|
||||
|
||||
sel_actions = Action.query.filter(Action.slug.in_(action_slugs)).all() if action_slugs else []
|
||||
sel_scenes = Scene.query.filter(Scene.slug.in_(scene_slugs)).all() if scene_slugs else []
|
||||
sel_styles = Style.query.filter(Style.slug.in_(style_slugs)).all() if style_slugs else []
|
||||
sel_detailers = Detailer.query.filter(Detailer.slug.in_(detailer_slugs)).all() if detailer_slugs else []
|
||||
|
||||
try:
|
||||
with open('comfy_workflow.json', 'r') as f:
|
||||
workflow = json.load(f)
|
||||
|
||||
# Build extras from mix-and-match selections
|
||||
extras = build_extras_prompt(sel_actions, [], sel_scenes, sel_styles, sel_detailers)
|
||||
if custom_positive:
|
||||
extras = f"{custom_positive}, {extras}" if extras else custom_positive
|
||||
|
||||
# Build multi-character prompt
|
||||
prompts = build_multi_prompt(char_a, char_b, extras_prompt=extras)
|
||||
|
||||
# Apply prompt overrides if provided
|
||||
override_main = request.form.get('override_prompt', '').strip()
|
||||
if override_main:
|
||||
prompts['main'] = override_main
|
||||
for key in ('char_a_main', 'char_b_main', 'char_a_face', 'char_b_face'):
|
||||
override = request.form.get(f'override_{key}', '').strip()
|
||||
if override:
|
||||
prompts[key] = override
|
||||
|
||||
# Parse optional seed
|
||||
seed_val = request.form.get('seed', '').strip()
|
||||
fixed_seed = int(seed_val) if seed_val else None
|
||||
|
||||
# Prepare workflow with both character LoRAs
|
||||
ckpt_obj = Checkpoint.query.filter_by(checkpoint_path=checkpoint).first() if checkpoint else None
|
||||
workflow = _prepare_workflow(
|
||||
workflow, char_a, prompts, checkpoint, custom_negative,
|
||||
action=sel_actions[0] if sel_actions else None,
|
||||
style=sel_styles[0] if sel_styles else None,
|
||||
detailer=sel_detailers[0] if sel_detailers else None,
|
||||
scene=sel_scenes[0] if sel_scenes else None,
|
||||
width=width,
|
||||
height=height,
|
||||
checkpoint_data=ckpt_obj.data if ckpt_obj else None,
|
||||
fixed_seed=fixed_seed,
|
||||
character_b=char_b,
|
||||
)
|
||||
|
||||
label = f"Multi: {char_a.name} + {char_b.name}"
|
||||
slug_pair = f"{char_a.slug}_{char_b.slug}"
|
||||
_finalize = _make_finalize('multi', slug_pair)
|
||||
job = _enqueue_job(label, workflow, _finalize)
|
||||
|
||||
# Save to session
|
||||
session['multi_char_a'] = char_a.slug
|
||||
session['multi_char_b'] = char_b.slug
|
||||
session.modified = True
|
||||
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
return {'status': 'queued', 'job_id': job['id']}
|
||||
|
||||
except Exception as e:
|
||||
logger.exception("Multi-char generation error: %s", e)
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
return {'error': str(e)}, 500
|
||||
|
||||
return render_template('multi_char.html', characters=characters, checkpoints=checkpoints,
|
||||
actions=actions, scenes=scenes, styles=styles, detailers=detailers,
|
||||
selected_char_a=session.get('multi_char_a', ''),
|
||||
selected_char_b=session.get('multi_char_b', ''))
|
||||
|
||||
@app.route('/multi/preview_prompt', methods=['POST'])
|
||||
def multi_preview_prompt():
|
||||
char_a_slug = request.form.get('char_a')
|
||||
char_b_slug = request.form.get('char_b')
|
||||
if not char_a_slug or not char_b_slug:
|
||||
return {'error': 'Both characters must be selected'}, 400
|
||||
|
||||
char_a = _resolve_character(char_a_slug)
|
||||
char_b = _resolve_character(char_b_slug)
|
||||
if not char_a or not char_b:
|
||||
return {'error': 'Character not found'}, 404
|
||||
|
||||
action_slugs = request.form.getlist('action_slugs')
|
||||
scene_slugs = request.form.getlist('scene_slugs')
|
||||
style_slugs = request.form.getlist('style_slugs')
|
||||
detailer_slugs = request.form.getlist('detailer_slugs')
|
||||
custom_positive = request.form.get('positive_prompt', '')
|
||||
|
||||
sel_actions = Action.query.filter(Action.slug.in_(action_slugs)).all() if action_slugs else []
|
||||
sel_scenes = Scene.query.filter(Scene.slug.in_(scene_slugs)).all() if scene_slugs else []
|
||||
sel_styles = Style.query.filter(Style.slug.in_(style_slugs)).all() if style_slugs else []
|
||||
sel_detailers = Detailer.query.filter(Detailer.slug.in_(detailer_slugs)).all() if detailer_slugs else []
|
||||
|
||||
extras = build_extras_prompt(sel_actions, [], sel_scenes, sel_styles, sel_detailers)
|
||||
if custom_positive:
|
||||
extras = f"{custom_positive}, {extras}" if extras else custom_positive
|
||||
|
||||
prompts = build_multi_prompt(char_a, char_b, extras_prompt=extras)
|
||||
return {
|
||||
'prompt': prompts['main'],
|
||||
'hand': prompts['hand'],
|
||||
'char_a_main': prompts['char_a_main'],
|
||||
'char_a_face': prompts['char_a_face'],
|
||||
'char_b_main': prompts['char_b_main'],
|
||||
'char_b_face': prompts['char_b_face'],
|
||||
}
|
||||
@@ -336,11 +336,12 @@ def register_routes(app):
|
||||
# No explicit field selection (e.g. batch generation) — build a selection
|
||||
# that includes identity + wardrobe + name + lora triggers, but NOT character
|
||||
# defaults (expression, pose, scene), so outfit covers stay generic.
|
||||
for key in ['base_specs', 'hair', 'eyes', 'hands', 'arms', 'torso', 'pelvis', 'legs', 'feet', 'extra']:
|
||||
from utils import _IDENTITY_KEYS, _WARDROBE_KEYS
|
||||
for key in _IDENTITY_KEYS:
|
||||
if character.data.get('identity', {}).get(key):
|
||||
selected_fields.append(f'identity::{key}')
|
||||
outfit_wardrobe = outfit.data.get('wardrobe', {})
|
||||
for key in ['full_body', 'headwear', 'top', 'bottom', 'legwear', 'footwear', 'hands', 'gloves', 'accessories']:
|
||||
for key in _WARDROBE_KEYS:
|
||||
if outfit_wardrobe.get(key):
|
||||
selected_fields.append(f'wardrobe::{key}')
|
||||
selected_fields.append('special::name')
|
||||
@@ -456,14 +457,13 @@ def register_routes(app):
|
||||
# Ensure required fields exist
|
||||
if 'wardrobe' not in outfit_data:
|
||||
outfit_data['wardrobe'] = {
|
||||
"full_body": "",
|
||||
"headwear": "",
|
||||
"top": "",
|
||||
"bottom": "",
|
||||
"legwear": "",
|
||||
"footwear": "",
|
||||
"base": "",
|
||||
"head": "",
|
||||
"upper_body": "",
|
||||
"lower_body": "",
|
||||
"hands": "",
|
||||
"accessories": ""
|
||||
"feet": "",
|
||||
"additional": ""
|
||||
}
|
||||
if 'lora' not in outfit_data:
|
||||
outfit_data['lora'] = {
|
||||
@@ -484,14 +484,13 @@ def register_routes(app):
|
||||
"outfit_id": safe_slug,
|
||||
"outfit_name": name,
|
||||
"wardrobe": {
|
||||
"full_body": "",
|
||||
"headwear": "",
|
||||
"top": "",
|
||||
"bottom": "",
|
||||
"legwear": "",
|
||||
"footwear": "",
|
||||
"base": "",
|
||||
"head": "",
|
||||
"upper_body": "",
|
||||
"lower_body": "",
|
||||
"hands": "",
|
||||
"accessories": ""
|
||||
"feet": "",
|
||||
"additional": ""
|
||||
},
|
||||
"lora": {
|
||||
"lora_name": "",
|
||||
|
||||
@@ -70,18 +70,24 @@ def register_routes(app):
|
||||
detailer_obj = _resolve_preset_entity('detailer', detailer_cfg.get('detailer_id'))
|
||||
look_obj = _resolve_preset_entity('look', look_cfg.get('look_id'))
|
||||
|
||||
# Checkpoint: preset override or session default
|
||||
preset_ckpt = ckpt_cfg.get('checkpoint_path')
|
||||
if preset_ckpt == 'random':
|
||||
ckpt_obj = Checkpoint.query.order_by(db.func.random()).first()
|
||||
ckpt_path = ckpt_obj.checkpoint_path if ckpt_obj else None
|
||||
ckpt_data = ckpt_obj.data if ckpt_obj else None
|
||||
elif preset_ckpt:
|
||||
ckpt_obj = Checkpoint.query.filter_by(checkpoint_path=preset_ckpt).first()
|
||||
ckpt_path = preset_ckpt
|
||||
# Checkpoint: form override > preset config > session default
|
||||
checkpoint_override = request.form.get('checkpoint_override', '').strip()
|
||||
if checkpoint_override:
|
||||
ckpt_obj = Checkpoint.query.filter_by(checkpoint_path=checkpoint_override).first()
|
||||
ckpt_path = checkpoint_override
|
||||
ckpt_data = ckpt_obj.data if ckpt_obj else None
|
||||
else:
|
||||
ckpt_path, ckpt_data = _get_default_checkpoint()
|
||||
preset_ckpt = ckpt_cfg.get('checkpoint_path')
|
||||
if preset_ckpt == 'random':
|
||||
ckpt_obj = Checkpoint.query.order_by(db.func.random()).first()
|
||||
ckpt_path = ckpt_obj.checkpoint_path if ckpt_obj else None
|
||||
ckpt_data = ckpt_obj.data if ckpt_obj else None
|
||||
elif preset_ckpt:
|
||||
ckpt_obj = Checkpoint.query.filter_by(checkpoint_path=preset_ckpt).first()
|
||||
ckpt_path = preset_ckpt
|
||||
ckpt_data = ckpt_obj.data if ckpt_obj else None
|
||||
else:
|
||||
ckpt_path, ckpt_data = _get_default_checkpoint()
|
||||
|
||||
# Resolve selected fields from preset toggles
|
||||
selected_fields = _resolve_preset_fields(data)
|
||||
@@ -107,7 +113,8 @@ def register_routes(app):
|
||||
extras_parts = []
|
||||
if action_obj:
|
||||
action_fields = action_cfg.get('fields', {})
|
||||
for key in ['full_body', 'additional', 'head', 'eyes', 'arms', 'hands']:
|
||||
from utils import _BODY_GROUP_KEYS
|
||||
for key in _BODY_GROUP_KEYS:
|
||||
val_cfg = action_fields.get(key, True)
|
||||
if val_cfg == 'random':
|
||||
val_cfg = random.choice([True, False])
|
||||
@@ -172,6 +179,23 @@ def register_routes(app):
|
||||
seed_val = request.form.get('seed', '').strip()
|
||||
fixed_seed = int(seed_val) if seed_val else None
|
||||
|
||||
# Resolution: form override > preset config > workflow default
|
||||
res_cfg = data.get('resolution', {})
|
||||
form_width = request.form.get('width', '').strip()
|
||||
form_height = request.form.get('height', '').strip()
|
||||
if form_width and form_height:
|
||||
gen_width = int(form_width)
|
||||
gen_height = int(form_height)
|
||||
elif res_cfg.get('random', False):
|
||||
_RES_OPTIONS = [
|
||||
(1024, 1024), (1152, 896), (896, 1152), (1344, 768),
|
||||
(768, 1344), (1280, 800), (800, 1280),
|
||||
]
|
||||
gen_width, gen_height = random.choice(_RES_OPTIONS)
|
||||
else:
|
||||
gen_width = res_cfg.get('width') or None
|
||||
gen_height = res_cfg.get('height') or None
|
||||
|
||||
workflow = _prepare_workflow(
|
||||
workflow, character, prompts,
|
||||
checkpoint=ckpt_path, checkpoint_data=ckpt_data,
|
||||
@@ -183,6 +207,8 @@ def register_routes(app):
|
||||
detailer=detailer_obj if detailer_cfg.get('use_lora', True) else None,
|
||||
look=look_obj,
|
||||
fixed_seed=fixed_seed,
|
||||
width=gen_width,
|
||||
height=gen_height,
|
||||
)
|
||||
|
||||
label = f"Preset: {preset.name} – {action}"
|
||||
@@ -258,13 +284,13 @@ def register_routes(app):
|
||||
'use_lora': request.form.get('char_use_lora') == 'on',
|
||||
'fields': {
|
||||
'identity': {k: _tog(request.form.get(f'id_{k}', 'true'))
|
||||
for k in ['base_specs', 'hair', 'eyes', 'hands', 'arms', 'torso', 'pelvis', 'legs', 'feet', 'extra']},
|
||||
for k in ['base', 'head', 'upper_body', 'lower_body', 'hands', 'feet', 'additional']},
|
||||
'defaults': {k: _tog(request.form.get(f'def_{k}', 'false'))
|
||||
for k in ['expression', 'pose', 'scene']},
|
||||
'wardrobe': {
|
||||
'outfit': request.form.get('wardrobe_outfit', 'default') or 'default',
|
||||
'fields': {k: _tog(request.form.get(f'wd_{k}', 'true'))
|
||||
for k in ['full_body', 'headwear', 'top', 'bottom', 'legwear', 'footwear', 'hands', 'gloves', 'accessories']},
|
||||
for k in ['base', 'head', 'upper_body', 'lower_body', 'hands', 'feet', 'additional']},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -273,7 +299,7 @@ def register_routes(app):
|
||||
'action': {'action_id': _entity_id(request.form.get('action_id')),
|
||||
'use_lora': request.form.get('action_use_lora') == 'on',
|
||||
'fields': {k: _tog(request.form.get(f'act_{k}', 'true'))
|
||||
for k in ['full_body', 'additional', 'head', 'eyes', 'arms', 'hands']}},
|
||||
for k in ['base', 'head', 'upper_body', 'lower_body', 'hands', 'feet', 'additional']}},
|
||||
'style': {'style_id': _entity_id(request.form.get('style_id')),
|
||||
'use_lora': request.form.get('style_use_lora') == 'on'},
|
||||
'scene': {'scene_id': _entity_id(request.form.get('scene_id')),
|
||||
@@ -284,6 +310,11 @@ def register_routes(app):
|
||||
'use_lora': request.form.get('detailer_use_lora') == 'on'},
|
||||
'look': {'look_id': _entity_id(request.form.get('look_id'))},
|
||||
'checkpoint': {'checkpoint_path': _entity_id(request.form.get('checkpoint_path'))},
|
||||
'resolution': {
|
||||
'width': int(request.form.get('res_width', 1024)),
|
||||
'height': int(request.form.get('res_height', 1024)),
|
||||
'random': request.form.get('res_random') == 'on',
|
||||
},
|
||||
'tags': [t.strip() for t in request.form.get('tags', '').split(',') if t.strip()],
|
||||
}
|
||||
|
||||
@@ -399,20 +430,21 @@ def register_routes(app):
|
||||
preset_data = {
|
||||
'character': {'character_id': 'random', 'use_lora': True,
|
||||
'fields': {
|
||||
'identity': {k: True for k in ['base_specs', 'hair', 'eyes', 'hands', 'arms', 'torso', 'pelvis', 'legs', 'feet', 'extra']},
|
||||
'identity': {k: True for k in ['base', 'head', 'upper_body', 'lower_body', 'hands', 'feet', 'additional']},
|
||||
'defaults': {k: False for k in ['expression', 'pose', 'scene']},
|
||||
'wardrobe': {'outfit': 'default',
|
||||
'fields': {k: True for k in ['full_body', 'headwear', 'top', 'bottom', 'legwear', 'footwear', 'hands', 'gloves', 'accessories']}},
|
||||
'fields': {k: True for k in ['base', 'head', 'upper_body', 'lower_body', 'hands', 'feet', 'additional']}},
|
||||
}},
|
||||
'outfit': {'outfit_id': None, 'use_lora': True},
|
||||
'action': {'action_id': None, 'use_lora': True,
|
||||
'fields': {k: True for k in ['full_body', 'additional', 'head', 'eyes', 'arms', 'hands']}},
|
||||
'fields': {k: True for k in ['base', 'head', 'upper_body', 'lower_body', 'hands', 'feet', 'additional']}},
|
||||
'style': {'style_id': None, 'use_lora': True},
|
||||
'scene': {'scene_id': None, 'use_lora': True,
|
||||
'fields': {k: True for k in ['background', 'foreground', 'furniture', 'colors', 'lighting', 'theme']}},
|
||||
'detailer': {'detailer_id': None, 'use_lora': True},
|
||||
'look': {'look_id': None},
|
||||
'checkpoint': {'checkpoint_path': None},
|
||||
'resolution': {'width': 1024, 'height': 1024, 'random': False},
|
||||
'tags': [],
|
||||
}
|
||||
|
||||
|
||||
25
routes/quick.py
Normal file
25
routes/quick.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import logging
|
||||
from flask import render_template
|
||||
from models import Preset
|
||||
from services.file_io import get_available_checkpoints
|
||||
from services.comfyui import get_loaded_checkpoint
|
||||
from services.workflow import _get_default_checkpoint
|
||||
|
||||
logger = logging.getLogger('gaze')
|
||||
|
||||
|
||||
def register_routes(app):
|
||||
|
||||
@app.route('/quick')
|
||||
def quick_generator():
|
||||
presets = Preset.query.order_by(Preset.name).all()
|
||||
checkpoints = get_available_checkpoints()
|
||||
|
||||
# Default to whatever is currently loaded in ComfyUI, then settings default
|
||||
selected_ckpt = get_loaded_checkpoint()
|
||||
if not selected_ckpt:
|
||||
default_path, _ = _get_default_checkpoint()
|
||||
selected_ckpt = default_path
|
||||
|
||||
return render_template('quick.html', presets=presets,
|
||||
checkpoints=checkpoints, selected_ckpt=selected_ckpt)
|
||||
@@ -202,7 +202,7 @@ def register_routes(app):
|
||||
else:
|
||||
# Auto-include essential character fields (minimal set for batch/default generation)
|
||||
selected_fields = []
|
||||
for key in ['base_specs', 'hair', 'eyes']:
|
||||
for key in ['base', 'head']:
|
||||
if character.data.get('identity', {}).get(key):
|
||||
selected_fields.append(f'identity::{key}')
|
||||
selected_fields.append('special::name')
|
||||
|
||||
@@ -78,11 +78,11 @@ def register_routes(app):
|
||||
if character:
|
||||
identity = character.data.get('identity', {})
|
||||
defaults = character.data.get('defaults', {})
|
||||
char_parts = [v for v in [identity.get('base_specs'), identity.get('hair'),
|
||||
identity.get('eyes'), defaults.get('expression')] if v]
|
||||
face_parts = [v for v in [identity.get('hair'), identity.get('eyes'),
|
||||
char_parts = [v for v in [identity.get('base'), identity.get('head'),
|
||||
defaults.get('expression')] if v]
|
||||
hand_parts = [v for v in [wardrobe.get('hands'), wardrobe.get('gloves')] if v]
|
||||
face_parts = [v for v in [identity.get('head'),
|
||||
defaults.get('expression')] if v]
|
||||
hand_parts = [v for v in [wardrobe.get('hands')] if v]
|
||||
main_parts = ([outfit_triggers] if outfit_triggers else []) + char_parts + wardrobe_parts + tags
|
||||
return {
|
||||
'main': _dedup_tags(', '.join(p for p in main_parts if p)),
|
||||
@@ -94,17 +94,16 @@ def register_routes(app):
|
||||
action_data = entity.data.get('action', {})
|
||||
action_triggers = entity.data.get('lora', {}).get('lora_triggers', '')
|
||||
tags = entity.data.get('tags', [])
|
||||
pose_fields = ['full_body', 'arms', 'hands', 'torso', 'pelvis', 'legs', 'feet', 'additional']
|
||||
pose_parts = [action_data.get(k, '') for k in pose_fields if action_data.get(k)]
|
||||
expr_parts = [action_data.get(k, '') for k in ['head', 'eyes'] if action_data.get(k)]
|
||||
from utils import _BODY_GROUP_KEYS
|
||||
pose_parts = [action_data.get(k, '') for k in _BODY_GROUP_KEYS if action_data.get(k)]
|
||||
expr_parts = [action_data.get('head', '')] if action_data.get('head') else []
|
||||
char_parts = []
|
||||
face_parts = list(expr_parts)
|
||||
hand_parts = [action_data.get('hands', '')] if action_data.get('hands') else []
|
||||
if character:
|
||||
identity = character.data.get('identity', {})
|
||||
char_parts = [v for v in [identity.get('base_specs'), identity.get('hair'),
|
||||
identity.get('eyes')] if v]
|
||||
face_parts = [v for v in [identity.get('hair'), identity.get('eyes')] + expr_parts if v]
|
||||
char_parts = [v for v in [identity.get('base'), identity.get('head')] if v]
|
||||
face_parts = [v for v in [identity.get('head')] + expr_parts if v]
|
||||
main_parts = ([action_triggers] if action_triggers else []) + char_parts + pose_parts + tags
|
||||
return {
|
||||
'main': _dedup_tags(', '.join(p for p in main_parts if p)),
|
||||
@@ -130,15 +129,15 @@ def register_routes(app):
|
||||
entity_parts = [p for p in [entity_triggers, det_prompt] + tags if p]
|
||||
|
||||
char_data_no_lora = _get_character_data_without_lora(character)
|
||||
base = build_prompt(char_data_no_lora, [], character.default_fields) if char_data_no_lora else {'main': '', 'face': '', 'hand': ''}
|
||||
base = build_prompt(char_data_no_lora, [], character.default_fields) if char_data_no_lora else {'main': '', 'face': '', 'hand': '', 'feet': ''}
|
||||
entity_str = ', '.join(entity_parts)
|
||||
if entity_str:
|
||||
base['main'] = f"{base['main']}, {entity_str}" if base['main'] else entity_str
|
||||
|
||||
if action is not None:
|
||||
action_data = action.data.get('action', {})
|
||||
action_parts = [action_data.get(k, '') for k in
|
||||
['full_body', 'arms', 'hands', 'torso', 'pelvis', 'legs', 'feet', 'additional', 'head', 'eyes']
|
||||
from utils import _BODY_GROUP_KEYS
|
||||
action_parts = [action_data.get(k, '') for k in _BODY_GROUP_KEYS
|
||||
if action_data.get(k)]
|
||||
action_str = ', '.join(action_parts)
|
||||
if action_str:
|
||||
|
||||
@@ -42,7 +42,7 @@ def register_routes(app):
|
||||
else:
|
||||
# Auto-include essential character fields (minimal set for batch/default generation)
|
||||
selected_fields = []
|
||||
for key in ['base_specs', 'hair', 'eyes']:
|
||||
for key in ['base', 'head']:
|
||||
if character.data.get('identity', {}).get(key):
|
||||
selected_fields.append(f'identity::{key}')
|
||||
selected_fields.append('special::name')
|
||||
|
||||
@@ -88,8 +88,8 @@ def register_routes(app):
|
||||
'outfit_id': slug,
|
||||
'outfit_name': name,
|
||||
'wardrobe': source_data.get('wardrobe', {
|
||||
'full_body': '', 'headwear': '', 'top': '', 'bottom': '',
|
||||
'legwear': '', 'footwear': '', 'hands': '', 'accessories': ''
|
||||
'base': '', 'head': '', 'upper_body': '', 'lower_body': '',
|
||||
'hands': '', 'feet': '', 'additional': ''
|
||||
}),
|
||||
'lora': source_data.get('lora', {'lora_name': '', 'lora_weight': 0.8, 'lora_triggers': ''}),
|
||||
'tags': source_data.get('tags', []),
|
||||
@@ -99,8 +99,8 @@ def register_routes(app):
|
||||
'action_id': slug,
|
||||
'action_name': name,
|
||||
'action': source_data.get('action', {
|
||||
'full_body': '', 'head': '', 'eyes': '', 'arms': '', 'hands': '',
|
||||
'torso': '', 'pelvis': '', 'legs': '', 'feet': '', 'additional': ''
|
||||
'base': '', 'head': '', 'upper_body': '', 'lower_body': '',
|
||||
'hands': '', 'feet': '', 'additional': ''
|
||||
}),
|
||||
'lora': source_data.get('lora', {'lora_name': '', 'lora_weight': 1.0, 'lora_triggers': ''}),
|
||||
'tags': source_data.get('tags', []),
|
||||
|
||||
Reference in New Issue
Block a user