Spaces:
No application file
No application file
Update app.py
Browse files
app.py
CHANGED
|
@@ -12,13 +12,17 @@ import uuid
|
|
| 12 |
import concurrent.futures
|
| 13 |
import re
|
| 14 |
|
|
|
|
|
|
|
|
|
|
| 15 |
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
|
| 16 |
if not GEMINI_API_KEY:
|
| 17 |
-
raise ValueError("GEMINI_API_KEY not found in environment variables.")
|
| 18 |
|
| 19 |
# Initialize Gemini client
|
| 20 |
client = genai.Client(api_key=GEMINI_API_KEY)
|
| 21 |
|
|
|
|
| 22 |
# --- Default Data Structures (Ported from TypeScript) ---
|
| 23 |
|
| 24 |
DEFAULT_WEBSITE_SETTINGS = {
|
|
@@ -319,20 +323,33 @@ def create_gradio_app():
|
|
| 319 |
}
|
| 320 |
}
|
| 321 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
response = client.models.generate_content(
|
| 323 |
model='gemini-2.5-flash',
|
| 324 |
contents=prompt,
|
| 325 |
config=types.GenerateContentConfig(
|
| 326 |
response_mime_type="application/json",
|
| 327 |
-
response_schema=schema
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
safety_settings={
|
| 331 |
-
types.HarmCategory.HARM_CATEGORY_HARASSMENT: types.HarmBlockThreshold.BLOCK_NONE,
|
| 332 |
-
types.HarmCategory.HARM_CATEGORY_HATE_SPEECH: types.HarmBlockThreshold.BLOCK_NONE,
|
| 333 |
-
types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: types.HarmBlockThreshold.BLOCK_NONE,
|
| 334 |
-
types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: types.HarmBlockThreshold.BLOCK_NONE,
|
| 335 |
-
}
|
| 336 |
)
|
| 337 |
design_plan = json.loads(response.text)
|
| 338 |
except Exception as e:
|
|
@@ -418,7 +435,8 @@ def create_gradio_app():
|
|
| 418 |
|
| 419 |
yield {
|
| 420 |
generating_view: gr.update(visible=False),
|
| 421 |
-
logo_picker_view: gr.update(visible=True
|
|
|
|
| 422 |
website_settings_state: new_settings,
|
| 423 |
active_page_path_state: active_page_path
|
| 424 |
}
|
|
@@ -432,7 +450,6 @@ def create_gradio_app():
|
|
| 432 |
|
| 433 |
# Update controls with the new settings
|
| 434 |
page_names = [p['name'] for p in settings['pages']]
|
| 435 |
-
page_paths = [p['path'] for p in settings['pages']]
|
| 436 |
active_page_name = get_page_by_path(active_path, settings)['name']
|
| 437 |
|
| 438 |
return {
|
|
@@ -465,21 +482,15 @@ def create_gradio_app():
|
|
| 465 |
|
| 466 |
# Create dynamic controls for the selected page's content blocks
|
| 467 |
content_controls = []
|
| 468 |
-
for
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
gr.Textbox(value=block.get('headline'), label="Headline", elem_id=f"{path}_{block['id']}_headline")
|
| 472 |
-
if 'subheadline' in block:
|
| 473 |
-
gr.Textbox(value=block.get('subheadline'), label="Subheadline", elem_id=f"{path}_{block['id']}_subheadline")
|
| 474 |
-
if 'text' in block:
|
| 475 |
-
gr.Textbox(value=block.get('text'), label="Text", lines=4, elem_id=f"{path}_{block['id']}_text")
|
| 476 |
-
# Add more controls for other block types (features, paragraphs, etc.) if needed
|
| 477 |
|
| 478 |
return {
|
| 479 |
active_page_path_state: path,
|
| 480 |
html_preview: html,
|
| 481 |
code_preview: html,
|
| 482 |
-
page_content_controls: gr.update(value=content_controls)
|
| 483 |
}
|
| 484 |
|
| 485 |
def handle_setting_change(settings, path, *values):
|
|
@@ -579,8 +590,9 @@ def create_gradio_app():
|
|
| 579 |
with gr.Tabs():
|
| 580 |
with gr.TabItem("Pages & Content"):
|
| 581 |
page_selector = gr.Radio(label="Select Page to Edit", choices=["Home"], value="Home")
|
| 582 |
-
|
| 583 |
-
|
|
|
|
| 584 |
with gr.TabItem("Global Settings"):
|
| 585 |
with gr.Accordion("Header & Footer", open=True):
|
| 586 |
header_title_input = gr.Textbox(label="Header: Site Title")
|
|
@@ -612,7 +624,7 @@ def create_gradio_app():
|
|
| 612 |
inputs=questionnaire_inputs,
|
| 613 |
outputs=[
|
| 614 |
questionnaire_view, generating_view, status_text, error_box,
|
| 615 |
-
logo_picker_view, website_settings_state, active_page_path_state
|
| 616 |
]
|
| 617 |
)
|
| 618 |
|
|
@@ -631,7 +643,7 @@ def create_gradio_app():
|
|
| 631 |
page_selector.change(
|
| 632 |
handle_page_change,
|
| 633 |
inputs=[page_selector, website_settings_state],
|
| 634 |
-
outputs=[active_page_path_state, html_preview, code_preview
|
| 635 |
)
|
| 636 |
|
| 637 |
# Consolidate setting controls for easier handling
|
|
|
|
| 12 |
import concurrent.futures
|
| 13 |
import re
|
| 14 |
|
| 15 |
+
# --- Configuration and Initialization ---
|
| 16 |
+
|
| 17 |
+
# Get the API key from environment variables
|
| 18 |
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
|
| 19 |
if not GEMINI_API_KEY:
|
| 20 |
+
raise ValueError("GEMINI_API_KEY not found in environment variables. Please set it in your Hugging Face Space secrets.")
|
| 21 |
|
| 22 |
# Initialize Gemini client
|
| 23 |
client = genai.Client(api_key=GEMINI_API_KEY)
|
| 24 |
|
| 25 |
+
|
| 26 |
# --- Default Data Structures (Ported from TypeScript) ---
|
| 27 |
|
| 28 |
DEFAULT_WEBSITE_SETTINGS = {
|
|
|
|
| 323 |
}
|
| 324 |
}
|
| 325 |
|
| 326 |
+
safety_settings = [
|
| 327 |
+
{
|
| 328 |
+
"category": types.HarmCategory.HARM_CATEGORY_HARASSMENT,
|
| 329 |
+
"threshold": types.HarmBlockThreshold.BLOCK_NONE,
|
| 330 |
+
},
|
| 331 |
+
{
|
| 332 |
+
"category": types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
|
| 333 |
+
"threshold": types.HarmBlockThreshold.BLOCK_NONE,
|
| 334 |
+
},
|
| 335 |
+
{
|
| 336 |
+
"category": types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
|
| 337 |
+
"threshold": types.HarmBlockThreshold.BLOCK_NONE,
|
| 338 |
+
},
|
| 339 |
+
{
|
| 340 |
+
"category": types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
|
| 341 |
+
"threshold": types.HarmBlockThreshold.BLOCK_NONE,
|
| 342 |
+
},
|
| 343 |
+
]
|
| 344 |
+
|
| 345 |
response = client.models.generate_content(
|
| 346 |
model='gemini-2.5-flash',
|
| 347 |
contents=prompt,
|
| 348 |
config=types.GenerateContentConfig(
|
| 349 |
response_mime_type="application/json",
|
| 350 |
+
response_schema=schema,
|
| 351 |
+
safety_settings=safety_settings
|
| 352 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
)
|
| 354 |
design_plan = json.loads(response.text)
|
| 355 |
except Exception as e:
|
|
|
|
| 435 |
|
| 436 |
yield {
|
| 437 |
generating_view: gr.update(visible=False),
|
| 438 |
+
logo_picker_view: gr.update(visible=True),
|
| 439 |
+
logo_gallery: gr.update(value=logo_results if logo_results else []),
|
| 440 |
website_settings_state: new_settings,
|
| 441 |
active_page_path_state: active_page_path
|
| 442 |
}
|
|
|
|
| 450 |
|
| 451 |
# Update controls with the new settings
|
| 452 |
page_names = [p['name'] for p in settings['pages']]
|
|
|
|
| 453 |
active_page_name = get_page_by_path(active_path, settings)['name']
|
| 454 |
|
| 455 |
return {
|
|
|
|
| 482 |
|
| 483 |
# Create dynamic controls for the selected page's content blocks
|
| 484 |
content_controls = []
|
| 485 |
+
# This part is complex with Gradio's current API for dynamic updates based on state.
|
| 486 |
+
# For this example, we'll keep it simple and not dynamically generate inputs,
|
| 487 |
+
# relying on a more complex (and currently absent) handle_content_change function.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
|
| 489 |
return {
|
| 490 |
active_page_path_state: path,
|
| 491 |
html_preview: html,
|
| 492 |
code_preview: html,
|
| 493 |
+
# page_content_controls: gr.update(value=content_controls) # Dynamic controls are tricky
|
| 494 |
}
|
| 495 |
|
| 496 |
def handle_setting_change(settings, path, *values):
|
|
|
|
| 590 |
with gr.Tabs():
|
| 591 |
with gr.TabItem("Pages & Content"):
|
| 592 |
page_selector = gr.Radio(label="Select Page to Edit", choices=["Home"], value="Home")
|
| 593 |
+
# Dynamic content controls are complex in Gradio, so we'll omit them for simplicity
|
| 594 |
+
gr.Markdown("*(Content editing is simplified for this demo. Changes can be made in the generated code.)*")
|
| 595 |
+
|
| 596 |
with gr.TabItem("Global Settings"):
|
| 597 |
with gr.Accordion("Header & Footer", open=True):
|
| 598 |
header_title_input = gr.Textbox(label="Header: Site Title")
|
|
|
|
| 624 |
inputs=questionnaire_inputs,
|
| 625 |
outputs=[
|
| 626 |
questionnaire_view, generating_view, status_text, error_box,
|
| 627 |
+
logo_picker_view, logo_gallery, website_settings_state, active_page_path_state
|
| 628 |
]
|
| 629 |
)
|
| 630 |
|
|
|
|
| 643 |
page_selector.change(
|
| 644 |
handle_page_change,
|
| 645 |
inputs=[page_selector, website_settings_state],
|
| 646 |
+
outputs=[active_page_path_state, html_preview, code_preview]
|
| 647 |
)
|
| 648 |
|
| 649 |
# Consolidate setting controls for easier handling
|