Files changed (1) hide show
  1. app.py +0 -946
app.py DELETED
@@ -1,946 +0,0 @@
1
- import os
2
- import uuid
3
-
4
- import gradio as gr
5
- import modelscope_studio.components.antd as antd
6
- import modelscope_studio.components.antdx as antdx
7
- import modelscope_studio.components.base as ms
8
- from openai import OpenAI
9
-
10
- # Qwen/QwQ-32B
11
-
12
- # =========== Configuration
13
- # API KEY
14
- client = OpenAI(
15
- base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
16
- api_key=os.getenv("DASHSCOPE_API_KEY"),
17
- )
18
-
19
- model = "qwq-32b"
20
-
21
- save_history = True
22
-
23
- # =========== Configuration
24
-
25
- is_modelscope_studio = os.getenv('MODELSCOPE_ENVIRONMENT') == 'studio'
26
-
27
-
28
- def get_text(text: str, cn_text: str):
29
- if is_modelscope_studio:
30
- return cn_text
31
- return text
32
-
33
-
34
- qwen_logo = os.path.join(os.path.dirname(__file__), "qwen.png")
35
-
36
- DEFAULT_PROMPTS = [{
37
- "category":
38
- "🖋 Make a plan",
39
- "prompts": [
40
- "Help me with a plan to start a business",
41
- "Help me with a plan to achieve my goals",
42
- "Help me with a plan for a successful interview"
43
- ]
44
- }, {
45
- "category":
46
- "📅 Help me write",
47
- "prompts": [
48
- "Help me write a story with a twist ending",
49
- "Help me write a blog post on mental health",
50
- "Help me write a letter to my future self"
51
- ]
52
- }]
53
-
54
- DEFAULT_SUGGESTIONS = [{
55
- "label":
56
- 'Make a plan',
57
- "value":
58
- "Make a plan",
59
- "children": [{
60
- "label": "Start a business",
61
- "value": "Help me with a plan to start a business"
62
- }, {
63
- "label": "Achieve my goals",
64
- "value": "Help me with a plan to achieve my goals"
65
- }, {
66
- "label": "Successful interview",
67
- "value": "Help me with a plan for a successful interview"
68
- }]
69
- }, {
70
- "label":
71
- 'Help me write',
72
- "value":
73
- "Help me write",
74
- "children": [{
75
- "label": "Story with a twist ending",
76
- "value": "Help me write a story with a twist ending"
77
- }, {
78
- "label": "Blog post on mental health",
79
- "value": "Help me write a blog post on mental health"
80
- }, {
81
- "label": "Letter to my future self",
82
- "value": "Help me write a letter to my future self"
83
- }]
84
- }]
85
-
86
- DEFAULT_CONVERSATIONS_HISTORY = [{"role": "placeholder"}]
87
-
88
- DEFAULT_LOCALE = 'zh_CN' if is_modelscope_studio else 'en_US'
89
-
90
- DEFAULT_THEME = {
91
- "token": {
92
- "colorPrimary": "#6A57FF",
93
- }
94
- }
95
-
96
-
97
- def format_history(history):
98
- messages = [{
99
- "role": "system",
100
- "content": "You are a helpful and harmless assistant.",
101
- }]
102
- for item in history:
103
- if item["role"] == "user":
104
- messages.append({"role": "user", "content": item["content"]})
105
- elif item["role"] == "assistant":
106
- messages.append({"role": "assistant", "content": item["content"]})
107
- return messages
108
-
109
-
110
- class Gradio_Events:
111
-
112
- @staticmethod
113
- def _submit(state_value):
114
- history = state_value["conversations_history"][
115
- state_value["conversation_id"]]
116
- # submit
117
- history_messages = format_history(history)
118
-
119
- history.append({
120
- "role": "assistant",
121
- "content": "",
122
- "key": str(uuid.uuid4()),
123
- "meta": {
124
- "reason_content": ""
125
- },
126
- "loading": True,
127
- })
128
-
129
- yield {
130
- chatbot: gr.update(items=history),
131
- state: gr.update(value=state_value),
132
- }
133
- try:
134
- response = client.chat.completions.create(
135
- model=model, # ModelScope Model-Id
136
- messages=history_messages,
137
- stream=True)
138
- thought_done = False
139
- for chunk in response:
140
- reasoning_content = chunk.choices[0].delta.reasoning_content
141
- content = chunk.choices[0].delta.content
142
- history[-1]["loading"] = False
143
-
144
- if content and not thought_done:
145
- thought_done = True
146
- history[-1]["meta"]["reason_content"] = history[-1][
147
- "content"]
148
-
149
- print("Reason: ",history[-1]["meta"]["reason_content"])
150
-
151
- history[-1]["content"] = ""
152
- history[-1]["meta"]["thought_end_message"] = get_text(
153
- "End of Thought", "已深度思考")
154
- if not thought_done:
155
- history[-1]["content"] += reasoning_content or ""
156
- else:
157
- history[-1]["content"] += content or ""
158
-
159
- yield {
160
- chatbot: gr.update(items=history),
161
- state: gr.update(value=state_value)
162
- }
163
- history[-1]["meta"]["end"] = True
164
-
165
- print("Answer: ",history[-1]["content"])
166
-
167
- yield {
168
- chatbot: gr.update(items=history),
169
- state: gr.update(value=state_value),
170
- }
171
- except Exception as e:
172
- history[-1]["loading"] = False
173
- history[-1]["meta"]["end"] = True
174
- history[-1]["meta"]["error"] = True
175
- history[-1]["content"] = "Failed to respond, please try again."
176
- yield {
177
- chatbot: gr.update(items=history),
178
- state: gr.update(value=state_value)
179
- }
180
- print('Error: ',e)
181
- raise e
182
-
183
-
184
- @staticmethod
185
- def submit(sender_value, state_value):
186
- if not state_value["conversation_id"]:
187
- random_id = str(uuid.uuid4())
188
- history = []
189
- state_value["conversation_id"] = random_id
190
- state_value["conversations_history"][random_id] = history
191
- state_value["conversations"].append({
192
- "label": sender_value,
193
- "key": random_id
194
- })
195
-
196
- history = state_value["conversations_history"][
197
- state_value["conversation_id"]]
198
- history.append({
199
- "role": "user",
200
- "meta": {},
201
- "key": str(uuid.uuid4()),
202
- "content": sender_value
203
- })
204
-
205
- # preprocess submit
206
- yield Gradio_Events.preprocess_submit()(state_value)
207
- try:
208
- for chunk in Gradio_Events._submit(state_value):
209
- yield chunk
210
- except Exception as e:
211
- raise e
212
- finally:
213
- # postprocess submit
214
- yield Gradio_Events.postprocess_submit(state_value)
215
-
216
- @staticmethod
217
- def regenerate_message(state_value, e: gr.EventData):
218
- conversation_key = e._data["component"]["conversationKey"]
219
- history = state_value["conversations_history"][
220
- state_value["conversation_id"]]
221
- index = -1
222
- for i, conversation in enumerate(history):
223
- if conversation["key"] == conversation_key:
224
- index = i
225
- break
226
- if index == -1:
227
- yield gr.skip()
228
- history = history[:index]
229
- state_value["conversations_history"][
230
- state_value["conversation_id"]] = history
231
-
232
- yield {
233
- chatbot:gr.update(items=history),
234
- state: gr.update(value=state_value)
235
- }
236
-
237
- # preprocess submit
238
- yield Gradio_Events.preprocess_submit(clear_input=False)(state_value)
239
- try:
240
- for chunk in Gradio_Events._submit(state_value):
241
- yield chunk
242
- except Exception as e:
243
- raise e
244
- finally:
245
- # postprocess submit
246
- yield Gradio_Events.postprocess_submit(state_value)
247
-
248
-
249
- @staticmethod
250
- def preprocess_submit(clear_input=True):
251
-
252
- def preprocess_submit_handler(state_value):
253
- history = state_value["conversations_history"][
254
- state_value["conversation_id"]]
255
- for conversation in history:
256
- if "meta" in conversation:
257
- conversation["meta"]["disabled"] = True
258
- return {
259
- sender: gr.update(value=None, loading=True) if clear_input else gr.update(loading=True),
260
- conversations:
261
- gr.update(active_key=state_value["conversation_id"],
262
- items=list(
263
- map(
264
- lambda item: {
265
- **item,
266
- "disabled":
267
- True if item["key"] != state_value[
268
- "conversation_id"] else False,
269
- }, state_value["conversations"]))),
270
- add_conversation_btn:
271
- gr.update(disabled=True),
272
- clear_btn:
273
- gr.update(disabled=True),
274
- conversation_delete_menu_item:
275
- gr.update(disabled=True),
276
- chatbot:
277
- gr.update(items=history),
278
- state:
279
- gr.update(value=state_value),
280
- }
281
-
282
- return preprocess_submit_handler
283
-
284
- @staticmethod
285
- def postprocess_submit(state_value):
286
- history = state_value["conversations_history"][
287
- state_value["conversation_id"]]
288
- for conversation in history:
289
- if "meta" in conversation:
290
- conversation["meta"]["disabled"] = False
291
- return {
292
- sender: gr.update(loading=False),
293
- conversation_delete_menu_item: gr.update(disabled=False),
294
- clear_btn: gr.update(disabled=False),
295
- conversations: gr.update(items=state_value["conversations"]),
296
- add_conversation_btn: gr.update(disabled=False),
297
- chatbot: gr.update(items=history),
298
- state: gr.update(value=state_value),
299
- }
300
-
301
- @staticmethod
302
- def cancel(state_value):
303
- history = state_value["conversations_history"][
304
- state_value["conversation_id"]]
305
- history[-1]["loading"] = False
306
- history[-1]["meta"]["end"] = True
307
- history[-1]["meta"]["canceled"] = True
308
- return Gradio_Events.postprocess_submit(state_value)
309
-
310
- @staticmethod
311
- def delete_message(state_value, e: gr.EventData):
312
- conversation_key = e._data["component"]["conversationKey"]
313
- history = state_value["conversations_history"][
314
- state_value["conversation_id"]]
315
- history = [item for item in history if item["key"] != conversation_key]
316
- state_value["conversations_history"][
317
- state_value["conversation_id"]] = history
318
-
319
- return gr.update(items=history if len(history) >
320
- 0 else DEFAULT_CONVERSATIONS_HISTORY), gr.update(
321
- value=state_value)
322
-
323
-
324
-
325
- @staticmethod
326
- def edit_message(state_value, e: gr.EventData):
327
- conversation_key = e._data["component"]["conversationKey"]
328
- history = state_value["conversations_history"][
329
- state_value["conversation_id"]]
330
- index = -1
331
- for i, conversation in enumerate(history):
332
- if conversation["key"] == conversation_key:
333
- index = i
334
- break
335
- if index == -1:
336
- return gr.skip()
337
- state_value["editing_message_index"] = index
338
- text = ''
339
- if isinstance(history[index]["content"], str):
340
- text = history[index]["content"]
341
- else:
342
- text = history[index]["content"]["text"]
343
- return gr.update(value=text), gr.update(value=state_value)
344
-
345
- @staticmethod
346
- def confirm_edit_message(edit_textarea_value, state_value):
347
- history = state_value["conversations_history"][
348
- state_value["conversation_id"]]
349
- message = history[state_value["editing_message_index"]]
350
- if isinstance(message["content"], str):
351
- message["content"] = edit_textarea_value
352
- else:
353
- message["content"]["text"] = edit_textarea_value
354
- return gr.update(items=history), gr.update(value=state_value)
355
-
356
- @staticmethod
357
- def select_suggestion(sender_value, e: gr.EventData):
358
- return gr.update(value=sender_value[:-1] + e._data["payload"][0])
359
-
360
- @staticmethod
361
- def apply_prompt(e: gr.EventData):
362
- return gr.update(value=e._data["payload"][0]["data"]["description"])
363
-
364
- @staticmethod
365
- def new_chat(state_value):
366
- if not state_value["conversation_id"]:
367
- return gr.skip()
368
- state_value["conversation_id"] = ""
369
- return gr.update(active_key=state_value["conversation_id"]), gr.update(
370
- items=DEFAULT_CONVERSATIONS_HISTORY), gr.update(value=state_value)
371
-
372
- @staticmethod
373
- def select_conversation(state_value, e: gr.EventData):
374
- active_key = e._data["payload"][0]
375
- if state_value["conversation_id"] == active_key or (
376
- active_key not in state_value["conversations_history"]):
377
- return gr.skip()
378
- state_value["conversation_id"] = active_key
379
- return gr.update(active_key=active_key), gr.update(
380
- items=state_value["conversations_history"][active_key]), gr.update(
381
- value=state_value)
382
-
383
- @staticmethod
384
- def click_conversation_menu(state_value, e: gr.EventData):
385
- conversation_id = e._data["payload"][0]["key"]
386
- operation = e._data["payload"][1]["key"]
387
- if operation == "delete":
388
- del state_value["conversations_history"][conversation_id]
389
-
390
- state_value["conversations"] = [
391
- item for item in state_value["conversations"]
392
- if item["key"] != conversation_id
393
- ]
394
-
395
- if state_value["conversation_id"] == conversation_id:
396
- state_value["conversation_id"] = ""
397
- return gr.update(
398
- items=state_value["conversations"],
399
- active_key=state_value["conversation_id"]), gr.update(
400
- items=DEFAULT_CONVERSATIONS_HISTORY), gr.update(
401
- value=state_value)
402
- else:
403
- return gr.update(
404
- items=state_value["conversations"]), gr.skip(), gr.update(
405
- value=state_value)
406
- return gr.skip()
407
-
408
- @staticmethod
409
- def clear_conversation_history(state_value):
410
- if not state_value["conversation_id"]:
411
- return gr.skip()
412
- state_value["conversations_history"][
413
- state_value["conversation_id"]] = []
414
- return gr.update(items=DEFAULT_CONVERSATIONS_HISTORY), gr.update(
415
- value=state_value)
416
-
417
- @staticmethod
418
- def close_modal():
419
- return gr.update(open=False)
420
-
421
- @staticmethod
422
- def open_modal():
423
- return gr.update(open=True)
424
-
425
- @staticmethod
426
- def update_browser_state(state_value):
427
-
428
- return gr.update(value=dict(
429
- conversations=state_value["conversations"],
430
- conversations_history=state_value["conversations_history"]))
431
-
432
- @staticmethod
433
- def apply_browser_state(browser_state_value, state_value):
434
- state_value["conversations"] = browser_state_value["conversations"]
435
- state_value["conversations_history"] = browser_state_value[
436
- "conversations_history"]
437
- return gr.update(
438
- items=browser_state_value["conversations"]), gr.update(
439
- value=state_value)
440
-
441
-
442
- css = """
443
- .gradio-container {
444
- padding: 0 !important;
445
- }
446
-
447
- .gradio-container > main.fillable {
448
- padding: 0 !important;
449
- }
450
-
451
- #chatbot {
452
- height: calc(100vh - 21px - 16px);
453
- }
454
-
455
- #chatbot .chatbot-conversations {
456
- height: 100%;
457
- background-color: var(--ms-gr-ant-color-bg-layout);
458
- }
459
-
460
- #chatbot .chatbot-conversations .chatbot-conversations-list {
461
- padding-left: 0;
462
- padding-right: 0;
463
- }
464
-
465
- #chatbot .chatbot-chat {
466
- padding: 32px;
467
- height: 100%;
468
- }
469
-
470
- @media (max-width: 768px) {
471
- #chatbot .chatbot-chat {
472
- padding: 0;
473
- }
474
- }
475
-
476
- #chatbot .chatbot-chat .chatbot-chat-messages {
477
- flex: 1;
478
- }
479
-
480
- #chatbot .chatbot-chat .chatbot-chat-messages .chatbot-chat-message .chatbot-chat-message-footer {
481
- visibility: hidden;
482
- opacity: 0;
483
- transition: opacity 0.2s;
484
- }
485
-
486
- #chatbot .chatbot-chat .chatbot-chat-messages .chatbot-chat-message:last-child .chatbot-chat-message-footer {
487
- visibility: visible;
488
- opacity: 1;
489
- }
490
-
491
- #chatbot .chatbot-chat .chatbot-chat-messages .chatbot-chat-message:hover .chatbot-chat-message-footer {
492
- visibility: visible;
493
- opacity: 1;
494
- }
495
- """
496
-
497
-
498
- def logo():
499
- with antd.Typography.Title(level=1,
500
- elem_style=dict(fontSize=24,
501
- padding=8,
502
- margin=0)):
503
- with antd.Flex(align="center", gap="small", justify="center"):
504
- antd.Image(qwen_logo,
505
- preview=False,
506
- alt="logo",
507
- width=24,
508
- height=24)
509
- ms.Span("QwQ-32B")
510
-
511
-
512
- with gr.Blocks(css=css, fill_width=True) as demo:
513
- state = gr.State({
514
- "conversations_history": {},
515
- "conversations": [],
516
- "conversation_id": "",
517
- "editing_message_index": -1,
518
- })
519
-
520
- with ms.Application(), antdx.XProvider(
521
- theme=DEFAULT_THEME, locale=DEFAULT_LOCALE), ms.AutoLoading():
522
- with antd.Row(gutter=[20, 20], wrap=False, elem_id="chatbot"):
523
- # Left Column
524
- with antd.Col(md=dict(flex="0 0 260px", span=24, order=0),
525
- span=0,
526
- order=1,
527
- elem_classes="chatbot-conversations"):
528
- with antd.Flex(vertical=True,
529
- gap="small",
530
- elem_style=dict(height="100%")):
531
- # Logo
532
- logo()
533
-
534
- # New Conversation Button
535
- with antd.Button(value=None,
536
- color="primary",
537
- variant="filled",
538
- block=True) as add_conversation_btn:
539
- ms.Text(get_text("New Conversation", "新建对话"))
540
- with ms.Slot("icon"):
541
- antd.Icon("PlusOutlined")
542
-
543
- # Conversations List
544
- with antdx.Conversations(
545
- elem_classes="chatbot-conversations-list",
546
- ) as conversations:
547
- with ms.Slot('menu.items'):
548
- with antd.Menu.Item(
549
- label="Delete", key="delete", danger=True
550
- ) as conversation_delete_menu_item:
551
- with ms.Slot("icon"):
552
- antd.Icon("DeleteOutlined")
553
- # Right Column
554
- with antd.Col(flex=1, elem_style=dict(height="100%")):
555
- with antd.Flex(vertical=True,
556
- gap="middle",
557
- elem_classes="chatbot-chat"):
558
- # Chatbot
559
- with antdx.Bubble.List(
560
- items=DEFAULT_CONVERSATIONS_HISTORY,
561
- elem_classes="chatbot-chat-messages") as chatbot:
562
- # Define Chatbot Roles
563
- with ms.Slot("roles"):
564
- # Placeholder Role
565
- with antdx.Bubble.List.Role(
566
- role="placeholder",
567
- styles=dict(content=dict(width="100%")),
568
- variant="borderless"):
569
- with ms.Slot("messageRender"):
570
- with antd.Space(
571
- direction="vertical",
572
- size=16,
573
- elem_style=dict(width="100%")):
574
- with antdx.Welcome(
575
- styles=dict(icon=dict(
576
- flexShrink=0)),
577
- variant="borderless",
578
- title=get_text(
579
- "Hello, I'm QwQ-32B",
580
- "你好,我是 QwQ-32B"),
581
- description=get_text(
582
- "You can type text to get started.",
583
- "你可以输入文本开始对话。"),
584
- ):
585
- with ms.Slot("icon"):
586
- antd.Image(qwen_logo,
587
- preview=False)
588
- with antdx.Prompts(title=get_text(
589
- "How can I help you today?",
590
- "有什么我能帮助你的吗?"),
591
- styles={
592
- "list": {
593
- "width":
594
- '100%',
595
- },
596
- "item": {
597
- "flex": 1,
598
- },
599
- }) as prompts:
600
- for item in DEFAULT_PROMPTS:
601
- with antdx.Prompts.Item(
602
- label=item["category"]
603
- ):
604
- for prompt in item[
605
- "prompts"]:
606
- antdx.Prompts.Item(
607
- description=prompt,
608
- )
609
-
610
- # User Role
611
- with antdx.Bubble.List.Role(
612
- role="user",
613
- placement="end",
614
- elem_classes="chatbot-chat-message",
615
- class_names=dict(
616
- footer="chatbot-chat-message-footer"),
617
- styles=dict(content=dict(
618
- maxWidth="100%",
619
- overflow='auto',
620
- ))):
621
- with ms.Slot(
622
- "messageRender",
623
- params_mapping="(content) => content"):
624
-
625
- ms.Markdown()
626
- with ms.Slot("footer",
627
- params_mapping="""(bubble) => {
628
- return {
629
- copy_btn: {
630
- copyable: { text: typeof bubble.content === 'string' ? bubble.content : bubble.content?.text, tooltips: false },
631
- },
632
- edit_btn: { conversationKey: bubble.key, disabled: bubble.meta.disabled },
633
- delete_btn: { conversationKey: bubble.key, disabled: bubble.meta.disabled },
634
- };
635
- }"""):
636
- with antd.Typography.Text(
637
- copyable=dict(tooltips=False),
638
- as_item="copy_btn"):
639
- with ms.Slot("copyable.icon"):
640
- with antd.Button(value=None,
641
- size="small",
642
- color="default",
643
- variant="text"):
644
- with ms.Slot("icon"):
645
- antd.Icon("CopyOutlined")
646
- with antd.Button(value=None,
647
- size="small",
648
- color="default",
649
- variant="text"):
650
- with ms.Slot("icon"):
651
- antd.Icon("CheckOutlined")
652
- with antd.Button(value=None,
653
- size="small",
654
- color="default",
655
- variant="text",
656
- as_item="edit_btn"
657
- ) as user_edit_btn:
658
- with ms.Slot("icon"):
659
- antd.Icon("EditOutlined")
660
- with antd.Popconfirm(
661
- title="Delete the message",
662
- description=
663
- "Are you sure to delete this message?",
664
- ok_button_props=dict(danger=True),
665
- as_item="delete_btn"
666
- ) as user_delete_popconfirm:
667
- with antd.Button(value=None,
668
- size="small",
669
- color="default",
670
- variant="text",
671
- as_item="delete_btn"):
672
- with ms.Slot("icon"):
673
- antd.Icon("DeleteOutlined")
674
-
675
- # Chatbot Role
676
- with antdx.Bubble.List.Role(
677
- role="assistant",
678
- placement="start",
679
- elem_classes="chatbot-chat-message",
680
- class_names=dict(
681
- footer="chatbot-chat-message-footer"),
682
- styles=dict(content=dict(
683
- maxWidth="100%", overflow='auto'))):
684
- with ms.Slot("avatar"):
685
- antd.Avatar(
686
- os.path.join(os.path.dirname(__file__),
687
- "qwen.png"))
688
- with ms.Slot(
689
- "messageRender",
690
- params_mapping="""(content, bubble) => {
691
- const reason_content = bubble?.meta?.reason_content
692
- const has_error = bubble?.meta?.error
693
- return {
694
- reasoning: reason_content || content,
695
- reasoning_container: has_error ? { style: { display: 'none' } } : undefined,
696
- answer: {
697
- value: reason_content || has_error ? content : undefined
698
- },
699
- collapse_label: bubble.meta?.thought_end_message,
700
- collapse_progress: bubble.meta?.thought_end_message ? { style: { display: 'none' } } : undefined,
701
- canceled: bubble.meta?.canceled ? undefined : { style: { display: 'none' } }
702
- }
703
- }"""):
704
- with antd.Flex(vertical=True,
705
- gap="middle"):
706
- with antd.Collapse(
707
- default_active_key=[
708
- "reasoning"
709
- ],
710
- as_item="reasoning_container"):
711
- with antd.Collapse.Item(
712
- key="reasoning"):
713
- with ms.Slot("label"):
714
- with antd.Space(
715
- size="middle"):
716
- ms.Span(
717
- get_text(
718
- "Thinking...",
719
- "思考中..."),
720
- as_item=
721
- "collapse_label")
722
- antd.Progress(
723
- percent="100",
724
- status="active",
725
- elem_style=dict(
726
- display="flex",
727
- alignItems=
728
- "center",
729
- ),
730
- show_info=False,
731
- size=[110, 5],
732
- as_item=
733
- "collapse_progress"
734
- )
735
- with antd.Alert(
736
- type="warning"):
737
- with ms.Slot(
738
- "description"):
739
- ms.Markdown(
740
- as_item="reasoning"
741
- )
742
- ms.Markdown(
743
- as_item="answer",
744
- elem_classes="answer-content")
745
-
746
- antd.Divider(as_item="canceled")
747
- antd.Typography.Text(get_text(
748
- "Chat completion paused.", "聊天已暂停。"),
749
- as_item="canceled",
750
- type="warning")
751
-
752
- with ms.Slot("footer",
753
- params_mapping="""(bubble) => {
754
- if (bubble?.meta?.end) {
755
- return {
756
- copy_btn: {
757
- copyable: { text: bubble.content, tooltips: false },
758
- },
759
- regenerate_btn: { conversationKey: bubble.key, disabled: bubble.meta.disabled },
760
- delete_btn: { conversationKey: bubble.key, disabled: bubble.meta.disabled },
761
- edit_btn: { conversationKey: bubble.key, disabled: bubble.meta.disabled },
762
- };
763
- }
764
- return { actions_container: { style: { display: 'none' } } };
765
- }"""):
766
- with ms.Div(as_item="actions_container"):
767
- with antd.Typography.Text(
768
- copyable=dict(tooltips=False),
769
- as_item="copy_btn"):
770
- with ms.Slot("copyable.icon"):
771
- with antd.Button(
772
- value=None,
773
- size="small",
774
- color="default",
775
- variant="text"):
776
- with ms.Slot("icon"):
777
- antd.Icon(
778
- "CopyOutlined")
779
- with antd.Button(
780
- value=None,
781
- size="small",
782
- color="default",
783
- variant="text"):
784
- with ms.Slot("icon"):
785
- antd.Icon(
786
- "CheckOutlined")
787
-
788
- with antd.Popconfirm(
789
- title=get_text(
790
- "Regenerate the message",
791
- "重新生成消息"),
792
- description=get_text(
793
- "Regenerate the message will also delete all subsequent messages.",
794
- "重新生成消息将会删除所有的后续消息。"),
795
- ok_button_props=dict(
796
- danger=True),
797
- as_item="regenerate_btn"
798
- ) as chatbot_regenerate_popconfirm:
799
- with antd.Button(
800
- value=None,
801
- size="small",
802
- color="default",
803
- variant="text",
804
- as_item="regenerate_btn",
805
- ):
806
- with ms.Slot("icon"):
807
- antd.Icon("SyncOutlined")
808
- with antd.Button(value=None,
809
- size="small",
810
- color="default",
811
- variant="text",
812
- as_item="edit_btn"
813
- ) as chatbot_edit_btn:
814
- with ms.Slot("icon"):
815
- antd.Icon("EditOutlined")
816
- with antd.Popconfirm(
817
- title=get_text("Delete the message", "删除消息"),
818
- description=get_text(
819
- "Are you sure to delete this message?",
820
- "确定要删除这条消息吗?"),
821
- ok_button_props=dict(
822
- danger=True),
823
- as_item="delete_btn"
824
- ) as chatbot_delete_popconfirm:
825
- with antd.Button(
826
- value=None,
827
- size="small",
828
- color="default",
829
- variant="text",
830
- as_item="delete_btn"):
831
- with ms.Slot("icon"):
832
- antd.Icon("DeleteOutlined")
833
-
834
- # Sender
835
- with antdx.Suggestion(
836
- items=DEFAULT_SUGGESTIONS,
837
- # onKeyDown Handler in Javascript
838
- should_trigger="""(e, { onTrigger, onKeyDown }) => {
839
- switch(e.key) {
840
- case '/':
841
- onTrigger()
842
- break
843
- case 'ArrowRight':
844
- case 'ArrowLeft':
845
- case 'ArrowUp':
846
- case 'ArrowDown':
847
- break;
848
- default:
849
- onTrigger(false)
850
- }
851
- onKeyDown(e)
852
- }""") as suggestion:
853
- with ms.Slot("children"):
854
- with antdx.Sender(placeholder=get_text(
855
- "Enter / to get suggestions",
856
- "输入 / 获取建议"), ) as sender:
857
- with ms.Slot("prefix"):
858
- # Clear Button
859
- with antd.Tooltip(title=get_text(
860
- "Clear Conversation History",
861
- "清空对话历史"), ):
862
- with antd.Button(
863
- value=None,
864
- type="text") as clear_btn:
865
- with ms.Slot("icon"):
866
- antd.Icon("ClearOutlined")
867
-
868
- # Modals
869
- with antd.Modal(title=get_text("Edit Message", "编辑消息"),
870
- open=False,
871
- centered=True,
872
- width="60%") as edit_modal:
873
- edit_textarea = antd.Input.Textarea(auto_size=dict(minRows=2,
874
- maxRows=6),
875
- elem_style=dict(width="100%"))
876
- # Events Handler
877
- if save_history:
878
- browser_state = gr.BrowserState(
879
- {
880
- "conversations_history": {},
881
- "conversations": [],
882
- },
883
- storage_key="qwen_qwq_chatbot_storage")
884
- state.change(fn=Gradio_Events.update_browser_state,
885
- inputs=[state],
886
- outputs=[browser_state])
887
-
888
- demo.load(fn=Gradio_Events.apply_browser_state,
889
- inputs=[browser_state, state],
890
- outputs=[conversations, state])
891
-
892
- add_conversation_btn.click(fn=Gradio_Events.new_chat,
893
- inputs=[state],
894
- outputs=[conversations, chatbot, state])
895
- conversations.active_change(fn=Gradio_Events.select_conversation,
896
- inputs=[state],
897
- outputs=[conversations, chatbot, state])
898
- conversations.menu_click(fn=Gradio_Events.click_conversation_menu,
899
- inputs=[state],
900
- outputs=[conversations, chatbot, state])
901
- prompts.item_click(fn=Gradio_Events.apply_prompt, outputs=[sender])
902
-
903
- clear_btn.click(fn=Gradio_Events.clear_conversation_history,
904
- inputs=[state],
905
- outputs=[chatbot, state])
906
-
907
- suggestion.select(fn=Gradio_Events.select_suggestion,
908
- inputs=[sender],
909
- outputs=[sender])
910
-
911
- gr.on(triggers=[user_edit_btn.click, chatbot_edit_btn.click],
912
- fn=Gradio_Events.edit_message,
913
- inputs=[state],
914
- outputs=[edit_textarea, state]).then(fn=Gradio_Events.open_modal,
915
- outputs=[edit_modal])
916
- edit_modal.ok(fn=Gradio_Events.confirm_edit_message,
917
- inputs=[edit_textarea, state],
918
- outputs=[chatbot, state]).then(fn=Gradio_Events.close_modal,
919
- outputs=[edit_modal])
920
- edit_modal.cancel(fn=Gradio_Events.close_modal, outputs=[edit_modal])
921
- gr.on(triggers=[
922
- chatbot_delete_popconfirm.confirm, user_delete_popconfirm.confirm
923
- ],
924
- fn=Gradio_Events.delete_message,
925
- inputs=[state],
926
- outputs=[chatbot, state])
927
-
928
- regenerating_event = chatbot_regenerate_popconfirm.confirm(
929
- fn=Gradio_Events.regenerate_message,
930
- inputs=[state],
931
- outputs=[sender, clear_btn, conversation_delete_menu_item, add_conversation_btn, conversations, chatbot, state])
932
-
933
- submit_event = sender.submit(fn=Gradio_Events.submit,
934
- inputs=[sender, state],
935
- outputs=[sender, clear_btn, conversation_delete_menu_item,
936
- add_conversation_btn, conversations,chatbot, state])
937
- sender.cancel(fn=None, cancels=[submit_event, regenerating_event])
938
- sender.cancel(fn=Gradio_Events.cancel,
939
- inputs=[state],
940
- outputs=[
941
- sender, conversation_delete_menu_item, clear_btn,
942
- conversations, add_conversation_btn, chatbot, state
943
- ])
944
-
945
- if __name__ == "__main__":
946
- demo.queue(default_concurrency_limit=200).launch(ssr_mode=False, max_threads=200)