File size: 5,377 Bytes
c2bd0f8
 
 
 
6a45c72
80360bc
6a45c72
 
07af51e
2ba6f7a
07af51e
6a45c72
2ba6f7a
825b8fb
 
 
2ba6f7a
 
 
6a45c72
 
07af51e
 
6a45c72
 
 
 
 
 
c2bd0f8
80360bc
dc4db04
 
 
 
 
 
 
 
 
d53218b
 
 
 
 
 
 
dc4db04
 
 
 
825b8fb
 
d53218b
 
825b8fb
 
 
 
 
 
 
 
 
 
 
 
dc4db04
 
 
 
 
 
 
 
 
 
 
 
 
 
a7965a4
 
 
dc4db04
 
c2bd0f8
 
50ed0d7
 
c2bd0f8
50ed0d7
cfedfe8
50ed0d7
6a45c72
 
 
 
 
 
80360bc
 
 
 
6a45c72
 
 
50ed0d7
c2bd0f8
50ed0d7
80360bc
5e7b7d4
 
8e7179d
 
5e7b7d4
 
80360bc
 
 
 
8e7179d
 
f0a7861
 
8e7179d
80360bc
8e7179d
80360bc
8e7179d
80360bc
 
 
c2bd0f8
f0a7861
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
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()