Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
import gradio as gr
|
| 3 |
from crewai import Agent, Task, Crew, Process, LLM
|
| 4 |
-
from crewai_tools import FileWriterTool
|
| 5 |
from dotenv import load_dotenv
|
| 6 |
import traceback
|
| 7 |
import shutil
|
|
@@ -479,7 +479,7 @@ Target Audience: {target_audience}
|
|
| 479 |
# --- SYSTEM SETUP ---
|
| 480 |
try:
|
| 481 |
llm = LLM(
|
| 482 |
-
model="gemini/gemini-
|
| 483 |
temperature=0.7,
|
| 484 |
api_key=os.environ.get("GOOGLE_API_KEY")
|
| 485 |
)
|
|
@@ -489,6 +489,8 @@ except Exception as e:
|
|
| 489 |
|
| 490 |
os.makedirs("outputs", exist_ok=True)
|
| 491 |
file_write_tool = FileWriterTool()
|
|
|
|
|
|
|
| 492 |
|
| 493 |
# --- ENHANCED AGENTS ---
|
| 494 |
designer = Agent(
|
|
@@ -572,7 +574,7 @@ developer = Agent(
|
|
| 572 |
),
|
| 573 |
verbose=True,
|
| 574 |
llm=llm,
|
| 575 |
-
tools=[file_write_tool],
|
| 576 |
allow_delegation=False
|
| 577 |
)
|
| 578 |
|
|
@@ -699,7 +701,7 @@ def create_development_task(website_type, page_type):
|
|
| 699 |
"- Implement smooth scrolling\n"
|
| 700 |
"- Add hover effects\n"
|
| 701 |
"- Include mobile menu\n\n"
|
| 702 |
-
f"Save files to 'outputs/' directory:\n"
|
| 703 |
f"- {'index.html' if page_type == 'Single-Page' else 'Multiple HTML files'}"
|
| 704 |
),
|
| 705 |
expected_output=(
|
|
@@ -747,7 +749,9 @@ chat_history = ChatHistory()
|
|
| 747 |
def clean_outputs_directory():
|
| 748 |
"""Clean the outputs directory"""
|
| 749 |
if os.path.exists("outputs"):
|
| 750 |
-
|
|
|
|
|
|
|
| 751 |
try:
|
| 752 |
os.remove(file)
|
| 753 |
except Exception as e:
|
|
@@ -756,17 +760,22 @@ def clean_outputs_directory():
|
|
| 756 |
def create_zip_archive():
|
| 757 |
"""Create a ZIP archive of output files"""
|
| 758 |
try:
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 764 |
except Exception as e:
|
| 765 |
print(f"Error creating ZIP: {e}")
|
| 766 |
return None
|
| 767 |
|
| 768 |
# --- MAIN GENERATION FUNCTION ---
|
| 769 |
-
def generate_website(website_type, project_name_input, name_method, page_type, custom_requirements
|
| 770 |
try:
|
| 771 |
if llm is None:
|
| 772 |
return (
|
|
@@ -781,13 +790,11 @@ def generate_website(website_type, project_name_input, name_method, page_type, c
|
|
| 781 |
# Generate project name with AI
|
| 782 |
project_name = f"{WEBSITE_TYPES[website_type]['emoji']} {website_type.split('/')[0]} Pro"
|
| 783 |
|
| 784 |
-
#
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
chat_history.add_message("User", f"Generate {website_type} - {page_type}")
|
| 791 |
|
| 792 |
# Clean outputs
|
| 793 |
clean_outputs_directory()
|
|
@@ -813,7 +820,7 @@ def generate_website(website_type, project_name_input, name_method, page_type, c
|
|
| 813 |
html_files = glob.glob("outputs/*.html")
|
| 814 |
if not html_files:
|
| 815 |
return (
|
| 816 |
-
"❌ No files generated. Please try again.",
|
| 817 |
None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
| 818 |
)
|
| 819 |
|
|
@@ -829,7 +836,9 @@ def generate_website(website_type, project_name_input, name_method, page_type, c
|
|
| 829 |
success_message = f"✅ **{project_name}** generated successfully!\n"
|
| 830 |
success_message += f"Type: {website_type} | Pages: {len(html_files)}"
|
| 831 |
|
| 832 |
-
|
|
|
|
|
|
|
| 833 |
|
| 834 |
if is_multipage:
|
| 835 |
zip_path = create_zip_archive()
|
|
@@ -853,42 +862,90 @@ def generate_website(website_type, project_name_input, name_method, page_type, c
|
|
| 853 |
error_trace = traceback.format_exc()
|
| 854 |
print(error_trace)
|
| 855 |
return (
|
| 856 |
-
f"❌
|
| 857 |
None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
| 858 |
)
|
| 859 |
|
|
|
|
| 860 |
def modify_website(modification_request):
|
| 861 |
-
"""Modify the existing website based on user request"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 862 |
if not chat_history.current_project:
|
| 863 |
-
return
|
| 864 |
-
|
|
|
|
|
|
|
|
|
|
| 865 |
chat_history.add_message("User", modification_request)
|
| 866 |
-
|
| 867 |
-
# Create modification task
|
| 868 |
-
modification_task = Task(
|
| 869 |
-
description=(
|
| 870 |
-
f"Modify the existing {chat_history.website_type} website.\n\n"
|
| 871 |
-
f"Previous context:\n{chat_history.get_context()}\n\n"
|
| 872 |
-
f"Modification request: {modification_request}\n\n"
|
| 873 |
-
"Update the HTML files accordingly."
|
| 874 |
-
),
|
| 875 |
-
expected_output="Modified HTML files with requested changes",
|
| 876 |
-
agent=developer,
|
| 877 |
-
tools=[file_write_tool]
|
| 878 |
-
)
|
| 879 |
-
|
| 880 |
-
crew = Crew(
|
| 881 |
-
agents=[developer],
|
| 882 |
-
tasks=[modification_task],
|
| 883 |
-
process=Process.sequential
|
| 884 |
-
)
|
| 885 |
-
|
| 886 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 887 |
result = crew.kickoff()
|
| 888 |
-
chat_history.add_message("System", f"
|
| 889 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 890 |
except Exception as e:
|
| 891 |
-
|
|
|
|
|
|
|
|
|
|
| 892 |
|
| 893 |
# --- GRADIO INTERFACE ---
|
| 894 |
with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
@@ -1026,16 +1083,16 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
| 1026 |
gr.Markdown(
|
| 1027 |
"""
|
| 1028 |
### Make Changes to Your Generated Website
|
| 1029 |
-
After generating a website, you can request modifications here.
|
| 1030 |
"""
|
| 1031 |
)
|
| 1032 |
modification_input = gr.Textbox(
|
| 1033 |
lines=3,
|
| 1034 |
-
placeholder="E.g., 'Change the hero background to blue gradient', 'Add more testimonials', 'Make the navigation sticky'",
|
| 1035 |
label="What would you like to change?"
|
| 1036 |
)
|
| 1037 |
modify_btn = gr.Button("🔧 Apply Modifications", variant="secondary")
|
| 1038 |
-
modification_status = gr.Markdown()
|
| 1039 |
|
| 1040 |
# Download Section
|
| 1041 |
with gr.Row():
|
|
@@ -1101,10 +1158,12 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
| 1101 |
outputs=[status_output, preview_output, download_single, download_zip, view_code_btn]
|
| 1102 |
)
|
| 1103 |
|
|
|
|
| 1104 |
modify_btn.click(
|
| 1105 |
fn=modify_website,
|
| 1106 |
inputs=[modification_input],
|
| 1107 |
-
outputs
|
|
|
|
| 1108 |
)
|
| 1109 |
|
| 1110 |
view_code_btn.click(
|
|
|
|
| 1 |
import os
|
| 2 |
import gradio as gr
|
| 3 |
from crewai import Agent, Task, Crew, Process, LLM
|
| 4 |
+
from crewai_tools import FileWriterTool, FileReadTool
|
| 5 |
from dotenv import load_dotenv
|
| 6 |
import traceback
|
| 7 |
import shutil
|
|
|
|
| 479 |
# --- SYSTEM SETUP ---
|
| 480 |
try:
|
| 481 |
llm = LLM(
|
| 482 |
+
model="gemini/gemini-pro",
|
| 483 |
temperature=0.7,
|
| 484 |
api_key=os.environ.get("GOOGLE_API_KEY")
|
| 485 |
)
|
|
|
|
| 489 |
|
| 490 |
os.makedirs("outputs", exist_ok=True)
|
| 491 |
file_write_tool = FileWriterTool()
|
| 492 |
+
# Add FileReadTool for modification tasks
|
| 493 |
+
file_read_tool = FileReadTool()
|
| 494 |
|
| 495 |
# --- ENHANCED AGENTS ---
|
| 496 |
designer = Agent(
|
|
|
|
| 574 |
),
|
| 575 |
verbose=True,
|
| 576 |
llm=llm,
|
| 577 |
+
tools=[file_write_tool, file_read_tool], # Give agent both read and write tools
|
| 578 |
allow_delegation=False
|
| 579 |
)
|
| 580 |
|
|
|
|
| 701 |
"- Implement smooth scrolling\n"
|
| 702 |
"- Add hover effects\n"
|
| 703 |
"- Include mobile menu\n\n"
|
| 704 |
+
f"Save files to 'outputs/' directory using the FileWriterTool:\n"
|
| 705 |
f"- {'index.html' if page_type == 'Single-Page' else 'Multiple HTML files'}"
|
| 706 |
),
|
| 707 |
expected_output=(
|
|
|
|
| 749 |
def clean_outputs_directory():
|
| 750 |
"""Clean the outputs directory"""
|
| 751 |
if os.path.exists("outputs"):
|
| 752 |
+
if os.path.exists("outputs/project.zip"):
|
| 753 |
+
os.remove("outputs/project.zip")
|
| 754 |
+
for file in glob.glob("outputs/*.html"):
|
| 755 |
try:
|
| 756 |
os.remove(file)
|
| 757 |
except Exception as e:
|
|
|
|
| 760 |
def create_zip_archive():
|
| 761 |
"""Create a ZIP archive of output files"""
|
| 762 |
try:
|
| 763 |
+
# We need to archive the contents of 'outputs', not the directory itself
|
| 764 |
+
# This makes the zip file cleaner when extracted.
|
| 765 |
+
base_name = "outputs/project"
|
| 766 |
+
root_dir = "outputs"
|
| 767 |
+
# We'll temporarily remove the zip file if it exists to avoid adding it to itself
|
| 768 |
+
if os.path.exists(base_name + '.zip'):
|
| 769 |
+
os.remove(base_name + '.zip')
|
| 770 |
+
|
| 771 |
+
shutil.make_archive(base_name, 'zip', root_dir, base_dir=None)
|
| 772 |
+
return "outputs/project.zip"
|
| 773 |
except Exception as e:
|
| 774 |
print(f"Error creating ZIP: {e}")
|
| 775 |
return None
|
| 776 |
|
| 777 |
# --- MAIN GENERATION FUNCTION ---
|
| 778 |
+
def generate_website(website_type, project_name_input, name_method, page_type, custom_requirements):
|
| 779 |
try:
|
| 780 |
if llm is None:
|
| 781 |
return (
|
|
|
|
| 790 |
# Generate project name with AI
|
| 791 |
project_name = f"{WEBSITE_TYPES[website_type]['emoji']} {website_type.split('/')[0]} Pro"
|
| 792 |
|
| 793 |
+
# Reset chat history for a new project
|
| 794 |
+
chat_history.reset()
|
| 795 |
+
chat_history.website_type = website_type
|
| 796 |
+
chat_history.project_name = project_name
|
| 797 |
+
chat_history.add_message("User", f"Generate a new {website_type} website named '{project_name}' ({page_type}).")
|
|
|
|
|
|
|
| 798 |
|
| 799 |
# Clean outputs
|
| 800 |
clean_outputs_directory()
|
|
|
|
| 820 |
html_files = glob.glob("outputs/*.html")
|
| 821 |
if not html_files:
|
| 822 |
return (
|
| 823 |
+
"❌ No HTML files were generated. The AI crew might have failed. Please check the console logs and try again.",
|
| 824 |
None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
| 825 |
)
|
| 826 |
|
|
|
|
| 836 |
success_message = f"✅ **{project_name}** generated successfully!\n"
|
| 837 |
success_message += f"Type: {website_type} | Pages: {len(html_files)}"
|
| 838 |
|
| 839 |
+
# **** FIX: Set current_project to enable modification ****
|
| 840 |
+
chat_history.current_project = project_name
|
| 841 |
+
chat_history.add_message("System", f"Successfully generated {project_name}. Files are available.")
|
| 842 |
|
| 843 |
if is_multipage:
|
| 844 |
zip_path = create_zip_archive()
|
|
|
|
| 862 |
error_trace = traceback.format_exc()
|
| 863 |
print(error_trace)
|
| 864 |
return (
|
| 865 |
+
f"❌ An unexpected error occurred during generation: {str(e)}",
|
| 866 |
None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
| 867 |
)
|
| 868 |
|
| 869 |
+
# **** FIX: Complete rewrite of modify_website function ****
|
| 870 |
def modify_website(modification_request):
|
| 871 |
+
"""Modify the existing website based on user request and update the UI."""
|
| 872 |
+
# This function now returns a 5-element tuple to update all relevant UI components
|
| 873 |
+
error_response = (
|
| 874 |
+
"❌ Please generate a website first before requesting modifications.",
|
| 875 |
+
None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
| 876 |
+
)
|
| 877 |
+
|
| 878 |
if not chat_history.current_project:
|
| 879 |
+
return error_response
|
| 880 |
+
|
| 881 |
+
if not modification_request or not modification_request.strip():
|
| 882 |
+
return ("⚠️ Please enter a modification request.", None, gr.update(), gr.update(), gr.update())
|
| 883 |
+
|
| 884 |
chat_history.add_message("User", modification_request)
|
| 885 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 886 |
try:
|
| 887 |
+
modification_task = Task(
|
| 888 |
+
description=(
|
| 889 |
+
f"You are modifying an existing '{chat_history.website_type}' website named '{chat_history.project_name}'.\n\n"
|
| 890 |
+
"First, you MUST use the FileReadTool to read the existing HTML file(s) in the 'outputs' directory to understand the current code structure. The main file is likely 'index.html'.\n\n"
|
| 891 |
+
f"The user's new modification request is: '{modification_request}'\n\n"
|
| 892 |
+
"Based on this request, you must update the HTML file(s) in the 'outputs' directory. "
|
| 893 |
+
"Use the FileWriterTool to overwrite the existing file(s) with the necessary changes. "
|
| 894 |
+
"Do NOT create new files unless the request explicitly asks for a new page. Overwrite the existing ones.\n"
|
| 895 |
+
"Maintain the existing design system, colors, fonts, Tailwind CSS classes, and overall structure unless specifically asked to change them."
|
| 896 |
+
),
|
| 897 |
+
expected_output="The complete, updated HTML code written back to the original file(s) in the 'outputs' directory using the FileWriterTool.",
|
| 898 |
+
agent=developer,
|
| 899 |
+
tools=[file_read_tool, file_write_tool]
|
| 900 |
+
)
|
| 901 |
+
|
| 902 |
+
crew = Crew(
|
| 903 |
+
agents=[developer],
|
| 904 |
+
tasks=[modification_task],
|
| 905 |
+
process=Process.sequential,
|
| 906 |
+
verbose=True
|
| 907 |
+
)
|
| 908 |
+
|
| 909 |
result = crew.kickoff()
|
| 910 |
+
chat_history.add_message("System", f"Modification applied: {modification_request[:50]}...")
|
| 911 |
+
|
| 912 |
+
# After modification, refresh the UI with the new files
|
| 913 |
+
html_files = glob.glob("outputs/*.html")
|
| 914 |
+
if not html_files:
|
| 915 |
+
return "❌ Modification failed: No HTML files found after update.", None, gr.update(), gr.update(), gr.update(visible=False)
|
| 916 |
+
|
| 917 |
+
preview_file = "outputs/index.html" if os.path.exists("outputs/index.html") else html_files[0]
|
| 918 |
+
with open(preview_file, "r", encoding="utf-8") as file:
|
| 919 |
+
html_content = file.read()
|
| 920 |
+
|
| 921 |
+
preview_html = f'<iframe srcdoc="{html_content.replace(chr(34), """)}" width="100%" height="800px" style="border: 2px solid #e0e0e0; border-radius: 8px;"></iframe>'
|
| 922 |
+
|
| 923 |
+
is_multipage = len(html_files) > 1
|
| 924 |
+
success_message = f"✅ Modifications applied successfully to **{chat_history.project_name}**!"
|
| 925 |
+
|
| 926 |
+
if is_multipage:
|
| 927 |
+
zip_path = create_zip_archive()
|
| 928 |
+
return (
|
| 929 |
+
success_message,
|
| 930 |
+
preview_html,
|
| 931 |
+
gr.update(value=preview_file, visible=True),
|
| 932 |
+
gr.update(value=zip_path, visible=True) if zip_path else gr.update(visible=False),
|
| 933 |
+
gr.update(visible=True)
|
| 934 |
+
)
|
| 935 |
+
else:
|
| 936 |
+
return (
|
| 937 |
+
success_message,
|
| 938 |
+
preview_html,
|
| 939 |
+
gr.update(value=preview_file, visible=True),
|
| 940 |
+
gr.update(visible=False),
|
| 941 |
+
gr.update(visible=True)
|
| 942 |
+
)
|
| 943 |
+
|
| 944 |
except Exception as e:
|
| 945 |
+
error_trace = traceback.format_exc()
|
| 946 |
+
print(error_trace)
|
| 947 |
+
return f"❌ Error applying modifications: {str(e)}", None, gr.update(), gr.update(), gr.update(visible=False)
|
| 948 |
+
|
| 949 |
|
| 950 |
# --- GRADIO INTERFACE ---
|
| 951 |
with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
|
|
| 1083 |
gr.Markdown(
|
| 1084 |
"""
|
| 1085 |
### Make Changes to Your Generated Website
|
| 1086 |
+
After generating a website, you can request modifications here. Your changes will update the live preview.
|
| 1087 |
"""
|
| 1088 |
)
|
| 1089 |
modification_input = gr.Textbox(
|
| 1090 |
lines=3,
|
| 1091 |
+
placeholder="E.g., 'Change the hero background to a blue gradient', 'Add more testimonials', 'Make the navigation sticky'",
|
| 1092 |
label="What would you like to change?"
|
| 1093 |
)
|
| 1094 |
modify_btn = gr.Button("🔧 Apply Modifications", variant="secondary")
|
| 1095 |
+
modification_status = gr.Markdown() # This will now be the output for modification status
|
| 1096 |
|
| 1097 |
# Download Section
|
| 1098 |
with gr.Row():
|
|
|
|
| 1158 |
outputs=[status_output, preview_output, download_single, download_zip, view_code_btn]
|
| 1159 |
)
|
| 1160 |
|
| 1161 |
+
# **** FIX: Update click handler for the modify button ****
|
| 1162 |
modify_btn.click(
|
| 1163 |
fn=modify_website,
|
| 1164 |
inputs=[modification_input],
|
| 1165 |
+
# The outputs now include the preview and download components to be refreshed
|
| 1166 |
+
outputs=[modification_status, preview_output, download_single, download_zip, view_code_btn]
|
| 1167 |
)
|
| 1168 |
|
| 1169 |
view_code_btn.click(
|