File size: 12,750 Bytes
af477d2
 
 
 
 
 
 
 
 
f4c8592
 
 
51820e8
af477d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
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)