Spaces:
Running
Running
cherrytest
commited on
Commit
·
785fbfa
1
Parent(s):
04351ab
upload
Browse files- README.md +11 -23
- app.py +882 -0
- assets/minimax-logo.png +0 -0
- config.py +104 -0
- requirements.txt +4 -0
- start.sh +16 -0
README.md
CHANGED
@@ -1,25 +1,13 @@
|
|
1 |
---
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
#- iic/MTWI
|
12 |
-
train:
|
13 |
-
#- iic/SIBR
|
14 |
-
models: #关联模型
|
15 |
-
#- iic/ofa_ocr-recognition_general_base_zh
|
16 |
-
|
17 |
-
## 启动文件(若SDK为Gradio/Streamlit,默认为app.py, 若为Static HTML, 默认为index.html)
|
18 |
-
# deployspec:
|
19 |
-
# entry_file: app.py
|
20 |
-
license: Apache License 2.0
|
21 |
---
|
22 |
-
|
23 |
-
|
24 |
-
git clone https://www.modelscope.cn/studios/MiniMax/MiniMax-M1.git
|
25 |
-
```
|
|
|
1 |
---
|
2 |
+
title: MiniMax M1
|
3 |
+
emoji: 💬
|
4 |
+
colorFrom: yellow
|
5 |
+
colorTo: purple
|
6 |
+
sdk: gradio
|
7 |
+
sdk_version: 5.0.1
|
8 |
+
app_file: app.py
|
9 |
+
pinned: false
|
10 |
+
license: apache-2.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
---
|
12 |
+
|
13 |
+
An MiniMax-M1 example chatbot using [MiniMax-M1](https://huggingface.co/spaces/MiniMaxAI/MiniMax-M1), [Gradio](https://gradio.app), [`modelscope_studio`](https://modelscope.cn/studios/modelscope/modelscope-studio).
|
|
|
|
app.py
ADDED
@@ -0,0 +1,882 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import base64
|
2 |
+
import gradio as gr
|
3 |
+
import json
|
4 |
+
import mimetypes
|
5 |
+
import os
|
6 |
+
import requests
|
7 |
+
import time
|
8 |
+
import modelscope_studio.components.legacy as legacy
|
9 |
+
import modelscope_studio.components.antd as antd
|
10 |
+
import modelscope_studio.components.antdx as antdx
|
11 |
+
import modelscope_studio.components.base as ms
|
12 |
+
import modelscope_studio.components.pro as pro
|
13 |
+
from modelscope_studio.components.pro.chatbot import (
|
14 |
+
ChatbotActionConfig, ChatbotBotConfig, ChatbotMarkdownConfig,
|
15 |
+
ChatbotPromptsConfig, ChatbotUserConfig, ChatbotWelcomeConfig)
|
16 |
+
from config import DEFAULT_PROMPTS, EXAMPLES, SystemPrompt
|
17 |
+
import re
|
18 |
+
|
19 |
+
|
20 |
+
MODEL_VERSION = os.environ['MODEL_VERSION']
|
21 |
+
API_URL = os.environ['API_URL']
|
22 |
+
API_KEY = os.environ['API_KEY']
|
23 |
+
SYSTEM_PROMPT = os.environ.get('SYSTEM_PROMPT')
|
24 |
+
MULTIMODAL_FLAG = os.environ.get('MULTIMODAL')
|
25 |
+
MODEL_CONTROL_DEFAULTS = json.loads(os.environ['MODEL_CONTROL_DEFAULTS'])
|
26 |
+
NAME_MAP = {
|
27 |
+
'system': os.environ.get('SYSTEM_NAME'),
|
28 |
+
'user': os.environ.get('USER_NAME'),
|
29 |
+
}
|
30 |
+
|
31 |
+
MODEL_NAME = 'MiniMax-M1'
|
32 |
+
|
33 |
+
|
34 |
+
def prompt_select(e: gr.EventData):
|
35 |
+
return gr.update(value=e._data["payload"][0]["value"]["description"])
|
36 |
+
|
37 |
+
|
38 |
+
def clear():
|
39 |
+
return gr.update(value=None)
|
40 |
+
|
41 |
+
|
42 |
+
def retry(chatbot_value, e: gr.EventData):
|
43 |
+
index = e._data["payload"][0]["index"]
|
44 |
+
chatbot_value = chatbot_value[:index]
|
45 |
+
|
46 |
+
yield gr.update(loading=True), gr.update(value=chatbot_value), gr.update(disabled=True)
|
47 |
+
for chunk in submit(None, chatbot_value):
|
48 |
+
yield chunk
|
49 |
+
|
50 |
+
|
51 |
+
def cancel(chatbot_value):
|
52 |
+
chatbot_value[-1]["loading"] = False
|
53 |
+
chatbot_value[-1]["status"] = "done"
|
54 |
+
chatbot_value[-1]["footer"] = "Chat completion paused"
|
55 |
+
return gr.update(value=chatbot_value), gr.update(loading=False), gr.update(disabled=False)
|
56 |
+
|
57 |
+
|
58 |
+
def add_name_for_message(message):
|
59 |
+
name = NAME_MAP.get(message['role'])
|
60 |
+
if name is not None:
|
61 |
+
message['name'] = name
|
62 |
+
|
63 |
+
|
64 |
+
def convert_content(content):
|
65 |
+
if isinstance(content, str):
|
66 |
+
return content
|
67 |
+
if isinstance(content, tuple):
|
68 |
+
return [{
|
69 |
+
'type': 'image_url',
|
70 |
+
'image_url': {
|
71 |
+
'url': encode_base64(content[0]),
|
72 |
+
},
|
73 |
+
}]
|
74 |
+
content_list = []
|
75 |
+
for key, val in content.items():
|
76 |
+
if key == 'text':
|
77 |
+
content_list.append({
|
78 |
+
'type': 'text',
|
79 |
+
'text': val,
|
80 |
+
})
|
81 |
+
elif key == 'files':
|
82 |
+
for f in val:
|
83 |
+
content_list.append({
|
84 |
+
'type': 'image_url',
|
85 |
+
'image_url': {
|
86 |
+
'url': encode_base64(f),
|
87 |
+
},
|
88 |
+
})
|
89 |
+
return content_list
|
90 |
+
|
91 |
+
|
92 |
+
def encode_base64(path):
|
93 |
+
guess_type = mimetypes.guess_type(path)[0]
|
94 |
+
if not guess_type.startswith('image/'):
|
95 |
+
raise gr.Error('not an image ({}): {}'.format(guess_type, path))
|
96 |
+
with open(path, 'rb') as handle:
|
97 |
+
data = handle.read()
|
98 |
+
return 'data:{};base64,{}'.format(
|
99 |
+
guess_type,
|
100 |
+
base64.b64encode(data).decode(),
|
101 |
+
)
|
102 |
+
|
103 |
+
|
104 |
+
def format_history(history):
|
105 |
+
"""Convert chatbot history format to API call format"""
|
106 |
+
messages = []
|
107 |
+
if SYSTEM_PROMPT is not None:
|
108 |
+
messages.append({
|
109 |
+
'role': 'system',
|
110 |
+
'content': SYSTEM_PROMPT,
|
111 |
+
})
|
112 |
+
|
113 |
+
for item in history:
|
114 |
+
if item["role"] == "user":
|
115 |
+
messages.append({
|
116 |
+
'role': 'user',
|
117 |
+
'content': convert_content(item["content"]),
|
118 |
+
})
|
119 |
+
elif item["role"] == "assistant":
|
120 |
+
# Extract reasoning content and main content
|
121 |
+
reasoning_content = ""
|
122 |
+
main_content = ""
|
123 |
+
|
124 |
+
if isinstance(item["content"], list):
|
125 |
+
for content_item in item["content"]:
|
126 |
+
if content_item.get("type") == "tool":
|
127 |
+
reasoning_content = content_item.get("content", "")
|
128 |
+
elif content_item.get("type") == "text":
|
129 |
+
main_content = content_item.get("content", "")
|
130 |
+
else:
|
131 |
+
main_content = item["content"]
|
132 |
+
|
133 |
+
messages.append({
|
134 |
+
'role': 'assistant',
|
135 |
+
'content': convert_content(main_content),
|
136 |
+
'reasoning_content': convert_content(reasoning_content),
|
137 |
+
})
|
138 |
+
|
139 |
+
return messages
|
140 |
+
|
141 |
+
|
142 |
+
def submit(sender_value, chatbot_value):
|
143 |
+
if sender_value is not None:
|
144 |
+
chatbot_value.append({
|
145 |
+
"role": "user",
|
146 |
+
"content": sender_value,
|
147 |
+
})
|
148 |
+
|
149 |
+
api_messages = format_history(chatbot_value)
|
150 |
+
|
151 |
+
for message in api_messages:
|
152 |
+
add_name_for_message(message)
|
153 |
+
|
154 |
+
chatbot_value.append({
|
155 |
+
"role": "assistant",
|
156 |
+
"content": [],
|
157 |
+
"loading": True,
|
158 |
+
"status": "pending"
|
159 |
+
})
|
160 |
+
|
161 |
+
yield {
|
162 |
+
sender: gr.update(value=None, loading=True),
|
163 |
+
clear_btn: gr.update(disabled=True),
|
164 |
+
chatbot: gr.update(value=chatbot_value)
|
165 |
+
}
|
166 |
+
|
167 |
+
try:
|
168 |
+
data = {
|
169 |
+
'model': MODEL_VERSION,
|
170 |
+
'messages': api_messages,
|
171 |
+
'stream': True,
|
172 |
+
'max_tokens': MODEL_CONTROL_DEFAULTS['tokens_to_generate'],
|
173 |
+
'temperature': MODEL_CONTROL_DEFAULTS['temperature'],
|
174 |
+
'top_p': MODEL_CONTROL_DEFAULTS['top_p'],
|
175 |
+
}
|
176 |
+
|
177 |
+
r = requests.post(
|
178 |
+
API_URL,
|
179 |
+
headers={
|
180 |
+
'Content-Type': 'application/json',
|
181 |
+
'Authorization': 'Bearer {}'.format(API_KEY),
|
182 |
+
},
|
183 |
+
data=json.dumps(data),
|
184 |
+
stream=True,
|
185 |
+
)
|
186 |
+
|
187 |
+
thought_done = False
|
188 |
+
start_time = time.time()
|
189 |
+
message_content = chatbot_value[-1]["content"]
|
190 |
+
|
191 |
+
# Reasoning content (tool type)
|
192 |
+
message_content.append({
|
193 |
+
"type": "tool",
|
194 |
+
"content": "",
|
195 |
+
"options": {
|
196 |
+
"title": "🤔 Thinking..."
|
197 |
+
}
|
198 |
+
})
|
199 |
+
|
200 |
+
# Main content (text type)
|
201 |
+
message_content.append({
|
202 |
+
"type": "text",
|
203 |
+
"content": "",
|
204 |
+
})
|
205 |
+
|
206 |
+
reasoning_start_time = None
|
207 |
+
reasoning_duration = None
|
208 |
+
|
209 |
+
for row in r.iter_lines():
|
210 |
+
if row.startswith(b'data:'):
|
211 |
+
data = json.loads(row[5:])
|
212 |
+
if 'choices' not in data:
|
213 |
+
raise gr.Error('request failed')
|
214 |
+
choice = data['choices'][0]
|
215 |
+
|
216 |
+
if 'delta' in choice:
|
217 |
+
delta = choice['delta']
|
218 |
+
reasoning_content = delta.get('reasoning_content', '')
|
219 |
+
content = delta.get('content', '')
|
220 |
+
|
221 |
+
chatbot_value[-1]["loading"] = False
|
222 |
+
|
223 |
+
# Handle reasoning content
|
224 |
+
if reasoning_content:
|
225 |
+
if reasoning_start_time is None:
|
226 |
+
reasoning_start_time = time.time()
|
227 |
+
message_content[-2]["content"] += reasoning_content
|
228 |
+
|
229 |
+
# Handle main content
|
230 |
+
if content:
|
231 |
+
message_content[-1]["content"] += content
|
232 |
+
|
233 |
+
if not thought_done:
|
234 |
+
thought_done = True
|
235 |
+
if reasoning_start_time is not None:
|
236 |
+
reasoning_duration = time.time() - reasoning_start_time
|
237 |
+
thought_cost_time = "{:.2f}".format(reasoning_duration)
|
238 |
+
else:
|
239 |
+
reasoning_duration = 0.0
|
240 |
+
thought_cost_time = "0.00"
|
241 |
+
message_content[-2]["options"] = {"title": f"End of Thought ({thought_cost_time}s)"}
|
242 |
+
|
243 |
+
yield {chatbot: gr.update(value=chatbot_value)}
|
244 |
+
|
245 |
+
elif 'message' in choice:
|
246 |
+
message_data = choice['message']
|
247 |
+
reasoning_content = message_data.get('reasoning_content', '')
|
248 |
+
main_content = message_data.get('content', '')
|
249 |
+
|
250 |
+
message_content[-2]["content"] = reasoning_content
|
251 |
+
message_content[-1]["content"] = main_content
|
252 |
+
|
253 |
+
if reasoning_content and main_content:
|
254 |
+
if reasoning_duration is None:
|
255 |
+
if reasoning_start_time is not None:
|
256 |
+
reasoning_duration = time.time() - reasoning_start_time
|
257 |
+
thought_cost_time = "{:.2f}".format(reasoning_duration)
|
258 |
+
else:
|
259 |
+
reasoning_duration = 0.0
|
260 |
+
thought_cost_time = "0.00"
|
261 |
+
else:
|
262 |
+
thought_cost_time = "{:.2f}".format(reasoning_duration)
|
263 |
+
message_content[-2]["options"] = {"title": f"End of Thought ({thought_cost_time}s)"}
|
264 |
+
|
265 |
+
chatbot_value[-1]["loading"] = False
|
266 |
+
yield {chatbot: gr.update(value=chatbot_value)}
|
267 |
+
|
268 |
+
chatbot_value[-1]["footer"] = "{:.2f}s".format(time.time() - start_time)
|
269 |
+
chatbot_value[-1]["status"] = "done"
|
270 |
+
yield {
|
271 |
+
clear_btn: gr.update(disabled=False),
|
272 |
+
sender: gr.update(loading=False),
|
273 |
+
chatbot: gr.update(value=chatbot_value),
|
274 |
+
}
|
275 |
+
|
276 |
+
except Exception as e:
|
277 |
+
chatbot_value[-1]["loading"] = False
|
278 |
+
chatbot_value[-1]["status"] = "done"
|
279 |
+
chatbot_value[-1]["content"] = "Request failed, please try again."
|
280 |
+
yield {
|
281 |
+
clear_btn: gr.update(disabled=False),
|
282 |
+
sender: gr.update(loading=False),
|
283 |
+
chatbot: gr.update(value=chatbot_value),
|
284 |
+
}
|
285 |
+
raise e
|
286 |
+
|
287 |
+
|
288 |
+
def remove_code_block(text):
|
289 |
+
# Try to match code blocks with language markers
|
290 |
+
patterns = [
|
291 |
+
r'```(?:html|HTML)\n([\s\S]+?)\n```', # Match ```html or ```HTML
|
292 |
+
r'```\n([\s\S]+?)\n```', # Match code blocks without language markers
|
293 |
+
r'```([\s\S]+?)```' # Match code blocks without line breaks
|
294 |
+
]
|
295 |
+
|
296 |
+
for pattern in patterns:
|
297 |
+
match = re.search(pattern, text, re.DOTALL)
|
298 |
+
if match:
|
299 |
+
extracted = match.group(1).strip()
|
300 |
+
print("Successfully extracted code block:", extracted)
|
301 |
+
return extracted
|
302 |
+
|
303 |
+
# If no code block is found, check if the entire text is HTML
|
304 |
+
if text.strip().startswith('<!DOCTYPE html>') or text.strip().startswith('<html'):
|
305 |
+
print("Text appears to be raw HTML, using as is")
|
306 |
+
return text.strip()
|
307 |
+
|
308 |
+
print("No code block found in text:", text)
|
309 |
+
return text.strip()
|
310 |
+
|
311 |
+
def send_to_sandbox(code):
|
312 |
+
# Add a wrapper to inject necessary permissions
|
313 |
+
wrapped_code = f"""
|
314 |
+
<!DOCTYPE html>
|
315 |
+
<html>
|
316 |
+
<head>
|
317 |
+
<meta charset="UTF-8">
|
318 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
319 |
+
<script>
|
320 |
+
// Create a safe storage alternative
|
321 |
+
const safeStorage = {{
|
322 |
+
_data: {{}},
|
323 |
+
getItem: function(key) {{
|
324 |
+
return this._data[key] || null;
|
325 |
+
}},
|
326 |
+
setItem: function(key, value) {{
|
327 |
+
this._data[key] = value;
|
328 |
+
}},
|
329 |
+
removeItem: function(key) {{
|
330 |
+
delete this._data[key];
|
331 |
+
}},
|
332 |
+
clear: function() {{
|
333 |
+
this._data = {{}};
|
334 |
+
}}
|
335 |
+
}};
|
336 |
+
|
337 |
+
// Replace native localStorage
|
338 |
+
Object.defineProperty(window, 'localStorage', {{
|
339 |
+
value: safeStorage,
|
340 |
+
writable: false
|
341 |
+
}});
|
342 |
+
|
343 |
+
// Add error handling without using alert
|
344 |
+
window.onerror = function(message, source, lineno, colno, error) {{
|
345 |
+
console.error('Error:', message);
|
346 |
+
}};
|
347 |
+
</script>
|
348 |
+
</head>
|
349 |
+
<body>
|
350 |
+
{code}
|
351 |
+
</body>
|
352 |
+
</html>
|
353 |
+
"""
|
354 |
+
encoded_html = base64.b64encode(wrapped_code.encode('utf-8')).decode('utf-8')
|
355 |
+
data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"
|
356 |
+
iframe = f'<iframe src="{data_uri}" width="100%" height="920px" sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-presentation" allow="display-capture"></iframe>'
|
357 |
+
print("Generated iframe:", iframe)
|
358 |
+
return iframe
|
359 |
+
|
360 |
+
def select_example(example):
|
361 |
+
if isinstance(example, dict):
|
362 |
+
return example.get("description", "")
|
363 |
+
return ""
|
364 |
+
|
365 |
+
def generate_code(query: str):
|
366 |
+
if not query:
|
367 |
+
return {
|
368 |
+
code_output: gr.update(value=None),
|
369 |
+
reasoning_output: gr.update(value=None),
|
370 |
+
sandbox: gr.update(value=None),
|
371 |
+
state_tab: gr.update(active_key="empty"),
|
372 |
+
output_tabs: gr.update(active_key="reasoning", visible=False),
|
373 |
+
loading: gr.update(tip="Thinking...")
|
374 |
+
}
|
375 |
+
|
376 |
+
print("Starting code generation with query:", query)
|
377 |
+
messages = [{
|
378 |
+
'role': 'system',
|
379 |
+
'content': SystemPrompt
|
380 |
+
}, {
|
381 |
+
'role': 'user',
|
382 |
+
'content': query
|
383 |
+
}]
|
384 |
+
|
385 |
+
max_retries = 3
|
386 |
+
retry_count = 0
|
387 |
+
|
388 |
+
while retry_count < max_retries:
|
389 |
+
try:
|
390 |
+
data = {
|
391 |
+
'model': MODEL_VERSION,
|
392 |
+
'messages': messages,
|
393 |
+
'stream': True,
|
394 |
+
'max_tokens': MODEL_CONTROL_DEFAULTS['tokens_to_generate'],
|
395 |
+
'temperature': MODEL_CONTROL_DEFAULTS['temperature'],
|
396 |
+
'top_p': MODEL_CONTROL_DEFAULTS['top_p'],
|
397 |
+
}
|
398 |
+
|
399 |
+
print(f"Attempt {retry_count + 1}: Sending request to API with data:", json.dumps(data, indent=2))
|
400 |
+
r = requests.post(
|
401 |
+
API_URL,
|
402 |
+
headers={
|
403 |
+
'Content-Type': 'application/json',
|
404 |
+
'Authorization': 'Bearer {}'.format(API_KEY),
|
405 |
+
},
|
406 |
+
data=json.dumps(data),
|
407 |
+
stream=True,
|
408 |
+
timeout=60 # Set 60 seconds timeout
|
409 |
+
)
|
410 |
+
|
411 |
+
content = ""
|
412 |
+
reasoning_content = ""
|
413 |
+
loading_text = "Thinking..."
|
414 |
+
|
415 |
+
for row in r.iter_lines():
|
416 |
+
if row.startswith(b'data:'):
|
417 |
+
data = json.loads(row[5:])
|
418 |
+
print("Received data from API:", json.dumps(data, indent=2))
|
419 |
+
if 'choices' not in data:
|
420 |
+
raise gr.Error('request failed')
|
421 |
+
choice = data['choices'][0]
|
422 |
+
|
423 |
+
if 'delta' in choice:
|
424 |
+
delta = choice['delta']
|
425 |
+
content += delta.get('content', '')
|
426 |
+
reasoning_content += delta.get('reasoning_content', '')
|
427 |
+
|
428 |
+
# Update loading text based on content
|
429 |
+
if content and not loading_text == "Generating code...":
|
430 |
+
loading_text = "Generating code..."
|
431 |
+
yield {
|
432 |
+
code_output: gr.update(value=content),
|
433 |
+
reasoning_output: gr.update(value=reasoning_content + "\n"),
|
434 |
+
sandbox: gr.update(value=None),
|
435 |
+
state_tab: gr.update(active_key="loading"),
|
436 |
+
output_tabs: gr.update(active_key="reasoning", visible=True),
|
437 |
+
loading: gr.update(tip=loading_text)
|
438 |
+
}
|
439 |
+
else:
|
440 |
+
yield {
|
441 |
+
code_output: gr.update(value=content),
|
442 |
+
reasoning_output: gr.update(value=reasoning_content + "\n"),
|
443 |
+
sandbox: gr.update(value=None),
|
444 |
+
state_tab: gr.update(active_key="loading"),
|
445 |
+
output_tabs: gr.update(active_key="reasoning", visible=True),
|
446 |
+
loading: gr.update(tip=loading_text)
|
447 |
+
}
|
448 |
+
elif 'message' in choice:
|
449 |
+
message_data = choice['message']
|
450 |
+
content = message_data.get('content', '')
|
451 |
+
reasoning_content = message_data.get('reasoning_content', '')
|
452 |
+
print("Final content:", content)
|
453 |
+
print("Final reasoning:", reasoning_content)
|
454 |
+
html_content = remove_code_block(content)
|
455 |
+
print("Extracted HTML:", html_content)
|
456 |
+
yield {
|
457 |
+
code_output: gr.update(value=content),
|
458 |
+
reasoning_output: gr.update(value=reasoning_content + "\n"),
|
459 |
+
sandbox: gr.update(value=send_to_sandbox(html_content)),
|
460 |
+
state_tab: gr.update(active_key="render"),
|
461 |
+
output_tabs: gr.update(active_key="code", visible=True),
|
462 |
+
loading: gr.update(tip="Done")
|
463 |
+
}
|
464 |
+
|
465 |
+
# If successful, break out of retry loop
|
466 |
+
break
|
467 |
+
|
468 |
+
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
|
469 |
+
retry_count += 1
|
470 |
+
if retry_count == max_retries:
|
471 |
+
print(f"Failed after {max_retries} attempts:", str(e))
|
472 |
+
raise gr.Error(f"Request failed after {max_retries} attempts: {str(e)}")
|
473 |
+
print(f"Attempt {retry_count} failed, retrying...")
|
474 |
+
time.sleep(1) # Wait 1 second before retrying
|
475 |
+
|
476 |
+
except Exception as e:
|
477 |
+
print("Error occurred:", str(e))
|
478 |
+
raise gr.Error(str(e))
|
479 |
+
|
480 |
+
css = """
|
481 |
+
/* Add styles for the main container */
|
482 |
+
.ant-tabs-content {
|
483 |
+
height: calc(100vh - 200px);
|
484 |
+
overflow: hidden;
|
485 |
+
}
|
486 |
+
|
487 |
+
.ant-tabs-tabpane {
|
488 |
+
height: 100%;
|
489 |
+
overflow-y: auto;
|
490 |
+
}
|
491 |
+
|
492 |
+
/* Modify existing styles */
|
493 |
+
.output-loading {
|
494 |
+
display: flex;
|
495 |
+
flex-direction: column;
|
496 |
+
align-items: center;
|
497 |
+
justify-content: center;
|
498 |
+
width: 100%;
|
499 |
+
height: 100%;
|
500 |
+
min-height: unset;
|
501 |
+
}
|
502 |
+
|
503 |
+
.output-html {
|
504 |
+
display: flex;
|
505 |
+
flex-direction: column;
|
506 |
+
width: 100%;
|
507 |
+
height: 100%;
|
508 |
+
min-height: unset;
|
509 |
+
background: #fff;
|
510 |
+
border-radius: 8px;
|
511 |
+
border: 1px solid #e8e8e8;
|
512 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
513 |
+
overflow: hidden;
|
514 |
+
}
|
515 |
+
|
516 |
+
.right_content {
|
517 |
+
display: flex;
|
518 |
+
flex-direction: column;
|
519 |
+
align-items: center;
|
520 |
+
justify-content: center;
|
521 |
+
width: 100%;
|
522 |
+
height: 100%;
|
523 |
+
min-height: unset;
|
524 |
+
background: #fff;
|
525 |
+
border-radius: 8px;
|
526 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
527 |
+
}
|
528 |
+
|
529 |
+
/* Add styles for the code playground container */
|
530 |
+
.code-playground-container {
|
531 |
+
height: 100%;
|
532 |
+
overflow-y: auto;
|
533 |
+
padding-right: 8px;
|
534 |
+
}
|
535 |
+
|
536 |
+
.code-playground-container::-webkit-scrollbar {
|
537 |
+
width: 6px;
|
538 |
+
}
|
539 |
+
|
540 |
+
.code-playground-container::-webkit-scrollbar-track {
|
541 |
+
background: #f1f1f1;
|
542 |
+
border-radius: 3px;
|
543 |
+
}
|
544 |
+
|
545 |
+
.code-playground-container::-webkit-scrollbar-thumb {
|
546 |
+
background: #888;
|
547 |
+
border-radius: 3px;
|
548 |
+
}
|
549 |
+
|
550 |
+
.code-playground-container::-webkit-scrollbar-thumb:hover {
|
551 |
+
background: #555;
|
552 |
+
}
|
553 |
+
|
554 |
+
.render_header {
|
555 |
+
display: flex;
|
556 |
+
align-items: center;
|
557 |
+
padding: 8px 16px;
|
558 |
+
background: #f5f5f5;
|
559 |
+
border-bottom: 1px solid #e8e8e8;
|
560 |
+
border-top-left-radius: 8px;
|
561 |
+
border-top-right-radius: 8px;
|
562 |
+
}
|
563 |
+
|
564 |
+
.header_btn {
|
565 |
+
width: 12px;
|
566 |
+
height: 12px;
|
567 |
+
border-radius: 50%;
|
568 |
+
margin-right: 8px;
|
569 |
+
display: inline-block;
|
570 |
+
}
|
571 |
+
|
572 |
+
.header_btn:nth-child(1) {
|
573 |
+
background: #ff5f56;
|
574 |
+
}
|
575 |
+
|
576 |
+
.header_btn:nth-child(2) {
|
577 |
+
background: #ffbd2e;
|
578 |
+
}
|
579 |
+
|
580 |
+
.header_btn:nth-child(3) {
|
581 |
+
background: #27c93f;
|
582 |
+
}
|
583 |
+
|
584 |
+
.output-html > iframe {
|
585 |
+
flex: 1;
|
586 |
+
border: none;
|
587 |
+
background: #fff;
|
588 |
+
}
|
589 |
+
|
590 |
+
.reasoning-box {
|
591 |
+
height: 300px;
|
592 |
+
overflow-y: auto;
|
593 |
+
background-color: #f5f5f5;
|
594 |
+
border-radius: 4px;
|
595 |
+
margin-bottom: 12px;
|
596 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
597 |
+
font-size: 14px;
|
598 |
+
line-height: 1.2;
|
599 |
+
white-space: pre-wrap;
|
600 |
+
word-break: break-word;
|
601 |
+
width: 100%;
|
602 |
+
box-sizing: border-box;
|
603 |
+
scroll-behavior: smooth;
|
604 |
+
}
|
605 |
+
|
606 |
+
.reasoning-box .ms-markdown {
|
607 |
+
padding: 0 12px;
|
608 |
+
}
|
609 |
+
|
610 |
+
.reasoning-box::-webkit-scrollbar {
|
611 |
+
width: 6px;
|
612 |
+
}
|
613 |
+
|
614 |
+
.reasoning-box::-webkit-scrollbar-track {
|
615 |
+
background: #f1f1f1;
|
616 |
+
border-radius: 3px;
|
617 |
+
}
|
618 |
+
|
619 |
+
.reasoning-box::-webkit-scrollbar-thumb {
|
620 |
+
background: #888;
|
621 |
+
border-radius: 3px;
|
622 |
+
}
|
623 |
+
|
624 |
+
.reasoning-box::-webkit-scrollbar-thumb:hover {
|
625 |
+
background: #555;
|
626 |
+
}
|
627 |
+
|
628 |
+
.markdown-container {
|
629 |
+
height: 300px;
|
630 |
+
overflow-y: auto;
|
631 |
+
background-color: #f5f5f5;
|
632 |
+
border-radius: 4px;
|
633 |
+
margin-bottom: 12px;
|
634 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
635 |
+
font-size: 14px;
|
636 |
+
line-height: 1.6;
|
637 |
+
white-space: pre-wrap;
|
638 |
+
word-break: break-word;
|
639 |
+
width: 100%;
|
640 |
+
box-sizing: border-box;
|
641 |
+
scroll-behavior: smooth;
|
642 |
+
}
|
643 |
+
|
644 |
+
/* Example card styles */
|
645 |
+
.example-card {
|
646 |
+
flex: 1 1 calc(50% - 20px);
|
647 |
+
max-width: calc(50% - 20px);
|
648 |
+
margin: 6px;
|
649 |
+
transition: all 0.3s;
|
650 |
+
cursor: pointer;
|
651 |
+
border: 1px solid #e8e8e8;
|
652 |
+
border-radius: 8px;
|
653 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
654 |
+
}
|
655 |
+
|
656 |
+
.example-card:hover {
|
657 |
+
transform: translateY(-4px);
|
658 |
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
659 |
+
border-color: #d9d9d9;
|
660 |
+
}
|
661 |
+
|
662 |
+
.example-card .ant-card-meta-title {
|
663 |
+
font-size: 16px;
|
664 |
+
font-weight: 500;
|
665 |
+
margin-bottom: 8px;
|
666 |
+
color: #262626;
|
667 |
+
}
|
668 |
+
|
669 |
+
.example-card .ant-card-meta-description {
|
670 |
+
color: #666;
|
671 |
+
font-size: 14px;
|
672 |
+
line-height: 1.5;
|
673 |
+
}
|
674 |
+
|
675 |
+
/* Example tabs styles */
|
676 |
+
.example-tabs .ant-tabs-nav {
|
677 |
+
margin-bottom: 16px;
|
678 |
+
}
|
679 |
+
|
680 |
+
.example-tabs .ant-tabs-tab {
|
681 |
+
padding: 8px 16px;
|
682 |
+
font-size: 15px;
|
683 |
+
}
|
684 |
+
|
685 |
+
.example-tabs .ant-tabs-tab-active {
|
686 |
+
font-weight: 500;
|
687 |
+
}
|
688 |
+
|
689 |
+
/* Empty state styles */
|
690 |
+
.right_content {
|
691 |
+
display: flex;
|
692 |
+
flex-direction: column;
|
693 |
+
align-items: center;
|
694 |
+
justify-content: center;
|
695 |
+
width: 100%;
|
696 |
+
min-height: 620px;
|
697 |
+
background: #fff;
|
698 |
+
border-radius: 8px;
|
699 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
700 |
+
}
|
701 |
+
|
702 |
+
/* Add styles for the example cards container */
|
703 |
+
.example-tabs .ant-tabs-content {
|
704 |
+
padding: 0 8px;
|
705 |
+
}
|
706 |
+
|
707 |
+
.example-tabs .ant-flex {
|
708 |
+
margin: 0 -8px;
|
709 |
+
width: calc(100% + 16px);
|
710 |
+
}
|
711 |
+
"""
|
712 |
+
|
713 |
+
def scroll_to_bottom():
|
714 |
+
return """
|
715 |
+
function() {
|
716 |
+
setTimeout(() => {
|
717 |
+
const reasoningBox = document.querySelector('.reasoning-box');
|
718 |
+
if (reasoningBox) {
|
719 |
+
reasoningBox.scrollTop = reasoningBox.scrollHeight;
|
720 |
+
}
|
721 |
+
const markdownContainer = document.querySelector('.markdown-container');
|
722 |
+
if (markdownContainer) {
|
723 |
+
markdownContainer.scrollTop = markdownContainer.scrollHeight;
|
724 |
+
}
|
725 |
+
}, 100);
|
726 |
+
}
|
727 |
+
"""
|
728 |
+
|
729 |
+
with gr.Blocks(css=css) as demo, ms.Application(), antdx.XProvider():
|
730 |
+
with antd.Tabs() as tabs:
|
731 |
+
with antd.Tabs.Item(key="chat", label="Chatbot"):
|
732 |
+
with antd.Flex(vertical=True, gap="middle"):
|
733 |
+
chatbot = pro.Chatbot(
|
734 |
+
height="calc(100vh - 200px)",
|
735 |
+
markdown_config=ChatbotMarkdownConfig(allow_tags=["think"]),
|
736 |
+
welcome_config=ChatbotWelcomeConfig(
|
737 |
+
variant="borderless",
|
738 |
+
icon="./assets/minimax-logo.png",
|
739 |
+
title="Hello, I'm MiniMax-M1",
|
740 |
+
description="You can input text to get started.",
|
741 |
+
prompts=ChatbotPromptsConfig(
|
742 |
+
title="How can I help you today?",
|
743 |
+
styles={
|
744 |
+
"list": {
|
745 |
+
"width": '100%',
|
746 |
+
},
|
747 |
+
"item": {
|
748 |
+
"flex": 1,
|
749 |
+
},
|
750 |
+
},
|
751 |
+
items=DEFAULT_PROMPTS
|
752 |
+
)
|
753 |
+
),
|
754 |
+
user_config=ChatbotUserConfig(actions=["copy", "edit"]),
|
755 |
+
bot_config=ChatbotBotConfig(
|
756 |
+
header=MODEL_NAME,
|
757 |
+
avatar="./assets/minimax-logo.png",
|
758 |
+
actions=["copy", "retry"]
|
759 |
+
)
|
760 |
+
)
|
761 |
+
|
762 |
+
with antdx.Sender() as sender:
|
763 |
+
with ms.Slot("prefix"):
|
764 |
+
with antd.Button(value=None, color="default", variant="text") as clear_btn:
|
765 |
+
with ms.Slot("icon"):
|
766 |
+
antd.Icon("ClearOutlined")
|
767 |
+
|
768 |
+
clear_btn.click(fn=clear, outputs=[chatbot])
|
769 |
+
submit_event = sender.submit(
|
770 |
+
fn=submit,
|
771 |
+
inputs=[sender, chatbot],
|
772 |
+
outputs=[sender, chatbot, clear_btn]
|
773 |
+
)
|
774 |
+
sender.cancel(
|
775 |
+
fn=cancel,
|
776 |
+
inputs=[chatbot],
|
777 |
+
outputs=[chatbot, sender, clear_btn],
|
778 |
+
cancels=[submit_event],
|
779 |
+
queue=False
|
780 |
+
)
|
781 |
+
chatbot.retry(
|
782 |
+
fn=retry,
|
783 |
+
inputs=[chatbot],
|
784 |
+
outputs=[sender, chatbot, clear_btn]
|
785 |
+
)
|
786 |
+
chatbot.welcome_prompt_select(fn=prompt_select, outputs=[sender])
|
787 |
+
|
788 |
+
with antd.Tabs.Item(key="code", label="Code Playground (WebDev)"):
|
789 |
+
with antd.Row(gutter=[32, 12], elem_classes="code-playground-container"):
|
790 |
+
with antd.Col(span=12):
|
791 |
+
with antd.Flex(vertical=True, gap="middle"):
|
792 |
+
code_input = antd.InputTextarea(
|
793 |
+
size="large",
|
794 |
+
allow_clear=True,
|
795 |
+
placeholder="Please enter what kind of application you want or choose an example below and click the button"
|
796 |
+
)
|
797 |
+
code_btn = antd.Button("Generate Code", type="primary", size="large")
|
798 |
+
with antd.Tabs(active_key="reasoning", visible=False) as output_tabs:
|
799 |
+
with antd.Tabs.Item(key="reasoning", label="🤔 Thinking Process"):
|
800 |
+
reasoning_output = legacy.Markdown(
|
801 |
+
elem_classes="reasoning-box"
|
802 |
+
)
|
803 |
+
with antd.Tabs.Item(key="code", label="💻 Generated Code"):
|
804 |
+
code_output = legacy.Markdown(elem_classes="markdown-container")
|
805 |
+
|
806 |
+
antd.Divider("Examples")
|
807 |
+
|
808 |
+
# Examples with categories
|
809 |
+
with antd.Tabs(elem_classes="example-tabs") as example_tabs:
|
810 |
+
for category, examples in EXAMPLES.items():
|
811 |
+
with antd.Tabs.Item(key=category, label=category):
|
812 |
+
with antd.Flex(gap="small", wrap=True):
|
813 |
+
for example in examples:
|
814 |
+
with antd.Card(
|
815 |
+
elem_classes="example-card",
|
816 |
+
hoverable=True
|
817 |
+
) as example_card:
|
818 |
+
antd.Card.Meta(
|
819 |
+
title=example['title'],
|
820 |
+
description=example['description']
|
821 |
+
)
|
822 |
+
|
823 |
+
example_card.click(
|
824 |
+
fn=select_example,
|
825 |
+
inputs=[gr.State(example)],
|
826 |
+
outputs=[code_input]
|
827 |
+
)
|
828 |
+
|
829 |
+
with antd.Col(span=12):
|
830 |
+
with ms.Div(elem_classes="right_panel"):
|
831 |
+
gr.HTML('''
|
832 |
+
<div class="render_header">
|
833 |
+
<span class="header_btn"></span>
|
834 |
+
<span class="header_btn"></span>
|
835 |
+
<span class="header_btn"></span>
|
836 |
+
</div>
|
837 |
+
''')
|
838 |
+
|
839 |
+
with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
|
840 |
+
with antd.Tabs.Item(key="empty"):
|
841 |
+
empty = antd.Empty(description="empty input", elem_classes="right_content")
|
842 |
+
with antd.Tabs.Item(key="loading"):
|
843 |
+
loading = antd.Spin(True, tip="Thinking and coding...", size="large", elem_classes="output-loading")
|
844 |
+
with antd.Tabs.Item(key="render"):
|
845 |
+
sandbox = gr.HTML(elem_classes="output-html")
|
846 |
+
|
847 |
+
code_btn.click(
|
848 |
+
generate_code,
|
849 |
+
inputs=[code_input],
|
850 |
+
outputs=[
|
851 |
+
code_output,
|
852 |
+
reasoning_output,
|
853 |
+
sandbox,
|
854 |
+
state_tab,
|
855 |
+
output_tabs,
|
856 |
+
loading
|
857 |
+
]
|
858 |
+
)
|
859 |
+
|
860 |
+
# Add auto-scroll functionality
|
861 |
+
reasoning_output.change(
|
862 |
+
fn=scroll_to_bottom,
|
863 |
+
inputs=[],
|
864 |
+
outputs=[],
|
865 |
+
)
|
866 |
+
code_output.change(
|
867 |
+
fn=scroll_to_bottom,
|
868 |
+
inputs=[],
|
869 |
+
outputs=[],
|
870 |
+
)
|
871 |
+
|
872 |
+
def on_tab_change(tab_key):
|
873 |
+
return gr.update(active_key=tab_key, visible=True)
|
874 |
+
|
875 |
+
output_tabs.change(
|
876 |
+
fn=on_tab_change,
|
877 |
+
inputs=[output_tabs],
|
878 |
+
outputs=[output_tabs],
|
879 |
+
)
|
880 |
+
|
881 |
+
if __name__ == '__main__':
|
882 |
+
demo.queue(default_concurrency_limit=50).launch(ssr_mode=False)
|
assets/minimax-logo.png
ADDED
![]() |
config.py
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
DEFAULT_PROMPTS = [
|
2 |
+
{
|
3 |
+
"label": "🤔 Logical Reasoning",
|
4 |
+
"children": [
|
5 |
+
{
|
6 |
+
"description": "A cat is lying on a blanket because it is warm. What does 'it' refer to in this sentence?"
|
7 |
+
},
|
8 |
+
{
|
9 |
+
"description": "Snowflake : white'' - Which of the following groups of words has a relationship most similar to the relationship in the above word group? [ ''Doctor : learned'', ''Woman : gentle'', ''River : flowing'', ''Peony : wealth'' ]"
|
10 |
+
}
|
11 |
+
]
|
12 |
+
},
|
13 |
+
{
|
14 |
+
"label": "📚 Knowledge Q&A",
|
15 |
+
"children": [
|
16 |
+
{
|
17 |
+
"description": "Why are most manhole covers round?"
|
18 |
+
},
|
19 |
+
{
|
20 |
+
"description": "What is the shortest distance between the United States and Russia?"
|
21 |
+
}
|
22 |
+
]
|
23 |
+
}
|
24 |
+
]
|
25 |
+
|
26 |
+
DEFAULT_CODE = {
|
27 |
+
"./index.html": """
|
28 |
+
<!DOCTYPE html>
|
29 |
+
<html lang="en">
|
30 |
+
<head>
|
31 |
+
<meta charset="UTF-8">
|
32 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
33 |
+
</head>
|
34 |
+
<body>
|
35 |
+
<h1>Hello, World!</h1>
|
36 |
+
</body>
|
37 |
+
</html>
|
38 |
+
"""
|
39 |
+
}
|
40 |
+
|
41 |
+
SystemPrompt = """
|
42 |
+
You are a web development engineer, writing web pages according to the instructions below. 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.
|
43 |
+
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.
|
44 |
+
Output only the HTML, without any additional descriptive text. Make the UI looks modern and beautiful.
|
45 |
+
"""
|
46 |
+
|
47 |
+
EXAMPLES = {
|
48 |
+
"UI Components": [
|
49 |
+
{
|
50 |
+
"title": "🔄 3D Flipping Card",
|
51 |
+
"description": "Create a 3D flipping card component that flips on hover. Include front and back content. Use only HTML and CSS (no JS). Make the flip smooth and realistic."
|
52 |
+
},
|
53 |
+
{
|
54 |
+
"title": "⚡ SVG Loading Animation",
|
55 |
+
"description": "Design an SVG dynamic loading animation with abstract style (e.g., rotating spinner, pulse dots) for web page loading status indication"
|
56 |
+
},
|
57 |
+
{
|
58 |
+
"title": "✨ Particle Background",
|
59 |
+
"description": "Create an HTML page with a canvas-based animated particle background. The particles should move smoothly and connect when close. Add a central heading text over the canvas"
|
60 |
+
},
|
61 |
+
{
|
62 |
+
"title": "🌈 Colorful Gradient Background",
|
63 |
+
"description": "Create an HTML page with a gradient background that transitions smoothly between multiple colors. Add a central heading text over the gradient"
|
64 |
+
}
|
65 |
+
],
|
66 |
+
"Interactive Apps": [
|
67 |
+
{
|
68 |
+
"title": "📋 TODO list",
|
69 |
+
"description": "Create a modern, interactive to-do list web app. It should allow users to add and remove items. Use beautiful styling and animations."
|
70 |
+
},
|
71 |
+
{
|
72 |
+
"title": "📝 Sticky Note Wall",
|
73 |
+
"description": "Create a sticky note wall where users can create, edit, drag, and delete colorful sticky notes. Make it visually appealing"
|
74 |
+
},
|
75 |
+
{
|
76 |
+
"title": "⌨️ Typing Speed Game",
|
77 |
+
"description": "Build a typing speed test web app. Randomly show a sentence, and track the user's typing speed in WPM (words per minute). Provide live feedback with colors and accuracy. Make it visually appealing."
|
78 |
+
},
|
79 |
+
{
|
80 |
+
"title": "💰 Personal Finance Tracker",
|
81 |
+
"description": "Create a personal finance tracker with user input, and visualize income and expenses using animated pie and bar charts. Use modern, responsive design in a single HTML file."
|
82 |
+
}
|
83 |
+
],
|
84 |
+
"Tools & Editors": [
|
85 |
+
{
|
86 |
+
"title": "📝 Markdown Editor with Preview",
|
87 |
+
"description": "Develop a modern markdown editor with real-time preview. Use a split pane layout for input and output, support bold, italics, headers, lists, links, images, etc. No external libraries."
|
88 |
+
},
|
89 |
+
{
|
90 |
+
"title": "🖼️ Image Filter Tool",
|
91 |
+
"description": "Create an image filter tool where users can upload an image and apply filters like grayscale, blur, brightness, contrast, etc. Show real-time preview."
|
92 |
+
}
|
93 |
+
],
|
94 |
+
"Games & Visualizations": [
|
95 |
+
{
|
96 |
+
"title": "🧩 Maze Generator and Pathfinding Visualizer",
|
97 |
+
"description": "Create a maze generator and pathfinding visualizer. Randomly generate a maze and visualize A* algorithm solving it step by step. Use canvas and animations. Make it visually appealing."
|
98 |
+
},
|
99 |
+
{
|
100 |
+
"title": "💥 Particle Explosion Effect",
|
101 |
+
"description": "Implement a particle explosion effect when the user clicks anywhere on the page. Use canvas and JavaScript to animate colorful particles that fade out."
|
102 |
+
}
|
103 |
+
]
|
104 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio==5.27.0
|
2 |
+
gradio-client>=0.30.0
|
3 |
+
requests
|
4 |
+
modelscope_studio==1.4.0
|
start.sh
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
|
3 |
+
# 设置环境变量
|
4 |
+
export API_URL="https://api.minimaxi.chat/v1/text/chatcompletion_v2"
|
5 |
+
export MODEL_CONTROL_DEFAULTS='{"tokens_to_generate": 40000, "temperature": 1, "top_p": 0.95}'
|
6 |
+
export MODEL_VERSION="MiniMax-Reasoning-01"
|
7 |
+
export API_KEY="your_api_key_here" # 请替换为你的实际API密钥
|
8 |
+
|
9 |
+
# 可选环境变量
|
10 |
+
export SYSTEM_PROMPT="你是小爱同学,一个有用的AI助手"
|
11 |
+
export MULTIMODAL="ON"
|
12 |
+
export SYSTEM_NAME="小爱同学"
|
13 |
+
export USER_NAME="用户"
|
14 |
+
|
15 |
+
# 启动应用
|
16 |
+
python app.py
|