import os
import logging
import gradio as gr
from dotenv import load_dotenv
import google.generativeai as genai
from auto_diffusers import AutoDiffusersGenerator
from simple_memory_calculator import SimpleMemoryCalculator
load_dotenv()
# Configure logging for Gradio app
logger = logging.getLogger(__name__)
class GradioAutodiffusers:
def __init__(self):
logger.info("Initializing GradioAutodiffusers")
self.api_key = os.getenv('GOOGLE_API_KEY')
if not self.api_key:
logger.error("GOOGLE_API_KEY not found in environment variables")
raise ValueError("GOOGLE_API_KEY not found in .env file")
logger.debug(f"API key found, length: {len(self.api_key)}")
try:
self.generator = AutoDiffusersGenerator(self.api_key)
logger.info("AutoDiffusersGenerator initialized successfully")
except Exception as e:
logger.error(f"Failed to initialize AutoDiffusersGenerator: {e}")
raise
try:
self.memory_calculator = SimpleMemoryCalculator()
logger.info("SimpleMemoryCalculator initialized successfully")
except Exception as e:
logger.error(f"Failed to initialize SimpleMemoryCalculator: {e}")
raise
# Default settings
self.current_model = 'gemini-2.5-flash-preview-05-20'
self.temperature = 0.7
self.max_output_tokens = 8192
self.top_p = 0.9
self.top_k = 40
logger.debug(f"Default model settings: {self.current_model}, temp={self.temperature}")
def update_model_settings(self, model_name, temperature, max_output_tokens, top_p, top_k):
"""Update Gemini model settings."""
logger.info(f"Updating model settings: {model_name}")
logger.debug(f"New settings: temp={temperature}, max_tokens={max_output_tokens}, top_p={top_p}, top_k={top_k}")
try:
self.current_model = model_name
self.temperature = temperature
self.max_output_tokens = max_output_tokens
self.top_p = top_p
self.top_k = top_k
# Update the generator's model with new settings
genai.configure(api_key=self.api_key)
generation_config = genai.types.GenerationConfig(
temperature=temperature,
max_output_tokens=max_output_tokens,
top_p=top_p,
top_k=top_k
)
self.generator.model = genai.GenerativeModel(model_name, generation_config=generation_config)
logger.info("Model settings updated successfully")
return f"✅ Model updated to {model_name} with new settings"
except Exception as e:
logger.error(f"Failed to update model settings: {e}")
return f"❌ Failed to update model: {str(e)}"
def get_generation_prompt(self, model_name, prompt_text, image_size, num_inference_steps, hardware_specs, optimization_profile):
"""Get the actual prompt that will be sent to Gemini API."""
return self.generator._create_generation_prompt(
model_name, prompt_text, image_size, num_inference_steps,
hardware_specs, optimization_profile
)
def analyze_model_memory(self, model_name, vram_gb):
"""Analyze model memory requirements and provide recommendations."""
try:
if not vram_gb:
vram_gb = 8 # Default
memory_info = self.memory_calculator.get_model_memory_requirements(model_name)
recommendations = self.memory_calculator.get_memory_recommendation(model_name, float(vram_gb))
formatted_info = self.memory_calculator.format_memory_info(model_name)
return memory_info, recommendations, formatted_info
except Exception as e:
error_msg = f"Error analyzing model memory: {str(e)}"
return {'error': error_msg}, {'error': error_msg}, error_msg
def generate_code_with_manual_specs(self,
gpu_name,
vram_gb,
ram_gb,
platform,
model_name,
prompt_text,
dtype_selection,
width,
height,
inference_steps,
memory_analysis=None):
"""Generate optimized code with manual hardware specifications."""
try:
# Create manual hardware specs
# Parse dtype selection
if dtype_selection == "Auto":
user_dtype = None
else:
user_dtype = f"torch.{dtype_selection}"
manual_specs = {
'platform': platform,
'architecture': 'manual_input',
'cpu_count': 8, # Default
'python_version': '3.11',
'cuda_available': 'nvidia' in gpu_name.lower() if gpu_name else False,
'mps_available': platform == 'Darwin' and 'apple' in gpu_name.lower() if gpu_name else False,
'torch_version': '2.0+',
'manual_input': True,
'ram_gb': int(ram_gb) if ram_gb else 16,
'user_dtype': user_dtype
}
# Add GPU info if provided
if gpu_name and vram_gb:
manual_specs['gpu_info'] = [{
'name': gpu_name,
'memory_mb': int(vram_gb) * 1024
}]
if 'nvidia' in gpu_name.lower():
manual_specs['cuda_available'] = True
manual_specs['cuda_device_count'] = 1
manual_specs['cuda_device_name'] = gpu_name
manual_specs['cuda_memory'] = int(vram_gb)
else:
manual_specs['gpu_info'] = None
# Generate optimized code with manual specs and memory analysis
optimized_code = self.generator.generate_optimized_code(
model_name=model_name,
prompt_text=prompt_text,
image_size=(int(height), int(width)),
num_inference_steps=int(inference_steps),
use_manual_specs=True,
manual_specs=manual_specs,
memory_analysis=memory_analysis
)
# Clean up any markdown formatting
if optimized_code.startswith('```python'):
optimized_code = optimized_code[9:]
if optimized_code.endswith('```'):
optimized_code = optimized_code[:-3]
return optimized_code.strip()
except Exception as e:
return f"Error generating code: {str(e)}"
def create_gradio_interface():
"""Create and configure the Gradio interface."""
app = GradioAutodiffusers()
with gr.Blocks(
title="Auto-Diffusers Code Generator",
theme=gr.themes.Soft(
primary_hue="violet",
secondary_hue="blue",
neutral_hue="slate",
radius_size=gr.themes.sizes.radius_lg,
font=[gr.themes.GoogleFont("Poppins"), gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"]
).set(
background_fill_primary="*neutral_25",
background_fill_secondary="*neutral_50",
block_background_fill="rgba(255, 255, 255, 0.95)",
block_border_width="0px",
block_shadow="0 8px 32px rgba(0, 0, 0, 0.08)",
panel_background_fill="rgba(255, 255, 255, 0.9)",
button_primary_background_fill="*primary_500",
button_primary_background_fill_hover="*primary_600",
button_secondary_background_fill="rgba(255, 255, 255, 0.8)",
button_secondary_background_fill_hover="rgba(255, 255, 255, 0.95)"
),
css="""
/* Global Styles */
.gradio-container {
background: #fef7f5 !important;
min-height: 100vh;
font-family: 'Georgia', 'Times New Roman', serif !important;
}
/* Remove main tag margin and center */
main {
margin: 0 auto !important;
max-width: 100% !important;
}
.main-container {
max-width: 1400px;
margin: 0 auto;
padding: 0.5rem 0.1rem;
/* Removed position: relative that can interfere with dropdown positioning */
}
/* Paper Card Effects */
.glass-card {
background: #fefcfa !important;
border: 1px solid #f4e6e1 !important;
border-radius: 12px !important;
margin-bottom: 0.5rem !important;
padding: 0.5rem !important;
border-top: 3px solid #f0c5b8 !important;
}
.ultra-glass {
background: #fefcfa !important;
border: 1px solid #f4e6e1 !important;
border-radius: 12px !important;
margin-bottom: 0.5rem !important;
padding: 0.5rem !important;
border-left: 4px solid #f0c5b8 !important;
}
/* Paper Header */
.hero-header {
background: #fdf5f3 !important;
border: 2px solid #f4e6e1 !important;
border-radius: 16px !important;
margin-bottom: 1rem !important;
position: relative;
overflow: hidden;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
}
/* Paper Buttons */
.generate-btn {
background: #e67e5a !important;
border: 2px solid #d96b47 !important;
color: #fefcfa !important;
font-weight: 600 !important;
font-size: 1.3rem !important;
padding: 1.2rem 2.5rem !important;
border-radius: 12px !important;
transition: all 0.3s ease !important;
font-family: 'Georgia', serif !important;
letter-spacing: 0.5px !important;
}
/* View Prompt Button */
.view-prompt-btn {
background: #f4e6e1 !important;
border: 1px solid #e8a491 !important;
color: #5a3a2a !important;
font-weight: 500 !important;
font-size: 0.9rem !important;
padding: 0.5rem 1rem !important;
border-radius: 8px !important;
transition: all 0.2s ease !important;
font-family: 'Georgia', serif !important;
margin-bottom: 0.5rem !important;
}
.view-prompt-btn:hover {
background: #f0c5b8 !important;
}
/* Modal Overlay - simple approach */
.modal-overlay {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
background: rgba(0, 0, 0, 0.5) !important;
z-index: 9999 !important;
justify-content: center !important;
align-items: center !important;
padding: 2rem !important;
box-sizing: border-box !important;
}
/* Show as flex only when visible class is present */
.modal-overlay.visible {
display: flex !important;
}
/* Modal Content */
.modal-content {
background: #fefcfa !important;
border: 2px solid #f0c5b8 !important;
border-radius: 16px !important;
max-width: 90vw !important;
max-height: 80vh !important;
width: 800px !important;
padding: 2rem !important;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3) !important;
overflow: hidden !important;
flex-direction: column !important;
}
/* Modal Header */
.modal-header {
justify-content: space-between !important;
align-items: center !important;
margin-bottom: 1rem !important;
padding-bottom: 1rem !important;
border-bottom: 1px solid #f0c5b8 !important;
}
/* Modal Close Button */
.modal-close-btn {
background: #f4e6e1 !important;
border: 1px solid #e8a491 !important;
color: #5a3a2a !important;
font-weight: 700 !important;
font-size: 1.2rem !important;
padding: 0.4rem 0.6rem !important;
border-radius: 6px !important;
min-width: 2rem !important;
height: 2rem !important;
align-items: center !important;
justify-content: center !important;
}
.modal-close-btn:hover {
background: #f0c5b8 !important;
}
/* Prompt Container */
.prompt-container {
background: #fcf3f0 !important;
border: 1px solid #f0c5b8 !important;
border-radius: 8px !important;
max-height: 400px !important;
overflow-y: auto !important;
flex: 1 !important;
}
.generate-btn:hover {
background: #d96b47 !important;
transform: translateY(-1px) !important;
}
.generate-btn:active {
transform: translateY(0px) !important;
}
/* Paper Section Headers */
.section-header {
background: #f9f0ec !important;
border: 1px solid #f0c5b8 !important;
border-radius: 8px !important;
padding: 0.7rem !important;
margin-bottom: 0.5rem !important;
}
/* Paper Inputs */
input[type="text"],
input[type="number"],
textarea {
background: #fefcfa !important;
border: 2px solid #f4e6e1 !important;
border-radius: 8px !important;
padding: 0.8rem 1.2rem !important;
font-weight: 500 !important;
color: #5a3a2a !important;
font-family: 'Georgia', serif !important;
font-size: 1rem !important;
}
input[type="text"]:focus,
input[type="number"]:focus,
textarea:focus {
background: #fefcfa !important;
border-color: #e8a491 !important;
outline: none !important;
}
/* CRITICAL: Reset all problematic CSS for dropdowns */
label:has(+ [data-testid="dropdown"]),
div:has([data-testid="dropdown"]),
[data-testid="dropdown"],
[data-testid="dropdown"] *,
.gradio-dropdown,
.gradio-dropdown * {
position: static !important;
transform: none !important;
backdrop-filter: none !important;
filter: none !important;
}
/* AGGRESSIVE FIX: Override ALL possible transparency sources */
* {
--dropdown-bg: #ffffff !important;
--dropdown-opacity: 1 !important;
}
/* Target every possible dropdown element with maximum specificity */
.gradio-container [data-testid="dropdown"] div[role="listbox"],
.gradio-container .gradio-dropdown .dropdown-content,
.gradio-container .dropdown-menu,
.gradio-container div[role="listbox"],
.gradio-container .svelte-1gfkn6j,
body [data-testid="dropdown"] div[role="listbox"],
body .dropdown-menu,
body div[role="listbox"],
html [data-testid="dropdown"] div[role="listbox"] {
background: #ffffff !important;
background-color: #ffffff !important;
opacity: 1 !important;
position: absolute !important;
z-index: 99999 !important;
border: 2px solid #d1d5db !important;
border-radius: 8px !important;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25) !important;
max-height: 200px !important;
overflow-y: auto !important;
backdrop-filter: none !important;
filter: none !important;
background-image: none !important;
background-blend-mode: normal !important;
/* Force solid with CSS variables */
background: var(--dropdown-bg, #ffffff) !important;
opacity: var(--dropdown-opacity, 1) !important;
}
/* Aggressive option styling */
.gradio-container [data-testid="dropdown"] div[role="listbox"] > *,
.gradio-container .dropdown-menu > *,
.gradio-container div[role="listbox"] > *,
body [data-testid="dropdown"] div[role="listbox"] > *,
body .dropdown-menu > *,
body div[role="listbox"] > * {
background: #ffffff !important;
background-color: #ffffff !important;
padding: 0.75rem 1rem !important;
color: #1f2937 !important;
cursor: pointer !important;
opacity: 1 !important;
border: none !important;
margin: 0 !important;
display: block !important;
width: 100% !important;
text-align: left !important;
}
/* Ensure dropdown menus appear correctly with SOLID background */
[data-testid="dropdown"] div[role="listbox"],
.gradio-dropdown .dropdown-content,
.dropdown-menu,
div[role="listbox"],
.svelte-1gfkn6j,
.gradio-container div[role="listbox"] {
position: absolute !important;
z-index: 9999 !important;
background: #ffffff !important;
background-color: #ffffff !important;
opacity: 1 !important;
border: 1px solid #d1d5db !important;
border-radius: 8px !important;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15) !important;
max-height: 200px !important;
overflow-y: auto !important;
backdrop-filter: none !important;
/* Force solid background */
background-image: none !important;
background-blend-mode: normal !important;
}
/* Dropdown option styling - SOLID background for each option */
[data-testid="dropdown"] div[role="listbox"] > *,
.dropdown-menu > *,
div[role="listbox"] > *,
.svelte-1gfkn6j > * {
background: #ffffff !important;
background-color: #ffffff !important;
padding: 0.5rem 0.75rem !important;
color: #374151 !important;
cursor: pointer !important;
transition: background-color 0.2s ease !important;
opacity: 1 !important;
}
/* Dropdown option hover effect */
[data-testid="dropdown"] div[role="listbox"] > *:hover,
.dropdown-menu > *:hover,
div[role="listbox"] > *:hover {
background: #f3f4f6 !important;
color: #1f2937 !important;
}
/* Dropdown option selected state */
[data-testid="dropdown"] div[role="listbox"] > *[aria-selected="true"],
.dropdown-menu > *.selected,
div[role="listbox"] > *[aria-selected="true"] {
background: #e0e7ff !important;
color: #3730a3 !important;
}
/* Paper Code Areas */
.code-container {
background: #f9f0ec !important;
border: 1px solid #f0c5b8 !important;
border-radius: 8px !important;
overflow: hidden !important;
}
/* Force text selection on ALL code elements */
.code-container,
.code-container *,
.code-container textarea,
.code-container input,
.code-container .cm-editor,
.code-container .cm-content,
.code-container .cm-line {
user-select: text !important;
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
cursor: text !important;
}
/* Make selection visible */
.code-container .cm-editor ::selection {
background: #3b82f6 !important;
color: white !important;
}
.code-container .cm-editor ::-moz-selection {
background: #3b82f6 !important;
color: white !important;
}
/* Make cursor visible */
.code-container .cm-cursor {
border-color: #3b82f6 !important;
border-width: 2px !important;
opacity: 1 !important;
visibility: visible !important;
}
/* Ensure selection works in CodeMirror */
.code-container .cm-selectionBackground {
background: #3b82f6 !important;
opacity: 0.3 !important;
}
/* Make sure focused state is visible */
.code-container .cm-focused {
outline: 2px solid #3b82f6 !important;
outline-offset: 2px !important;
}
/* Code textbox styling */
.code-container textarea {
background: #ffffff !important;
border: none !important;
border-radius: 4px !important;
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Fira Code', monospace !important;
font-size: 14px !important;
line-height: 1.5 !important;
padding: 1.5rem !important;
color: #2d3748 !important;
font-weight: 500 !important;
resize: vertical !important;
white-space: pre !important;
overflow-wrap: normal !important;
word-break: normal !important;
}
/* Enable soft wrapping for code content */
.code-container .cm-content {
white-space: pre-wrap !important;
padding: 1.5rem !important;
color: #5a3a2a !important;
font-size: 14px !important;
font-weight: 500 !important;
}
.code-container .cm-focused {
outline: none !important;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3) !important;
}
.code-container .cm-line {
padding-left: 0.5rem !important;
white-space: pre-wrap !important;
word-wrap: break-word !important;
overflow-wrap: break-word !important;
}
/* Force wrapping ONLY - NO SCROLLING */
.code-container .cm-editor {
white-space: pre-wrap !important;
overflow-x: hidden !important;
}
.code-container .cm-scroller {
overflow-x: hidden !important;
width: 100% !important;
}
.code-container .cm-editor .cm-content {
white-space: pre-wrap !important;
word-break: break-all !important;
overflow-wrap: anywhere !important;
width: 100% !important;
max-width: 100% !important;
}
.code-container .cm-editor .cm-line {
white-space: pre-wrap !important;
word-break: break-all !important;
overflow-wrap: anywhere !important;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
}
/* Force the entire code container to have no horizontal overflow */
.code-container,
.code-container * {
overflow-x: hidden !important;
max-width: 100% !important;
}
/* Moderate syntax highlighting for Python */
.code-container .cm-keyword { color: #7c3aed !important; }
.code-container .cm-string { color: #059669 !important; }
.code-container .cm-comment { color: #6b7280 !important; font-style: italic !important; }
.code-container .cm-number { color: #dc2626 !important; }
.code-container .cm-variable { color: #1e40af !important; }
.code-container .cm-function { color: #7c2d12 !important; }
.code-container .cm-operator { color: #374151 !important; }
/* Paper Code header */
.code-container label {
background: #f5e6e0 !important;
color: #5a3a2a !important;
padding: 0.75rem 1.25rem !important;
border-radius: 8px 8px 0 0 !important;
font-weight: 700 !important;
font-size: 1.1rem !important;
margin: 0 !important;
border: none !important;
border-bottom: 1px solid #f0c5b8 !important;
font-family: 'Georgia', serif !important;
}
/* Custom scrollbar for code area */
.code-container .cm-scroller::-webkit-scrollbar {
width: 6px !important;
height: 6px !important;
}
.code-container .cm-scroller::-webkit-scrollbar-track {
background: rgba(243, 244, 246, 0.8) !important;
border-radius: 3px !important;
}
.code-container .cm-scroller::-webkit-scrollbar-thumb {
background: rgba(156, 163, 175, 0.8) !important;
border-radius: 3px !important;
}
.code-container .cm-scroller::-webkit-scrollbar-thumb:hover {
background: rgba(107, 114, 128, 0.9) !important;
}
/* Paper Line numbers */
.code-container .cm-lineNumbers {
background: #f5e6e0 !important;
color: #b8847a !important;
border-right: 1px solid #f0c5b8 !important;
padding-right: 0.5rem !important;
}
.code-container .cm-lineNumbers .cm-gutterElement {
color: #b8847a !important;
font-weight: 400 !important;
}
/* Paper Memory Cards */
.memory-card {
background: #fcf3f0 !important;
border: 1px solid #f4e6e1 !important;
border-radius: 12px !important;
padding: 0.7rem !important;
border-left: 4px solid #e8a491 !important;
}
/* Paper Labels */
label {
font-weight: 600 !important;
color: #5a3a2a !important;
font-size: 1.1rem !important;
font-family: 'Georgia', serif !important;
}
/* Memory Analysis Spacing */
.memory-analysis-spacing {
padding-top: 1rem !important;
border-top: 1px solid rgba(226, 232, 240, 0.6) !important;
}
/* FINAL OVERRIDE: Nuclear option for dropdown transparency */
[role="listbox"] {
background: white !important;
opacity: 1 !important;
}
[role="listbox"] > * {
background: white !important;
opacity: 1 !important;
}
/* Gradio-specific nuclear option */
.gradio-app [role="listbox"],
.gradio-app [role="listbox"] > * {
background: #ffffff !important;
background-color: #ffffff !important;
opacity: 1 !important;
}
/* Last resort: override all possible transparent backgrounds */
div[style*="background"] {
background: unset !important;
}
[role="listbox"][style*="background"] {
background: #ffffff !important;
}