Spaces:
No application file
No application file
Update app.py
Browse files
app.py
CHANGED
|
@@ -11,6 +11,7 @@ import base64
|
|
| 11 |
import uuid
|
| 12 |
import concurrent.futures
|
| 13 |
import re
|
|
|
|
| 14 |
|
| 15 |
# --- Configuration and Initialization ---
|
| 16 |
|
|
@@ -87,7 +88,7 @@ Based *only* on the requirements above, generate a single, comprehensive JSON ob
|
|
| 87 |
"""
|
| 88 |
|
| 89 |
def generate_image(prompt: str, aspect_ratio: str):
|
| 90 |
-
"""Generates an image using Gemini and returns a base64 data URL."""
|
| 91 |
print(f"Generating image for prompt: {prompt}")
|
| 92 |
try:
|
| 93 |
# Refactored to use the new client.models.generate_content method
|
|
@@ -103,14 +104,25 @@ def generate_image(prompt: str, aspect_ratio: str):
|
|
| 103 |
|
| 104 |
if image_part:
|
| 105 |
mime_type = image_part.inline_data.mime_type
|
| 106 |
-
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
else:
|
| 109 |
print(f"Warning: Image generation failed for prompt: {prompt}. No image data in response.")
|
| 110 |
-
return
|
| 111 |
except Exception as e:
|
| 112 |
print(f"Error generating image for prompt '{prompt}': {e}")
|
| 113 |
-
return
|
| 114 |
|
| 115 |
def generate_page_html(page, settings):
|
| 116 |
"""Generates the HTML for a single page based on the website settings."""
|
|
@@ -388,7 +400,7 @@ def create_gradio_app():
|
|
| 388 |
|
| 389 |
# --- Step 2: Generate Images in Parallel ---
|
| 390 |
tasks = []
|
| 391 |
-
logo_prompts = image_prompts.get('logoPrompts', [])
|
| 392 |
block_prompts = image_prompts.get('blockImagePrompts', [])
|
| 393 |
|
| 394 |
if logo_prompts:
|
|
@@ -399,20 +411,23 @@ def create_gradio_app():
|
|
| 399 |
if block_prompts:
|
| 400 |
yield {status_text: f"Generating {len(block_prompts)} content images..."}
|
| 401 |
for p_info in block_prompts:
|
|
|
|
| 402 |
tasks.append(("block", p_info))
|
| 403 |
|
| 404 |
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
|
| 405 |
future_to_task = {executor.submit(generate_image, task[1]['prompt'] if task[0]=='block' else task[1], '16:9' if task[0]=='block' and task[1].get('type')=='hero' else '1:1'): task for task in tasks}
|
| 406 |
|
| 407 |
-
|
|
|
|
| 408 |
for i, future in enumerate(concurrent.futures.as_completed(future_to_task)):
|
| 409 |
task_type, task_data = future_to_task[future]
|
| 410 |
try:
|
| 411 |
-
|
| 412 |
-
if not
|
| 413 |
|
| 414 |
if task_type == "logo":
|
| 415 |
-
|
|
|
|
| 416 |
|
| 417 |
elif task_type == "block":
|
| 418 |
original_block_id = task_data['blockId']
|
|
@@ -427,7 +442,7 @@ def create_gradio_app():
|
|
| 427 |
if not block_to_update: continue
|
| 428 |
|
| 429 |
key_to_update = 'bgImage' if block_to_update.get('type') == 'hero' else 'image'
|
| 430 |
-
block_to_update[key_to_update] =
|
| 431 |
|
| 432 |
yield {status_text: f"Processing images... ({i+1}/{len(tasks)})"}
|
| 433 |
|
|
@@ -437,13 +452,15 @@ def create_gradio_app():
|
|
| 437 |
yield {
|
| 438 |
generating_view: gr.update(visible=False),
|
| 439 |
logo_picker_view: gr.update(visible=True),
|
| 440 |
-
logo_gallery: gr.update(value=
|
| 441 |
website_settings_state: new_settings,
|
| 442 |
-
active_page_path_state: active_page_path
|
|
|
|
| 443 |
}
|
| 444 |
|
| 445 |
-
def handle_logo_select(evt: gr.SelectData, settings, active_path):
|
| 446 |
-
|
|
|
|
| 447 |
settings['header']['logoUrl'] = logo_url
|
| 448 |
|
| 449 |
page = get_page_by_path(active_path, settings)
|
|
@@ -532,6 +549,7 @@ def create_gradio_app():
|
|
| 532 |
# --- State Management ---
|
| 533 |
website_settings_state = gr.State(DEFAULT_WEBSITE_SETTINGS)
|
| 534 |
active_page_path_state = gr.State("index.html")
|
|
|
|
| 535 |
|
| 536 |
# --- View: Welcome ---
|
| 537 |
with gr.Column(visible=True) as welcome_view:
|
|
@@ -625,13 +643,14 @@ def create_gradio_app():
|
|
| 625 |
inputs=questionnaire_inputs,
|
| 626 |
outputs=[
|
| 627 |
questionnaire_view, generating_view, status_text, error_box,
|
| 628 |
-
logo_picker_view, logo_gallery, website_settings_state, active_page_path_state
|
|
|
|
| 629 |
]
|
| 630 |
)
|
| 631 |
|
| 632 |
logo_gallery.select(
|
| 633 |
handle_logo_select,
|
| 634 |
-
inputs=[website_settings_state, active_page_path_state],
|
| 635 |
outputs=[
|
| 636 |
logo_picker_view, preview_view, website_settings_state, html_preview, code_preview,
|
| 637 |
page_selector, header_title_input, footer_text_input,
|
|
|
|
| 11 |
import uuid
|
| 12 |
import concurrent.futures
|
| 13 |
import re
|
| 14 |
+
import tempfile
|
| 15 |
|
| 16 |
# --- Configuration and Initialization ---
|
| 17 |
|
|
|
|
| 88 |
"""
|
| 89 |
|
| 90 |
def generate_image(prompt: str, aspect_ratio: str):
|
| 91 |
+
"""Generates an image using Gemini and returns a file path and a base64 data URL."""
|
| 92 |
print(f"Generating image for prompt: {prompt}")
|
| 93 |
try:
|
| 94 |
# Refactored to use the new client.models.generate_content method
|
|
|
|
| 104 |
|
| 105 |
if image_part:
|
| 106 |
mime_type = image_part.inline_data.mime_type
|
| 107 |
+
image_data = image_part.inline_data.data
|
| 108 |
+
|
| 109 |
+
# Create base64 URL
|
| 110 |
+
base64_data = base64.b64encode(image_data).decode("utf-8")
|
| 111 |
+
base64_url = f"data:{mime_type};base64,{base64_data}"
|
| 112 |
+
|
| 113 |
+
# Save to temp file
|
| 114 |
+
extension = mime_type.split('/')[-1]
|
| 115 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=f".{extension}") as temp_file:
|
| 116 |
+
temp_file.write(image_data)
|
| 117 |
+
temp_filepath = temp_file.name
|
| 118 |
+
|
| 119 |
+
return temp_filepath, base64_url
|
| 120 |
else:
|
| 121 |
print(f"Warning: Image generation failed for prompt: {prompt}. No image data in response.")
|
| 122 |
+
return None, None
|
| 123 |
except Exception as e:
|
| 124 |
print(f"Error generating image for prompt '{prompt}': {e}")
|
| 125 |
+
return None, None
|
| 126 |
|
| 127 |
def generate_page_html(page, settings):
|
| 128 |
"""Generates the HTML for a single page based on the website settings."""
|
|
|
|
| 400 |
|
| 401 |
# --- Step 2: Generate Images in Parallel ---
|
| 402 |
tasks = []
|
| 403 |
+
logo_prompts = [re.sub(r'import\s.*', '', p).strip() for p in image_prompts.get('logoPrompts', [])]
|
| 404 |
block_prompts = image_prompts.get('blockImagePrompts', [])
|
| 405 |
|
| 406 |
if logo_prompts:
|
|
|
|
| 411 |
if block_prompts:
|
| 412 |
yield {status_text: f"Generating {len(block_prompts)} content images..."}
|
| 413 |
for p_info in block_prompts:
|
| 414 |
+
p_info['prompt'] = re.sub(r'import\s.*', '', p_info.get('prompt', '')).strip()
|
| 415 |
tasks.append(("block", p_info))
|
| 416 |
|
| 417 |
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
|
| 418 |
future_to_task = {executor.submit(generate_image, task[1]['prompt'] if task[0]=='block' else task[1], '16:9' if task[0]=='block' and task[1].get('type')=='hero' else '1:1'): task for task in tasks}
|
| 419 |
|
| 420 |
+
logo_filepaths = []
|
| 421 |
+
logo_base64s = []
|
| 422 |
for i, future in enumerate(concurrent.futures.as_completed(future_to_task)):
|
| 423 |
task_type, task_data = future_to_task[future]
|
| 424 |
try:
|
| 425 |
+
filepath, base64_url = future.result()
|
| 426 |
+
if not filepath or not base64_url: continue
|
| 427 |
|
| 428 |
if task_type == "logo":
|
| 429 |
+
logo_filepaths.append(filepath)
|
| 430 |
+
logo_base64s.append(base64_url)
|
| 431 |
|
| 432 |
elif task_type == "block":
|
| 433 |
original_block_id = task_data['blockId']
|
|
|
|
| 442 |
if not block_to_update: continue
|
| 443 |
|
| 444 |
key_to_update = 'bgImage' if block_to_update.get('type') == 'hero' else 'image'
|
| 445 |
+
block_to_update[key_to_update] = base64_url
|
| 446 |
|
| 447 |
yield {status_text: f"Processing images... ({i+1}/{len(tasks)})"}
|
| 448 |
|
|
|
|
| 452 |
yield {
|
| 453 |
generating_view: gr.update(visible=False),
|
| 454 |
logo_picker_view: gr.update(visible=True),
|
| 455 |
+
logo_gallery: gr.update(value=logo_filepaths if logo_filepaths else []),
|
| 456 |
website_settings_state: new_settings,
|
| 457 |
+
active_page_path_state: active_page_path,
|
| 458 |
+
generated_logos_state: logo_base64s
|
| 459 |
}
|
| 460 |
|
| 461 |
+
def handle_logo_select(evt: gr.SelectData, settings, active_path, all_logo_base64s):
|
| 462 |
+
selected_index = evt.index
|
| 463 |
+
logo_url = all_logo_base64s[selected_index]
|
| 464 |
settings['header']['logoUrl'] = logo_url
|
| 465 |
|
| 466 |
page = get_page_by_path(active_path, settings)
|
|
|
|
| 549 |
# --- State Management ---
|
| 550 |
website_settings_state = gr.State(DEFAULT_WEBSITE_SETTINGS)
|
| 551 |
active_page_path_state = gr.State("index.html")
|
| 552 |
+
generated_logos_state = gr.State([])
|
| 553 |
|
| 554 |
# --- View: Welcome ---
|
| 555 |
with gr.Column(visible=True) as welcome_view:
|
|
|
|
| 643 |
inputs=questionnaire_inputs,
|
| 644 |
outputs=[
|
| 645 |
questionnaire_view, generating_view, status_text, error_box,
|
| 646 |
+
logo_picker_view, logo_gallery, website_settings_state, active_page_path_state,
|
| 647 |
+
generated_logos_state
|
| 648 |
]
|
| 649 |
)
|
| 650 |
|
| 651 |
logo_gallery.select(
|
| 652 |
handle_logo_select,
|
| 653 |
+
inputs=[website_settings_state, active_page_path_state, generated_logos_state],
|
| 654 |
outputs=[
|
| 655 |
logo_picker_view, preview_view, website_settings_state, html_preview, code_preview,
|
| 656 |
page_selector, header_title_input, footer_text_input,
|