mgbam commited on
Commit
227495f
·
verified ·
1 Parent(s): b134386

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +117 -203
app.py CHANGED
@@ -1,216 +1,130 @@
1
- import os
2
- from typing import Dict, List, Optional, Tuple
3
- import logging
4
- import asyncio
5
 
 
 
 
 
 
 
6
  import gradio as gr
7
 
8
- from config import (
9
- AVAILABLE_MODELS, DEMO_LIST, HTML_SYSTEM_PROMPT,
10
- )
11
- from api_clients import generation_code, tavily_client
12
- from chat_processing import (
13
- clear_history, history_to_chatbot_messages, update_image_input_visibility, update_submit_button,
14
- get_gradio_language, send_to_sandbox
15
- )
16
- from file_processing import create_multimodal_message
17
- from web_extraction import enhance_query_with_search, perform_web_search
18
- from ux_components import create_top_demo_cards
19
-
20
- # --- Gradio App UI ---
21
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
22
-
23
- # Update the Gradio theme to use modern styling
24
- theme = gr.themes.Base(
25
- primary_hue=gr.themes.colors.blue,
26
- secondary_hue=gr.themes.colors.blue, # Keeping it consistent
27
- neutral_hue=gr.themes.colors.neutral,
28
- font=gr.themes.GoogleFont("Inter"),
29
- font_mono=gr.themes.GoogleFont("JetBrains Mono"),
30
- )
31
-
32
- def demo_card_click(evt: gr.EventData):
33
- """Handles clicks on the demo cards to populate the input textbox."""
34
- # This function seems complex for its purpose. Gradio's event data can be tricky.
35
- # A simpler approach might be to directly pass the description.
36
- # For now, keeping the logic but adding comments.
37
- try:
38
- # Get the index from the event data
39
- if hasattr(e, '_data') and e._data:
40
- # Try different ways to get the index
41
- if 'index' in e._data:
42
- index = e._data['index']
43
- elif 'component' in e._data and 'index' in e._data['component']:
44
- index = e._data['component']['index']
45
- elif 'target' in e._data and 'index' in e._data['target']:
46
- index = e._data['target']['index']
47
- else:
48
- # If we can't get the index, try to extract it from the card data
49
- index = 0
50
- else:
51
- index = 0
52
-
53
- # Ensure index is within bounds
54
- if index >= len(DEMO_LIST):
55
- index = 0
56
-
57
- return DEMO_LIST[index]['description']
58
- except (KeyError, IndexError, AttributeError) as e:
59
- # Return the first demo description as fallback
60
- return DEMO_LIST[0]['description']
61
-
62
-
63
- with gr.Blocks(
64
- theme=gr.themes.Base(
65
- primary_hue=gr.themes.colors.blue,
66
- secondary_hue=gr.themes.colors.blue,
67
- neutral_hue=gr.themes.colors.neutral,
68
- font=gr.themes.GoogleFont("Inter"),
69
- font_mono=gr.themes.GoogleFont("JetBrains Mono"),
70
- text_size=gr.themes.sizes.text_lg,
71
- spacing_size=gr.themes.sizes.spacing_lg,
72
- radius_size=gr.themes.sizes.radius_lg,
73
- ),
74
- title="AnyCoder - AI Code Generator",
75
- css="""
76
- .col-header { text-transform: uppercase; font-size: 0.9em; letter-spacing: 0.05em; color: #555; border-bottom: 1px solid #eee; padding-bottom: 0.5em; margin-bottom: 1em; }
77
- .col-header + div { margin-top: 0; } /* Remove extra spacing */
78
- .gradio-container .gr-button-primary { background: linear-gradient(to right, #42a5f5, #4791db); color: white; } /* Blue gradient */
79
- .gradio-container .gr-button-secondary { background-color: #e3f2fd; color: #1e88e5; } /* Lighter blue */
80
- .gradio-container .gr-button-small { font-size: 0.875rem; padding: 0.5rem 1rem; } /* Smaller buttons*/
81
- .gradio-container .gr-textbox, .gradio-container .gr-dropdown { border-radius: 6px; }
82
- .gradio-container .tabs { border-bottom: 2px solid #e0f2f7; } /* Tabs container line */
83
- .gradio-container .tabitem { padding: 1rem; } /* Tab content padding*/
84
- .gradio-container .gr-code { border-radius: 6px; background-color: #f5f5f5; } /* Code background */
85
- """
86
- ) as demo:
87
- gr.HTML("<h1 align='center'>Shasha - AI Code Generator</h1>")
88
- history = gr.State([])
89
- setting = gr.State({
90
- "system": HTML_SYSTEM_PROMPT,
91
- })
92
- current_model = gr.State(AVAILABLE_MODELS[0]) # Moonshot Kimi-K2
93
- open_panel = gr.State(None)
94
- last_login_state = gr.State(None)
95
-
96
- with gr.Row(equal_height=False): # Ensure columns can have different heights
97
  with gr.Column(scale=1):
