File size: 24,627 Bytes
5255efb
e023114
 
 
 
 
 
 
 
 
 
 
5255efb
 
e023114
5255efb
 
 
 
 
 
e023114
 
5255efb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e023114
 
 
 
 
 
 
 
 
 
 
 
 
2aef356
686b2e4
e023114
 
5255efb
 
e023114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5255efb
e023114
 
 
 
 
 
5255efb
e023114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5255efb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
'''
1. 大模型以Qwen API形式提供。
1. 重塑了Qwen作为大语言模型做Text2SQL的提示词:
    sys_prompt = """
    1. 你是一个将文字转换成SQL语句的人工智能。
    2. 你需要注意:你只需要用纯文本回复代码的内容,即你不允许回复代码以外的任何信息。
    3. SQL变量默认是中文,而且只能从如下的名称列表中选择,你不可以使用这些名字以外的变量名:"长度","宽度","价格","产品ID","比率","类别","*"
    4. 你不能写IF, THEN的SQL语句,需要使用CASE。
    5. 我需要你转换的文字如下:"""   
    
    total_prompt = sys_prompt + "在数据表格table01中," + prompt


'''
##TODO: 2. 账号功能。

import time
import os
import pandas as pd
import streamlit as st
from code_editor import code_editor
import streamlit_authenticator as stauth

# from utils.setup import setup_connexion, setup_session_state
# from utils.vanna_calls import (
#     generate_questions_cached,
#     run_sql_cached,
#     generate_plotly_code_cached,
#     generate_plot_cached,
#     generate_followup_cached,
# )
# import chatsql003 ### 本地ChatGLT 版本。
import chatsql004 ###Qwen API 版本。
import sql_command
# from streamlit_pandas_profiling import st_profile_report
import dashscope
from dotenv import load_dotenv


load_dotenv()
### 设置openai的API key
dashscope.api_key = os.environ['dashscope_api_key']

st.set_page_config(layout="wide", page_icon="🧩", page_title="本地化国产大模型数据库查询演示")
# setup_connexion()

def clear_all():
    st.session_state.conversation = None
    st.session_state.chat_history = None
    st.session_state.messages = []
    message_placeholder = st.empty()
    st.session_state["my_question"] = None
    return None
## 原始的控制面板
# st.sidebar.title("大模型控制面板")
# st.sidebar.checkbox("Show SQL", value=True, key="show_sql")
# st.sidebar.checkbox("Show Table", value=True, key="show_table")
# st.sidebar.checkbox("Show Plotly Code", value=True, key="show_plotly_code")
# st.sidebar.checkbox("Show Chart", value=True, key="show_chart")
# st.sidebar.checkbox("Show Follow-up Questions", value=True, key="show_followup")
# st.sidebar.button("清除记录,重启一轮新对话", on_click=setup_session_state, use_container_width=True, type='primary')

st.title("本地化国产大模型数据库查询演示")
# st.title("大语言模型SQL数据库查询中心")
# st.info("声明:内容由人工智能生成,仅供参考。如果您本人使用或对外传播本服务生成的输出,您应当主动核查输出内容的真实性、准确性,避免传播虚假信息。") ## 颜色比较明显。
st.markdown("_声明:内容由人工智能生成,仅供参考。如果您本人使用或对外传播本服务生成的输出,您应当主动核查输出内容的真实性、准确性,避免传播虚假信息。_")


### authentication with a local yaml file.
import yaml
from yaml.loader import SafeLoader
with open('./config.yaml') as file:
    config = yaml.load(file, Loader=SafeLoader)
authenticator = stauth.Authenticate(
    config['credentials'],
    config['cookie']['name'],
    config['cookie']['key'],
    config['cookie']['expiry_days'],
    config['preauthorized']
)

user, authentication_status, username = authenticator.login('main')
# user, authentication_status, username = authenticator.login('用户登录', 'main')
print('登录的用户:', username)

