From cf2aa2144631b1b0b3b0c1936a4006894c7baad7 Mon Sep 17 00:00:00 2001 From: imClumsyPanda Date: Tue, 11 Apr 2023 19:52:59 +0800 Subject: [PATCH] update webui.py and README.md --- README.md | 32 +++++++++++++++-------- knowledge_based_chatglm.py | 19 ++++++-------- requirements.txt | 1 + webui.py | 52 +++++++++++++++++++++----------------- 4 files changed, 59 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index b6b62a3..25bcaa9 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,6 @@ ## 更新信息 -**[2023/04/11]** -1. 加入Webui V0.1版本,同步当日之前的更新内容; -2. 自动读取knowledge_based_chatglm.py中LLM及embedding模型枚举,选择后点击setting进行模型加载,可随时切换模型进行测试 -3. 可手动调节保留对话历史长度,可根据显存大小自行调节 -4. 添加上传文件功能,通过下拉框选择已上传的文件,点击loading加载文件,过程中可随时更换加载的文件 -5. 底部添加use via API可对接到自己系统 - **[2023/04/07]** 1. 解决加载 ChatGLM 模型时发生显存占用为双倍的问题 (感谢 [@suc16](https://github.com/suc16) 和 [@myml](https://github.com/myml)) ; 2. 新增清理显存机制; @@ -44,6 +37,9 @@ 3. 增加 GPU 显存需求更小的`chatglm-6b-int4`、`chatglm-6b-int4-qe`作为 LLM 模型备选项; 4. 更正`README.md`中的代码错误(感谢 [@calcitem](https://github.com/calcitem))。 +**[2023/04/11]** +1. 加入 Web UI V0.1 版本。 + ## 使用方式 @@ -67,10 +63,27 @@ pip install -r requirements.txt ``` 注:使用 langchain.document_loaders.UnstructuredFileLoader 进行非结构化文件接入时,可能需要依据文档进行其他依赖包的安装,请参考 [langchain 文档](https://python.langchain.com/en/latest/modules/indexes/document_loaders/examples/unstructured_file.html) -### 2. 执行 [knowledge_based_chatglm.py](knowledge_based_chatglm.py) 脚本 +### 2. 执行脚本体验 Web UI 或命令行交互 +执行 [webui.py](webui.py) 脚本体验 **Web 交互** +```commandline +python webui.py +``` +执行后效果如下图所示: +![webui](./img/ui1.png) +Web UI 中提供的 API 接口如下图所示: +![webui](./img/ui2.png) +Web UI 可以实现如下功能: +1. 自动读取`knowledge_based_chatglm.py`中`LLM`及`embedding`模型枚举,选择后点击`setting`进行模型加载,可随时切换模型进行测试 +2. 可手动调节保留对话历史长度,可根据显存大小自行调节 +3. 添加上传文件功能,通过下拉框选择已上传的文件,点击`loading`加载文件,过程中可随时更换加载的文件 +4. 底部添加`use via API`可对接到自己系统 + +或执行 [knowledge_based_chatglm.py](knowledge_based_chatglm.py) 脚本体验**命令行交互** ```commandline python knowledge_based_chatglm.py ``` + + ### 已知问题 - 目前已测试支持 txt、docx、md 格式文件,更多文件格式请参考 [langchain 文档](https://python.langchain.com/en/latest/modules/indexes/document_loaders/examples/unstructured_file.html),目前已知文档中若含有特殊字符,可能存在文件无法加载的问题; - 使用 macOS 运行本项目时,可能因为 macOS 版本为 13.3 及以上版本导致与 pytorch 不兼容,无法正常运行的情况。 @@ -115,9 +128,6 @@ A: 将 https://github.com/nltk/nltk_data/blob/gh-pages/packages/taggers/averaged >4. 引入更多的评估指标:可以引入更多的评估指标来评估模型的表现,从而发现 ChatGLM-6B 存在的不足和局限性。 >5. 改进模型架构:可以改进 ChatGLM-6B 的模型架构,提高模型的性能和表现。例如,可以使用更大的神经网络或者改进的卷积神经网络结构。 - - - ## 路线图 - [x] 实现 langchain + ChatGLM-6B 本地知识应用 - [x] 基于 langchain 实现非结构化文件接入 diff --git a/knowledge_based_chatglm.py b/knowledge_based_chatglm.py index ca1065e..fb34150 100644 --- a/knowledge_based_chatglm.py +++ b/knowledge_based_chatglm.py @@ -18,7 +18,6 @@ LLM_HISTORY_LEN = 3 # Show reply with source text from input document REPLY_WITH_SOURCE = True - embedding_model_dict = { "ernie-tiny": "nghuyong/ernie-3.0-nano-zh", "ernie-base": "nghuyong/ernie-3.0-base-zh", @@ -26,17 +25,15 @@ embedding_model_dict = { } llm_model_dict = { + "chatglm-6b-int4-qe": "THUDM/chatglm-6b-int4-qe", + "chatglm-6b-int4": "THUDM/chatglm-6b-int4", "chatglm-6b": "THUDM/chatglm-6b", - "glm-6b-int4": "THUDM/chatglm-6b-int4", - "glm-int4-qe": "THUDM/chatglm-6b-int4-qe", } -chatglm = None -embeddings = None -def init_cfg(LLM_MODEL,EMBEDDING_MODEL, LLM_HISTORY_LEN,V_SEARCH_TOP_K=6): - global chatglm,embeddings,VECTOR_SEARCH_TOP_K - VECTOR_SEARCH_TOP_K=V_SEARCH_TOP_K +def init_cfg(LLM_MODEL, EMBEDDING_MODEL, LLM_HISTORY_LEN, V_SEARCH_TOP_K=6): + global chatglm, embeddings, VECTOR_SEARCH_TOP_K + VECTOR_SEARCH_TOP_K = V_SEARCH_TOP_K chatglm = ChatGLM() chatglm.load_model(model_name_or_path=llm_model_dict[LLM_MODEL]) @@ -44,8 +41,8 @@ def init_cfg(LLM_MODEL,EMBEDDING_MODEL, LLM_HISTORY_LEN,V_SEARCH_TOP_K=6): embeddings = HuggingFaceEmbeddings(model_name=embedding_model_dict[EMBEDDING_MODEL], ) + def init_knowledge_vector_store(filepath): - loader = UnstructuredFileLoader(filepath, mode="elements") docs = loader.load() vector_store = FAISS.from_documents(docs, embeddings) @@ -53,7 +50,7 @@ def init_knowledge_vector_store(filepath): def get_knowledge_based_answer(query, vector_store, chat_history=[]): - global chatglm,embeddings + global chatglm, embeddings system_template = """基于以下内容,简洁和专业的来回答用户的问题。 如果无法从中得到答案,请说 "不知道" 或 "没有足够的相关信息",不要试图编造答案。答案请使用中文。 ---------------- @@ -81,7 +78,7 @@ def get_knowledge_based_answer(query, vector_store, chat_history=[]): if __name__ == "__main__": - init_cfg(LLM_MODEL,EMBEDDING_MODEL, LLM_HISTORY_LEN) + init_cfg(LLM_MODEL, EMBEDDING_MODEL, LLM_HISTORY_LEN) filepath = input("Input your local knowledge file path 请输入本地知识文件路径:") vector_store = init_knowledge_vector_store(filepath) history = [] diff --git a/requirements.txt b/requirements.txt index 85d8fd7..0415d52 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ beautifulsoup4 icetk cpm_kernels faiss-cpu +gradio diff --git a/webui.py b/webui.py index 2ea94f4..9b55ebf 100644 --- a/webui.py +++ b/webui.py @@ -4,17 +4,6 @@ import shutil import knowledge_based_chatglm as kb -# class kb: -# def __init__(self): -# pass - -# def init_knowledge_vector_store(filepath): -# return filepath - -# def get_knowledge_based_answer(*args): -# return args - - def get_file_list(): if not os.path.exists("content"): return [] @@ -32,18 +21,26 @@ def upload_file(file): if not os.path.exists("content"): os.mkdir("content") filename = os.path.basename(file.name) - shutil.move(file.name, "content/"+filename) + shutil.move(file.name, "content/" + filename) # file_list首位插入新上传的文件 file_list.insert(0, filename) return gr.Dropdown.update(choices=file_list, value=filename) -def getAnswer(q, v, h): +def get_answer(query, vector_store, history): resp, history = kb.get_knowledge_based_answer( - query=q, vector_store=v, chat_history=h) + query=query, vector_store=vector_store, chat_history=history) return history, history +def get_model_status(history): + return history + [[None, "模型已完成加载,请选择要加载的文档"]] + + +def get_file_status(history): + return history + [[None, "文档已完成加载,请开始提问"]] + + with gr.Blocks(css=""" .importantButton { background: linear-gradient(45deg, #7e0570,#5d1c99, #6e00ff) !important; @@ -65,7 +62,11 @@ with gr.Blocks(css=""" """) with gr.Row(): with gr.Column(scale=2): - chatbot = gr.Chatbot(elem_id="chat-box", + chatbot = gr.Chatbot([[None, """欢迎使用 langchain-ChatGLM Web UI,开始提问前,请依次如下 3 个步骤: +1. 选择语言模型、Embedding 模型及相关参数后点击"step.1: setting",并等待加载完成提示 +2. 上传或选择已有文件作为本地知识文档输入后点击"step.2 loading",并等待加载完成提示 +3. 输入要提交的问题后点击"step.3 asking" """]], + elem_id="chat-box", show_label=False).style(height=600) with gr.Column(scale=1): with gr.Column(): @@ -84,15 +85,19 @@ with gr.Blocks(css=""" kb.init_cfg(args[0], args[1], args[2], args[3]), show_progress=True, api_name="init_cfg", - inputs=[llm_model, embedding_model, VECTOR_SEARCH_TOP_K, LLM_HISTORY_LEN]) + inputs=[llm_model, embedding_model, VECTOR_SEARCH_TOP_K, LLM_HISTORY_LEN] + ).then( + get_model_status, chatbot, chatbot + ) with gr.Column(): with gr.Tab("select"): selectFile = gr.Dropdown( - file_list, label="content file", interactive=True, value=file_list[0] if len(file_list) > 0 else None) + file_list, label="content file", interactive=True, + value=file_list[0] if len(file_list) > 0 else None) with gr.Tab("upload"): file = gr.File(label="content file", file_types=[ - '.txt', '.md', '.docx']).style(height=100) + '.txt', '.md', '.docx']).style(height=100) # 将上传的文件保存到content文件夹下,并更新下拉框 file.upload(upload_file, inputs=file, outputs=selectFile) history = gr.State([]) @@ -100,10 +105,12 @@ with gr.Blocks(css=""" load_button = gr.Button("step.2:loading") load_button.click(lambda fileName: kb.init_knowledge_vector_store( - "content/"+fileName), + "content/" + fileName), show_progress=True, api_name="init_knowledge_vector_store", - inputs=selectFile, outputs=vector_store) + inputs=selectFile, outputs=vector_store).then( + get_file_status, chatbot, chatbot, show_progress=True, + ) with gr.Row(): with gr.Column(scale=2): @@ -112,9 +119,8 @@ with gr.Blocks(css=""" with gr.Column(scale=1): generate_button = gr.Button( "step.3:asking", elem_classes="importantButton") - generate_button.click(getAnswer, [query, vector_store, history], - [chatbot, history],api_name="get_knowledge_based_answer") - + generate_button.click(get_answer, [query, vector_store, chatbot], + [chatbot, history], api_name="get_knowledge_based_answer") demo.queue(concurrency_count=3).launch( server_name='0.0.0.0', share=False, inbrowser=False)