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, "
Gemini API key not configured. Check the logs.
" # 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"{code}"
preview_html = html_content
else:
# For backend, show a formatted version of the code
preview_html = f"{code}"
# 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"Error occurred: {str(e)}
" # 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)