File size: 7,472 Bytes
b931367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439ab17
b931367
439ab17
 
 
 
 
 
 
 
 
 
 
 
 
 
b931367
 
 
439ab17
b931367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439ab17
 
b931367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439ab17
b931367
 
 
 
439ab17
b931367
 
 
 
 
 
 
 
 
 
 
439ab17
b931367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439ab17
b931367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439ab17
b931367
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import gradio as gr
import uuid
from datetime import datetime
import pandas as pd
from model_handler import ModelHandler
from config import CHAT_MODEL_SPECS, LING_1T
from recommand_config import RECOMMENDED_INPUTS
from ui_components.model_selector import create_model_selector

def create_chat_tab():
    model_handler = ModelHandler()

    conversation_store = gr.BrowserState(default_value=[], storage_key="ling_conversation_history")
    current_conversation_id = gr.BrowserState(default_value=None, storage_key="ling_current_conversation_id")

    def get_history_df(history):
        if not history:
            return pd.DataFrame({'ID': [], '对话': []})
        df = pd.DataFrame(history)
        return df[['id', 'title']].rename(columns={'id': 'ID', 'title': '对话'})

    def handle_new_chat(history, current_conv_id=None):
        # Try to find the current conversation
        current_convo = next((c for c in history if c["id"] == current_conv_id), None) if history else None

        # If current conversation exists and is empty, reuse it
        if current_convo and not current_convo.get("messages", []):
            return (
                current_conv_id,
                history,
                [],
                gr.update(value=get_history_df(history))
            )

        conv_id = str(uuid.uuid4())
        new_convo = {
            "id": conv_id, "title": "(新对话)",
            "messages": [], "timestamp": datetime.now().isoformat()
        }
        updated_history = [new_convo] + (history or [])
        return (
            conv_id,
            updated_history,
            [],
            gr.update(value=get_history_df(updated_history))
        )

    def load_conversation_from_df(df: pd.DataFrame, evt: gr.SelectData, history):
        if evt.index is None:
            return None, []
        selected_id = df.iloc[evt.index[0]]['ID']
        for convo in history:
            if convo["id"] == selected_id:
                return selected_id, convo["messages"]
        # Fallback to new chat if something goes wrong
        new_id, _, new_msgs, _ = handle_new_chat(history)
        return new_id, new_msgs

    with gr.Row(equal_height=False, elem_id="indicator-chat-tab"):
        with gr.Column(scale=1):
            new_chat_btn = gr.Button("➕ 新对话")
            history_df = gr.DataFrame(
                value=get_history_df(conversation_store.value),
                headers=["ID", "对话记录"],
                datatype=["str", "str"],
                interactive=False,
                visible=True,
                column_widths=["0%", "99%"]
            )

        with gr.Column(scale=4):
            chatbot = gr.Chatbot(height=500, type='messages')
            with gr.Row():
                textbox = gr.Textbox(placeholder="输入消息...", container=False, scale=7)
                submit_btn = gr.Button("发送", scale=1)
            
            gr.Markdown("### 推荐对话")
            recommended_dataset = gr.Dataset(
                components=[gr.Textbox(visible=False)],
                samples=[[item["task"]] for item in RECOMMENDED_INPUTS],
                label="推荐场景", headers=["选择一个场景试试"],
            )

        with gr.Column(scale=1):
            model_dropdown, model_description_markdown = create_model_selector(
                model_specs=CHAT_MODEL_SPECS,
                default_model_constant=LING_1T
            )

            system_prompt_textbox = gr.Textbox(label="系统提示词", lines=5, placeholder="输入系统提示词...")
            temperature_slider = gr.Slider(minimum=0, maximum=1.0, value=0.7, step=0.1, label="温度参数")

        # --- Event Handlers --- #
        # The change handler is now encapsulated within create_model_selector
        def on_select_recommendation(evt: gr.SelectData, history, current_conv_id):
            selected_task = evt.value[0]
            item = next((i for i in RECOMMENDED_INPUTS if i["task"] == selected_task), None)
            if not item: return gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()

            new_id, new_history, new_messages, history_df_update = handle_new_chat(history, current_conv_id)

            return (
                new_id, new_history,
                gr.update(value=item["model"]),
                gr.update(value=item["system_prompt"]),
                gr.update(value=item["temperature"]),
                gr.update(value=item["user_message"]),
                history_df_update,
                new_messages
            )

        recommended_dataset.select(on_select_recommendation, inputs=[conversation_store, current_conversation_id], outputs=[current_conversation_id, conversation_store, model_dropdown, system_prompt_textbox, temperature_slider, textbox, history_df, chatbot], show_progress="none")

        def chat_stream(conv_id, history, model_display_name, message, chat_history, system_prompt, temperature):
            if not message:
                yield chat_history
                return
            model_constant = next((k for k, v in CHAT_MODEL_SPECS.items() if v["display_name"] == model_display_name), LING_1T)
            response_generator = model_handler.get_response(model_constant, message, chat_history, system_prompt, temperature)
            for history_update in response_generator:
                yield history_update

        def on_chat_stream_complete(conv_id, history, final_chat_history):
            current_convo = next((c for c in history if c["id"] == conv_id), None)
            if not current_convo:
                return history, gr.update()

            if len(final_chat_history) > len(current_convo["messages"]) and current_convo["title"] == "(新对话)":
                user_message = final_chat_history[-2]["content"] if len(final_chat_history) > 1 else final_chat_history[0]["content"]
                current_convo["title"] = user_message[:50]

            current_convo["messages"] = final_chat_history
            current_convo["timestamp"] = datetime.now().isoformat()

            history = sorted([c for c in history if c["id"] != conv_id] + [current_convo], key=lambda x: x["timestamp"], reverse=True)
            return history, gr.update(value=get_history_df(history))

        submit_btn.click(
            chat_stream,
            [current_conversation_id, conversation_store, model_dropdown, textbox, chatbot, system_prompt_textbox, temperature_slider],
            [chatbot]
        ).then(
            on_chat_stream_complete,
            [current_conversation_id, conversation_store, chatbot],
            [conversation_store, history_df]
        )
        textbox.submit(
            chat_stream,
            [current_conversation_id, conversation_store, model_dropdown, textbox, chatbot, system_prompt_textbox, temperature_slider],
            [chatbot]
        ).then(
            on_chat_stream_complete,
            [current_conversation_id, conversation_store, chatbot],
            [conversation_store, history_df]
        )

        new_chat_btn.click(handle_new_chat, inputs=[conversation_store, current_conversation_id], outputs=[current_conversation_id, conversation_store, chatbot, history_df])
        history_df.select(load_conversation_from_df, inputs=[history_df, conversation_store], outputs=[current_conversation_id, chatbot])

    return conversation_store, current_conversation_id, history_df, chatbot