Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| from generator import generate_app, enhance_app | |
| from helpers import save_as_zip | |
| import uuid | |
| import time | |
| def extract_react_preview(code: str) -> str: | |
| return f""" | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset='UTF-8' /> | |
| <script crossorigin src=\"https://unpkg.com/react@18/umd/react.development.js\"></script> | |
| <script crossorigin src=\"https://unpkg.com/react-dom@18/umd/react-dom.development.js\"></script> | |
| <script src=\"https://unpkg.com/@babel/standalone/babel.min.js\"></script> | |
| <style> | |
| body {{ font-family: sans-serif; padding: 20px; }} | |
| </style> | |
| </head> | |
| <body> | |
| <div id='root'></div> | |
| <script type='text/babel'> | |
| {code} | |
| ReactDOM.createRoot(document.getElementById('root')).render(<App />); | |
| </script> | |
| </body> | |
| </html> | |
| """ | |
| def run_app(user_input, enhance_prompt, action, state, progress=gr.Progress()): | |
| import google.generativeai as genai | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| progress(0, desc="Authenticating with Gemini...") | |
| genai.configure(api_key=os.getenv("GOOGLE_API_KEY")) | |
| model = genai.GenerativeModel("gemini-pro") | |
| progress(0.2, desc="Sending prompt to Gemini...") | |
| if "weather" in user_input.lower() or "temperature" in user_input.lower(): | |
| from datetime import datetime | |
| now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| fake_weather = f"π€οΈ As of {now}, the weather is sunny and 30Β°C in Lahore." | |
| return fake_weather, None, "<p>Weather bot reply successful.</p>", {}, {} | |
| prompt_text = f"""Create a full React app based on this idea: | |
| {user_input} | |
| Return only relevant files like App.jsx, index.html, styles, utils or components in plain code blocks with filenames.""" | |
| try: | |
| response = model.generate_content(prompt_text) | |
| print("π FULL GEMINI RESPONSE RAW >>>\n", response) | |
| print("π Gemini TEXT PREVIEW >>>\n", getattr(response, "text", "(no .text found)")) | |
| if not hasattr(response, "text") or not response.text.strip(): | |
| raise ValueError("Gemini response is empty.") | |
| parts = response.text.split("```") | |
| except Exception as e: | |
| print("β Gemini error:", e) | |
| return ( | |
| "β Error: Could not generate app from Gemini.", | |
| None, | |
| "<p style='color:red;'>Gemini API failed or returned empty. Try again.</p>", | |
| {}, | |
| {} | |
| ) | |
| files = {} | |
| current_file = None | |
| for part in parts: | |
| if part.strip().startswith("jsx") or part.strip().startswith("javascript") or part.strip().startswith("html"): | |
| lines = part.strip().split("\n") | |
| if len(lines) > 1 and lines[1].startswith("// filename:"): | |
| current_file = lines[1].replace("// filename:", "").strip() | |
| files[current_file] = "\n".join(lines[2:]) | |
| app_code = files.get("App.jsx", next(iter(files.values()), "")) | |
| preview_html = extract_react_preview(app_code) | |
| zip_bytes = save_as_zip({"files": files}) | |
| with open("generated_app.zip", "wb") as f: | |
| f.write(zip_bytes) | |
| state = {"bundle": {"full_code": app_code, "files": files}, "history": []} | |
| return app_code, "generated_app.zip", preview_html, files, state | |
| with gr.Blocks(title="Auto App Builder") as iface: | |
| gr.Markdown("# β‘ Auto App Builder (Gemini Powered)\n_Powered by Google Gemini API_") | |
| with gr.Row(): | |
| inp = gr.Textbox(label="App Idea", placeholder="e.g. Inventory system with login", lines=2) | |
| btn = gr.Button("π Generate App") | |
| with gr.Row(): | |
| with gr.Column(): | |
| code_out = gr.Code(label="π Generated Code") | |
| enh = gr.Textbox(label="Enhancement Prompt", placeholder="e.g. Add login, PDF export, dark mode...", lines=1) | |
| btn_enh = gr.Button("β¨ Enhance") | |
| zip_file = gr.File(label="β¬οΈ Download App ZIP", interactive=True) | |
| gr.Markdown("### π File Explorer") | |
| file_selector = gr.Dropdown(choices=[], label="Select File") | |
| file_viewer = gr.Code(label="π File Content") | |
| with gr.Column(): | |
| gr.Markdown("### π Live React Preview") | |
| preview = gr.HTML(label="React App Preview") | |
| state = gr.State() | |
| def update_file_tree(code, zip_name, preview_path, files, state): | |
| if isinstance(files, dict) and len(files) > 0: | |
| keys = list(files.keys()) | |
| default_key = keys[0] if keys else None | |
| return gr.update(choices=keys, value=default_key), files.get(default_key, "") | |
| else: | |
| return gr.update(choices=[], value=None), "" | |
| btn.click( | |
| fn=run_app, | |
| inputs=[inp, enh, gr.State(""), state], | |
| outputs=[code_out, zip_file, preview, file_selector, state] | |
| ).then( | |
| fn=lambda code, zip_name, preview_path, state_obj: update_file_tree(code, zip_name, preview_path, state_obj.get("bundle", {}).get("files", {}), state_obj), | |
| inputs=[code_out, zip_file, preview, state], | |
| outputs=[file_selector, file_viewer] | |
| ) | |
| file_selector.change( | |
| lambda name, state: state["bundle"]["files"].get(name, "") if state and "bundle" in state else "", | |
| inputs=[file_selector, state], | |
| outputs=file_viewer | |
| ) | |
| iface.launch() | |