feat: integrate HF Router and enhance UI workflow
Browse files- Switched Hugging Face integration to the OpenAI-compatible Router.
- Refactored `modules/integrations.py` to use `openai` SDK.
- Updated `modules/config.py` with `HF_BASE_URL` and `Qwen/Qwen2.5-72B-Instruct` model.
- Implemented dynamic backend availability checking for Ollama and ComfyUI at startup.
- Fixed refined prompt persistence issue when loading characters.
- Fixed aspect ratio handling for Hugging Face image generation.
- Renamed "Settings & Generation" section to "AI Backend Configuration" and relocated "Refine Prompt" button for better workflow.
- Updated `requirements.txt` with `openai` and `python-dotenv`.
- features.yaml +35 -0
- hf_example.py +0 -23
- hf_hub_example.py +0 -13
- modules/config.py +3 -2
- modules/integrations.py +49 -10
- modules/ui_layout.py +20 -5
- requirements.txt +2 -0
features.yaml
CHANGED
|
@@ -42,6 +42,13 @@ appearance:
|
|
| 42 |
Blue: "deep sapphire blue"
|
| 43 |
Green: "forest green"
|
| 44 |
Purple: "regal purple"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
hair_style:
|
| 46 |
Short: "neatly trimmed short"
|
| 47 |
Long: "flowing long"
|
|
@@ -51,6 +58,9 @@ appearance:
|
|
| 51 |
Ponytail: "tied back in a ponytail"
|
| 52 |
Bun: "styled in a tight bun"
|
| 53 |
Curly: "thickly curly"
|
|
|
|
|
|
|
|
|
|
| 54 |
eye_color:
|
| 55 |
Brown: "warm brown"
|
| 56 |
Blue: "piercing blue"
|
|
@@ -59,6 +69,9 @@ appearance:
|
|
| 59 |
Amber: "glowing amber"
|
| 60 |
Red: "intense crimson red"
|
| 61 |
Violet: "mysterious violet"
|
|
|
|
|
|
|
|
|
|
| 62 |
build:
|
| 63 |
Athletic: "an athletic and toned"
|
| 64 |
Muscular: "a powerful, muscular"
|
|
@@ -66,6 +79,7 @@ appearance:
|
|
| 66 |
Stocky: "a solid and stocky"
|
| 67 |
Average: "a well-proportioned"
|
| 68 |
Scrawny: "a thin and scrawny"
|
|
|
|
| 69 |
skin_tone:
|
| 70 |
Pale: "porcelain pale"
|
| 71 |
Fair: "smooth fair"
|
|
@@ -73,6 +87,9 @@ appearance:
|
|
| 73 |
Olive: "warm olive"
|
| 74 |
Dark: "rich dark"
|
| 75 |
Deep: "deep ebony"
|
|
|
|
|
|
|
|
|
|
| 76 |
distinguishing_feature:
|
| 77 |
Scars: "a collection of jagged battle scars across the face"
|
| 78 |
Tattoos: "intricate glowing tattoos covering the neck and arms"
|
|
@@ -80,6 +97,9 @@ appearance:
|
|
| 80 |
Cybernetic Eye: "a glowing cybernetic eye that whirrs softly"
|
| 81 |
Glowing Runes: "mystical runes etched into the skin that pulse with light"
|
| 82 |
Jeweled Bindi: "a shimmering jeweled bindi placed between the brows"
|
|
|
|
|
|
|
|
|
|
| 83 |
None: "no particularly distinguishing facial features"
|
| 84 |
|
| 85 |
expression_pose:
|
|
@@ -98,6 +118,13 @@ expression_pose:
|
|
| 98 |
Ready Stance: "crouched in a dynamic ready stance"
|
| 99 |
Meditating: "seated in a peaceful meditating position"
|
| 100 |
Action: "frozen in the middle of a powerful action"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
equipment:
|
| 103 |
armor:
|
|
@@ -156,6 +183,14 @@ environment:
|
|
| 156 |
Mountains: "rugged mountain peak against a dramatic sky"
|
| 157 |
City Street: "bustling medieval city street with cobblestones"
|
| 158 |
Abstract Magic: "swirling vortex of abstract magical energy"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
lighting:
|
| 160 |
Natural Sunlight: "bathed in warm, natural sunlight"
|
| 161 |
Dim Torchlight: "illuminated by the flickering glow of dim torchlight"
|
|
|
|
| 42 |
Blue: "deep sapphire blue"
|
| 43 |
Green: "forest green"
|
| 44 |
Purple: "regal purple"
|
| 45 |
+
Salt and Pepper: "salt and pepper"
|
| 46 |
+
Dirty Blonde: "dusty dirty blonde"
|
| 47 |
+
Auburn: "rich auburn"
|
| 48 |
+
Copper: "burnished copper"
|
| 49 |
+
Platinum: "pale platinum blonde"
|
| 50 |
+
Pink: "soft pastel pink"
|
| 51 |
+
Teal: "vibrant teal"
|
| 52 |
hair_style:
|
| 53 |
Short: "neatly trimmed short"
|
| 54 |
Long: "flowing long"
|
|
|
|
| 58 |
Ponytail: "tied back in a ponytail"
|
| 59 |
Bun: "styled in a tight bun"
|
| 60 |
Curly: "thickly curly"
|
| 61 |
+
Mohawk: "a sharp, jagged mohawk"
|
| 62 |
+
Undercut: "a stylish undercut"
|
| 63 |
+
Dreadlocks: "thick, well-maintained dreadlocks"
|
| 64 |
eye_color:
|
| 65 |
Brown: "warm brown"
|
| 66 |
Blue: "piercing blue"
|
|
|
|
| 69 |
Amber: "glowing amber"
|
| 70 |
Red: "intense crimson red"
|
| 71 |
Violet: "mysterious violet"
|
| 72 |
+
Heterochromia: "mismatched, with one blue and one brown eye"
|
| 73 |
+
Cloudy: "milky white and cloudy, suggesting blindness"
|
| 74 |
+
Black: "solid, ink-black voids"
|
| 75 |
build:
|
| 76 |
Athletic: "an athletic and toned"
|
| 77 |
Muscular: "a powerful, muscular"
|
|
|
|
| 79 |
Stocky: "a solid and stocky"
|
| 80 |
Average: "a well-proportioned"
|
| 81 |
Scrawny: "a thin and scrawny"
|
| 82 |
+
Towering: "a towering and massive"
|
| 83 |
skin_tone:
|
| 84 |
Pale: "porcelain pale"
|
| 85 |
Fair: "smooth fair"
|
|
|
|
| 87 |
Olive: "warm olive"
|
| 88 |
Dark: "rich dark"
|
| 89 |
Deep: "deep ebony"
|
| 90 |
+
Alabaster: "ghostly alabaster"
|
| 91 |
+
Vitiligo: "mottled with striking vitiligo patterns"
|
| 92 |
+
Ashen: "pale, ashen grey"
|
| 93 |
distinguishing_feature:
|
| 94 |
Scars: "a collection of jagged battle scars across the face"
|
| 95 |
Tattoos: "intricate glowing tattoos covering the neck and arms"
|
|
|
|
| 97 |
Cybernetic Eye: "a glowing cybernetic eye that whirrs softly"
|
| 98 |
Glowing Runes: "mystical runes etched into the skin that pulse with light"
|
| 99 |
Jeweled Bindi: "a shimmering jeweled bindi placed between the brows"
|
| 100 |
+
Mechanical Jaw: "a heavy, reinforced mechanical jaw"
|
| 101 |
+
Third Eye: "a mystical third eye centered on the forehead"
|
| 102 |
+
Burn Marks: "faint, web-like burn marks tracing down the neck"
|
| 103 |
None: "no particularly distinguishing facial features"
|
| 104 |
|
| 105 |
expression_pose:
|
|
|
|
| 118 |
Ready Stance: "crouched in a dynamic ready stance"
|
| 119 |
Meditating: "seated in a peaceful meditating position"
|
| 120 |
Action: "frozen in the middle of a powerful action"
|
| 121 |
+
Kneeling: "humbly kneeling on one knee"
|
| 122 |
+
Floating: "magically floating inches above the ground"
|
| 123 |
+
Weapon Maintenance: "focused on meticulously sharpening their weapon"
|
| 124 |
+
Casting: "with hands glowing, in the middle of casting a powerful spell"
|
| 125 |
+
Defending: "braced firmly behind a raised shield"
|
| 126 |
+
Sitting: "seated regally upon an ornate throne"
|
| 127 |
+
Crouching: "crouched low, blending into the shadows"
|
| 128 |
|
| 129 |
equipment:
|
| 130 |
armor:
|
|
|
|
| 183 |
Mountains: "rugged mountain peak against a dramatic sky"
|
| 184 |
City Street: "bustling medieval city street with cobblestones"
|
| 185 |
Abstract Magic: "swirling vortex of abstract magical energy"
|
| 186 |
+
Desert: "vast desert with shifting orange sands"
|
| 187 |
+
Arctic: "frozen arctic tundra under a pale sun"
|
| 188 |
+
Steampunk Lab: "cluttered steampunk laboratory with hissing brass pipes"
|
| 189 |
+
Volcanic Cave: "dark volcanic cave with rivers of molten lava"
|
| 190 |
+
Enchanted Grove: "ethereal grove filled with giant glowing mushrooms"
|
| 191 |
+
Ruined Temple: "ancient ruined temple overgrown with thick ivy"
|
| 192 |
+
Cyberpunk Street: "rain-slicked cyberpunk street with neon holographic signs"
|
| 193 |
+
Undersea: "majestic undersea city surrounded by coral and bubbles"
|
| 194 |
lighting:
|
| 195 |
Natural Sunlight: "bathed in warm, natural sunlight"
|
| 196 |
Dim Torchlight: "illuminated by the flickering glow of dim torchlight"
|
hf_example.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
import os
|
| 2 |
-
from openai import OpenAI
|
| 3 |
-
from dotenv import load_dotenv
|
| 4 |
-
|
| 5 |
-
# Load environment variables
|
| 6 |
-
load_dotenv()
|
| 7 |
-
|
| 8 |
-
client = OpenAI(
|
| 9 |
-
base_url="https://router.huggingface.co/v1",
|
| 10 |
-
api_key=os.environ["HF_TOKEN"],
|
| 11 |
-
)
|
| 12 |
-
|
| 13 |
-
completion = client.completions.create(
|
| 14 |
-
model="mistralai/Mixtral-8x22B-Instruct-v0.1:fireworks-ai",
|
| 15 |
-
messages=[
|
| 16 |
-
{
|
| 17 |
-
"role": "user",
|
| 18 |
-
"content": "Calculate the weight of the earth."
|
| 19 |
-
}
|
| 20 |
-
],
|
| 21 |
-
)
|
| 22 |
-
|
| 23 |
-
print(completion.choices[0].message)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hf_hub_example.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
| 1 |
-
import os
|
| 2 |
-
from huggingface_hub import InferenceClient
|
| 3 |
-
|
| 4 |
-
client = InferenceClient(
|
| 5 |
-
provider="replicate",
|
| 6 |
-
api_key=os.environ["HF_TOKEN"],
|
| 7 |
-
)
|
| 8 |
-
|
| 9 |
-
# output is a PIL.Image object
|
| 10 |
-
image = client.text_to_image(
|
| 11 |
-
"Astronaut riding a horse",
|
| 12 |
-
model="ByteDance/SDXL-Lightning",
|
| 13 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/config.py
CHANGED
|
@@ -15,8 +15,9 @@ OLLAMA_HOST = os.getenv("OLLAMA_HOST", "127.0.0.1")
|
|
| 15 |
OLLAMA_PORT = os.getenv("OLLAMA_PORT", "11434")
|
| 16 |
OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "llama3")
|
| 17 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 18 |
-
|
| 19 |
-
|
|
|
|
| 20 |
|
| 21 |
# Gemini Settings
|
| 22 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
|
|
|
| 15 |
OLLAMA_PORT = os.getenv("OLLAMA_PORT", "11434")
|
| 16 |
OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "llama3")
|
| 17 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 18 |
+
HF_BASE_URL = "https://router.huggingface.co/v1"
|
| 19 |
+
HF_TEXT_MODEL = "Qwen/Qwen2.5-72B-Instruct"
|
| 20 |
+
HF_IMAGE_MODEL = "black-forest-labs/FLUX.1-dev"
|
| 21 |
|
| 22 |
# Gemini Settings
|
| 23 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
modules/integrations.py
CHANGED
|
@@ -2,6 +2,7 @@ import os
|
|
| 2 |
import requests
|
| 3 |
import json
|
| 4 |
import gradio as gr
|
|
|
|
| 5 |
import uuid
|
| 6 |
import time
|
| 7 |
import io
|
|
@@ -16,7 +17,7 @@ from google import genai
|
|
| 16 |
from google.genai import types
|
| 17 |
from .config import (
|
| 18 |
GEMINI_API_KEY, OLLAMA_HOST, OLLAMA_PORT, COMFY_URL,
|
| 19 |
-
COMFY_WORKFLOW_FILE, PROMPTS_FILE, HF_TOKEN,
|
| 20 |
HF_TEXT_MODEL, HF_IMAGE_MODEL, GEMINI_TEXT_MODEL,
|
| 21 |
GEMINI_IMAGE_MODEL
|
| 22 |
)
|
|
@@ -31,6 +32,17 @@ if GEMINI_API_KEY:
|
|
| 31 |
except Exception as e:
|
| 32 |
print(f"Error initializing Gemini: {e}")
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
def load_system_prompt(key="refinement"):
|
| 35 |
"""Loads a system prompt from prompts.yaml."""
|
| 36 |
try:
|
|
@@ -53,6 +65,14 @@ def get_ollama_models():
|
|
| 53 |
except Exception:
|
| 54 |
return []
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
def refine_with_gemini(prompt, mode="refinement"):
|
| 57 |
if not gemini_active:
|
| 58 |
return "Gemini API key not found in .env file."
|
|
@@ -104,22 +124,32 @@ def refine_with_ollama(prompt, model, mode="refinement"):
|
|
| 104 |
return f"Error refining prompt with Ollama: {e}"
|
| 105 |
|
| 106 |
def refine_with_hf(prompt, token=None, mode="refinement"):
|
| 107 |
-
"""Refines the prompt using Hugging Face
|
| 108 |
-
|
| 109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
return "Error: Hugging Face token not found. Please log in or provide a token."
|
| 111 |
|
| 112 |
system_prompt = load_system_prompt(mode)
|
| 113 |
model_id = HF_TEXT_MODEL
|
| 114 |
|
| 115 |
try:
|
| 116 |
-
client = InferenceClient(api_key=active_token)
|
| 117 |
messages = [
|
| 118 |
{"role": "system", "content": system_prompt},
|
| 119 |
{"role": "user", "content": f"Original Prompt: {prompt}"}
|
| 120 |
]
|
| 121 |
|
| 122 |
-
response =
|
| 123 |
model=model_id,
|
| 124 |
messages=messages,
|
| 125 |
max_tokens=500,
|
|
@@ -127,7 +157,7 @@ def refine_with_hf(prompt, token=None, mode="refinement"):
|
|
| 127 |
)
|
| 128 |
return response.choices[0].message.content.strip()
|
| 129 |
except Exception as e:
|
| 130 |
-
return f"Hugging Face Error: {e}"
|
| 131 |
|
| 132 |
def refine_master(prompt, backend, ollama_model, manual_token=None, character_name=None):
|
| 133 |
"""Routes prompt refinement to the selected backend."""
|
|
@@ -269,15 +299,24 @@ def generate_image_with_hf(prompt, aspect_ratio, token=None, character_name="Unn
|
|
| 269 |
return None, None, "Error: Hugging Face token not found. Please log in or provide a token."
|
| 270 |
|
| 271 |
model_id = HF_IMAGE_MODEL
|
| 272 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 273 |
|
| 274 |
try:
|
| 275 |
client = InferenceClient(api_key=active_token)
|
| 276 |
-
img = client.text_to_image(
|
| 277 |
|
| 278 |
# Embed metadata
|
| 279 |
metadata = PngInfo()
|
| 280 |
-
metadata.add_text("Comment",
|
| 281 |
metadata.add_text("CharacterName", character_name)
|
| 282 |
|
| 283 |
safe_name = "".join([c if c.isalnum() else "_" for c in character_name]).strip("_")
|
|
|
|
| 2 |
import requests
|
| 3 |
import json
|
| 4 |
import gradio as gr
|
| 5 |
+
from openai import OpenAI
|
| 6 |
import uuid
|
| 7 |
import time
|
| 8 |
import io
|
|
|
|
| 17 |
from google.genai import types
|
| 18 |
from .config import (
|
| 19 |
GEMINI_API_KEY, OLLAMA_HOST, OLLAMA_PORT, COMFY_URL,
|
| 20 |
+
COMFY_WORKFLOW_FILE, PROMPTS_FILE, HF_TOKEN, HF_BASE_URL,
|
| 21 |
HF_TEXT_MODEL, HF_IMAGE_MODEL, GEMINI_TEXT_MODEL,
|
| 22 |
GEMINI_IMAGE_MODEL
|
| 23 |
)
|
|
|
|
| 32 |
except Exception as e:
|
| 33 |
print(f"Error initializing Gemini: {e}")
|
| 34 |
|
| 35 |
+
# Setup Hugging Face Router
|
| 36 |
+
hf_client = None
|
| 37 |
+
if HF_TOKEN:
|
| 38 |
+
try:
|
| 39 |
+
hf_client = OpenAI(
|
| 40 |
+
base_url=HF_BASE_URL,
|
| 41 |
+
api_key=HF_TOKEN,
|
| 42 |
+
)
|
| 43 |
+
except Exception as e:
|
| 44 |
+
print(f"Error initializing HF Client: {e}")
|
| 45 |
+
|
| 46 |
def load_system_prompt(key="refinement"):
|
| 47 |
"""Loads a system prompt from prompts.yaml."""
|
| 48 |
try:
|
|
|
|
| 65 |
except Exception:
|
| 66 |
return []
|
| 67 |
|
| 68 |
+
def check_comfy_availability():
|
| 69 |
+
"""Checks if ComfyUI is running by pinging the URL."""
|
| 70 |
+
try:
|
| 71 |
+
response = requests.get(f"{COMFY_URL}/system_stats", timeout=2)
|
| 72 |
+
return response.status_code == 200
|
| 73 |
+
except Exception:
|
| 74 |
+
return False
|
| 75 |
+
|
| 76 |
def refine_with_gemini(prompt, mode="refinement"):
|
| 77 |
if not gemini_active:
|
| 78 |
return "Gemini API key not found in .env file."
|
|
|
|
| 124 |
return f"Error refining prompt with Ollama: {e}"
|
| 125 |
|
| 126 |
def refine_with_hf(prompt, token=None, mode="refinement"):
|
| 127 |
+
"""Refines the prompt using Hugging Face Router (OpenAI compatible)."""
|
| 128 |
+
active_client = hf_client
|
| 129 |
+
|
| 130 |
+
# If a manual token is provided, create a temporary client
|
| 131 |
+
if token:
|
| 132 |
+
try:
|
| 133 |
+
active_client = OpenAI(
|
| 134 |
+
base_url=HF_BASE_URL,
|
| 135 |
+
api_key=token,
|
| 136 |
+
)
|
| 137 |
+
except Exception as e:
|
| 138 |
+
return f"Error initializing manual HF Client: {e}"
|
| 139 |
+
|
| 140 |
+
if not active_client:
|
| 141 |
return "Error: Hugging Face token not found. Please log in or provide a token."
|
| 142 |
|
| 143 |
system_prompt = load_system_prompt(mode)
|
| 144 |
model_id = HF_TEXT_MODEL
|
| 145 |
|
| 146 |
try:
|
|
|
|
| 147 |
messages = [
|
| 148 |
{"role": "system", "content": system_prompt},
|
| 149 |
{"role": "user", "content": f"Original Prompt: {prompt}"}
|
| 150 |
]
|
| 151 |
|
| 152 |
+
response = active_client.chat.completions.create(
|
| 153 |
model=model_id,
|
| 154 |
messages=messages,
|
| 155 |
max_tokens=500,
|
|
|
|
| 157 |
)
|
| 158 |
return response.choices[0].message.content.strip()
|
| 159 |
except Exception as e:
|
| 160 |
+
return f"Hugging Face Router Error: {e}"
|
| 161 |
|
| 162 |
def refine_master(prompt, backend, ollama_model, manual_token=None, character_name=None):
|
| 163 |
"""Routes prompt refinement to the selected backend."""
|
|
|
|
| 299 |
return None, None, "Error: Hugging Face token not found. Please log in or provide a token."
|
| 300 |
|
| 301 |
model_id = HF_IMAGE_MODEL
|
| 302 |
+
|
| 303 |
+
# Resolution mapping
|
| 304 |
+
res_map = {
|
| 305 |
+
"1:1": (1024, 1024),
|
| 306 |
+
"16:9": (1344, 768),
|
| 307 |
+
"9:16": (768, 1344),
|
| 308 |
+
"4:3": (1152, 864),
|
| 309 |
+
"3:4": (864, 1152)
|
| 310 |
+
}
|
| 311 |
+
width, height = res_map.get(aspect_ratio, (1024, 1024))
|
| 312 |
|
| 313 |
try:
|
| 314 |
client = InferenceClient(api_key=active_token)
|
| 315 |
+
img = client.text_to_image(prompt, model=model_id, width=width, height=height)
|
| 316 |
|
| 317 |
# Embed metadata
|
| 318 |
metadata = PngInfo()
|
| 319 |
+
metadata.add_text("Comment", prompt)
|
| 320 |
metadata.add_text("CharacterName", character_name)
|
| 321 |
|
| 322 |
safe_name = "".join([c if c.isalnum() else "_" for c in character_name]).strip("_")
|
modules/ui_layout.py
CHANGED
|
@@ -5,7 +5,7 @@ from .core_logic import (
|
|
| 5 |
save_character, load_character, get_example_list, load_example_character
|
| 6 |
)
|
| 7 |
from .integrations import (
|
| 8 |
-
get_ollama_models, refine_master, generate_image_master
|
| 9 |
)
|
| 10 |
from .name_generator import generate_fantasy_name
|
| 11 |
|
|
@@ -100,13 +100,18 @@ def build_ui():
|
|
| 100 |
load_btn = gr.UploadButton("📂 Load Character", file_types=[".json"], variant="secondary", scale=1)
|
| 101 |
|
| 102 |
with gr.Group():
|
| 103 |
-
gr.Markdown("### ⚙️
|
| 104 |
with gr.Row():
|
| 105 |
ollama_models = get_ollama_models()
|
| 106 |
ollama_active = len(ollama_models) > 0
|
|
|
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
refinement_backend = gr.Radio(
|
| 109 |
-
choices=
|
| 110 |
value="Gemini (Cloud)",
|
| 111 |
label="Prompt Refinement Backend",
|
| 112 |
scale=2
|
|
@@ -121,14 +126,17 @@ def build_ui():
|
|
| 121 |
)
|
| 122 |
|
| 123 |
with gr.Row():
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
backend_selector = gr.Radio(
|
| 125 |
-
choices=
|
| 126 |
value="Gemini (Cloud)",
|
| 127 |
label="Image Generation Backend",
|
| 128 |
scale=2
|
| 129 |
)
|
| 130 |
with gr.Column(scale=1):
|
| 131 |
-
refine_btn = gr.Button("🧠 Refine Prompt", variant="primary")
|
| 132 |
gen_img_btn = gr.Button("🖼️ Generate Image", variant="primary")
|
| 133 |
|
| 134 |
with gr.Row():
|
|
@@ -145,6 +153,7 @@ def build_ui():
|
|
| 145 |
with gr.Column(scale=1):
|
| 146 |
gr.Markdown("### 📝 Prompts & Output")
|
| 147 |
prompt_output = gr.Textbox(label="Generated Technical Prompt", lines=4, interactive=False, buttons=["copy"])
|
|
|
|
| 148 |
regenerate_btn = gr.Button("✨ Randomize Features", variant="secondary")
|
| 149 |
refined_output = gr.Textbox(label="Refined Artistic Prompt", lines=6, interactive=True, buttons=["copy", "paste", "clear"])
|
| 150 |
|
|
@@ -217,6 +226,9 @@ def build_ui():
|
|
| 217 |
fn=generate_prompt,
|
| 218 |
inputs=all_input_components,
|
| 219 |
outputs=prompt_output
|
|
|
|
|
|
|
|
|
|
| 220 |
)
|
| 221 |
|
| 222 |
load_example_btn.click(
|
|
@@ -227,6 +239,9 @@ def build_ui():
|
|
| 227 |
fn=generate_prompt,
|
| 228 |
inputs=all_input_components,
|
| 229 |
outputs=prompt_output
|
|
|
|
|
|
|
|
|
|
| 230 |
)
|
| 231 |
|
| 232 |
demo.load(fn=generate_prompt, inputs=all_input_components, outputs=prompt_output)
|
|
|
|
| 5 |
save_character, load_character, get_example_list, load_example_character
|
| 6 |
)
|
| 7 |
from .integrations import (
|
| 8 |
+
get_ollama_models, check_comfy_availability, refine_master, generate_image_master
|
| 9 |
)
|
| 10 |
from .name_generator import generate_fantasy_name
|
| 11 |
|
|
|
|
| 100 |
load_btn = gr.UploadButton("📂 Load Character", file_types=[".json"], variant="secondary", scale=1)
|
| 101 |
|
| 102 |
with gr.Group():
|
| 103 |
+
gr.Markdown("### ⚙️ AI Backend Configuration")
|
| 104 |
with gr.Row():
|
| 105 |
ollama_models = get_ollama_models()
|
| 106 |
ollama_active = len(ollama_models) > 0
|
| 107 |
+
comfy_active = check_comfy_availability()
|
| 108 |
|
| 109 |
+
refinement_choices = ["Gemini (Cloud)", "Hugging Face (Cloud)"]
|
| 110 |
+
if ollama_active:
|
| 111 |
+
refinement_choices.append("Ollama (Local)")
|
| 112 |
+
|
| 113 |
refinement_backend = gr.Radio(
|
| 114 |
+
choices=refinement_choices,
|
| 115 |
value="Gemini (Cloud)",
|
| 116 |
label="Prompt Refinement Backend",
|
| 117 |
scale=2
|
|
|
|
| 126 |
)
|
| 127 |
|
| 128 |
with gr.Row():
|
| 129 |
+
img_choices = ["Gemini (Cloud)", "Hugging Face (Cloud)"]
|
| 130 |
+
if comfy_active:
|
| 131 |
+
img_choices.append("ComfyUI (Local)")
|
| 132 |
+
|
| 133 |
backend_selector = gr.Radio(
|
| 134 |
+
choices=img_choices,
|
| 135 |
value="Gemini (Cloud)",
|
| 136 |
label="Image Generation Backend",
|
| 137 |
scale=2
|
| 138 |
)
|
| 139 |
with gr.Column(scale=1):
|
|
|
|
| 140 |
gen_img_btn = gr.Button("🖼️ Generate Image", variant="primary")
|
| 141 |
|
| 142 |
with gr.Row():
|
|
|
|
| 153 |
with gr.Column(scale=1):
|
| 154 |
gr.Markdown("### 📝 Prompts & Output")
|
| 155 |
prompt_output = gr.Textbox(label="Generated Technical Prompt", lines=4, interactive=False, buttons=["copy"])
|
| 156 |
+
refine_btn = gr.Button("🧠 Refine Prompt", variant="primary")
|
| 157 |
regenerate_btn = gr.Button("✨ Randomize Features", variant="secondary")
|
| 158 |
refined_output = gr.Textbox(label="Refined Artistic Prompt", lines=6, interactive=True, buttons=["copy", "paste", "clear"])
|
| 159 |
|
|
|
|
| 226 |
fn=generate_prompt,
|
| 227 |
inputs=all_input_components,
|
| 228 |
outputs=prompt_output
|
| 229 |
+
).then(
|
| 230 |
+
fn=lambda: "",
|
| 231 |
+
outputs=refined_output
|
| 232 |
)
|
| 233 |
|
| 234 |
load_example_btn.click(
|
|
|
|
| 239 |
fn=generate_prompt,
|
| 240 |
inputs=all_input_components,
|
| 241 |
outputs=prompt_output
|
| 242 |
+
).then(
|
| 243 |
+
fn=lambda: "",
|
| 244 |
+
outputs=refined_output
|
| 245 |
)
|
| 246 |
|
| 247 |
demo.load(fn=generate_prompt, inputs=all_input_components, outputs=prompt_output)
|
requirements.txt
CHANGED
|
@@ -6,3 +6,5 @@ requests
|
|
| 6 |
Pillow
|
| 7 |
huggingface_hub
|
| 8 |
fictional-names
|
|
|
|
|
|
|
|
|
| 6 |
Pillow
|
| 7 |
huggingface_hub
|
| 8 |
fictional-names
|
| 9 |
+
openai
|
| 10 |
+
python-dotenv
|