Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,103 +1,171 @@
|
|
|
|
1 |
import gradio as gr
|
2 |
import google.generativeai as genai
|
3 |
-
from PIL import Image
|
4 |
import io
|
5 |
import base64
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
-
# Mapping styles to instructions
|
8 |
STYLE_INSTRUCTIONS = {
|
9 |
-
"General":
|
10 |
-
"Describe this design as a single, cohesive, and concise prompt suitable for Flux 1.1 Pro. "
|
11 |
-
"Focus on key elements such as text, symbols, layout, and overall style."
|
12 |
-
),
|
13 |
"Realistic": (
|
14 |
-
"
|
15 |
-
"
|
16 |
),
|
17 |
"Kawaii/Cartoon": (
|
18 |
-
"
|
19 |
-
"
|
20 |
),
|
21 |
"Vector": (
|
22 |
-
"
|
23 |
-
"
|
24 |
-
"Specify that the design should be created in a clean, professional vector and illustration style, "
|
25 |
-
"emphasizing sharp lines, geometric shapes, and smooth gradients where applicable. "
|
26 |
-
"The entire design must be in black and white, using only shades of gray for depth and contrast. "
|
27 |
-
"Avoid any use of color unless it is essential to the design's purpose. "
|
28 |
-
"Avoid cartoonish or overly stylized elements unless they align with the design's purpose. "
|
29 |
-
"Use clear and direct language to convey the design's theme, humor, or purpose, if applicable. "
|
30 |
-
"Ensure the description is compact, well-structured, and optimized for creating a graphic. "
|
31 |
-
"Include only essential details and avoid unnecessary elaboration."
|
32 |
),
|
33 |
"Silhouette": (
|
34 |
-
"
|
35 |
-
"
|
36 |
),
|
37 |
}
|
38 |
|
39 |
-
#
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
except Exception as e:
|
47 |
-
return f"โ Error: {str(e)}"
|
48 |
-
|
49 |
-
# Function to generate a prompt using Gemini
|
50 |
-
def generate_prompt(image, api_key, style):
|
51 |
-
if not api_key:
|
52 |
-
return "โ Error: Please enter your Google Gemini API key."
|
53 |
-
|
54 |
-
try:
|
55 |
-
genai.configure(api_key=api_key)
|
56 |
-
model = genai.GenerativeModel("gemini-1.5-pro")
|
57 |
-
|
58 |
-
# Convert image to base64
|
59 |
-
image_bytes = io.BytesIO()
|
60 |
-
image.save(image_bytes, format=image.format if image.format else "PNG")
|
61 |
-
image_base64 = base64.b64encode(image_bytes.getvalue()).decode('utf-8')
|
62 |
-
|
63 |
-
instruction = STYLE_INSTRUCTIONS.get(style, STYLE_INSTRUCTIONS["General"])
|
64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
response = model.generate_content([
|
66 |
-
|
67 |
-
{"mime_type": "image/png", "data": image_base64}
|
68 |
])
|
|
|
69 |
|
70 |
-
|
71 |
-
except Exception as e:
|
72 |
-
return f"โ Error generating prompt: {str(e)}"
|
73 |
-
|
74 |
-
# Gradio Interface
|
75 |
-
def main():
|
76 |
-
with gr.Blocks() as app:
|
77 |
-
gr.Markdown("## ๐จ Flux Prompt Generator with Gemini 1.5 Pro")
|
78 |
-
|
79 |
-
api_key = gr.Textbox(label="๐ Google Gemini API Key", type="password", placeholder="Paste your Gemini API key here")
|
80 |
-
check_button = gr.Button("โ
Check API Key")
|
81 |
-
check_output = gr.Textbox(label="API Key Status")
|
82 |
|
|
|
|
|
|
|
83 |
with gr.Row():
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
return app
|
100 |
|
101 |
-
#
|
102 |
-
|
103 |
-
app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
import gradio as gr
|
3 |
import google.generativeai as genai
|
4 |
+
from PIL import Image, ImageEnhance, ImageFilter
|
5 |
import io
|
6 |
import base64
|
7 |
+
import json
|
8 |
+
import time
|
9 |
+
try:
|
10 |
+
import pyperclip
|
11 |
+
except ImportError:
|
12 |
+
os.system('pip install pyperclip')
|
13 |
+
import pyperclip
|
14 |
+
|
15 |
+
# --- Security First Configuration ---
|
16 |
+
GEMINI_KEY = os.environ.get("GEMINI_KEY", "") # Load from environment variable
|
17 |
+
|
18 |
+
# --- Template Optimization System ---
|
19 |
+
BASE_TEMPLATE = (
|
20 |
+
"Describe this design as a single, cohesive, and concise prompt suitable for Flux 1.1 Pro. "
|
21 |
+
"Focus on key elements such as text, symbols, layout, and overall style."
|
22 |
+
)
|
23 |
|
|
|
24 |
STYLE_INSTRUCTIONS = {
|
25 |
+
"General": BASE_TEMPLATE,
|
|
|
|
|
|
|
26 |
"Realistic": (
|
27 |
+
f"{BASE_TEMPLATE} Focus on photorealistic details: textures, lighting, depth. "
|
28 |
+
"Avoid illustrations/cartoon styles. Use technical photography terms."
|
29 |
),
|
30 |
"Kawaii/Cartoon": (
|
31 |
+
f"{BASE_TEMPLATE} Emphasize cute, rounded shapes, playful expressions, "
|
32 |
+
"vibrant colors. Use anime/kawaii terminology."
|
33 |
),
|
34 |
"Vector": (
|
35 |
+
f"{BASE_TEMPLATE} Specify clean vector style with sharp lines, geometric shapes. "
|
36 |
+
"Black/white only with gray gradients. Use design technical terms."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
),
|
38 |
"Silhouette": (
|
39 |
+
f"{BASE_TEMPLATE} Use high-contrast black/white silhouettes. "
|
40 |
+
"Focus on bold shapes and outlines. Eliminate interior details."
|
41 |
),
|
42 |
}
|
43 |
|
44 |
+
# --- Flux Configuration Engine ---
|
45 |
+
FLUX_SPECS = {
|
46 |
+
"aspect_ratios": ["1:1", "16:9", "4:3", "9:16", "Custom"],
|
47 |
+
"output_formats": ["SVG", "PNG-300dpi", "PDF", "EPS"],
|
48 |
+
"color_modes": ["B&W", "CMYK", "Spot Colors", "RGB"],
|
49 |
+
"complexity_levels": ["Minimal", "Medium", "High", "Ultra"]
|
50 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
+
# --- Quality Control Systems ---
|
53 |
+
class QualityValidator:
|
54 |
+
VALIDATION_PROMPT = """Analyze this Flux prompt on:
|
55 |
+
1. Technical specificity (1-5)
|
56 |
+
2. Style adherence (1-5)
|
57 |
+
3. Flux compatibility (1-5)
|
58 |
+
Respond ONLY as JSON: {"total": x/15, "issues": [list]}"""
|
59 |
+
|
60 |
+
@classmethod
|
61 |
+
def validate(cls, prompt, model):
|
62 |
+
try:
|
63 |
+
response = model.generate_content([cls.VALIDATION_PROMPT, prompt])
|
64 |
+
return json.loads(response.text)
|
65 |
+
except:
|
66 |
+
return {"total": 0, "issues": ["Validation failed"]}
|
67 |
+
|
68 |
+
# --- Image Processing Pipeline ---
|
69 |
+
def preprocess_image(img):
|
70 |
+
"""Enhance image quality before analysis"""
|
71 |
+
img = img.convert("RGB")
|
72 |
+
img = ImageEnhance.Contrast(img).enhance(1.2)
|
73 |
+
img = img.filter(ImageFilter.SHARPEN)
|
74 |
+
return img
|
75 |
+
|
76 |
+
# --- Core Application Logic ---
|
77 |
+
def generate_prompt(image, api_key, style, creativity, neg_prompt, flux_specs):
|
78 |
+
genai.configure(api_key=api_key or GEMINI_KEY)
|
79 |
+
model = genai.GenerativeModel("gemini-1.5-pro", generation_config={
|
80 |
+
"temperature": creativity,
|
81 |
+
"top_p": 0.95
|
82 |
+
})
|
83 |
+
|
84 |
+
# Pre-process image
|
85 |
+
img = preprocess_image(image)
|
86 |
+
img_bytes = io.BytesIO()
|
87 |
+
img.save(img_bytes, format="PNG")
|
88 |
+
img_b64 = base64.b64encode(img_bytes.getvalue()).decode()
|
89 |
+
|
90 |
+
# Build instruction
|
91 |
+
instruction = f"{STYLE_INSTRUCTIONS[style]}\nAVOID: {neg_prompt}\nFLUX SPECS: {flux_specs}"
|
92 |
+
|
93 |
+
# Generate initial prompt
|
94 |
+
response = model.generate_content([instruction, {"mime_type": "image/png", "data": img_b64}])
|
95 |
+
raw_prompt = response.text
|
96 |
+
|
97 |
+
# Quality validation
|
98 |
+
validation = QualityValidator.validate(raw_prompt, model)
|
99 |
+
if validation["total"] < 10: # Regenerate if low quality
|
100 |
response = model.generate_content([
|
101 |
+
f"Improve this prompt addressing: {validation['issues']}\n\n{raw_prompt}"
|
|
|
102 |
])
|
103 |
+
raw_prompt = response.text
|
104 |
|
105 |
+
return raw_prompt, validation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
+
# --- UI Components ---
|
108 |
+
def create_advanced_params():
|
109 |
+
with gr.Accordion("โ๏ธ Advanced Parameters", open=False):
|
110 |
with gr.Row():
|
111 |
+
creativity = gr.Slider(0.0, 1.0, 0.7, label="Creativity")
|
112 |
+
neg_prompt = gr.Textbox(label="๐ซ Avoid in Prompt", placeholder="e.g., no text, avoid gradients")
|
113 |
+
with gr.Row():
|
114 |
+
aspect = gr.Dropdown(FLUX_SPECS["aspect_ratios"], value="1:1", label="Aspect Ratio")
|
115 |
+
fmt = gr.Dropdown(FLUX_SPECS["output_formats"], value="SVG", label="Output Format")
|
116 |
+
color = gr.Dropdown(FLUX_SPECS["color_modes"], value="B&W", label="Color Mode")
|
117 |
+
complexity = gr.Dropdown(FLUX_SPECS["complexity_levels"], value="Medium", label="Complexity")
|
118 |
+
return [creativity, neg_prompt, aspect, fmt, color, complexity]
|
119 |
+
|
120 |
+
# --- Gradio Interface ---
|
121 |
+
def build_interface():
|
122 |
+
with gr.Blocks(title="Flux Pro Generator") as app:
|
123 |
+
# Security First
|
124 |
+
api_key = gr.Textbox(label="๐ Gemini API Key", value=GEMINI_KEY, type="password",
|
125 |
+
info="Set GEMINI_KEY environment variable for production")
|
126 |
+
|
127 |
+
# Main Workflow
|
128 |
+
with gr.Row():
|
129 |
+
with gr.Column(scale=1):
|
130 |
+
img_input = gr.Image(label="๐ผ๏ธ Upload Design", type="pil", sources=["upload", "clipboard"])
|
131 |
+
style = gr.Dropdown(list(STYLE_INSTRUCTIONS), value="General", label="๐จ Target Style")
|
132 |
+
adv_params = create_advanced_params()
|
133 |
+
|
134 |
+
with gr.Column(scale=2):
|
135 |
+
prompt_output = gr.Textbox(label="๐ Optimized Prompt", lines=8, interactive=False)
|
136 |
+
with gr.Row():
|
137 |
+
gen_btn = gr.Button("โจ Generate", variant="primary")
|
138 |
+
copy_btn = gr.Button("๐ Copy")
|
139 |
+
quality_report = gr.JSON(label="๐ Quality Report")
|
140 |
+
|
141 |
+
# Enterprise Features
|
142 |
+
token_counter = gr.Textbox(label="๐งฎ Token Usage", interactive=False)
|
143 |
+
history = gr.State([])
|
144 |
+
|
145 |
+
# Event Handling
|
146 |
+
gen_btn.click(
|
147 |
+
generate_prompt,
|
148 |
+
inputs=[img_input, api_key, style] + adv_params,
|
149 |
+
outputs=[prompt_output, quality_report]
|
150 |
+
)
|
151 |
+
|
152 |
+
copy_btn.click(
|
153 |
+
lambda x: (pyperclip.copy(x), x),
|
154 |
+
inputs=prompt_output,
|
155 |
+
outputs=prompt_output
|
156 |
+
)
|
157 |
|
158 |
return app
|
159 |
|
160 |
+
# --- Production Deployment ---
|
161 |
+
if __name__ == "__main__":
|
162 |
+
app = build_interface()
|
163 |
+
app.launch(
|
164 |
+
server_name="0.0.0.0",
|
165 |
+
server_port=int(os.getenv("PORT", 7860)),
|
166 |
+
share=False,
|
167 |
+
auth=(
|
168 |
+
os.getenv("APP_USER", "admin"),
|
169 |
+
os.getenv("APP_PWD", "admin")
|
170 |
+
) if os.getenv("ENV") == "prod" else None
|
171 |
+
)
|