### Streamlit Sidebar 左侧工具栏
# st.sidebar.write(st.session_state)
if authentication_status:

    with st.sidebar:
        st.markdown(
            """
            <style>
            [data-testid="stSidebar"][aria-expanded="true"]{
                min-width: 500px;
                max-width: 500px;
            }
            """,
            unsafe_allow_html=True,
        )
        
        # st.header(f'**大语言模型专家系统工作设定区**')
        st.header(f'**欢迎 **{username}** 使用本系统** ')
        st.write(f'_Large Language Model Expert System Working Environment_')
        # st.write(f'_Welcome and Hope U Enjoy Staying Here_')
        authenticator.logout('登出', 'sidebar')
        ### siderbar的题目。
        ### siderbar的题目。
        # st.header(f'**大语言模型专家系统工作设定区**')
        # st.header(f'**欢迎 **{username}** 使用本系统** ') ## 用户登录显示。
        st.sidebar.button("清除记录,重启一轮新对话", on_click=clear_all, use_container_width=True, type='primary')
        # st.sidebar.button("清除记录,重启一轮新对话", on_click=setup_session_state, use_container_width=True, type='primary')

        ### 展示当前数据库
        # st.markdown("#### 当前数据库中的数据:")
        with st.expander("#### 当前数据库中的数据", expanded=True):
            my_db = pd.read_sql_table('table01', 'sqlite:///myexcelDB.db')
            st.dataframe(my_db, width=400)

            ## 在sidebar上的三个分页显示,用st.tabs实现。
        tab_1, tab_2, tab_4 = st.tabs(['使用须知', '模型参数', '角色设定'])
        # tab_1, tab_2, tab_3, tab_4 = st.tabs(['使用须知', '模型参数', '提示词模板', '系统角色设定'])

        # with st.expander(label='**使用须知**', expanded=False):
        with tab_1:
            # st.markdown("#### 快速上手指南")
            # with st.text(body="说明"):
            #     st.markdown("* 重启一轮新对话时,只需要刷新页面(按Ctrl/Command + R)即可。")
            with st.text(body="说明"):
                st.markdown("""* 简介

    本系统使用大模型技术,将自然语言描述转换为SQL查询语句。用户可以输入自然语言问题,系统会自动生成相应的SQL语句,并返回查询结果。

    * 使用步骤

    在文本框中输入您的自然语言问题。
    系统会自动生成相应的SQL语句,并显示在下方。
    点击“满意,请执行语句”选项,可查看查询结果。点击”不满意,需要改正语句“可以手动修改SQL语句。

    * 注意事项

    本系统仍在开发中,可能会存在一些错误或不准确的地方。
    自然语言描述越清晰,生成的SQL语句越准确。
    系统支持的SQL语法有限,请尽量使用简单易懂的语法。
    """)
            # with st.text(body="说明"):
            #     st.markdown("""在构建大语言模型本地知识库问答系统时,需要注意以下几点:

            #                 LLM的选择:LLM的选择应根据系统的应用场景和需求进行。对于需要处理通用问题的系统,可以选择通用LLM;对于需要处理特定领域问题的系统,可以选择针对该领域进行微调的LLM。
            #                 本地知识库的构建:本地知识库应包含系统所需的所有知识。知识的组织方式应便于LLM的访问和处理。
            #                 系统的评估:系统应进行充分的评估,以确保其能够准确地回答用户问题。
            #                 大语言模型本地知识库问答系统具有以下优势:

            #                 准确性:LLM和本地知识库的结合可以提高系统的准确性。
            #                 全面性:LLM和本地知识库的结合可以使系统能够回答更广泛的问题。
            #                 效率:LLM可以快速生成候选答案,而本地知识库可以快速评估候选答案的准确性。
            #                 """)
                            
                            
            # with st.text(body="说明"):
            #     st.markdown(
            #         "* “数据分析模式”暂时只支持1000个单元格以内的数据分析,单元格中的内容不支持中文数据(表头也尽量不使用中文)。一般运行时间在1至10分钟左右,期间需要保持网络畅通。")
            # with st.text(body="说明"):
            #     st.markdown("* “数据分析模式”推荐上传csv格式的文件,部分Excel文件容易出现数据不兼容的情况。")

        ## 大模型参数
        # with st.expander(label='**大语言模型参数**', expanded=True):
        with tab_2:
            max_tokens = st.slider(label='Max_Token(生成结果时最大字数)', min_value=100, max_value=4096, value=2048, step=100)
            temperature = st.slider(label='Temperature (温度)', min_value=0.0, max_value=1.0, value=0.8, step=0.1)
            top_p = st.slider(label='Top_P (核采样)', min_value=0.0, max_value=1.0, value=0.6, step=0.1)
            frequency_penalty = st.slider(label='Frequency Penalty (重复度惩罚因子)', min_value=-2.0, max_value=2.0, value=1.0, step=0.1)
            presence_penalty = st.slider(label='Presence Penalty (控制主题的重复度)', min_value=-2.0, max_value=2.0, value=1.0, step=0.1)

        ## reset password widget
        # try:
        #     if authenticator.reset_password(st.session_state["username"], 'Reset password'):
        #         st.success('Password modified successfully')
        # except Exception as e:
        #     st.error(e)

        # with st.header(body="欢迎"):
        #     st.markdown("# 欢迎使用大语言模型商业智能中心")
        # with st.expander(label=("**重要的使用注意事项**"), expanded=True):
        # with st.container():

        ##NOTE: 在SQL场景去不需要展示这些提示词。
        # with tab_3:
        #     # st.markdown("#### Prompt提示词参考资料")
        #     # with st.expander(label="**大语言模型基础提示词Prompt示例**", expanded=False):
        #     st.code(
        #         body="继续用中文写一篇关于 [文章主题] 的文章,以下列句子开头:[文章开头]。", language='plaintext')
        #     st.code(body="将以下文字概括为 100 个字,使其易于阅读和理解。避免使用复杂的句子结构或技术术语。",
        #             language='plaintext')
        #     st.code(body="给我出一个迪奥2023春季发布会活动策划。", language='plaintext')
        #     st.code(body="帮我按照正式会议结构写一个会邀:主题是xx手机游戏立项会议。", language='plaintext')
        #     st.code(body="帮我写一个车内健康监测全场景落地的项目计划,用表格。", language='plaintext')
        #     st.code(
        #         body="同时掷两枚质地均匀的骰子,则两枚骰子向上的点数之和为 7 的概率是多少。", language='plaintext')
        #     st.code(body="写一篇产品经理的演讲稿,注意使用以下词汇: 赋能,抓手,中台,闭环,落地,漏斗,沉淀,给到,同步,对齐,对标,迭代,拉通,打通,升级,交付,聚焦,倒逼,复盘,梳理,方案,联动,透传,咬合,洞察,渗透,兜底,解耦,耦合,复用,拆解。", language='plaintext')

            # with st.expander(label="**数据分析模式的专用提示词Prompt示例**", expanded=False):
            #     # with st.subheader(body="提示词Prompt"):
            #     st.code(body="分析此数据集并绘制一些'有趣的图表'。", language='python')
            #     st.code(
            #         body="对于这个文件中的数据,你需要要找出[X,Y]数据之间的寻找'相关性'。", language='python')
            #     st.code(body="对于这个文件中的[xxx]数据给我一个'整体的分析'。", language='python')
            #     st.code(body="对于[xxx]数据给我一个'直方图',提供图表,并给出分析结果。", language='python')
            #     st.code(body="对于[xxx]数据给我一个'小提琴图',并给出分析结果。", language='python')
            #     st.code(
            #         body="对于[X,Y,Z]数据在一个'分布散点图 (stripplot)',所有的数据在一张图上展现, 并给出分析结果。", language='python')
            #     st.code(body="对于[X,Y]数据,进行'T检验',你需要展示图表,并给出分析结果。",
            #             language='python')
            #     st.code(body="对于[X,Y]数据给我一个3个类别的'聚类分析',并给出分析结果。",
            #             language='python')
                
        with tab_4:
            st.text_area(label='系统角色设定', value='你是一个人工智能,你需要回答我提出的问题,或者完成我交代的任务。你需要使用我提问的语言(如中文、英文)来回答。', height=200, label_visibility='hidden')


