Coloring commited on
Commit
978eafc
·
1 Parent(s): 2bac858

feat: add layout template `chatbot`

Browse files
app.py CHANGED
@@ -80,6 +80,9 @@ index_menu_items = [{
80
  "children": [{
81
  "label": get_text("Coder-Artifacts", "Coder-Artifacts"),
82
  "key": "coder_artifacts"
 
 
 
83
  }]
84
  }]
85
 
 
80
  "children": [{
81
  "label": get_text("Coder-Artifacts", "Coder-Artifacts"),
82
  "key": "coder_artifacts"
83
+ }, {
84
+ "label": get_text("Chatbot", "Chatbot"),
85
+ "key": "chatbot"
86
  }]
87
  }]
88
 
layout_templates/chatbot/README-zh_CN.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Chatbot
2
+
3
+ 用于构建聊天机器人界面的应用模板。
4
+
5
+ ## 示例
6
+
7
+ <demo name="app" position="bottom" collapsible="true"></demo>
layout_templates/chatbot/README.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Coder Artifacts
2
+
3
+ A application template for building chatbot interfaces.
4
+
5
+ ## Examples
6
+
7
+ <demo name="app" position="bottom" collapsible="true"></demo>
layout_templates/chatbot/app.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from helper.Docs import Docs
2
+
3
+ docs = Docs(__file__)
4
+
5
+ if __name__ == "__main__":
6
+ docs.render().queue().launch()
layout_templates/chatbot/demos/app.py ADDED
@@ -0,0 +1,665 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import os
3
+ import uuid
4
+
5
+ import gradio as gr
6
+ import modelscope_studio.components.antd as antd
7
+ import modelscope_studio.components.antdx as antdx
8
+ import modelscope_studio.components.base as ms
9
+ from openai import OpenAI
10
+
11
+ # =========== Configuration
12
+
13
+ # API KEY
14
+ MODELSCOPE_ACCESS_TOKEN = os.getenv('MODELSCOPE_ACCESS_TOKEN')
15
+
16
+ client = OpenAI(
17
+ base_url='https://api-inference.modelscope.cn/v1/',
18
+ api_key=MODELSCOPE_ACCESS_TOKEN,
19
+ )
20
+
21
+ model = "Qwen/Qwen2.5-VL-72B-Instruct"
22
+
23
+ # =========== Configuration
24
+
25
+ DEFAULT_PROMPTS = [{
26
+ "category":
27
+ "🖋 Make a plan",
28
+ "prompts": [
29
+ "Help me with a plan to start a business",
30
+ "Help me with a plan to achieve my goals",
31
+ "Help me with a plan for a successful interview"
32
+ ]
33
+ }, {
34
+ "category":
35
+ "📅 Help me write",
36
+ "prompts": [
37
+ "Help me write a story with a twist ending",
38
+ "Help me write a blog post on mental health",
39
+ "Help me write a letter to my future self"
40
+ ]
41
+ }]
42
+
43
+ DEFAULT_SUGGESTIONS = [{
44
+ "label":
45
+ 'Make a plan',
46
+ "value":
47
+ "Make a plan",
48
+ "children": [{
49
+ "label": "Start a business",
50
+ "value": "Help me with a plan to start a business"
51
+ }, {
52
+ "label": "Achieve my goals",
53
+ "value": "Help me with a plan to achieve my goals"
54
+ }, {
55
+ "label": "Successful interview",
56
+ "value": "Help me with a plan for a successful interview"
57
+ }]
58
+ }, {
59
+ "label":
60
+ 'Help me write',
61
+ "value":
62
+ "Help me write",
63
+ "children": [{
64
+ "label": "Story with a twist ending",
65
+ "value": "Help me write a story with a twist ending"
66
+ }, {
67
+ "label": "Blog post on mental health",
68
+ "value": "Help me write a blog post on mental health"
69
+ }, {
70
+ "label": "Letter to my future self",
71
+ "value": "Help me write a letter to my future self"
72
+ }]
73
+ }]
74
+
75
+ DEFAULT_CONVERSATIONS_HISTORY = [{"role": "placeholder"}]
76
+
77
+ DEFAULT_LOCALE = 'en_US'
78
+
79
+ DEFAULT_THEME = {
80
+ "token": {
81
+ "colorPrimary": "#6A57FF",
82
+ }
83
+ }
84
+
85
+
86
+ class Gradio_Events:
87
+
88
+ @staticmethod
89
+ def submit(state_value):
90
+ # Define your code here
91
+ # The best way is to use the image url.
92
+ def image_to_base64(image_path):
93
+ with open(image_path, "rb") as image_file:
94
+ encoded_string = base64.b64encode(
95
+ image_file.read()).decode('utf-8')
96
+ return f"data:image/jpeg;base64,{encoded_string}"
97
+
98
+ def format_history(history):
99
+ messages = [{
100
+ "role": "system",
101
+ "content": "You are a helpful and harmless assistant.",
102
+ }]
103
+ for item in history:
104
+ if item["role"] == "user":
105
+ messages.append({
106
+ "role":
107
+ "user",
108
+ "content": [{
109
+ "type": "text",
110
+ "text": item["content"]["text"]
111
+ }] + [{
112
+ "type": "image_url",
113
+ "image_url": image_to_base64(file["path"])
114
+ } for file in item["content"]["files"]]
115
+ })
116
+ elif item["role"] == "assistant":
117
+ messages.append(item)
118
+ return messages
119
+
120
+ history = state_value["conversations_histories"][
121
+ state_value["conversation_id"]]
122
+ history_messages = format_history(history)
123
+
124
+ history.append({
125
+ "role": "assistant",
126
+ "content": "",
127
+ "meta": {},
128
+ "loading": True,
129
+ })
130
+
131
+ yield {
132
+ chatbot: gr.update(items=history),
133
+ state: gr.update(value=state_value),
134
+ }
135
+ try:
136
+ response = client.chat.completions.create(
137
+ model=model, # ModelScope Model-Id
138
+ messages=history_messages,
139
+ stream=True)
140
+ for chunk in response:
141
+ history[-1]["content"] += chunk.choices[0].delta.content
142
+ history[-1]["loading"] = False
143
+ yield {
144
+ chatbot: gr.update(items=history),
145
+ state: gr.update(value=state_value)
146
+ }
147
+ history[-1]["meta"]["end"] = True
148
+ yield {
149
+ chatbot: gr.update(items=history),
150
+ state: gr.update(value=state_value),
151
+ }
152
+ except Exception as e:
153
+ history[-1]["loading"] = False
154
+ history[-1]["content"] = ""
155
+ history[-1]["role"] = "assistant-error"
156
+ yield {
157
+ chatbot: gr.update(items=history),
158
+ state: gr.update(value=state_value)
159
+ }
160
+ raise e
161
+
162
+ @staticmethod
163
+ def preprocess_submit(sender_value, attachments_value, state_value):
164
+ if not state_value["conversation_id"]:
165
+ random_id = str(uuid.uuid4())
166
+ history = []
167
+ state_value["conversation_id"] = random_id
168
+ state_value["conversations_histories"][random_id] = history
169
+ state_value["conversations"].append({
170
+ "label": sender_value,
171
+ "key": random_id
172
+ })
173
+
174
+ history = state_value["conversations_histories"][
175
+ state_value["conversation_id"]]
176
+ history.append({
177
+ "role":
178
+ "user",
179
+ "content":
180
+ dict(text=sender_value,
181
+ files=[
182
+ dict(path=f, size=os.path.getsize(f))
183
+ for f in attachments_value
184
+ ])
185
+ })
186
+ return {
187
+ add_conversation_btn:
188
+ gr.update(disabled=True),
189
+ sender:
190
+ gr.update(value=None, loading=True),
191
+ attachments:
192
+ gr.update(value=[]),
193
+ attachments_badge:
194
+ gr.update(dot=False),
195
+ clear_btn:
196
+ gr.update(disabled=True),
197
+ conversations:
198
+ gr.update(active_key=state_value["conversation_id"],
199
+ items=list(
200
+ map(
201
+ lambda item: {
202
+ **item,
203
+ "disabled":
204
+ True if item["key"] != state_value[
205
+ "conversation_id"] else False,
206
+ }, state_value["conversations"]))),
207
+ conversation_delete_menu_item:
208
+ gr.update(disabled=True),
209
+ state:
210
+ gr.update(value=state_value),
211
+ }
212
+
213
+ @staticmethod
214
+ def postprocess_submit(state_value):
215
+ return {
216
+ sender: gr.update(loading=False),
217
+ conversation_delete_menu_item: gr.update(disabled=False),
218
+ clear_btn: gr.update(disabled=False),
219
+ conversations: gr.update(items=state_value["conversations"]),
220
+ add_conversation_btn: gr.update(disabled=False)
221
+ }
222
+
223
+ @staticmethod
224
+ def cancel(state_value):
225
+ history = state_value["conversations_histories"][
226
+ state_value["conversation_id"]]
227
+ history[-1]["loading"] = False
228
+ history[-1]["meta"]["end"] = True
229
+ return {
230
+ **Gradio_Events.postprocess_submit(state_value),
231
+ chatbot:
232
+ gr.update(items=state_value["conversations_histories"][
233
+ state_value["conversation_id"]]),
234
+ state:
235
+ gr.update(value=state_value),
236
+ }
237
+
238
+ @staticmethod
239
+ def select_suggestion(sender_value, e: gr.EventData):
240
+ return gr.update(value=sender_value[:-1] + e._data["payload"][0])
241
+
242
+ @staticmethod
243
+ def apply_prompt(e: gr.EventData):
244
+ return gr.update(value=e._data["payload"][0]["data"]["description"])
245
+
246
+ @staticmethod
247
+ def new_chat(state_value):
248
+ if not state_value["conversation_id"]:
249
+ return gr.skip()
250
+ state_value["conversation_id"] = ""
251
+ return gr.update(active_key=state_value["conversation_id"]), gr.update(
252
+ items=DEFAULT_CONVERSATIONS_HISTORY), gr.update(value=state_value)
253
+
254
+ @staticmethod
255
+ def select_conversation(state_value, e: gr.EventData):
256
+ active_key = e._data["payload"][0]
257
+ if state_value["conversation_id"] == active_key or (
258
+ active_key not in state_value["conversations_histories"]):
259
+ return gr.skip()
260
+ state_value["conversation_id"] = active_key
261
+ return gr.update(active_key=active_key), gr.update(
262
+ items=state_value["conversations_histories"]
263
+ [active_key]), gr.update(value=state_value)
264
+
265
+ @staticmethod
266
+ def click_conversation_menu(state_value, e: gr.EventData):
267
+ conversation_id = e._data["payload"][0]["key"]
268
+ operation = e._data["payload"][1]["key"]
269
+ if operation == "delete":
270
+ del state_value["conversations_histories"][conversation_id]
271
+
272
+ state_value["conversations"] = [
273
+ item for item in state_value["conversations"]
274
+ if item["key"] != conversation_id
275
+ ]
276
+
277
+ if state_value["conversation_id"] == conversation_id:
278
+ state_value["conversation_id"] = ""
279
+ return gr.update(
280
+ items=state_value["conversations"],
281
+ active_key=state_value["conversation_id"]), gr.update(
282
+ items=DEFAULT_CONVERSATIONS_HISTORY), gr.update(
283
+ value=state_value)
284
+ else:
285
+ return gr.update(
286
+ items=state_value["conversations"]), gr.skip(), gr.update(
287
+ value=state_value)
288
+ return gr.skip()
289
+
290
+ @staticmethod
291
+ def clear_conversation_history(state_value):
292
+ if not state_value["conversation_id"]:
293
+ return gr.skip()
294
+ state_value["conversations_histories"][
295
+ state_value["conversation_id"]] = []
296
+ return gr.update(items=DEFAULT_CONVERSATIONS_HISTORY), gr.update(
297
+ value=state_value)
298
+
299
+ @staticmethod
300
+ def toggle_attachments(state_value, attachments_value):
301
+ state_value["attachments_open"] = not state_value["attachments_open"]
302
+ return gr.update(open=state_value["attachments_open"]), gr.update(
303
+ dot=len(attachments_value) > 0
304
+ and not state_value["attachments_open"]), gr.update(
305
+ value=state_value)
306
+
307
+ @staticmethod
308
+ def paste_file(attachments_value, state_value, e: gr.EventData):
309
+ state_value["attachments_open"] = True
310
+ return gr.update(value=attachments_value +
311
+ e._data["payload"][0]), gr.update(
312
+ open=True), gr.update(value=state_value)
313
+
314
+
315
+ css = """
316
+ #chatbot {
317
+ height: calc(100vh - 32px - 21px - 16px);
318
+ }
319
+
320
+ #chatbot .chatbot-conversations {
321
+ height: 100%;
322
+ background-color: var(--ms-gr-ant-color-bg-layout);
323
+ }
324
+
325
+ #chatbot .chatbot-conversations .chatbot-conversations-list {
326
+ padding-left: 0;
327
+ padding-right: 0;
328
+ }
329
+
330
+ #chatbot .chatbot-chat {
331
+ padding: 32px;
332
+ height: 100%;
333
+ }
334
+
335
+ @media (max-width: 768px) {
336
+ #chatbot .chatbot-chat {
337
+ padding: 0;
338
+ }
339
+ }
340
+
341
+ #chatbot .chatbot-chat .chatbot-chat-messages {
342
+ flex: 1;
343
+ }
344
+ #chatbot .chatbot-sender-actions .ms-gr-ant-sender-actions-btn-loading-button {
345
+ color: var(--ms-gr-ant-color-primary);
346
+ }
347
+ """
348
+
349
+
350
+ def logo():
351
+ with antd.Typography.Title(level=1,
352
+ elem_style=dict(fontSize=24,
353
+ padding=8,
354
+ margin=0)):
355
+ with antd.Flex(align="center", gap="small", justify="center"):
356
+ antd.Image(
357
+ "https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original",
358
+ preview=False,
359
+ alt="logo",
360
+ width=24,
361
+ height=24)
362
+ ms.Span("Chatbot")
363
+
364
+
365
+ with gr.Blocks(css=css) as demo:
366
+ state = gr.State({
367
+ "conversations_histories": {},
368
+ "conversations": [],
369
+ "conversation_id": "",
370
+ "attachments_open": False,
371
+ })
372
+ with ms.Application(), antdx.XProvider(
373
+ theme=DEFAULT_THEME, locale=DEFAULT_LOCALE), ms.AutoLoading():
374
+ with antd.Row(gutter=[20, 20], wrap=False, elem_id="chatbot"):
375
+ # Left Column
376
+ with antd.Col(md=dict(flex="0 0 260px", span=24, order=0),
377
+ span=0,
378
+ order=1,
379
+ elem_classes="chatbot-conversations"):
380
+ with antd.Flex(vertical=True,
381
+ gap="small",
382
+ elem_style=dict(height="100%")):
383
+ # Logo
384
+ logo()
385
+
386
+ # New Conversation Button
387
+ with antd.Button(color="primary",
388
+ variant="filled",
389
+ block=True) as add_conversation_btn:
390
+ ms.Text("New Conversation")
391
+ with ms.Slot("icon"):
392
+ antd.Icon("PlusOutlined")
393
+
394
+ # Conversations List
395
+ with antdx.Conversations(
396
+ elem_classes="chatbot-conversations-list",
397
+ ) as conversations:
398
+ with ms.Slot('menu.items'):
399
+ with antd.Menu.Item(
400
+ label="Delete", key="delete", danger=True
401
+ ) as conversation_delete_menu_item:
402
+ with ms.Slot("icon"):
403
+ antd.Icon("DeleteOutlined")
404
+ # Right Column
405
+ with antd.Col(flex=1, elem_style=dict(height="100%")):
406
+ with antd.Flex(vertical=True, elem_classes="chatbot-chat"):
407
+ # Chatbot
408
+ with antdx.Bubble.List(
409
+ items=DEFAULT_CONVERSATIONS_HISTORY,
410
+ elem_classes="chatbot-chat-messages") as chatbot:
411
+ # Define Chatbot Roles
412
+ with ms.Slot("roles"):
413
+ # Placeholder Role
414
+ with antdx.Bubble.List.Role(
415
+ role="placeholder",
416
+ styles=dict(content=dict(width="100%")),
417
+ variant="borderless"):
418
+ with ms.Slot("messageRender"):
419
+ with antd.Space(
420
+ direction="vertical",
421
+ size=16,
422
+ elem_style=dict(width="100%")):
423
+ antdx.Welcome(
424
+ styles=dict(icon=dict(
425
+ flexShrink=0)),
426
+ variant="borderless",
427
+ icon=
428
+ "https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp",
429
+ title=f"Hello, I'm {model}",
430
+ description=
431
+ "You can upload images and text to get started.",
432
+ )
433
+ with antdx.Prompts(
434
+ title=
435
+ "How can I help you today?",
436
+ styles={
437
+ "list": {
438
+ "width": '100%',
439
+ },
440
+ "item": {
441
+ "flex": 1,
442
+ },
443
+ }) as prompts:
444
+ for item in DEFAULT_PROMPTS:
445
+ with antdx.Prompts.Item(
446
+ label=item["category"]
447
+ ):
448
+ for prompt in item[
449
+ "prompts"]:
450
+ antdx.Prompts.Item(
451
+ description=prompt,
452
+ )
453
+
454
+ # User Role
455
+ with antdx.Bubble.List.Role(
456
+ role="user",
457
+ placement="end",
458
+ styles=dict(content=dict(
459
+ maxWidth="100%",
460
+ overflow='auto',
461
+ ))):
462
+ with ms.Slot("avatar"):
463
+ with antd.Avatar():
464
+ with ms.Slot("icon"):
465
+ antd.Icon("UserOutlined")
466
+ with ms.Slot("messageRender",
467
+ params_mapping="""(content) => {
468
+ if (typeof content === 'string') {
469
+ return { content, files: [], files_container: { style: { display: 'none' }} }
470
+ }
471
+ return { content: content.text, files_container: content.files?.length > 0 ? undefined : { style: { display: 'none' }}, files: (content.files || []).map(file => ({ item: file }))}
472
+ }"""):
473
+ with antd.Flex(vertical=True,
474
+ gap="middle"):
475
+ with antd.Flex(
476
+ gap="middle",
477
+ wrap=True,
478
+ as_item="files_container"):
479
+ with ms.Each(as_item="files"):
480
+ antdx.Attachments.FileCard()
481
+ ms.Markdown(as_item="content")
482
+ # Chatbot Role
483
+ with antdx.Bubble.List.Role(
484
+ role="assistant",
485
+ placement="start",
486
+ styles=dict(content=dict(
487
+ maxWidth="100%", overflow='auto'))):
488
+ with ms.Slot("avatar"):
489
+ with antd.Avatar():
490
+ with ms.Slot("icon"):
491
+ antd.Icon("RobotOutlined")
492
+ with ms.Slot(
493
+ "messageRender",
494
+ params_mapping=
495
+ "(content) => ({ value: content })"):
496
+ ms.Markdown()
497
+ with ms.Slot("footer",
498
+ params_mapping="""(bubble) => {
499
+ return bubble?.meta?.end ? { copyable: { text: bubble.content, tooltips: false } } : { style: { display: 'none' } }
500
+ }"""):
501
+ with antd.Typography.Text(copyable=dict(
502
+ tooltips=False)):
503
+ with ms.Slot("copyable.icon"):
504
+ with antd.Button(value=None,
505
+ size="small",
506
+ color="default",
507
+ variant="text"):
508
+ with ms.Slot("icon"):
509
+ antd.Icon("CopyOutlined")
510
+ with antd.Button(value=None,
511
+ size="small",
512
+ color="default",
513
+ variant="text"):
514
+ with ms.Slot("icon"):
515
+ antd.Icon("CheckOutlined")
516
+ # Error Chatbot Role
517
+ with antdx.Bubble.List.Role(
518
+ role="assistant-error",
519
+ placement="start",
520
+ styles=dict(content=dict(
521
+ maxWidth="100%", overflow='auto'))):
522
+ with ms.Slot("avatar"):
523
+ with antd.Avatar():
524
+ with ms.Slot("icon"):
525
+ antd.Icon("RobotOutlined")
526
+ with ms.Slot("messageRender"):
527
+ antd.Typography.Text(
528
+ "Failed to respond, please try again.",
529
+ type="danger")
530
+ # Sender
531
+ with antdx.Suggestion(
532
+ items=DEFAULT_SUGGESTIONS,
533
+ # onKeyDown Handler in Javascript
534
+ should_trigger="""(e, { onTrigger, onKeyDown }) => {
535
+ switch(e.key) {
536
+ case '/':
537
+ onTrigger()
538
+ break
539
+ case 'ArrowRight':
540
+ case 'ArrowLeft':
541
+ case 'ArrowUp':
542
+ case 'ArrowDown':
543
+ break;
544
+ default:
545
+ onTrigger(false)
546
+ }
547
+ onKeyDown(e)
548
+ }""") as suggestion:
549
+ with ms.Slot("children"):
550
+ with antdx.Sender(
551
+ class_names=dict(
552
+ actions="chatbot-sender-actions"),
553
+ placeholder="Enter / to get suggestions"
554
+ ) as sender:
555
+ with ms.Slot("prefix"):
556
+ # Attachments Button
557
+ with antd.Tooltip(
558
+ title="Upload Attachments"):
559
+ with antd.Badge(dot=False
560
+ ) as attachments_badge:
561
+ with antd.Button(
562
+ value=None, type="text"
563
+ ) as attachments_btn:
564
+ with ms.Slot("icon"):
565
+ antd.Icon("LinkOutlined")
566
+ # Clear Button
567
+ with antd.Tooltip(
568
+ title="Clear Conversation History"
569
+ ):
570
+ with antd.Button(
571
+ value=None,
572
+ type="text") as clear_btn:
573
+ with ms.Slot("icon"):
574
+ antd.Icon("ClearOutlined")
575
+ # Attachments
576
+ with ms.Slot("header"):
577
+ with antdx.Sender.Header(
578
+ title="Attachments",
579
+ open=False,
580
+ styles={
581
+ "content": {
582
+ "padding": 0,
583
+ },
584
+ }) as sender_header:
585
+ with antdx.Attachments(
586
+ max_count=6,
587
+ accept="image/*",
588
+ multiple=True) as attachments:
589
+ with ms.Slot(
590
+ "placeholder.title",
591
+ params_mapping=
592
+ """(type) => type === 'drop' ? 'Drop file here' : 'Upload files'"""
593
+ ):
594
+ ms.Span()
595
+ with ms.Slot(
596
+ "placeholder.description",
597
+ params_mapping=
598
+ "(type) => ({ style: { display: type === 'drop'? 'none' : undefined } })"
599
+ ):
600
+ ms.Span(
601
+ "Click or drag files to this area to upload"
602
+ )
603
+ with ms.Slot(
604
+ "placeholder.icon",
605
+ params_mapping=
606
+ "(type) => ({ style: { display: type === 'drop'? 'none' : undefined } })"
607
+ ):
608
+ antd.Icon(
609
+ "CloudUploadOutlined")
610
+
611
+ # Events Handler
612
+ add_conversation_btn.click(fn=Gradio_Events.new_chat,
613
+ inputs=[state],
614
+ outputs=[conversations, chatbot, state])
615
+ conversations.active_change(fn=Gradio_Events.select_conversation,
616
+ inputs=[state],
617
+ outputs=[conversations, chatbot, state])
618
+ conversations.menu_click(fn=Gradio_Events.click_conversation_menu,
619
+ inputs=[state],
620
+ outputs=[conversations, chatbot, state])
621
+ prompts.item_click(fn=Gradio_Events.apply_prompt, outputs=[sender])
622
+
623
+ attachments_btn.click(fn=Gradio_Events.toggle_attachments,
624
+ inputs=[state, attachments],
625
+ outputs=[sender_header, attachments_badge, state])
626
+ clear_btn.click(fn=Gradio_Events.clear_conversation_history,
627
+ inputs=[state],
628
+ outputs=[chatbot, state])
629
+ sender_header.open_change(
630
+ fn=Gradio_Events.toggle_attachments,
631
+ inputs=[state, attachments],
632
+ outputs=[sender_header, attachments_badge, state])
633
+ suggestion.select(fn=Gradio_Events.select_suggestion,
634
+ inputs=[sender],
635
+ outputs=[sender])
636
+
637
+ sender.paste_file(fn=Gradio_Events.paste_file,
638
+ inputs=[attachments, state],
639
+ outputs=[attachments, sender_header, state])
640
+
641
+ submit_event = sender.submit(fn=Gradio_Events.preprocess_submit,
642
+ inputs=[sender, attachments, state],
643
+ outputs=[
644
+ sender, attachments, attachments_badge,
645
+ clear_btn, conversation_delete_menu_item,
646
+ add_conversation_btn, conversations, state
647
+ ]).then(fn=Gradio_Events.submit,
648
+ inputs=[state],
649
+ outputs=[chatbot, state])
650
+ submit_event.then(fn=Gradio_Events.postprocess_submit,
651
+ inputs=[state],
652
+ outputs=[
653
+ sender, conversation_delete_menu_item, clear_btn,
654
+ conversations, add_conversation_btn
655
+ ])
656
+ sender.cancel(fn=None, cancels=[submit_event])
657
+ sender.cancel(fn=Gradio_Events.cancel,
658
+ inputs=[state],
659
+ outputs=[
660
+ sender, conversation_delete_menu_item, clear_btn,
661
+ conversations, add_conversation_btn, chatbot, state
662
+ ])
663
+
664
+ if __name__ == "__main__":
665
+ demo.queue().launch(ssr_mode=False)
layout_templates/coder_artifacts/README.md CHANGED
@@ -1,6 +1,6 @@
1
  # Coder Artifacts
2
 
3
- Application template for building code generation interfaces.
4
 
5
  ## Examples
6
 
 
1
  # Coder Artifacts
2
 
3
+ A Application template for building code generation interfaces.
4
 
5
  ## Examples
6
 
requirements.txt CHANGED
@@ -1,2 +1,2 @@
1
- modelscope_studio==1.1.5
2
  openai
 
1
+ modelscope_studio==1.1.6
2
  openai
src/pyproject.toml CHANGED
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
8
 
9
  [project]
10
  name = "modelscope_studio"
11
- version = "1.1.5"
12
  description = "A third-party component library based on Gradio."
13
  readme = "README.md"
14
  license = "Apache-2.0"
 
8
 
9
  [project]
10
  name = "modelscope_studio"
11
+ version = "1.1.6"
12
  description = "A third-party component library based on Gradio."
13
  readme = "README.md"
14
  license = "Apache-2.0"