mroccuper commited on
Commit
cb93ca5
ยท
verified ยท
1 Parent(s): a740663

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -148
app.py CHANGED
@@ -1,6 +1,5 @@
1
  import os
2
  import gradio as gr
3
- import requests
4
  import json
5
  import time
6
  import traceback
@@ -8,14 +7,6 @@ import io
8
  import base64
9
  from PIL import Image, ImageEnhance, ImageFilter
10
 
11
- # Conditional imports
12
- try:
13
- import google.generativeai as genai
14
- GENAI_AVAILABLE = True
15
- except ImportError:
16
- GENAI_AVAILABLE = False
17
- print("Warning: google-generativeai not installed, will attempt on-demand import")
18
-
19
  # --- Environment Configuration ---
20
  GEMINI_KEY = os.environ.get("GEMINI_KEY", "")
21
  DEFAULT_PORT = int(os.environ.get("PORT", 7860))
@@ -44,49 +35,6 @@ FLUX_SPECS = {
44
  "dpi_options": [72, 150, 300, 600]
45
  }
46
 
47
- # --- Quality Control System ---
48
- class QualityValidator:
49
- VALIDATION_TEMPLATE = """Analyze this Flux prompt:
50
- 1. Score style adherence (1-5)
51
- 2. List technical issues
52
- 3. Suggest improvements
53
- Respond ONLY as JSON: {"score": x/10, "issues": [], "suggestions": []}"""
54
-
55
- @classmethod
56
- def validate(cls, prompt, model):
57
- try:
58
- with gr.utils.TempFiles() as temp:
59
- response = model.generate_content([cls.VALIDATION_TEMPLATE, prompt])
60
- return json.loads(response.text)
61
- except Exception as e:
62
- print(f"Validation error: {str(e)}")
63
- return {"score": 0, "issues": ["Validation failed"], "suggestions": []}
64
-
65
- # --- Lazy API Initialization ---
66
- def init_genai_api(api_key):
67
- """Initialize Gemini API with error handling"""
68
- if not GENAI_AVAILABLE:
69
- try:
70
- # Attempt dynamic import
71
- global genai
72
- import google.generativeai as genai
73
- except ImportError:
74
- raise ValueError("Failed to import google.generativeai. Install with: pip install google-generativeai")
75
-
76
- try:
77
- genai.configure(api_key=api_key)
78
- # Test connection with minimal request
79
- model = genai.GenerativeModel("gemini-1.5-pro")
80
- model.generate_content("test", request_options={"timeout": 5})
81
- return model
82
- except Exception as e:
83
- if "authentication" in str(e).lower():
84
- raise ValueError("Invalid API key or authentication error")
85
- elif "timeout" in str(e).lower():
86
- raise ValueError("API connection timeout - check your internet connection")
87
- else:
88
- raise ValueError(f"API initialization error: {str(e)}")
89
-
90
  # --- Image Processing Pipeline ---
91
  def preprocess_image(img):
92
  """Convert and enhance uploaded images"""
