offerpk3's picture
Update app.py
d53218b verified
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()