Spaces:
Runtime error
Runtime error
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) |