Spaces:
Running
Running
import os | |
import gradio as gr | |
import traceback | |
from PIL import Image, ImageEnhance, ImageFilter | |
import io | |
import base64 | |
import google.generativeai as genai | |
# --- Environment Configuration --- | |
GEMINI_KEY = os.environ.get("GEMINI_KEY", "") | |
# --- Style Template Optimization --- | |
BASE_TEMPLATE = """Describe this design as a concise Flux 1.1 Pro prompt focusing on: | |
- Key visual elements | |
- Technical specifications | |
- Style consistency | |
- Functional requirements""" | |
STYLE_INSTRUCTIONS = { | |
"General": BASE_TEMPLATE, | |
"Realistic": f"{BASE_TEMPLATE}\nPHOTOREALISTIC RULES: Use photography terms, texture details, accurate lighting", | |
"Kawaii": f"{BASE_TEMPLATE}\nKAWAII RULES: Rounded shapes, pastel colors, cute expressions", | |
"Vector": f"{BASE_TEMPLATE}\nVECTOR RULES: Clean lines, geometric shapes, B&W gradients", | |
"Silhouette": f"{BASE_TEMPLATE}\nSILHOUETTE RULES: High contrast, minimal details, strong outlines" | |
} | |
# --- Flux Configuration --- | |
FLUX_SPECS = { | |
"aspect_ratios": ["1:1", "16:9", "4:3", "9:16"], | |
"color_modes": ["B&W", "CMYK", "RGB"], | |
"dpi_options": [72, 150, 300, 600] | |
} | |
# --- Image Processing Pipeline --- | |
def preprocess_image(img): | |
try: | |
if isinstance(img, str): # Handle file paths | |
img = Image.open(img) | |
img = img.convert("RGB") | |
img = ImageEnhance.Contrast(img).enhance(1.2) | |
img = img.filter(ImageFilter.SHARPEN) | |
return img | |
except Exception as e: | |
raise ValueError(f"π΄ Image processing failed: {str(e)}") | |
# --- Core Generation Engine --- | |
def generate_prompt(image, api_key, style, creativity, neg_prompt, aspect, color_mode, dpi): | |
try: | |
# Step 1: Input Validation | |
if not image: | |
return "", "β οΈ Please upload an image." | |
api_key = api_key or GEMINI_KEY | |
if not api_key: | |
return "", "π API key required - set in env (GEMINI_KEY) or input field." | |
# Step 2: Gemini Setup | |
try: | |
genai.configure(api_key=api_key) | |
model = genai.GenerativeModel("gemini-1.5-pro") | |
except ImportError: | |
return "", "π« Failed to import google.generativeai. Install with: pip install google-generativeai" | |
except Exception as e: | |
if "authentication" in str(e).lower(): | |
return "", "π Invalid API key or authentication error." | |
else: | |
return "", f"βοΈ API initialization error: {str(e)}" | |
# Step 3: Preprocess Image | |
try: | |
img = preprocess_image(image) | |
img_bytes = io.BytesIO() | |
img.save(img_bytes, format="PNG") | |
img_b64 = base64.b64encode(img_bytes.getvalue()).decode() | |
except Exception as e: | |
return "", f"πΌοΈ Image preparation failed: {str(e)}" | |
# Step 4: Build Instruction Prompt | |
try: | |
instruction = f"{STYLE_INSTRUCTIONS[style]}\nAVOID: {neg_prompt}\n" | |
instruction += f"ASPECT: {aspect}, COLORS: {color_mode}, DPI: {dpi}\n" | |
except KeyError: | |
return "", "π οΈ Invalid style selected. Please choose from available options." | |
# Step 5: Call Gemini API | |
try: | |
response = model.generate_content( | |
contents=[instruction, {"mime_type": "image/png", "data": img_b64}], | |
generation_config={"temperature": creativity} | |
) | |
raw_prompt = response.text | |
except Exception as e: | |
return "", f"π€ Prompt generation failed: {str(e)}" | |
return raw_prompt, "β Prompt generated successfully!" | |
except Exception as e: | |
traceback.print_exc() | |
return "", f"π₯ Unexpected error: {str(e)}" | |
# --- Main Interface --- | |
def build_interface(): | |
global STYLE_INSTRUCTIONS # Ensure access to global dict | |
with gr.Blocks(title="Flux Pro Generator") as app: | |
gr.Markdown("# π¨ Flux Pro Prompt Generator") | |
gr.Markdown("Generate optimized design prompts from images using Google's Gemini.") | |
with gr.Row(): | |
# Left Panel: Image Upload & API Key | |
with gr.Column(scale=1): | |
api_key = gr.Textbox( | |
label="π Gemini API Key", | |
value=GEMINI_KEY, | |
type="password", | |
info="Set GEMINI_KEY environment variable for production." | |
) | |
img_input = gr.Image( | |
label="πΌοΈ Upload Design", | |
type="pil", | |
sources=["upload"], | |
interactive=True | |
) | |
# Right Panel: Prompt Output + Controls Below | |
with gr.Column(scale=2): | |
status_msg = gr.Textbox(label="π’ Status", interactive=False) | |
prompt_output = gr.Textbox( | |
label="π Optimized Prompt", | |
lines=8, | |
interactive=True | |
) | |
# Controls under prompt box | |
style = gr.Dropdown( | |
list(STYLE_INSTRUCTIONS.keys()), | |
value="General", | |
label="π¨ Target Style" | |
) | |
with gr.Accordion("βοΈ Advanced Settings", open=False): | |
creativity = gr.Slider(0.0, 1.0, 0.7, label="π§ Creativity Level") | |
neg_prompt = gr.Textbox(label="π« Negative Prompts", placeholder="What to avoid") | |
aspect = gr.Dropdown(FLUX_SPECS["aspect_ratios"], value="1:1", label="Aspect Ratio") | |
color_mode = gr.Dropdown(FLUX_SPECS["color_modes"], value="RGB", label="Color Mode") | |
dpi = gr.Dropdown([str(d) for d in FLUX_SPECS["dpi_options"]], value="300", label="Output DPI") | |
gen_btn = gr.Button("β¨ Generate Prompt", variant="primary") | |
# Event Handling | |
gen_btn.click( | |
fn=generate_prompt, | |
inputs=[ | |
img_input, api_key, style, creativity, | |
neg_prompt, aspect, color_mode, dpi | |
], | |
outputs=[prompt_output, status_msg], | |
api_name="generate" | |
) | |
return app | |
# --- Production Launch --- | |
if __name__ == "__main__": | |
app = build_interface() | |
app.launch() |