Updated generation pages.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import re
|
||||
from models import db, Character
|
||||
from utils import _IDENTITY_KEYS, _WARDROBE_KEYS, parse_orientation
|
||||
from utils import _IDENTITY_KEYS, _WARDROBE_KEYS, _BODY_GROUP_KEYS, parse_orientation
|
||||
|
||||
|
||||
def _dedup_tags(prompt_str):
|
||||
@@ -114,15 +114,21 @@ def build_prompt(data, selected_fields=None, default_fields=None, active_outfit=
|
||||
style_data = data.get('style', {})
|
||||
participants = data.get('participants', {})
|
||||
|
||||
# Pre-calculate Hand/Glove priority
|
||||
# Priority: wardrobe gloves > wardrobe hands (outfit) > identity hands (character)
|
||||
hand_val = ""
|
||||
if wardrobe.get('gloves') and is_selected('wardrobe', 'gloves'):
|
||||
hand_val = wardrobe.get('gloves')
|
||||
elif wardrobe.get('hands') and is_selected('wardrobe', 'hands'):
|
||||
hand_val = wardrobe.get('hands')
|
||||
elif identity.get('hands') and is_selected('identity', 'hands'):
|
||||
hand_val = identity.get('hands')
|
||||
# Helper: collect selected values from identity + wardrobe for a given group key
|
||||
def _group_val(key):
|
||||
parts = []
|
||||
id_val = identity.get(key, '')
|
||||
wd_val = wardrobe.get(key, '')
|
||||
if id_val and is_selected('identity', key):
|
||||
val = id_val
|
||||
# Filter out conflicting tags from base if participants data is present
|
||||
if participants and key == 'base':
|
||||
val = re.sub(r'\b(1girl|1boy|solo)\b', '', val).replace(', ,', ',').strip(', ')
|
||||
if val:
|
||||
parts.append(val)
|
||||
if wd_val and is_selected('wardrobe', key):
|
||||
parts.append(wd_val)
|
||||
return ', '.join(parts)
|
||||
|
||||
# 1. Main Prompt
|
||||
parts = []
|
||||
@@ -131,12 +137,10 @@ def build_prompt(data, selected_fields=None, default_fields=None, active_outfit=
|
||||
if participants:
|
||||
if participants.get('solo_focus') == 'true':
|
||||
parts.append('(solo focus:1.2)')
|
||||
|
||||
orientation = participants.get('orientation', '')
|
||||
if orientation:
|
||||
parts.extend(parse_orientation(orientation))
|
||||
else:
|
||||
# Default behavior
|
||||
parts.append("(solo:1.2)")
|
||||
|
||||
# Use character_id (underscores to spaces) for tags compatibility
|
||||
@@ -144,13 +148,10 @@ def build_prompt(data, selected_fields=None, default_fields=None, active_outfit=
|
||||
if char_tag and is_selected('special', 'name'):
|
||||
parts.append(char_tag)
|
||||
|
||||
for key in ['base_specs', 'hair', 'eyes', 'extra']:
|
||||
val = identity.get(key)
|
||||
if val and is_selected('identity', key):
|
||||
# Filter out conflicting tags if participants data is present
|
||||
if participants and key == 'base_specs':
|
||||
# Remove 1girl, 1boy, solo, etc.
|
||||
val = re.sub(r'\b(1girl|1boy|solo)\b', '', val).replace(', ,', ',').strip(', ')
|
||||
# Add all body groups to main prompt
|
||||
for key in _BODY_GROUP_KEYS:
|
||||
val = _group_val(key)
|
||||
if val:
|
||||
parts.append(val)
|
||||
|
||||
# Add defaults (expression, pose, scene)
|
||||
@@ -159,21 +160,12 @@ def build_prompt(data, selected_fields=None, default_fields=None, active_outfit=
|
||||
if val and is_selected('defaults', key):
|
||||
parts.append(val)
|
||||
|
||||
# Add hand priority value to main prompt
|
||||
if hand_val:
|
||||
parts.append(hand_val)
|
||||
|
||||
for key in ['full_body', 'top', 'bottom', 'headwear', 'legwear', 'footwear', 'accessories']:
|
||||
val = wardrobe.get(key)
|
||||
if val and is_selected('wardrobe', key):
|
||||
parts.append(val)
|
||||
|
||||
# Standard character styles
|
||||
char_aesthetic = data.get('styles', {}).get('aesthetic')
|
||||
if char_aesthetic and is_selected('styles', 'aesthetic'):
|
||||
parts.append(f"{char_aesthetic} style")
|
||||
|
||||
# New Styles Gallery logic
|
||||
# Styles Gallery logic
|
||||
if style_data.get('artist_name') and is_selected('style', 'artist_name'):
|
||||
parts.append(f"by {style_data['artist_name']}")
|
||||
if style_data.get('artistic_style') and is_selected('style', 'artistic_style'):
|
||||
@@ -187,26 +179,98 @@ def build_prompt(data, selected_fields=None, default_fields=None, active_outfit=
|
||||
if lora.get('lora_triggers') and is_selected('lora', 'lora_triggers'):
|
||||
parts.append(lora.get('lora_triggers'))
|
||||
|
||||
# 2. Face Prompt: Tag, Eyes, Expression, Headwear, Action details
|
||||
# 2. Face Prompt: head group + expression + action head
|
||||
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 defaults.get('expression') and is_selected('defaults', 'expression'): face_parts.append(defaults.get('expression'))
|
||||
if wardrobe.get('headwear') and is_selected('wardrobe', 'headwear'): face_parts.append(wardrobe.get('headwear'))
|
||||
if char_tag and is_selected('special', 'name'):
|
||||
face_parts.append(char_tag)
|
||||
head_val = _group_val('head')
|
||||
if head_val:
|
||||
face_parts.append(head_val)
|
||||
if defaults.get('expression') and is_selected('defaults', 'expression'):
|
||||
face_parts.append(defaults.get('expression'))
|
||||
if action_data.get('head') and is_selected('action', 'head'):
|
||||
face_parts.append(action_data.get('head'))
|
||||
|
||||
# Add specific Action expression details if available
|
||||
if action_data.get('head') and is_selected('action', 'head'): face_parts.append(action_data.get('head'))
|
||||
if action_data.get('eyes') and is_selected('action', 'eyes'): face_parts.append(action_data.get('eyes'))
|
||||
# 3. Hand Prompt: hands group + action hands
|
||||
hand_parts = []
|
||||
hands_val = _group_val('hands')
|
||||
if hands_val:
|
||||
hand_parts.append(hands_val)
|
||||
if action_data.get('hands') and is_selected('action', 'hands'):
|
||||
hand_parts.append(action_data.get('hands'))
|
||||
|
||||
# 3. Hand Prompt: Hand value (Gloves or Hands), Action details
|
||||
hand_parts = [hand_val] if hand_val else []
|
||||
if action_data.get('arms') and is_selected('action', 'arms'): hand_parts.append(action_data.get('arms'))
|
||||
if action_data.get('hands') and is_selected('action', 'hands'): hand_parts.append(action_data.get('hands'))
|
||||
# 4. Feet Prompt: feet group + action feet
|
||||
feet_parts = []
|
||||
feet_val = _group_val('feet')
|
||||
if feet_val:
|
||||
feet_parts.append(feet_val)
|
||||
if action_data.get('feet') and is_selected('action', 'feet'):
|
||||
feet_parts.append(action_data.get('feet'))
|
||||
|
||||
return {
|
||||
"main": _dedup_tags(", ".join(parts)),
|
||||
"face": _dedup_tags(", ".join(face_parts)),
|
||||
"hand": _dedup_tags(", ".join(hand_parts))
|
||||
"hand": _dedup_tags(", ".join(hand_parts)),
|
||||
"feet": _dedup_tags(", ".join(feet_parts)),
|
||||
}
|
||||
|
||||
|
||||
def build_multi_prompt(char_a, char_b, extras_prompt=''):
|
||||
"""Build prompts for a two-character generation using BREAK separation.
|
||||
|
||||
Returns dict with combined prompts (main, face, hand) and per-character
|
||||
prompts (char_a_main, char_a_face, char_b_main, char_b_face) for the
|
||||
per-person/face ADetailer passes.
|
||||
"""
|
||||
# Build individual prompts with all fields selected
|
||||
prompts_a = build_prompt(char_a.data)
|
||||
prompts_b = build_prompt(char_b.data)
|
||||
|
||||
# Strip solo/orientation tags from individual prompts — we'll add combined ones
|
||||
_solo_orientation_tags = {
|
||||
'solo', '(solo:1.2)', '(solo focus:1.2)',
|
||||
'1girl', '1boy', '2girls', '2boys', '3girls', '3boys',
|
||||
'hetero', 'yuri', 'yaoi',
|
||||
'multiple girls', 'multiple boys',
|
||||
}
|
||||
|
||||
def _strip_tags(prompt_str, tags_to_remove):
|
||||
parts = [t.strip() for t in prompt_str.split(',') if t.strip()]
|
||||
return ', '.join(p for p in parts if p.lower() not in tags_to_remove)
|
||||
|
||||
main_a = _strip_tags(prompts_a['main'], _solo_orientation_tags)
|
||||
main_b = _strip_tags(prompts_b['main'], _solo_orientation_tags)
|
||||
|
||||
# Compute combined orientation
|
||||
orient_a = char_a.data.get('participants', {}).get('orientation', '1F')
|
||||
orient_b = char_b.data.get('participants', {}).get('orientation', '1F')
|
||||
|
||||
# Count total M and F across both characters
|
||||
combined_m = orient_a.upper().count('M') + orient_b.upper().count('M')
|
||||
combined_f = orient_a.upper().count('F') + orient_b.upper().count('F')
|
||||
combined_orientation = f"{combined_m}M{combined_f}F" if combined_m else f"{combined_f}F"
|
||||
if combined_f == 0:
|
||||
combined_orientation = f"{combined_m}M"
|
||||
orientation_tags = parse_orientation(combined_orientation)
|
||||
|
||||
# Build combined main prompt with BREAK separation
|
||||
orientation_str = ', '.join(orientation_tags)
|
||||
combined_main = f"{orientation_str}, {main_a} BREAK {main_b}"
|
||||
if extras_prompt:
|
||||
combined_main = f"{extras_prompt}, {combined_main}"
|
||||
|
||||
# Merge face/hand prompts for the hand detailer (shared, not per-character)
|
||||
hand_parts = [p for p in [prompts_a['hand'], prompts_b['hand']] if p]
|
||||
|
||||
return {
|
||||
"main": _dedup_tags(combined_main),
|
||||
"face": "", # not used — per-character face prompts go to SEGS detailers
|
||||
"hand": _dedup_tags(', '.join(hand_parts)),
|
||||
# Per-character prompts for SEGS-based ADetailer passes
|
||||
"char_a_main": _dedup_tags(main_a),
|
||||
"char_a_face": _dedup_tags(prompts_a['face']),
|
||||
"char_b_main": _dedup_tags(main_b),
|
||||
"char_b_face": _dedup_tags(prompts_b['face']),
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +284,7 @@ def build_extras_prompt(actions, outfits, scenes, styles, detailers):
|
||||
if lora.get('lora_triggers'):
|
||||
parts.append(lora['lora_triggers'])
|
||||
parts.extend(data.get('tags', []))
|
||||
for key in ['full_body', 'additional']:
|
||||
for key in _BODY_GROUP_KEYS:
|
||||
val = data.get('action', {}).get(key)
|
||||
if val:
|
||||
parts.append(val)
|
||||
@@ -228,7 +292,7 @@ def build_extras_prompt(actions, outfits, scenes, styles, detailers):
|
||||
for outfit in outfits:
|
||||
data = outfit.data
|
||||
wardrobe = data.get('wardrobe', {})
|
||||
for key in ['full_body', 'headwear', 'top', 'bottom', 'legwear', 'footwear', 'hands', 'accessories']:
|
||||
for key in _BODY_GROUP_KEYS:
|
||||
val = wardrobe.get(key)
|
||||
if val:
|
||||
parts.append(val)
|
||||
|
||||
Reference in New Issue
Block a user