@@ -111,11 +59,18 @@ def generate_prompt(image, api_key, style, creativity, neg_prompt, aspect, color
111
  if not api_key:
112
  return {"error": "API key required - set in env (GEMINI_KEY) or input field"}
113
 
114
- # Initialize model with proper error handling
115
  try:
116
- model = init_genai_api(api_key)
117
- except ValueError as e:
118
- return {"error": str(e)}
 
 
 
 
 
 
 
119
 
120
  # Process image with timeout protection
121
  start_time = time.time()
@@ -132,30 +87,15 @@ def generate_prompt(image, api_key, style, creativity, neg_prompt, aspect, color
132
  try:
133
  response = model.generate_content(
134
  contents=[instruction, {"mime_type": "image/png", "data": img_b64}],
135
- generation_config={"temperature": creativity},
136
- request_options={"timeout": API_TIMEOUT}
137
  )
138
  raw_prompt = response.text
139
- except requests.exceptions.Timeout:
140
- return {"error": "API request timed out (>30s). Try a smaller image or check your connection."}
141
  except Exception as e:
142
  return {"error": f"Generation failed: {str(e)}"}
143
 
144
- # Quality validation (skip if taking too long)
145
  validation = {"score": 8, "issues": [], "suggestions": []}
146
- if time.time() - start_time < 20: # Only validate if we have time
147
- try:
148
- validation = QualityValidator.validate(raw_prompt, model)
149
- if validation.get("score", 0) < 7:
150
- response = model.generate_content(
151
- f"Improve this prompt: {raw_prompt}\nIssues: {validation['issues']}",
152
- request_options={"timeout": 10}
153
- )
154
- raw_prompt = response.text
155
- except:
156
- # Continue even if validation fails
157
- pass
158
-
159
  # Token tracking
160
  input_tokens = len(img_b64) // 4 # Approximate base64 token count
161
  output_tokens = len(raw_prompt.split())
@@ -170,18 +110,6 @@ def generate_prompt(image, api_key, style, creativity, neg_prompt, aspect, color
170
  traceback.print_exc()
171
  return {"error": str(e)}
172
 
173
- # --- UI Components ---
174
- def create_advanced_controls():
175
- with gr.Accordion("โš™๏ธ Advanced Settings", open=False):
176
- with gr.Row():
177
- creativity = gr.Slider(0.0, 1.0, 0.7, label="Creativity Level")
178
- neg_prompt = gr.Textbox(label="๐Ÿšซ Negative Prompts", placeholder="What to avoid")
179
- with gr.Row():
180
- aspect = gr.Dropdown(FLUX_SPECS["aspect_ratios"], value="1:1", label="Aspect Ratio")
181
- color_mode = gr.Dropdown(FLUX_SPECS["color_modes"], value="RGB", label="Color Mode")
182
- dpi = gr.Dropdown([str(d) for d in FLUX_SPECS["dpi_options"]], value="300", label="Output DPI")
183
- return [creativity, neg_prompt, aspect, color_mode, dpi]
184
-
185
  # --- UI Response Formatting ---
186
  def format_generation_response(result):
187
  """Format the response from generate_prompt for the UI"""
@@ -190,9 +118,13 @@ def format_generation_response(result):
190
  else:
191
  return result.get("prompt", ""), result.get("validation", {}), result.get("stats", {})
192
 
 
 
 
 
193
  # --- Main Interface ---
194
  def build_interface():
195
- with gr.Blocks(title="Flux Pro Generator", theme=gr.themes.Soft()) as app:
196
  # Header
197
  gr.Markdown("# ๐ŸŽจ Flux Pro Prompt Generator")
198
  gr.Markdown("Generate optimized design prompts from images using Google's Gemini")
@@ -206,7 +138,7 @@ def build_interface():
206
  )
207
 
208
  # Main Workflow
209
- with gr.Row(variant="panel"):
210
  with gr.Column(scale=1):
211
  img_input = gr.Image(
212
  label="๐Ÿ–ผ๏ธ Upload Design",
@@ -219,18 +151,28 @@ def build_interface():
219
  value="General",
220
  label="๐ŸŽจ Target Style"
221
  )
222
- adv_controls = create_advanced_controls()
 
 
 
 
 
 
 
 
223
  gen_btn = gr.Button("โœจ Generate Prompt", variant="primary")
224
- status_msg = gr.Textbox(label="Status", visible=True)
225
 
226
  with gr.Column(scale=2):
227
  prompt_output = gr.Textbox(
228
  label="๐Ÿ“ Optimized Prompt",
229
  lines=8,
230
- interactive=False
 
231
  )
 
232
  with gr.Row():
233
- copy_btn = gr.Button("๐Ÿ“‹ Copy")
 
234
  quality_report = gr.JSON(
235
  label="๐Ÿ” Quality Report",
236
  visible=True
@@ -239,69 +181,27 @@ def build_interface():
239
  label="๐Ÿงฎ Token Usage",
240
  visible=True
241
  )
242
-
243
  # Event Handling
244
  gen_btn.click(
245
- lambda *args: format_generation_response(generate_prompt(*args)),
246
- inputs=[img_input, api_key, style] + adv_controls,
 
 
 
247
  outputs=[prompt_output, quality_report, token_stats],
248
  api_name="generate"
 
 
 
249
  )
250
 
251
- # Add a JavaScript function for clipboard functionality
252
- app.load(None, None, None, _js="""
253
- function setupCopyButton() {
254
- // Find the copy button by its text
255
- const copyButtons = Array.from(document.querySelectorAll('button')).filter(
256
- button => button.textContent.includes('Copy')
257
- );
258
-
259
- if (copyButtons.length > 0) {
260
- const copyBtn = copyButtons[0];
261
- copyBtn.addEventListener('click', function() {
262
- // Find the prompt output textarea
263
- const textareas = document.querySelectorAll('textarea');
264
- let promptTextarea = null;
265
-
266
- for (let textarea of textareas) {
267
- if (textarea.closest('div').querySelector('label')?.textContent.includes('Optimized Prompt')) {
268
- promptTextarea = textarea;
269
- break;
270
- }
271
- }
272
-
273
- if (promptTextarea && promptTextarea.value) {
274
- navigator.clipboard.writeText(promptTextarea.value)
275
- .then(() => {
276
- const originalText = copyBtn.textContent;
277
- copyBtn.textContent = "โœ“ Copied!";
278
- setTimeout(() => {
279
- copyBtn.textContent = originalText;
280
- }, 2000);
281
- })
282
- .catch(err => {
283
- console.error('Failed to copy: ', err);
284
- alert('Copy failed. Please select and copy manually.');
285
- });
286
- }
287
- });
288
- }
289
- }
290
-
291
- // Run our setup once the DOM is fully loaded
292
- if (document.readyState === 'loading') {
293
- document.addEventListener('DOMContentLoaded', setupCopyButton);
294
- } else {
295
- // DOM already loaded, run setup
296
- setTimeout(setupCopyButton, 1000);
297
- }
298
- """)
299
-
300
- # Add a simple no-op function for the copy button
301
  copy_btn.click(
302
- lambda x: x,
303
  inputs=prompt_output,
304
- outputs=prompt_output
 
305
  )
306
 
307
  return app
@@ -309,4 +209,4 @@ def build_interface():
309
  # --- Production Launch ---
310
  if __name__ == "__main__":
311
  app = build_interface()
312
- app.launch(server_name="0.0.0.0", server_port=DEFAULT_PORT, share=False)
 
1
  import os
2
  import gradio as gr
 
3
  import json
4
  import time
5
  import traceback
 
7
  import base64
8
  from PIL import Image, ImageEnhance, ImageFilter
9
 
 
 
 
 
 
 
 
 
10
  # --- Environment Configuration ---
11
  GEMINI_KEY = os.environ.get("GEMINI_KEY", "")
12
  DEFAULT_PORT = int(os.environ.get("PORT", 7860))
 
35
  "dpi_options": [72, 150, 300, 600]
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  # --- Image Processing Pipeline ---
39
  def preprocess_image(img):
40
  """Convert and enhance uploaded images"""
 
59
  if not api_key:
60
  return {"error": "API key required - set in env (GEMINI_KEY) or input field"}
61
 
62
+ # Import and configure Gemini only when needed
63
  try:
64
+ import google.generativeai as genai
65
+ genai.configure(api_key=api_key)
66
+ model = genai.GenerativeModel("gemini-1.5-pro")
67
+ except ImportError:
68
+ return {"error": "Failed to import google.generativeai. Install with: pip install google-generativeai"}
69
+ except Exception as e:
70
+ if "authentication" in str(e).lower():
71
+ return {"error": "Invalid API key or authentication error"}
72
+ else:
73
+ return {"error": f"API initialization error: {str(e)}"}
74
 
75
  # Process image with timeout protection
76
  start_time = time.time()
 
87
  try:
88
  response = model.generate_content(
89
  contents=[instruction, {"mime_type": "image/png", "data": img_b64}],
90
+ generation_config={"temperature": creativity}
 
91
  )
92
  raw_prompt = response.text
 
 
93
  except Exception as e:
94
  return {"error": f"Generation failed: {str(e)}"}
95
 
96
+ # Simple quality validation
97
  validation = {"score": 8, "issues": [], "suggestions": []}
98
+
 
 
 
 
 
 
 
 
 
 
 
 
99
  # Token tracking
100
  input_tokens = len(img_b64) // 4 # Approximate base64 token count
101
  output_tokens = len(raw_prompt.split())
 
110
  traceback.print_exc()
111
  return {"error": str(e)}
112
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  # --- UI Response Formatting ---
114
  def format_generation_response(result):
115
  """Format the response from generate_prompt for the UI"""
 
118
  else:
119
  return result.get("prompt", ""), result.get("validation", {}), result.get("stats", {})
120
 
121
+ # Modern copy function using Gradio's JavaScript API
122
+ def copy_text(text):
123
+ return gr.update(value=text), f"โœ“ Copied: '{text[:20]}...'", gr.Button.update(variant="secondary")
124
+
125
  # --- Main Interface ---
126
  def build_interface():
127
+ with gr.Blocks(title="Flux Pro Generator", theme="soft") as app:
128
  # Header
129
  gr.Markdown("# ๐ŸŽจ Flux Pro Prompt Generator")
130
  gr.Markdown("Generate optimized design prompts from images using Google's Gemini")
 
138
  )
139
 
140
  # Main Workflow
141
+ with gr.Row():
142
  with gr.Column(scale=1):
143
  img_input = gr.Image(
144
  label="๐Ÿ–ผ๏ธ Upload Design",
 
151
  value="General",
152
  label="๐ŸŽจ Target Style"
153
  )
154
+
155
+ # Advanced Settings
156
+ with gr.Accordion("โš™๏ธ Advanced Settings", open=False):
157
+ creativity = gr.Slider(0.0, 1.0, 0.7, label="Creativity Level")
158
+ neg_prompt = gr.Textbox(label="๐Ÿšซ Negative Prompts", placeholder="What to avoid")
159
+ aspect = gr.Dropdown(FLUX_SPECS["aspect_ratios"], value="1:1", label="Aspect Ratio")
160
+ color_mode = gr.Dropdown(FLUX_SPECS["color_modes"], value="RGB", label="Color Mode")
161
+ dpi = gr.Dropdown([str(d) for d in FLUX_SPECS["dpi_options"]], value="300", label="Output DPI")
162
+
163
  gen_btn = gr.Button("โœจ Generate Prompt", variant="primary")
 
164
 
165
  with gr.Column(scale=2):
166
  prompt_output = gr.Textbox(
167
  label="๐Ÿ“ Optimized Prompt",
168
  lines=8,
169
+ interactive=True,
170
+ show_copy_button=True # Modern Gradio has built-in copy button
171
  )
172
+ status_msg = gr.Textbox(label="Status", visible=True)
173
  with gr.Row():
174
+ copy_btn = gr.Button("๐Ÿ“‹ Copy to Clipboard", variant="secondary")
175
+
176
  quality_report = gr.JSON(
177
  label="๐Ÿ” Quality Report",
178
  visible=True
 
181
  label="๐Ÿงฎ Token Usage",
182
  visible=True
183
  )
184
+
185
  # Event Handling
186
  gen_btn.click(
187
+ fn=generate_prompt,
188
+ inputs=[
189
+ img_input, api_key, style, creativity,
190
+ neg_prompt, aspect, color_mode, dpi
191
+ ],
192
  outputs=[prompt_output, quality_report, token_stats],
193
  api_name="generate"
194
+ ).then(
195
+ fn=lambda: gr.update(value="Generation complete!"),
196
+ outputs=status_msg
197
  )
198
 
199
+ # Modern copy implementation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  copy_btn.click(
201
+ fn=copy_text,
202
  inputs=prompt_output,
203
+ outputs=[prompt_output, status_msg, copy_btn],
204
+ js="(text) => { if(text) { navigator.clipboard.writeText(text); } return [text]; }"
205
  )
206
 
207
  return app
 
209
  # --- Production Launch ---
210
  if __name__ == "__main__":
211
  app = build_interface()
212
+ app.launch(server_name="0.0.0.0", server_port=DEFAULT_PORT)