Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import google.generativeai as genai | |
| import zipfile | |
| import os | |
| import re | |
| import toml # Import the toml library | |
| # Load secrets from secrets.toml | |
| try: | |
| # Use os.path.join to ensure correct path | |
| secrets_path = os.path.join(os.path.dirname(__file__), "secrets.toml") | |
| secrets = toml.load(secrets_path) | |
| GEMINI_API_KEY = secrets["AIzaSyC_MFgpk5t3woYooMIPkIA5-Kzaon13-m0"] # Corrected Line! Access the key *by name* | |
| except FileNotFoundError: | |
| print("Error: secrets.toml not found. Make sure it exists in the same directory.") | |
| GEMINI_API_KEY = None # Or some default value | |
| except KeyError: | |
| print("Error: GEMINI_API_KEY not found in secrets.toml.") | |
| GEMINI_API_KEY = None | |
| # Step 3: Configure Gemini API | |
| if GEMINI_API_KEY: | |
| genai.configure(api_key=GEMINI_API_KEY) | |
| model = genai.GenerativeModel("gemini-1.5-pro") | |
| else: | |
| print("Gemini API key not found. The app will not function correctly.") | |
| model = None | |
| # Step 4: Define enhanced prompts for Firebase integration | |
| FIREBASE_SETUP_PROMPT = """ | |
| Add detailed Firebase setup instructions including: | |
| 1. How to create a Firebase project if not already done | |
| 2. How to add the Firebase SDK to the project | |
| 3. Proper configuration with environment variables or config files | |
| 4. Security best practices | |
| """ | |
| FIREBASE_AUTH_PROMPT = """ | |
| Include complete Firebase Authentication implementation with: | |
| 1. User sign-up functionality | |
| 2. Login functionality | |
| 3. Password reset capabilities | |
| 4. Session management | |
| 5. Protected routes | |
| """ | |
| FIREBASE_DATABASE_PROMPT = """ | |
| Include Firebase Realtime Database or Firestore implementation with: | |
| 1. Data structure design | |
| 2. CRUD operations | |
| 3. Real-time listeners | |
| 4. Security rules | |
| """ | |
| FIREBASE_HOSTING_PROMPT = """ | |
| Include Firebase Hosting implementation instructions: | |
| 1. Project structure for hosting | |
| 2. Configuration files | |
| 3. Deployment commands | |
| 4. Custom domain setup (if needed) | |
| """ | |
| # Step 5: Define the Web Development Agent function | |
| def web_dev_agent(prompt, task_type, use_firebase, include_auth, include_database, include_hosting): | |
| try: | |
| if model is None: | |
| return "Error: Gemini API key not configured.", None, "<html><body><p>Gemini API key not configured. Check the logs.</p></body></html>" | |
| # Base prompt | |
| full_prompt = f"You are an expert web development agent. Generate detailed, production-ready {task_type} code for the following task: {prompt}.\n\n" | |
| # Add Firebase-specific instructions if requested | |
| if use_firebase: | |
| full_prompt += f"{FIREBASE_SETUP_PROMPT}\n\n" | |
| if include_auth: | |
| full_prompt += f"{FIREBASE_AUTH_PROMPT}\n\n" | |
| if include_database: | |
| full_prompt += f"{FIREBASE_DATABASE_PROMPT}\n\n" | |
| if include_hosting: | |
| full_prompt += f"{FIREBASE_HOSTING_PROMPT}\n\n" | |
| # Add specific instructions based on task type | |
| if task_type.lower() == "frontend": | |
| full_prompt += "Focus on responsive design, clean UI, and modern frameworks like React, Vue, or Angular as appropriate. Include HTML, CSS, and JavaScript.\n\n" | |
| else: | |
| full_prompt += "Focus on secure, scalable backend architecture. Include proper error handling, logging, and API documentation.\n\n" | |
| # Add final instruction for code quality | |
| full_prompt += "Provide complete, well-commented code with clear instructions on how to implement it. Include package.json or similar configuration files where appropriate." | |
| # Generate content using Gemini API | |
| response = model.generate_content(full_prompt) | |
| code = response.text | |
| # Extract and organize code files from the response | |
| files = extract_code_files(code, task_type.lower()) | |
| # Create output directory | |
| os.makedirs("web_output", exist_ok=True) | |
| # Create individual files | |
| for filename, content in files.items(): | |
| file_path = os.path.join("web_output", filename) | |
| os.makedirs(os.path.dirname(file_path), exist_ok=True) | |
| with open(file_path, "w") as f: | |
| f.write(content) | |
| # Create a README file | |
| readme_content = f"# Web Development Project\n\n## Description\n{prompt}\n\n## Task Type\n{task_type}\n\n" | |
| if use_firebase: | |
| readme_content += "## Firebase Features\n" | |
| if include_auth: | |
| readme_content += "- Authentication\n" | |
| if include_database: | |
| readme_content += "- Database\n" | |
| if include_hosting: | |
| readme_content += "- Hosting\n" | |
| with open(os.path.join("web_output", "README.md"), "w") as f: | |
| f.write(readme_content) | |
| # Create a zip file | |
| zip_path = "web_output/code.zip" | |
| with zipfile.ZipFile(zip_path, 'w') as zipf: | |
| for root, _, files in os.walk("web_output"): | |
| for file in files: | |
| if file != "code.zip": | |
| file_path = os.path.join(root, file) | |
| arcname = os.path.relpath(file_path, "web_output") | |
| zipf.write(file_path, arcname=arcname) | |
| # Create preview HTML for frontend tasks | |
| if task_type.lower() == "frontend": | |
| # Try to find an index.html or main HTML file | |
| html_content = files.get("index.html", "") | |
| if not html_content: | |
| for filename, content in files.items(): | |
| if filename.endswith(".html"): | |
| html_content = content | |
| break | |
| # If no HTML file found, create a simple preview of the code | |
| if not html_content: | |
| html_content = f"<html><body><h2>Code Preview</h2><pre>{code}</pre></body></html>" | |
| preview_html = html_content | |
| else: | |
| # For backend, show a formatted version of the code | |
| preview_html = f"<html><body><h2>Backend Code Preview</h2><pre>{code}</pre></body></html>" | |
| # Return the full code, zip path, and preview | |
| return code, zip_path, preview_html | |
| except Exception as e: | |
| return f"Error: {str(e)}", None, f"<html><body><p>Error occurred: {str(e)}</p></body></html>" | |
| # Helper function to extract code files from the response | |
| def extract_code_files(code_text, task_type): | |
| files = {} | |
| # Try to extract code blocks with filename specifications | |
| file_pattern = r"```[\w\s]*\n?(.+?)\n```" | |
| filename_pattern = r"[`\s]*([\w\-\.\/]+\.\w+)[`\s]*[:]*" | |
| # Look for filename specifications followed by code blocks | |
| filename_matches = re.finditer(filename_pattern, code_text, re.MULTILINE) | |
| for match in filename_matches: | |
| filename = match.group(1) | |
| start_pos = match.end() | |
| # Look for the next code block after the filename | |
| code_block_match = re.search(r"```[\w\s]*\n(.*?)```", code_text[start_pos:], re.DOTALL) | |
| if code_block_match: | |
| content = code_block_match.group(1).strip() | |
| files[filename] = content | |
| # If no files were extracted using the above method, try another approach | |
| if not files: | |
| # Extract all code blocks and try to infer filenames | |
| code_blocks = re.finditer(r"```([\w\s]*)\n(.*?)```", code_text, re.DOTALL) | |
| file_counter = { | |
| "html": 0, | |
| "css": 0, | |
| "js": 0, | |
| "jsx": 0, | |
| "tsx": 0, | |
| "py": 0, | |
| "json": 0, | |
| } | |
| for i, match in enumerate(code_blocks): | |
| lang = match.group(1).strip().lower() | |
| content = match.group(2).strip() | |
| # Try to infer filename from language or context | |
| if lang == "html": | |
| filename = "index.html" if file_counter["html"] == 0 else f"page{file_counter['html']}.html" | |
| file_counter["html"] += 1 | |
| elif lang == "css": | |
| filename = "styles.css" if file_counter["css"] == 0 else f"styles{file_counter['css']}.css" | |
| file_counter["css"] += 1 | |
| elif lang == "javascript" or lang == "js": | |
| filename = "script.js" if file_counter["js"] == 0 else f"script{file_counter['js']}.js" | |
| file_counter["js"] += 1 | |
| elif lang == "jsx": | |
| filename = "App.jsx" if file_counter["jsx"] == 0 else f"Component{file_counter['jsx']}.jsx" | |
| file_counter["jsx"] += 1 | |
| elif lang == "tsx": | |
| filename = "App.tsx" if file_counter["tsx"] == 0 else f"Component{file_counter['tsx']}.tsx" | |
| file_counter["tsx"] += 1 | |
| elif lang == "python" or lang == "py": | |
| filename = "app.py" if file_counter["py"] == 0 else f"module{file_counter['py']}.py" | |
| file_counter["py"] += 1 | |
| elif lang == "json": | |
| filename = "package.json" if file_counter["json"] == 0 else f"config{file_counter['json']}.json" | |
| file_counter["json"] += 1 | |
| else: | |
| # If language can't be determined, use a generic filename | |
| filename = f"file{i}.txt" | |
| files[filename] = content | |
| # If we still don't have any files, just create a single file with the entire response | |
| if not files: | |
| if task_type == "frontend": | |
| files["index.html"] = code_text | |
| else: | |
| files["app.js"] = code_text | |
| return files | |
| # Step 6: Create the Gradio UI | |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# Gemini 2.0 Web Development Agent with Firebase Integration") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| prompt = gr.Textbox( | |
| lines=5, | |
| placeholder="Describe your web development task in detail. Example: 'Create a responsive blog homepage with a navigation bar, featured posts section, and footer'", | |
| label="Describe your frontend/backend task" | |
| ) | |
| with gr.Column(scale=1): | |
| task_type = gr.Radio( | |
| ["Frontend", "Backend", "Full-Stack"], | |
| value="Frontend", | |
| label="Task Type" | |
| ) | |
| use_firebase = gr.Checkbox( | |
| label="Include Firebase Integration", | |
| value=False | |
| ) | |
| with gr.Group(visible=False) as firebase_options: | |
| include_auth = gr.Checkbox(label="Authentication (Sign up/Login)", value=True) | |
| include_database = gr.Checkbox(label="Database (Realtime or Firestore)", value=True) | |
| include_hosting = gr.Checkbox(label="Hosting", value=True) | |
| submit_btn = gr.Button("Generate Code", variant="primary") | |
| # Make Firebase options visible only when Firebase integration is checked | |
| use_firebase.change( | |
| fn=lambda x: gr.Group(visible=x), | |
| inputs=[use_firebase], | |
| outputs=[firebase_options] | |
| ) | |
| with gr.Tabs(): | |
| with gr.TabItem("Code"): | |
| output_code = gr.Code(language="html", label="Generated Code") | |
| with gr.TabItem("Preview"): | |
| preview = gr.HTML(label="Preview (for Frontend only)") | |
| with gr.TabItem("Download"): | |
| gr.Markdown("### Download your code") | |
| download_btn = gr.File(label="Download Code (.zip)") | |
| # Connect the function to the button | |
| submit_btn.click( | |
| fn=web_dev_agent, | |
| inputs=[prompt, task_type, use_firebase, include_auth, include_database, include_hosting], | |
| outputs=[output_code, download_btn, preview] | |
| ) | |
| gr.Markdown(""" | |
| ## How to Use | |
| 1. Enter a detailed description of your web development task | |
| 2. Select the task type (Frontend, Backend, or Full-Stack) | |
| 3. Check "Include Firebase Integration" if you want Firebase features | |
| 4. Select which Firebase features you want to include | |
| 5. Click "Generate Code" | |
| 6. View the generated code in the "Code" tab | |
| 7. See a preview in the "Preview" tab (for Frontend code) | |
| 8. Download the code as a zip file from the "Download" tab | |
| ## Firebase Setup | |
| After downloading the code: | |
| 1. Create a Firebase project at [Firebase Console](https://console.firebase.google.com/) | |
| 2. Follow the setup instructions in the generated code | |
| 3. Deploy your application using Firebase CLI | |
| """) | |
| # Launch the Gradio app - DO NOT INCLUDE THIS LINE FOR HUGGING FACE | |
| #demo.launch(debug=True) |