98
- gr.Markdown("## Controls", elem_classes=["col-header"])
99
- input = gr.Textbox(
100
- label="What would you like to build?",
101
- placeholder="Describe your application...",
102
- lines=4,
103
- interactive=True
104
- )
105
- # Language dropdown for code generation
106
- language_choices = [
107
- "python", "c", "cpp", "markdown", "latex", "json", "html", "css", "javascript", "jinja2", "typescript", "yaml", "dockerfile", "shell", "r", "sql"
108
- ]
109
- language_dropdown = gr.Dropdown(
110
- choices=language_choices,
111
- value="html",
112
- label="Code Language"
113
- )
114
- website_url_input = gr.Textbox(
115
- label="Website URL for redesign",
116
- placeholder="https://example.com",
117
- lines=1
118
- )
119
- file_input = gr.File(
120
- label="Reference file",
121
- file_types=[".pdf", ".txt", ".md", ".csv", ".docx", ".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".tif", ".gif", ".webp"]
122
- )
123
- image_input = gr.Image(
124
- label="UI design image",
125
- visible=False # Hidden by default; shown only for ERNIE-VL or GLM-VL
126
- )
127
- with gr.Row(equal_height=True): #Keep buttons vertically aligned
128
- btn = gr.Button("Generate", variant="primary", size="lg", scale=2, interactive=False,)
129
- clear_btn = gr.Button("Clear", variant="secondary", size="sm", scale=1)
130
-
131
- gr.Markdown("---",)
132
- gr.Markdown("### Quick Examples", elem_classes=["col-header"])
133
- quick_examples_col = create_top_demo_cards(input)
134
 
135
- gr.Markdown("---",)
136
- gr.Markdown("### Settings", elem_classes=["col-header"])
137
- search_toggle = gr.Checkbox(
138
- label="🔍 Web search",
139
- value=False,
140
- )
141
- if not tavily_client:
142
- gr.Markdown("⚠️ Web search unavailable", visible=True)
143
 
144
- model_dropdown = gr.Dropdown(
145
- choices=[model['name'] for model in AVAILABLE_MODELS],
146
- value=AVAILABLE_MODELS[0]['name'], # Moonshot Kimi-K2
147
- label="Model",
148
- )
149
-
150
- with gr.Accordion("Advanced Settings", open=False):
151
- system_prompt_input = gr.Textbox(
152
- value=HTML_SYSTEM_PROMPT,
153
- label="System Prompt",
154
- lines=5
155
- )
156
- save_prompt_btn = gr.Button("Save Prompt", variant="secondary", size="sm", min_width=100, elem_classes="gr-button-small")
157
-
158
-
159
- with gr.Column(scale=3):
160
- model_display = gr.Markdown(f"**Model:** {AVAILABLE_MODELS[0]['name']}", visible=True)
161
  with gr.Tabs():
162
- with gr.Tab("Code"):
163
- code_output = gr.Code(
164
- language="html",
165
- lines=28,
166
- interactive=False,
167
- label="Generated Code"
168
- )
169
  with gr.Tab("Preview"):
170
- sandbox = gr.HTML(label="Live Preview")
 
 
171
  with gr.Tab("History"):
172
- history_output = gr.Chatbot(show_label=False, height=600, type="messages")
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- # --- Event Handlers ---
175
- def on_model_change(model_name):
176
- for m in AVAILABLE_MODELS:
177
- if m['name'] == model_name:
178
- return m, f"**Model:** {m['name']}", update_image_input_visibility(m)
179
- return AVAILABLE_MODELS[0], f"**Model:** {AVAILABLE_MODELS[0]['name']}", update_image_input_visibility(AVAILABLE_MODELS[0])
180
-
181
- def save_prompt(prompt_text):
182
- return {setting: {"system": prompt_text}}
183
-
184
- def update_code_language(language):
185
- return gr.update(language=get_gradio_language(language))
186
-
187
- def preview_logic(code, language):
188
- if language == "html":
189
- return send_to_sandbox(code)
190
- else:
191
- return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML.</div>"
192
-
193
- async def submit_query(*args):
194
- """Handles the main code generation logic asynchronously."""
195
- async for update in generation_code(*args):
196
- yield update
197
-
198
- btn.click(fn=submit_query,
199
- inputs=[input, image_input, file_input, website_url_input, setting, history, current_model, search_toggle, language_dropdown],
200
- outputs=[code_output, history, sandbox, history_output])
201
-
202
- input.change(update_submit_button, inputs=input, outputs=btn)
203
-
204
- model_dropdown.change(
205
- on_model_change,
206
- inputs=model_dropdown,
207
- outputs=[current_model, model_display, image_input]
208
  )
209
- save_prompt_btn.click(save_prompt, inputs=system_prompt_input, outputs=setting)
210
- # Update preview when code or language changes
211
- language_dropdown.change(update_code_language, inputs=language_dropdown, outputs=code_output)
212
- code_output.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
213
- clear_btn.click(clear_history, outputs=[history, history_output, file_input, website_url_input])
214
 
215
  if __name__ == "__main__":
216
- demo.queue(api_open=False, default_concurrency_limit=20).launch(ssr_mode=True, mcp_server=False, show_api=False)
 
1
+ # /app.py
 
 
 
2
 
3
+ """
4
+ Main Gradio application for AnyCoder.
5
+
6
+ This file defines the user interface, handles user interactions, and orchestrates
7
+ the calls to the backend logic in other modules.
8
+ """
9
  import gradio as gr
10
 
11
+ from config import AVAILABLE_MODELS, DEMO_LIST, MULTIMODAL_MODELS
12
+ from core import generate_code
13
+ from deployment import deploy_to_hf_space
14
+ from utils import get_gradio_language
15
+
16
+ # --- UI Helper Functions ---
17
+
18
+ def send_to_sandbox(code: str, language: str) -> str:
19
+ """Generates an iframe for the preview tab."""
20
+ if language == "html" and code:
21
+ return f'<iframe srcdoc="{code.replace("\"", """)}" width="100%" height="920px" style="border:0;"></iframe>'
22
+ return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only for HTML.</div>"
23
+
24
+ # --- Event Handlers ---
25
+
26
+ def on_generate_click(
27
+ query: str, image: gr.Image, file: gr.File, website_url: str,
28
+ history: list, model_name: str, enable_search: bool, language: str
29
+ ):
30
+ """Handler for the 'Generate' button click event."""
31
+ if not query and not image and not file and not website_url:
32
+ yield {
33
+ code_output: gr.update(value="Please provide a prompt, image, file, or URL.", language="text"),
34
+ history_output: history
35
+ }
36
+ return
37
+
38
+ model_config = next((m for m in AVAILABLE_MODELS if m['name'] == model_name), AVAILABLE_MODELS[0])
39
+
40
+ # Stream the response
41
+ for response in generate_code(query, image, file.name if file else None, website_url, history, model_config, enable_search, language):
42
+ ui_update = {
43
+ code_output: gr.update(value=response.get("code_output"), language=get_gradio_language(language)),
44
+ sandbox: send_to_sandbox(response.get("code_output", ""), language)
45
+ }
46
+ if "history" in response:
47
+ ui_update[history_state] = response["history"]
48
+ ui_update[history_output] = response["history"]
49
+ yield ui_update
50
+
51
+ def on_model_change(model_name: str):
52
+ """Updates UI elements when the model selection changes."""
53
+ model_id = next((m['id'] for m in AVAILABLE_MODELS if m['name'] == model_name), None)
54
+ return gr.update(visible=model_id in MULTIMODAL_MODELS)
55
+
56
+ def on_language_change(language: str):
57
+ """Updates the code output and preview when language changes."""
58
+ return gr.update(language=get_gradio_language(language))
59
+
60
+ def on_deploy_click(code: str, space_name: str, sdk_name: str, hf_token: str):
61
+ """Handler for the deploy button."""
62
+ sdk_map = {"Static (HTML)": "static", "Gradio (Python)": "gradio"}
63
+ sdk = sdk_map.get(sdk_name, "static")
64
+ return gr.update(value=deploy_to_hf_space(code, space_name, sdk, hf_token), visible=True)
65
+
66
+ # --- Gradio UI Layout ---
67
+ with gr.Blocks(theme=gr.themes.Default(primary_hue="blue"), title="AnyCoder") as demo:
68
+ history_state = gr.State([])
69
+ hf_token_state = gr.State()
70
+
71
+ gr.Markdown("# 🤖 AnyCoder - AI Code Generator")
72
+ gr.Markdown("Describe what you want to build, upload a design, or provide a URL to redesign. The AI will generate the code for you.")
73
+
74
+ with gr.Row():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  with gr.Column(scale=1):
76
+ # --- Inputs ---
77
+ input_prompt = gr.Textbox(label="Prompt", placeholder="e.g., a login form with a blue button", lines=3)
78
+ language_dropdown = gr.Dropdown(choices=["html", "python", "javascript", "css"], value="html", label="Language")
79
+ website_url_input = gr.Textbox(label="URL to Redesign", placeholder="https://example.com")
80
+ file_input = gr.File(label="Reference File (PDF, TXT, DOCX, image)")
81
+ image_input = gr.Image(label="UI Design Image", type="numpy", visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
+ # --- Controls ---
84
+ with gr.Accordion("Settings", open=False):
85
+ model_dropdown = gr.Dropdown(choices=[m['name'] for m in AVAILABLE_MODELS], value=AVAILABLE_MODELS[0]['name'], label="Model")
86
+ search_toggle = gr.Checkbox(label="Enable Web Search", value=False)
 
 
 
 
87
 
88
+ with gr.Row():
89
+ clear_btn = gr.Button("Clear")
90
+ generate_btn = gr.Button("Generate", variant="primary", scale=2)
91
+
92
+ # --- Deployment ---
93
+ with gr.Accordion("🚀 Deploy to Hugging Face", open=False):
94
+ login_button = gr.LoginButton()
95
+ space_name_input = gr.Textbox(label="New App Name", placeholder="my-cool-app")
96
+ sdk_dropdown = gr.Dropdown(choices=["Static (HTML)", "Gradio (Python)"], value="Static (HTML)", label="App Type")
97
+ deploy_btn = gr.Button("Deploy")
98
+ deploy_status = gr.Markdown(visible=False)
99
+
100
+ with gr.Column(scale=2):
101
+ # --- Outputs ---
 
 
 
102
  with gr.Tabs():
 
 
 
 
 
 
 
103
  with gr.Tab("Preview"):
104
+ sandbox = gr.HTML(label="Live Preview", elem_id="sandbox-preview")
105
+ with gr.Tab("Code"):
106
+ code_output = gr.Code(label="Generated Code", language="html", interactive=True)
107
  with gr.Tab("History"):
108
+ history_output = gr.Chatbot(label="Conversation History", bubble_full_width=False)
109
+
110
+ # --- Event Wiring ---
111
+ generate_btn.click(
112
+ fn=on_generate_click,
113
+ inputs=[input_prompt, image_input, file_input, website_url_input, history_state, model_dropdown, search_toggle, language_dropdown],
114
+ outputs=[code_output, sandbox, history_state, history_output]
115
+ )
116
+ clear_btn.click(lambda: ([], [], None, None, None, "", ""), outputs=[history_state, history_output, input_prompt, image_input, file_input, website_url_input, code_output])
117
+
118
+ model_dropdown.change(on_model_change, inputs=model_dropdown, outputs=image_input)
119
+ language_dropdown.change(on_language_change, inputs=language_dropdown, outputs=code_output)
120
+ language_dropdown.change(lambda code, lang: send_to_sandbox(code, lang), inputs=[code_output, language_dropdown], outputs=sandbox)
121
 
122
+ login_button.login(lambda token: gr.update(value=token), outputs=hf_token_state)
123
+ deploy_btn.click(
124
+ on_deploy_click,
125
+ inputs=[code_output, space_name_input, sdk_dropdown, hf_token_state],
126
+ outputs=deploy_status
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  )
 
 
 
 
 
128
 
129
  if __name__ == "__main__":
130
+ demo.queue().launch()