Spaces:
Running
Running
Upload 3 files
Browse files- app.py +475 -0
- config.py +100 -0
- requirements.txt +4 -0
app.py
ADDED
@@ -0,0 +1,475 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
import modelscope_studio.components.antd as antd
|
5 |
+
import modelscope_studio.components.base as ms
|
6 |
+
import modelscope_studio.components.pro as pro
|
7 |
+
from openai import OpenAI
|
8 |
+
from config import API_KEY, MODEL, SYSTEM_PROMPT, ENDPOINT, EXAMPLES, DEFAULT_LOCALE, DEFAULT_THEME
|
9 |
+
|
10 |
+
client = OpenAI(api_key=API_KEY, base_url=ENDPOINT)
|
11 |
+
|
12 |
+
react_imports = {
|
13 |
+
"lucide-react": "https://esm.sh/[email protected]",
|
14 |
+
"recharts": "https://esm.sh/[email protected]",
|
15 |
+
"framer-motion": "https://esm.sh/[email protected]",
|
16 |
+
"matter-js": "https://esm.sh/[email protected]",
|
17 |
+
"p5": "https://esm.sh/[email protected]",
|
18 |
+
"konva": "https://esm.sh/[email protected]",
|
19 |
+
"react-konva": "https://esm.sh/[email protected]",
|
20 |
+
"three": "https://esm.sh/[email protected]",
|
21 |
+
"@react-three/fiber": "https://esm.sh/@react-three/[email protected]",
|
22 |
+
"@react-three/drei": "https://esm.sh/@react-three/[email protected]",
|
23 |
+
"@tailwindcss/browser": "https://esm.sh/@tailwindcss/[email protected]",
|
24 |
+
"react": "https://esm.sh/react@^19.0.0",
|
25 |
+
"react/": "https://esm.sh/react@^19.0.0/",
|
26 |
+
"react-dom": "https://esm.sh/react-dom@^19.0.0",
|
27 |
+
"react-dom/": "https://esm.sh/react-dom@^19.0.0/"
|
28 |
+
}
|
29 |
+
|
30 |
+
|
31 |
+
class GradioEvents:
|
32 |
+
|
33 |
+
@staticmethod
|
34 |
+
def generate_code(input_value, system_prompt_input_value, state_value):
|
35 |
+
|
36 |
+
# FIX: Define the helper function inside the method so it's in the correct scope.
|
37 |
+
def get_generated_files(text):
|
38 |
+
patterns = {
|
39 |
+
'html': r'```html\n(.+?)\n```',
|
40 |
+
'jsx': r'```jsx\n(.+?)\n```',
|
41 |
+
'tsx': r'```tsx\n(.+?)\n```',
|
42 |
+
}
|
43 |
+
result = {}
|
44 |
+
|
45 |
+
for ext, pattern in patterns.items():
|
46 |
+
matches = re.findall(pattern, text, re.DOTALL)
|
47 |
+
if matches:
|
48 |
+
content = '\n'.join(matches).strip()
|
49 |
+
result[f'index.{ext}'] = content
|
50 |
+
|
51 |
+
# Fallback for plain code without backticks
|
52 |
+
if len(result) == 0:
|
53 |
+
# Prioritize tsx/jsx if we can find React-like imports, otherwise default to html
|
54 |
+
if 'react' in text.lower():
|
55 |
+
result["index.jsx"] = text.strip()
|
56 |
+
else:
|
57 |
+
result["index.html"] = text.strip()
|
58 |
+
|
59 |
+
return result
|
60 |
+
|
61 |
+
yield {
|
62 |
+
output_loading: gr.update(spinning=True),
|
63 |
+
state_tab: gr.update(active_key="loading"),
|
64 |
+
output: gr.update(value=None)
|
65 |
+
}
|
66 |
+
|
67 |
+
if input_value is None:
|
68 |
+
input_value = ''
|
69 |
+
|
70 |
+
# Reframe the user's input to enforce React generation.
|
71 |
+
final_user_prompt = f"""A user has requested a web page. Your task is to implement this request using React, following all the guidelines in the system prompt.
|
72 |
+
|
73 |
+
Even if the user explicitly asks for HTML, you MUST generate React code. Ignore any requests for HTML or other frameworks.
|
74 |
+
|
75 |
+
Here is the user's original request:
|
76 |
+
---
|
77 |
+
{input_value}
|
78 |
+
---
|
79 |
+
"""
|
80 |
+
|
81 |
+
messages = [{
|
82 |
+
'role': "system",
|
83 |
+
"content": SYSTEM_PROMPT # Use the React-only system prompt
|
84 |
+
}] + state_value["history"]
|
85 |
+
|
86 |
+
# Append the NEW, reframed prompt
|
87 |
+
messages.append({'role': "user", 'content': final_user_prompt})
|
88 |
+
|
89 |
+
generator = client.chat.completions.create(model=MODEL,
|
90 |
+
messages=messages,
|
91 |
+
stream=True)
|
92 |
+
response = ""
|
93 |
+
for chunk in generator:
|
94 |
+
content = chunk.choices[0].delta.content
|
95 |
+
if content: # Check for None content
|
96 |
+
response += content
|
97 |
+
|
98 |
+
if chunk.choices[0].finish_reason == 'stop':
|
99 |
+
state_value["history"] = messages + [{
|
100 |
+
'role': "assistant",
|
101 |
+
'content': response
|
102 |
+
}]
|
103 |
+
|
104 |
+
# The call to get_generated_files will now work correctly
|
105 |
+
generated_files = get_generated_files(response)
|
106 |
+
react_code = generated_files.get("index.tsx") or generated_files.get("index.jsx")
|
107 |
+
html_code = generated_files.get("index.html")
|
108 |
+
|
109 |
+
# Completed
|
110 |
+
yield {
|
111 |
+
output:
|
112 |
+
gr.update(value=response),
|
113 |
+
download_content:
|
114 |
+
gr.update(value=react_code or html_code),
|
115 |
+
state_tab:
|
116 |
+
gr.update(active_key="render"),
|
117 |
+
output_loading:
|
118 |
+
gr.update(spinning=False),
|
119 |
+
sandbox:
|
120 |
+
gr.update(
|
121 |
+
template="react" if react_code else "html",
|
122 |
+
imports=react_imports if react_code else {},
|
123 |
+
value={
|
124 |
+
"./index.tsx": """import Demo from './demo.tsx'
|
125 |
+
import "@tailwindcss/browser"
|
126 |
+
|
127 |
+
export default Demo
|
128 |
+
""",
|
129 |
+
"./demo.tsx": react_code
|
130 |
+
} if react_code else {"./index.html": html_code}),
|
131 |
+
state:
|
132 |
+
gr.update(value=state_value)
|
133 |
+
}
|
134 |
+
|
135 |
+
else:
|
136 |
+
# Generating
|
137 |
+
yield {
|
138 |
+
output: gr.update(value=response),
|
139 |
+
output_loading: gr.update(spinning=False),
|
140 |
+
}
|
141 |
+
|
142 |
+
@staticmethod
|
143 |
+
def select_example(example: dict):
|
144 |
+
return lambda: gr.update(value=example["description"])
|
145 |
+
|
146 |
+
@staticmethod
|
147 |
+
def close_modal():
|
148 |
+
return gr.update(open=False)
|
149 |
+
|
150 |
+
@staticmethod
|
151 |
+
def open_modal():
|
152 |
+
return gr.update(open=True)
|
153 |
+
|
154 |
+
@staticmethod
|
155 |
+
def disable_btns(btns: list):
|
156 |
+
return lambda: [gr.update(disabled=True) for _ in btns]
|
157 |
+
|
158 |
+
@staticmethod
|
159 |
+
def enable_btns(btns: list):
|
160 |
+
return lambda: [gr.update(disabled=False) for _ in btns]
|
161 |
+
|
162 |
+
@staticmethod
|
163 |
+
def update_system_prompt(system_prompt_input_value, state_value):
|
164 |
+
state_value["system_prompt"] = system_prompt_input_value
|
165 |
+
return gr.update(value=state_value)
|
166 |
+
|
167 |
+
@staticmethod
|
168 |
+
def reset_system_prompt(state_value):
|
169 |
+
return gr.update(value=state_value["system_prompt"])
|
170 |
+
|
171 |
+
@staticmethod
|
172 |
+
def render_history(statue_value):
|
173 |
+
return gr.update(value=statue_value["history"])
|
174 |
+
|
175 |
+
@staticmethod
|
176 |
+
def clear_history(state_value):
|
177 |
+
gr.Success("History Cleared.")
|
178 |
+
state_value["history"] = []
|
179 |
+
return gr.update(value=state_value)
|
180 |
+
|
181 |
+
|
182 |
+
css = """
|
183 |
+
#coder-artifacts .output-empty,.output-loading {
|
184 |
+
display: flex;
|
185 |
+
flex-direction: column;
|
186 |
+
align-items: center;
|
187 |
+
justify-content: center;
|
188 |
+
width: 100%;
|
189 |
+
min-height: 680px;
|
190 |
+
}
|
191 |
+
|
192 |
+
#coder-artifacts #output-container .ms-gr-ant-tabs-content,.ms-gr-ant-tabs-tabpane {
|
193 |
+
height: 100%;
|
194 |
+
}
|
195 |
+
|
196 |
+
#coder-artifacts .output-html {
|
197 |
+
display: flex;
|
198 |
+
flex-direction: column;
|
199 |
+
width: 100%;
|
200 |
+
min-height: 680px;
|
201 |
+
max-height: 1200px;
|
202 |
+
}
|
203 |
+
|
204 |
+
#coder-artifacts .output-html > iframe {
|
205 |
+
flex: 1;
|
206 |
+
}
|
207 |
+
|
208 |
+
#coder-artifacts-code-drawer .output-code {
|
209 |
+
flex:1;
|
210 |
+
}
|
211 |
+
#coder-artifacts-code-drawer .output-code .ms-gr-ant-spin-nested-loading {
|
212 |
+
min-height: 100%;
|
213 |
+
}
|
214 |
+
|
215 |
+
"""
|
216 |
+
|
217 |
+
with gr.Blocks(css=css) as demo:
|
218 |
+
# Global State
|
219 |
+
state = gr.State({"system_prompt": "", "history": []})
|
220 |
+
with ms.Application(elem_id="coder-artifacts") as app:
|
221 |
+
with antd.ConfigProvider(theme=DEFAULT_THEME, locale=DEFAULT_LOCALE):
|
222 |
+
|
223 |
+
with ms.AutoLoading():
|
224 |
+
with antd.Row(gutter=[32, 12],
|
225 |
+
elem_style=dict(marginTop=20),
|
226 |
+
align="stretch"):
|
227 |
+
# Left Column
|
228 |
+
with antd.Col(span=24, md=8):
|
229 |
+
with antd.Flex(vertical=True, gap="middle", wrap=True):
|
230 |
+
with antd.Flex(justify="center",
|
231 |
+
align="center",
|
232 |
+
vertical=True,
|
233 |
+
gap="middle"):
|
234 |
+
antd.Typography.Title(
|
235 |
+
"React-Coder-WebDev",
|
236 |
+
level=1,
|
237 |
+
elem_style=dict(fontSize=24))
|
238 |
+
# Input
|
239 |
+
input = antd.Input.Textarea(
|
240 |
+
size="large",
|
241 |
+
allow_clear=True,
|
242 |
+
auto_size=dict(minRows=2, maxRows=6),
|
243 |
+
placeholder=
|
244 |
+
"Describe the web application you want to create",
|
245 |
+
elem_id="input-container")
|
246 |
+
# Input Notes
|
247 |
+
with antd.Flex(justify="space-between"):
|
248 |
+
antd.Typography.Text(
|
249 |
+
"Note: The model supports multi-round dialogue, you can make the model generate interfaces by returning React or HTML code.",
|
250 |
+
strong=True,
|
251 |
+
type="warning")
|
252 |
+
|
253 |
+
tour_btn = antd.Button("Usage Tour",
|
254 |
+
variant="filled",
|
255 |
+
color="default")
|
256 |
+
# Submit Button
|
257 |
+
submit_btn = antd.Button("Submit",
|
258 |
+
type="primary",
|
259 |
+
block=True,
|
260 |
+
size="large",
|
261 |
+
elem_id="submit-btn")
|
262 |
+
|
263 |
+
antd.Divider("Settings")
|
264 |
+
|
265 |
+
# Settings Area
|
266 |
+
with antd.Space(size="small",
|
267 |
+
wrap=True,
|
268 |
+
elem_id="settings-area"):
|
269 |
+
# system_prompt_btn = antd.Button(
|
270 |
+
# "⚙️ Set System Prompt", type="default")
|
271 |
+
history_btn = antd.Button(
|
272 |
+
"📜 History",
|
273 |
+
type="default",
|
274 |
+
elem_id="history-btn",
|
275 |
+
)
|
276 |
+
cleat_history_btn = antd.Button(
|
277 |
+
"🧹 Clear History", danger=True)
|
278 |
+
|
279 |
+
antd.Divider("Examples")
|
280 |
+
|
281 |
+
# Examples
|
282 |
+
with antd.Flex(gap="small", wrap=True):
|
283 |
+
for example in EXAMPLES:
|
284 |
+
with antd.Card(
|
285 |
+
elem_style=dict(
|
286 |
+
flex="1 1 fit-content"),
|
287 |
+
hoverable=True) as example_card:
|
288 |
+
antd.Card.Meta(
|
289 |
+
title=example['title'],
|
290 |
+
description=example['description'])
|
291 |
+
|
292 |
+
example_card.click(
|
293 |
+
fn=GradioEvents.select_example(
|
294 |
+
example),
|
295 |
+
outputs=[input])
|
296 |
+
|
297 |
+
# Right Column
|
298 |
+
with antd.Col(span=24, md=16):
|
299 |
+
with antd.Card(
|
300 |
+
title="Output",
|
301 |
+
elem_style=dict(height="100%",
|
302 |
+
display="flex",
|
303 |
+
flexDirection="column"),
|
304 |
+
styles=dict(body=dict(height=0, flex=1)),
|
305 |
+
elem_id="output-container"):
|
306 |
+
# Output Container Extra
|
307 |
+
with ms.Slot("extra"):
|
308 |
+
with ms.Div(elem_id="output-container-extra"):
|
309 |
+
with antd.Button(
|
310 |
+
"Download Code",
|
311 |
+
type="link",
|
312 |
+
href_target="_blank",
|
313 |
+
disabled=True,
|
314 |
+
) as download_btn:
|
315 |
+
with ms.Slot("icon"):
|
316 |
+
antd.Icon("DownloadOutlined")
|
317 |
+
download_content = gr.Text(visible=False)
|
318 |
+
|
319 |
+
view_code_btn = antd.Button(
|
320 |
+
"🧑💻 View Code", type="primary")
|
321 |
+
# Output Content
|
322 |
+
with antd.Tabs(
|
323 |
+
elem_style=dict(height="100%"),
|
324 |
+
active_key="empty",
|
325 |
+
render_tab_bar="() => null") as state_tab:
|
326 |
+
with antd.Tabs.Item(key="empty"):
|
327 |
+
antd.Empty(
|
328 |
+
description=
|
329 |
+
"Enter your request to generate code",
|
330 |
+
elem_classes="output-empty")
|
331 |
+
with antd.Tabs.Item(key="loading"):
|
332 |
+
with antd.Spin(
|
333 |
+
tip="Generating code...",
|
334 |
+
size="large",
|
335 |
+
elem_classes="output-loading"):
|
336 |
+
# placeholder
|
337 |
+
ms.Div()
|
338 |
+
with antd.Tabs.Item(key="render"):
|
339 |
+
sandbox = pro.WebSandbox(
|
340 |
+
height="100%",
|
341 |
+
elem_classes="output-html",
|
342 |
+
template="html",
|
343 |
+
)
|
344 |
+
|
345 |
+
# Modals and Drawers
|
346 |
+
with antd.Modal(open=False,
|
347 |
+
title="System Prompt",
|
348 |
+
width="800px") as system_prompt_modal:
|
349 |
+
system_prompt_input = antd.Input.Textarea(
|
350 |
+
# SYSTEM_PROMPT,
|
351 |
+
value="",
|
352 |
+
size="large",
|
353 |
+
placeholder="Enter your system prompt here",
|
354 |
+
allow_clear=True,
|
355 |
+
auto_size=dict(minRows=4, maxRows=14))
|
356 |
+
|
357 |
+
with antd.Drawer(
|
358 |
+
open=False,
|
359 |
+
title="Output Code",
|
360 |
+
placement="right",
|
361 |
+
get_container=
|
362 |
+
"() => document.querySelector('.gradio-container')",
|
363 |
+
elem_id="coder-artifacts-code-drawer",
|
364 |
+
styles=dict(
|
365 |
+
body=dict(display="flex",
|
366 |
+
flexDirection="column-reverse")),
|
367 |
+
width="750px") as output_code_drawer:
|
368 |
+
with ms.Div(elem_classes="output-code"):
|
369 |
+
with antd.Spin(spinning=False) as output_loading:
|
370 |
+
output = ms.Markdown()
|
371 |
+
|
372 |
+
with antd.Drawer(
|
373 |
+
open=False,
|
374 |
+
title="Chat History",
|
375 |
+
placement="left",
|
376 |
+
get_container=
|
377 |
+
"() => document.querySelector('.gradio-container')",
|
378 |
+
width="750px") as history_drawer:
|
379 |
+
history_output = gr.Chatbot(
|
380 |
+
show_label=False,
|
381 |
+
type="messages",
|
382 |
+
height='100%',
|
383 |
+
elem_classes="history_chatbot")
|
384 |
+
# Tour
|
385 |
+
with antd.Tour(open=False) as usage_tour:
|
386 |
+
antd.Tour.Step(
|
387 |
+
title="Step 1",
|
388 |
+
description=
|
389 |
+
"Describe the web application you want to create.",
|
390 |
+
get_target=
|
391 |
+
"() => document.querySelector('#input-container')")
|
392 |
+
antd.Tour.Step(
|
393 |
+
title="Step 2",
|
394 |
+
description="Click the submit button.",
|
395 |
+
get_target=
|
396 |
+
"() => document.querySelector('#submit-btn')")
|
397 |
+
antd.Tour.Step(
|
398 |
+
title="Step 3",
|
399 |
+
description="Wait for the result.",
|
400 |
+
get_target=
|
401 |
+
"() => document.querySelector('#output-container')"
|
402 |
+
)
|
403 |
+
antd.Tour.Step(
|
404 |
+
title="Step 4",
|
405 |
+
description=
|
406 |
+
"Download the generated HTML here or view the code.",
|
407 |
+
get_target=
|
408 |
+
"() => document.querySelector('#output-container-extra')"
|
409 |
+
)
|
410 |
+
antd.Tour.Step(
|
411 |
+
title="Additional Settings",
|
412 |
+
description="You can change chat history here.",
|
413 |
+
get_target=
|
414 |
+
"() => document.querySelector('#settings-area')")
|
415 |
+
# Event Handler
|
416 |
+
gr.on(fn=GradioEvents.close_modal,
|
417 |
+
triggers=[usage_tour.close, usage_tour.finish],
|
418 |
+
outputs=[usage_tour])
|
419 |
+
tour_btn.click(fn=GradioEvents.open_modal, outputs=[usage_tour])
|
420 |
+
|
421 |
+
# system_prompt_btn.click(fn=GradioEvents.open_modal,
|
422 |
+
# outputs=[system_prompt_modal])
|
423 |
+
|
424 |
+
system_prompt_modal.ok(GradioEvents.update_system_prompt,
|
425 |
+
inputs=[system_prompt_input, state],
|
426 |
+
outputs=[state]).then(fn=GradioEvents.close_modal,
|
427 |
+
outputs=[system_prompt_modal])
|
428 |
+
|
429 |
+
system_prompt_modal.cancel(GradioEvents.close_modal,
|
430 |
+
outputs=[system_prompt_modal]).then(
|
431 |
+
fn=GradioEvents.reset_system_prompt,
|
432 |
+
inputs=[state],
|
433 |
+
outputs=[system_prompt_input])
|
434 |
+
output_code_drawer.close(fn=GradioEvents.close_modal,
|
435 |
+
outputs=[output_code_drawer])
|
436 |
+
cleat_history_btn.click(fn=GradioEvents.clear_history,
|
437 |
+
inputs=[state],
|
438 |
+
outputs=[state])
|
439 |
+
history_btn.click(fn=GradioEvents.open_modal,
|
440 |
+
outputs=[history_drawer
|
441 |
+
]).then(fn=GradioEvents.render_history,
|
442 |
+
inputs=[state],
|
443 |
+
outputs=[history_output])
|
444 |
+
history_drawer.close(fn=GradioEvents.close_modal, outputs=[history_drawer])
|
445 |
+
|
446 |
+
download_btn.click(fn=None,
|
447 |
+
inputs=[download_content],
|
448 |
+
js="""(content) => {
|
449 |
+
const blob = new Blob([content], { type: 'text/plain' })
|
450 |
+
const url = URL.createObjectURL(blob)
|
451 |
+
const a = document.createElement('a')
|
452 |
+
a.href = url
|
453 |
+
a.download = 'output.txt'
|
454 |
+
a.click()
|
455 |
+
}""")
|
456 |
+
view_code_btn.click(fn=GradioEvents.open_modal,
|
457 |
+
outputs=[output_code_drawer])
|
458 |
+
submit_btn.click(
|
459 |
+
fn=GradioEvents.open_modal,
|
460 |
+
outputs=[output_code_drawer],
|
461 |
+
).then(fn=GradioEvents.disable_btns([submit_btn, download_btn]),
|
462 |
+
outputs=[submit_btn, download_btn]).then(
|
463 |
+
fn=GradioEvents.generate_code,
|
464 |
+
inputs=[input, system_prompt_input, state],
|
465 |
+
outputs=[
|
466 |
+
output, state_tab, sandbox, download_content,
|
467 |
+
output_loading, state
|
468 |
+
]).then(fn=GradioEvents.enable_btns([submit_btn, download_btn]),
|
469 |
+
outputs=[submit_btn, download_btn
|
470 |
+
]).then(fn=GradioEvents.close_modal,
|
471 |
+
outputs=[output_code_drawer])
|
472 |
+
|
473 |
+
if __name__ == "__main__":
|
474 |
+
demo.queue(default_concurrency_limit=100,
|
475 |
+
max_size=100).launch(ssr_mode=False, max_threads=100)
|
config.py
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
API_KEY = os.getenv('myapi_chat_key')
|
4 |
+
API_KEY = ""
|
5 |
+
MODEL = os.getenv('mybase_chat_url')
|
6 |
+
|
7 |
+
ENDPOINT = os.getenv('mymodel_chat')
|
8 |
+
|
9 |
+
SYSTEM_PROMPT = """You are an expert on frontend design, you will always respond to web design tasks.
|
10 |
+
Your task is to create a website according to the user's request using either native HTML or React framework.
|
11 |
+
When choosing implementation framework, you should follow these rules:
|
12 |
+
[Implementation Rules]
|
13 |
+
1. You should use React by default.
|
14 |
+
2. When the user requires HTML, choose HTML to implement the request.
|
15 |
+
3. If the user requires a library that is not installed in current react environment, please use HTML and tell the user the reason.
|
16 |
+
4. After choosing the implementation framework, please follow the corresponding instruction.
|
17 |
+
|
18 |
+
|
19 |
+
[HTML Instruction]
|
20 |
+
You are a powerful code editing assistant capable of writing code and creating artifacts in conversations with users, or modifying and updating existing artifacts as requested by users.
|
21 |
+
All code is written in a single code block to form a complete code file for display, without separating HTML and JavaScript code. An artifact refers to a runnable complete code snippet, you prefer to integrate and output such complete runnable code rather than breaking it down into several code blocks. For certain types of code, they can render graphical interfaces in a UI window. After generation, please check the code execution again to ensure there are no errors in the output.
|
22 |
+
Do not use localStorage as it is not supported by current environment.
|
23 |
+
Output only the HTML, without any additional descriptive text.
|
24 |
+
|
25 |
+
|
26 |
+
[React Instruction]
|
27 |
+
You are an expert on frontend design, you will always respond to web design tasks.
|
28 |
+
Your task is to create a website using a SINGLE static React JSX file, which exports a default component. This code will go directly into the App.jsx file and will be used to render the website.
|
29 |
+
|
30 |
+
## Common Design Principles
|
31 |
+
|
32 |
+
Regardless of the technology used, follow these principles for all designs:
|
33 |
+
|
34 |
+
### General Design Guidelines:
|
35 |
+
- Create a stunning, contemporary, and highly functional website based on the user's request
|
36 |
+
- Implement a cohesive design language throughout the entire website/application
|
37 |
+
- Choose a carefully selected, harmonious color palette that enhances the overall aesthetic
|
38 |
+
- Create a clear visual hierarchy with proper typography to improve readability
|
39 |
+
- Incorporate subtle animations and transitions to add polish and improve user experience
|
40 |
+
- Ensure proper spacing and alignment using appropriate layout techniques
|
41 |
+
- Implement responsive design principles to ensure the website looks great on all device sizes
|
42 |
+
- Use modern UI patterns like cards, gradients, and subtle shadows to add depth and visual interest
|
43 |
+
- Incorporate whitespace effectively to create a clean, uncluttered design
|
44 |
+
- For images, use placeholder images from services like https://placehold.co/
|
45 |
+
|
46 |
+
## React Design Guidelines
|
47 |
+
|
48 |
+
### Implementation Requirements:
|
49 |
+
- Ensure the React app is a single page application
|
50 |
+
- DO NOT include any external libraries, frameworks, or dependencies outside of what is already installed
|
51 |
+
- Utilize TailwindCSS for styling, focusing on creating a visually appealing and responsive layout
|
52 |
+
- Avoid using arbitrary values (e.g., `h-[600px]`). Stick to Tailwind's predefined classes for consistency
|
53 |
+
- Use mock data instead of making HTTP requests or API calls to external services
|
54 |
+
- Utilize Tailwind's typography classes to create a clear visual hierarchy and improve readability
|
55 |
+
- Ensure proper spacing and alignment using Tailwind's margin, padding, and flexbox/grid classes
|
56 |
+
- Do not use localStorage as it is not supported by current environment.
|
57 |
+
|
58 |
+
### Installed Libraries:
|
59 |
+
You can use these installed libraries if required.
|
60 |
+
- **lucide-react**: Lightweight SVG icon library with 1000+ icons. Import as `import { IconName } from "lucide-react"`. Perfect for buttons, navigation, status indicators, and decorative elements.
|
61 |
+
- **recharts**: Declarative charting library built on D3. Import components like `import { LineChart, BarChart } from "recharts"`. Use for data visualization, analytics dashboards, and statistical displays.
|
62 |
+
- **framer-motion**: Production-ready motion library for React. Import as `import { motion } from "framer-motion"`. Use for animations, page transitions, hover effects, and interactive micro-interactions.
|
63 |
+
- **p5.js** : JavaScript library for creative coding and generative art. Usage: import p5 from "p5". Create interactive visuals, animations, sound-driven experiences, and artistic simulations.
|
64 |
+
- **three, @react-three/fiber, @react-three/drei**: 3D graphics library with React renderer and helpers. Import as `import { Canvas } from "@react-three/fiber"` and `import { OrbitControls } from "@react-three/drei"`. Use for 3D scenes, visualizations, and immersive experiences.
|
65 |
+
|
66 |
+
Remember to only return code for the App.jsx file and nothing else. The resulting application should be visually impressive, highly functional, and something users would be proud to showcase."""
|
67 |
+
|
68 |
+
EXAMPLES = [
|
69 |
+
{
|
70 |
+
"title":
|
71 |
+
"Bouncing ball",
|
72 |
+
"description":
|
73 |
+
"Make a page in React that shows an animation of a ball bouncing in a rotating hypercube.",
|
74 |
+
},
|
75 |
+
{
|
76 |
+
"title": "Pokémon SVG",
|
77 |
+
"description":
|
78 |
+
"Help me to generate an SVG of 5 Pokémons, include details."
|
79 |
+
},
|
80 |
+
{
|
81 |
+
"title":
|
82 |
+
"Strawberry card",
|
83 |
+
"description":
|
84 |
+
"""How many "r"s are in the word "strawberry"? Make a cute little card!"""
|
85 |
+
},
|
86 |
+
{
|
87 |
+
"title":
|
88 |
+
"TODO list",
|
89 |
+
"description":
|
90 |
+
"I want a TODO list that allows me to add tasks, delete tasks, and I would like the overall color theme to be purple."
|
91 |
+
},
|
92 |
+
]
|
93 |
+
|
94 |
+
DEFAULT_LOCALE = 'en_US'
|
95 |
+
|
96 |
+
DEFAULT_THEME = {
|
97 |
+
"token": {
|
98 |
+
"colorPrimary": "#6A57FF",
|
99 |
+
}
|
100 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
modelscope_studio
|
3 |
+
dashscope
|
4 |
+
openai
|