myavatar = "./2D.png"

def set_question(question):
    st.session_state["my_question"] = question


assistant_message_suggested = st.chat_message(
    "assistant", avatar=myavatar
)

##! 注意在填写列名时,最佳的选择是使用双引号将名字框出来。否则LLM会不认识。
if assistant_message_suggested.button("点击这里可以查看参考问题示例 ℹ️"):
    questions = [
        '你查一下长度超过10的数据有哪些?',
        '你告诉我长度超过30且宽度超过10的数据有哪些?',
        '宽度超过20且价格超过25的数据有哪些?',
        '”长度“超过10且”宽度“超过15且”类别“是”甲“的数据有哪些?',
        '长度超过10以上的价格的总和是多少?',
        '长度排名前三的产品ID和价格和长度?',

    ]
    st.session_state["my_question"] = None
    # questions = generate_questions_cached() ## orignal. 
    for i, question in enumerate(questions):
        time.sleep(0.05)
        button = st.button(
            question,
            on_click=set_question,
            args=(question,),
        )

my_question = st.session_state.get("my_question", default=None)

if my_question is None:
    my_question = st.chat_input(
        "请在这里提交您的查询问题",
    )

if my_question:
    st.session_state["my_question"] = my_question
    user_message = st.chat_message("user")
    user_message.write(f"{my_question}")

    # sql = generate_sql_cached(question=my_question) ## original. 核心函数。用ChatGPT输出SQL语句。
    # sql = chatsql003.main(prompt=my_question) ## 通过本地LLM输出SQL语句。
    sql = chatsql004.main(prompt=my_question) ## 通过本地LLM输出SQL语句。

    if sql:
        if st.session_state.get("show_sql", True):
            assistant_message_sql = st.chat_message(
                "assistant", avatar=myavatar
            )
            assistant_message_sql.code(sql, language="sql", line_numbers=True)

        user_message_sql_check = st.chat_message("user")
        user_message_sql_check.write(f"您是否满意上面的SQL查询语句答案?")
        with user_message_sql_check:
            happy_sql = st.radio(
                # "Happy",
                label="您的反馈:",
                options=["未决定", "满意,请执行语句", "不满意,需要改正语句"], ## 去掉第一个happy选项。
                # options=["", "yes", "no"], ## original。
                key="radio_sql",
                index=0,
                horizontal=True,
                label_visibility='visible',
            )
            
        # ## 非original。后期添加内容。Working.
        if happy_sql == "未决定":
            df = None
            st.session_state["df"] = None
        
        if happy_sql == "不满意,需要改正语句":
            st.warning(
                "请您手动修正SQL语句,按Shift + Enter提交"
            )
            sql_response = code_editor(sql, lang="sql")
            fixed_sql_query = sql_response["text"]

            if fixed_sql_query != "":
                # df = run_sql_cached(sql=fixed_sql_query) ## original. 核心函数。
                df = sql_command.llm_query(sql_command=fixed_sql_query)
            else:
                df = None

        elif happy_sql == "满意,请执行语句":
            # df = run_sql_cached(sql=sql) ## original. 核心函数。
            df = sql_command.llm_query(sql_command=sql) ## working. 

        else:
            df = None

        if df is not None:
            st.session_state["df"] = df
            
        if st.session_state.get("df") is not None:
            ## 显示查询的结果汇总信息
            # with st.container():
            query_info_describe = st.chat_message("assistant", avatar=myavatar)
            if df is not None:
                with query_info_describe:
                    metric_col1, metric_col2, metric_col3, metric_col4 = st.columns(4)
                    metric_col1.metric(label='查询结果中的行数', value=f"{df.shape[0]} 行", delta=None)
                    metric_col2.metric(label='查询结果中的列数', value=f"{df.shape[1]} 列", delta=None)
                    metric_col3.metric(label='查询结果中的单元格数', value=f"{df.size} 个", delta=None)
                    metric_col4.metric(label='查询结果中的缺失值', value=f"{df.isnull().sum().sum()} 个", delta=None)
            
            if st.session_state.get("show_table", True):
                df = st.session_state.get("df")
                
                assistant_message_table = st.chat_message(
                    "assistant",
                    avatar=myavatar
                )
                
                ### 目前是最佳显示方式
                if len(df) > 10:
                    assistant_message_table.markdown("**查询结果较多,当前只显示前10行数据**") ##TODO: 看看是否有其他更好的显示方式。
                    assistant_message_table.dataframe(df.head(10), hide_index=True)
                    # assistant_message_table.dataframe(df.head(100), use_container_width=True)
                else:
                    assistant_message_table.dataframe(df, hide_index=True)
                    # assistant_message_table.dataframe(df,use_container_width=True)
                
                ## 以下是其他datafram的显示方式,均不理想。
                # st.dataframe(df, use_container_width=True, height=100)
                                
                ## streamlit AwesomeTable, Dark模式下显示有问题。可以在sidebar上显示内容。
                # from awesome_table import AwesomeTable
                # AwesomeTable(df,show_order=True, show_search=True, show_search_order_in_sidebar=True)
                # # AwesomeTable(pd.json_normalize(df))

            # ## 展示图形
            # # code = generate_plotly_code_cached(question=my_question, sql=sql, df=df) ## orignal. 用LLM来构建统计图表:https://github.com/vanna-ai/vanna/blob/main/src/vanna/mistral/mistral.py
            
            # if st.session_state.get("show_plotly_code", False):
            #     assistant_message_plotly_code = st.chat_message(
            #         "assistant",
            #         avatar=myavatar,
            #     )
            #     assistant_message_plotly_code.code(
            #         code, language="python", line_numbers=True
            #     )

            # user_message_plotly_check = st.chat_message("user")
            # user_message_plotly_check.write(
            #     f"Are you happy with the generated Plotly code?"
            # )
            # with user_message_plotly_check:
            #     happy_plotly = st.radio(
            #         "Happy",
            #         options=["", "yes", "no"],
            #         key="radio_plotly",
            #         index=0,
            #     )

            # if happy_plotly == "no":
            #     st.warning(
            #         "Please fix the generated Python code. Once you're done hit Shift + Enter to submit"
            #     )
            #     python_code_response = code_editor(code, lang="python")
            #     code = python_code_response["text"]
            # elif happy_plotly == "":
            #     code = None

            # if code is not None and code != "":
            #     if st.session_state.get("show_chart", True):
            #         assistant_message_chart = st.chat_message(
            #             "assistant",
            #             avatar=myavatar,
            #         )
            #         fig = generate_plot_cached(code=code, df=df)
            #         if fig is not None:
            #             assistant_message_chart.plotly_chart(fig)
            #         else:
            #             assistant_message_chart.error("I couldn't generate a chart")
            
                ## Data Visualization: Ydata_profiling (pandas_profiling)
                # from ydata_profiling import ProfileReport
                # pr = ProfileReport(df)
                # # with st.expander(label='**数据汇总信息**', expanded=False):
                # with st.container():
                #     st_profile_report(pr)
                #     # st.stop()
                
                ## 数据可视化内容,高级版。
                ## pywalker: https://github.com/Kanaries/pygwalker/tree/main
                user_message_plot_check = st.chat_message("user")
                user_message_plot_check.write(f"您是否希望基于上述查询结果进行数据可视化?")
                with user_message_plot_check:
                    happy_plot = st.radio(
                        # "Happy",
                        label="您的反馈:",
                        options=["未决定", "是,需要进行数据可视化", "否,不需要进行数据可视化"], ## 去掉第一个happy选项。
                        # options=["", "yes", "no"], ## original。
                        key="radio_plot",
                        index=0,
                        horizontal=True,
                        label_visibility='visible',
                    )
                
                if happy_plot == "是,需要进行数据可视化":
                    import pygwalker as pyg
                    import streamlit.components.v1 as components
                    import streamlit as st
                    from pygwalker.api.streamlit import init_streamlit_comm, get_streamlit_html
                    
                    # Initialize pygwalker communication
                    init_streamlit_comm()

                    # When using `use_kernel_calc=True`, you should cache your pygwalker html, if you don't want your memory to explode
                    @st.cache_resource
                    def get_pyg_html(df: pd.DataFrame) -> str:
                        # When you need to publish your application, you need set `debug=False`,prevent other users to write your config file.
                        # If you want to use feature of saving chart config, set `debug=True`
                        html = get_streamlit_html(df, spec="./gw0.json", use_kernel_calc=True, debug=False)
                        return html
                    # walker = pyg.walk(df)
                    components.html(get_pyg_html(df), width=1200, height=800, scrolling=True)
                
                
                ### streamlit echarts: https://github.com/andfanilo/streamlit-echarts
                # from streamlit_echarts import st_echarts
                # from streamlit_echarts import st_pyecharts

                # st_pyecharts(df)


                

                ### Follow-up questions session. 
                # if st.session_state.get("show_followup", True):
                #     assistant_message_followup = st.chat_message(
                #         "assistant",
                #         avatar=myavatar,
                #     )
                #     followup_questions = generate_followup_cached(
                #         question=my_question, df=df
                #     )
                #     st.session_state["df"] = None

                #     if len(followup_questions) > 0:
                #         assistant_message_followup.text(
                #             "Here are some possible follow-up questions"
                #         )
                #         # Print the first 5 follow-up questions
                #         for question in followup_questions[:5]:
                #             time.sleep(0.05)
                #             assistant_message_followup.write(question)

    else:
        assistant_message_error = st.chat_message(
            "assistant", avatar=myavatar
        )
        assistant_message_error.error("我无法回答您的问题,请重新提问,谢谢!")