樣式定制
使用gradio設(shè)置頁面的視覺組件和交互邏輯,位于
webui.py
文章來源:http://www.zghlxwxcb.cn/news/detail-622911.html
import gradio as gr
import shutil
from chains.local_doc_qa import LocalDocQA
from configs.model_config import *
import nltk
import models.shared as shared
from models.loader.args import parser
from models.loader import LoaderCheckPoint
import os
nltk.data.path = [NLTK_DATA_PATH] + nltk.data.path
embedding_model_dict_list = list(embedding_model_dict.keys())
llm_model_dict_list = list(llm_model_dict.keys())
local_doc_qa = LocalDocQA()
# 記錄運(yùn)行日志到 CSV文件
flag_csv_logger = gr.CSVLogger()
block_css = """.importantButton {
background: linear-gradient(45deg, #7e0570,#5d1c99, #6e00ff) !important;
border: none !important;
}
.importantButton:hover {
background: linear-gradient(45deg, #ff00e0,#8500ff, #6e00ff) !important;
border: none !important;
}"""
webui_title = """
# ??langchain-ChatGLM WebUI??
?? [https://github.com/imClumsyPanda/langchain-ChatGLM](https://github.com/imClumsyPanda/langchain-ChatGLM)
"""
# 檢索知識庫
default_vs = get_vs_list()[0] if len(get_vs_list()) > 1 else "為空"
init_message = f"""歡迎使用 langchain-ChatGLM Web UI!
請?jiān)谟覀?cè)切換模式,目前支持直接與 LLM 模型對話或基于本地知識庫問答。
知識庫問答模式,選擇知識庫名稱后,即可開始問答,當(dāng)前知識庫{default_vs},如有需要可以在選擇知識庫名稱后上傳文件/文件夾至知識庫。
知識庫暫不支持文件刪除,該功能將在后續(xù)版本中推出。
"""
# 初始化消息
model_status = init_model()
default_theme_args = dict(
font=["Source Sans Pro", 'ui-sans-serif', 'system-ui', 'sans-serif'],
font_mono=['IBM Plex Mono', 'ui-monospace', 'Consolas', 'monospace'],
)
# Blocks API用于構(gòu)建交互式界面,創(chuàng)建一個名為demo的塊。該塊包含三個狀態(tài)變量:
# vs_path、file_status和model_status
with gr.Blocks(css=block_css, theme=gr.themes.Default(**default_theme_args)) as demo:
# gr.State是Gradio提供的一種不可見控件,用于存儲同一用戶運(yùn)行演示時的會話狀態(tài)。
# 當(dāng)用戶刷新頁面時,State變量的值被清除。它的目的是在后臺存儲一些變量方便訪問和交互。
vs_path, file_status, model_status = gr.State(
os.path.join(KB_ROOT_PATH, get_vs_list()[0], "vector_store") if len(get_vs_list()) > 1 else ""), gr.State(
""), gr.State(
model_status)
gr.Markdown(webui_title)
# Tab用來控制功能切換的標(biāo)簽
with gr.Tab("對話"):
# gr.Row() 會創(chuàng)建一個水平方向的行,之后的組件默認(rèn)會按順序水平排列在這一行內(nèi)
# 這里是將對話框和選擇框放在同一行,做了一個大對齊
with gr.Row():
# 這一列的寬度是默認(rèn)列寬的 10 倍
with gr.Column(scale=10):
# 最上面的框
chatbot = gr.Chatbot([[None, init_message], [None, model_status.value]],
elem_id="chat-box",
show_label=False).style(height=750)
# 最下面的輸入框,注意可通過調(diào)用.style()方法來設(shè)置組件的 CSS 樣式
query = gr.Textbox(show_label=False,
placeholder="請輸入提問內(nèi)容,按回車進(jìn)行提交").style(container=False)
with gr.Column(scale=5):
# Radio 組件實(shí)現(xiàn)了一個單選按鈕組,可以通過mode變量得到用戶的選擇
mode = gr.Radio(["LLM 對話", "知識庫問答", "Bing搜索問答"],
label="請選擇使用模式",
value="知識庫問答", )
# 使用 Grace 的 Accordion 組件創(chuàng)建了一個折疊面板
# visible 屬性來顯示或隱藏這個面板
knowledge_set = gr.Accordion("知識庫設(shè)定", visible=False)
vs_setting = gr.Accordion("配置知識庫")
# 為單選按鈕綁定 change 事件處理函數(shù) change_mode
mode.change(fn=change_mode,
# change_mode函數(shù)的輸入輸出
inputs=[mode, chatbot],
outputs=[vs_setting, knowledge_set, chatbot])
with vs_setting:
vs_refresh = gr.Button("更新已有知識庫選項(xiàng)")
# 下拉框
# interactive=True時,組件變?yōu)榻换タ捎脿顟B(tài),用戶可以修改或選擇
select_vs = gr.Dropdown(get_vs_list(),
label="請選擇要加載的知識庫",
interactive=True,
value=get_vs_list()[0] if len(get_vs_list()) > 0 else None
)
vs_name = gr.Textbox(label="請輸入新建知識庫名稱,當(dāng)前知識庫命名暫不支持中文",
lines=1,
interactive=True,
visible=True)
vs_add = gr.Button(value="添加至知識庫選項(xiàng)", visible=True)
vs_delete = gr.Button("刪除本知識庫", visible=False)
file2vs = gr.Column(visible=False)
with file2vs:
# load_vs = gr.Button("加載知識庫")
gr.Markdown("向知識庫中添加文件")
sentence_size = gr.Number(value=SENTENCE_SIZE, precision=0,
label="文本入庫分句長度限制",
interactive=True, visible=True)
with gr.Tab("上傳文件"):
files = gr.File(label="添加文件",
file_types=['.txt', '.md', '.docx', '.pdf', '.png', '.jpg', ".csv"],
file_count="multiple",
show_label=False)
load_file_button = gr.Button("上傳文件并加載知識庫")
with gr.Tab("上傳文件夾"):
folder_files = gr.File(label="添加文件",
file_count="directory",
show_label=False)
load_folder_button = gr.Button("上傳文件夾并加載知識庫")
with gr.Tab("刪除文件"):
files_to_delete = gr.CheckboxGroup(choices=[],
label="請從知識庫已有文件中選擇要刪除的文件",
interactive=True)
delete_file_button = gr.Button("從知識庫中刪除選中文件")
# 這里綁定了select_vs,后面還有一個test,因此綁定的refresh_vs_list函數(shù)要返回兩個值
# select_vs此時的值被改變了,因此觸發(fā)了change動作綁定的change_vs_name_input函數(shù)
vs_refresh.click(fn=refresh_vs_list,
inputs=[],
outputs=select_vs)
vs_add.click(fn=add_vs_name,
inputs=[vs_name, chatbot],
outputs=[select_vs, vs_name, vs_add, file2vs, chatbot, vs_delete])
vs_delete.click(fn=delete_vs,
inputs=[select_vs, chatbot],
outputs=[select_vs, vs_name, vs_add, file2vs, chatbot, vs_delete])
select_vs.change(fn=change_vs_name_input,
inputs=[select_vs, chatbot],
outputs=[vs_name, vs_add, file2vs, vs_path, chatbot, files_to_delete, vs_delete])
load_file_button.click(get_vector_store,
show_progress=True,
inputs=[select_vs, files, sentence_size, chatbot, vs_add, vs_add],
outputs=[vs_path, files, chatbot, files_to_delete], )
load_folder_button.click(get_vector_store,
show_progress=True,
inputs=[select_vs, folder_files, sentence_size, chatbot, vs_add,
vs_add],
outputs=[vs_path, folder_files, chatbot, files_to_delete], )
flag_csv_logger.setup([query, vs_path, chatbot, mode], "flagged")
query.submit(get_answer,
[query, vs_path, chatbot, mode],
[chatbot, query])
delete_file_button.click(delete_file,
show_progress=True,
inputs=[select_vs, files_to_delete, chatbot],
outputs=[files_to_delete, chatbot])
with gr.Tab("知識庫測試 Beta"):
# gr.Row() 會創(chuàng)建一個水平方向的行,之后的組件默認(rèn)會按順序水平排列在這一行內(nèi)
# 這里是將對話框和選擇框放在同一行,做了一個大對齊
with gr.Row():
# 這一列的寬度是默認(rèn)列寬的 10 倍
with gr.Column(scale=10):
# 最上面的框
chatbot = gr.Chatbot([[None, knowledge_base_test_mode_info]],
elem_id="chat-box",
show_label=False).style(height=750)
# 最下面的輸入框
query = gr.Textbox(show_label=False,
placeholder="請輸入提問內(nèi)容,按回車進(jìn)行提交").style(container=False)
with gr.Column(scale=5):
# Radio 組件實(shí)現(xiàn)了一個單選按鈕組,可以通過mode變量得到用戶的選擇,這里直接設(shè)不可見
mode = gr.Radio(["知識庫測試"], # "知識庫問答",
label="請選擇使用模式",
value="知識庫測試",
visible=False)
# 使用 Grace 的 Accordion 組件創(chuàng)建了一個折疊面板
knowledge_set = gr.Accordion("知識庫設(shè)定", visible=True)
vs_setting = gr.Accordion("配置知識庫", visible=True)
# 為單選按鈕綁定 change 事件處理函數(shù) change_mode
mode.change(fn=change_mode,
inputs=[mode, chatbot],
outputs=[vs_setting, knowledge_set, chatbot])
with knowledge_set:
# 數(shù)字輸入組件
score_threshold = gr.Number(value=VECTOR_SEARCH_SCORE_THRESHOLD,
label="知識相關(guān)度 Score 閾值,分值越低匹配度越高",
precision=0,
interactive=True)
vector_search_top_k = gr.Number(value=VECTOR_SEARCH_TOP_K, precision=0,
label="獲取知識庫內(nèi)容條數(shù)", interactive=True)
chunk_conent = gr.Checkbox(value=False,
label="是否啟用上下文關(guān)聯(lián)",
interactive=True)
chunk_sizes = gr.Number(value=CHUNK_SIZE, precision=0,
label="匹配單段內(nèi)容的連接上下文后最大長度",
interactive=True, visible=False)
chunk_conent.change(fn=change_chunk_conent,
inputs=[chunk_conent, gr.Textbox(value="chunk_conent", visible=False), chatbot],
outputs=[chunk_sizes, chatbot])
with vs_setting:
vs_refresh = gr.Button("更新已有知識庫選項(xiàng)")
# 不同Tab下標(biāo)志同一動作開始的刷新鍵可以共用一個名字,但是各Tab下動作影響的
# 組件需要起不同的名字,并且在函數(shù)返回時依次賦值給各個組件并更新
select_vs_test = gr.Dropdown(get_vs_list(),
label="請選擇要加載的知識庫",
interactive=True,
value=get_vs_list()[0] if len(get_vs_list()) > 0 else None)
vs_name = gr.Textbox(label="請輸入新建知識庫名稱,當(dāng)前知識庫命名暫不支持中文",
lines=1,
interactive=True,
visible=True)
vs_add = gr.Button(value="添加至知識庫選項(xiàng)", visible=True)
file2vs = gr.Column(visible=False)
with file2vs:
# load_vs = gr.Button("加載知識庫")
gr.Markdown("向知識庫中添加單條內(nèi)容或文件")
sentence_size = gr.Number(value=SENTENCE_SIZE, precision=0,
label="文本入庫分句長度限制",
interactive=True, visible=True)
with gr.Tab("上傳文件"):
files = gr.File(label="添加文件",
file_types=['.txt', '.md', '.docx', '.pdf'],
file_count="multiple",
show_label=False
)
load_file_button = gr.Button("上傳文件并加載知識庫")
with gr.Tab("上傳文件夾"):
folder_files = gr.File(label="添加文件",
# file_types=['.txt', '.md', '.docx', '.pdf'],
file_count="directory",
show_label=False)
load_folder_button = gr.Button("上傳文件夾并加載知識庫")
with gr.Tab("添加單條內(nèi)容"):
one_title = gr.Textbox(label="標(biāo)題", placeholder="請輸入要添加單條段落的標(biāo)題", lines=1)
one_conent = gr.Textbox(label="內(nèi)容", placeholder="請輸入要添加單條段落的內(nèi)容", lines=5)
one_content_segmentation = gr.Checkbox(value=True, label="禁止內(nèi)容分句入庫",
interactive=True)
load_conent_button = gr.Button("添加內(nèi)容并加載知識庫")
# 將上傳的文件保存到content文件夾下,并更新下拉框,注意這里是select_vs_test
vs_refresh.click(fn=refresh_vs_list,
inputs=[],
outputs=select_vs_test)
vs_add.click(fn=add_vs_name,
inputs=[vs_name, chatbot],
outputs=[select_vs_test, vs_name, vs_add, file2vs, chatbot])
select_vs_test.change(fn=change_vs_name_input,
inputs=[select_vs_test, chatbot],
outputs=[vs_name, vs_add, file2vs, vs_path, chatbot])
load_file_button.click(get_vector_store,
show_progress=True,
inputs=[select_vs_test, files, sentence_size, chatbot, vs_add, vs_add],
outputs=[vs_path, files, chatbot], )
load_folder_button.click(get_vector_store,
show_progress=True,
inputs=[select_vs_test, folder_files, sentence_size, chatbot, vs_add,
vs_add],
outputs=[vs_path, folder_files, chatbot], )
load_conent_button.click(get_vector_store,
show_progress=True,
inputs=[select_vs_test, one_title, sentence_size, chatbot,
one_conent, one_content_segmentation],
outputs=[vs_path, files, chatbot], )
flag_csv_logger.setup([query, vs_path, chatbot, mode], "flagged")
query.submit(get_answer,
[query, vs_path, chatbot, mode, score_threshold, vector_search_top_k, chunk_conent,
chunk_sizes],
[chatbot, query])
with gr.Tab("模型配置"):
llm_model = gr.Radio(llm_model_dict_list,
label="LLM 模型",
value=LLM_MODEL,
interactive=True)
no_remote_model = gr.Checkbox(shared.LoaderCheckPoint.no_remote_model,
label="加載本地模型",
interactive=True)
llm_history_len = gr.Slider(0, 10,
value=LLM_HISTORY_LEN,
step=1,
label="LLM 對話輪數(shù)",
interactive=True)
use_ptuning_v2 = gr.Checkbox(USE_PTUNING_V2,
label="使用p-tuning-v2微調(diào)過的模型",
interactive=True)
use_lora = gr.Checkbox(USE_LORA,
label="使用lora微調(diào)的權(quán)重",
interactive=True)
embedding_model = gr.Radio(embedding_model_dict_list,
label="Embedding 模型",
value=EMBEDDING_MODEL,
interactive=True)
top_k = gr.Slider(1, 20, value=VECTOR_SEARCH_TOP_K, step=1,
label="向量匹配 top k", interactive=True)
load_model_button = gr.Button("重新加載模型")
load_model_button.click(reinit_model, show_progress=True,
inputs=[llm_model, embedding_model, llm_history_len, no_remote_model, use_ptuning_v2,
use_lora, top_k, chatbot], outputs=chatbot)
# load_knowlege_button = gr.Button("重新構(gòu)建知識庫")
# load_knowlege_button.click(reinit_vector_store, show_progress=True,
# inputs=[select_vs, chatbot], outputs=chatbot)
demo.load(
# 加載初始化邏輯refresh_vs_list,并傳入輸出組件
fn=refresh_vs_list,
inputs=None,
outputs=[select_vs, select_vs_test],
# 加入后臺執(zhí)行隊(duì)列
queue=True,
show_progress=False,
)
(demo
# 限制回調(diào)函數(shù)的最多并發(fā)執(zhí)行數(shù)為3以避免應(yīng)用過載
.queue(concurrency_count=3)
.launch(server_name='172.20.63.134',
server_port=7860,
show_api=False,
share=False,
inbrowser=False))
回調(diào)函數(shù)具體實(shí)現(xiàn)
監(jiān)聽到前端的事件后調(diào)用的回調(diào)函數(shù),負(fù)責(zé)實(shí)現(xiàn)前后端交互。需要注意的一點(diǎn)是,chatbot中顯示新的聊天內(nèi)容并不是在原來的基礎(chǔ)上添加,而是從頭到尾的重新打印,所以基本上每個函數(shù)都要傳舊的history和返回新的history。文章來源地址http://www.zghlxwxcb.cn/news/detail-622911.html
獲取知識庫列表
def get_vs_list():
# 返回當(dāng)前最新的經(jīng)排序后的知識庫列表
lst_default = ["新建知識庫"]
if not os.path.exists(KB_ROOT_PATH):
return lst_default
lst = os.listdir(KB_ROOT_PATH)
if not lst:
return lst_default
lst.sort()
return lst_default + lst
獲取不同模式下的回答
- query.submit動作綁定的函數(shù)
def get_answer(query, vs_path, history, mode, score_threshold=VECTOR_SEARCH_SCORE_THRESHOLD,
vector_search_top_k=VECTOR_SEARCH_TOP_K, chunk_conent: bool = True,
chunk_size=CHUNK_SIZE, streaming: bool = STREAMING):
if mode == "Bing搜索問答":
for resp, history in local_doc_qa.get_search_result_based_answer(
query=query, chat_history=history, streaming=streaming):
source = "\n\n"
source += "".join(
[
f"""<details> <summary>出處 [{i + 1}] <a href="{doc.metadata["source"]}" target="_blank">{doc.metadata["source"]}</a> </summary>\n"""
f"""{doc.page_content}\n"""
f"""</details>"""
for i, doc in
enumerate(resp["source_documents"])])
history[-1][-1] += source
yield history, ""
# "index.faiss"是向量索引的文件名,可以根據(jù)文件存在性,來判斷向量索引是否需要構(gòu)建。
elif mode == "知識庫問答" and vs_path is not None and os.path.exists(vs_path) and "index.faiss" in os.listdir(
vs_path):
# 注意score_threshold, vector_search_top_k, chunk_conent,chunk_size
# 這幾個參數(shù)壓根沒傳進(jìn)get_knowledge_based_answer
for resp, history in local_doc_qa.get_knowledge_based_answer(
query=query, vs_path=vs_path, chat_history=history, streaming=streaming):
source = "\n\n"
source += "".join(
[f"""<details> <summary>出處 [{i + 1}] {os.path.split(doc.metadata["source"])[-1]}</summary>\n"""
f"""{doc.page_content}\n"""
f"""</details>"""
for i, doc in
enumerate(resp["source_documents"])])
history[-1][-1] += source
# 分別賦值給chatbot和query
yield history, ""
elif mode == "知識庫測試":
if os.path.exists(vs_path):
# 使用了全部傳入?yún)?shù),但是只是用于測試文件匹配度不能回答
resp, prompt = local_doc_qa.get_knowledge_based_conent_test(query=query, vs_path=vs_path,
score_threshold=score_threshold,
vector_search_top_k=vector_search_top_k,
chunk_conent=chunk_conent,
chunk_size=chunk_size)
if not resp["source_documents"]:
yield history + [[query,
"根據(jù)您的設(shè)定,沒有匹配到任何內(nèi)容,請確認(rèn)您設(shè)置的知識相關(guān)度 Score 閾值是否過小或其他參數(shù)是否正確。"]], ""
else:
source = "\n".join(
[
f"""<details open> <summary>【知識相關(guān)度 Score】:{doc.metadata["score"]} - 【出處{i + 1}】: {os.path.split(doc.metadata["source"])[-1]} </summary>\n"""
f"""{doc.page_content}\n"""
f"""</details>"""
for i, doc in
enumerate(resp["source_documents"])])
history.append([query, "以下內(nèi)容為知識庫中滿足設(shè)置條件的匹配結(jié)果:\n\n" + source])
yield history, ""
else:
yield history + [[query,
"請選擇知識庫后進(jìn)行測試,當(dāng)前未選擇知識庫。"]], ""
else:
answer_result_stream_result = local_doc_qa.llm_model_chain(
{"prompt": query, "history": history, "streaming": streaming})
for answer_result in answer_result_stream_result['answer_result_stream']:
resp = answer_result.llm_output["answer"]
history = answer_result.history
history[-1][-1] = resp
yield history, ""
logger.info(f"flagging: username={FLAG_USER_NAME},query={query},vs_path={vs_path},mode={mode},history={history}")
flag_csv_logger.flag([query, vs_path, history, mode], username=FLAG_USER_NAME)
模型初始化
- 初始化model_status
def init_model():
args = parser.parse_args()
args_dict = vars(args)
shared.loaderCheckPoint = LoaderCheckPoint(args_dict)
llm_model_ins = shared.loaderLLM()
llm_model_ins.history_len = LLM_HISTORY_LEN
try:
local_doc_qa.init_cfg(llm_model=llm_model_ins)
answer_result_stream_result = local_doc_qa.llm_model_chain(
{"prompt": "你好", "history": [], "streaming": False})
for answer_result in answer_result_stream_result['answer_result_stream']:
print(answer_result.llm_output)
reply = """模型已成功加載,可以開始對話,或從右側(cè)選擇模式后開始對話"""
logger.info(reply)
return reply
except Exception as e:
logger.error(e)
reply = """模型未成功加載,請到頁面左上角"模型配置"選項(xiàng)卡中重新選擇后點(diǎn)擊"加載模型"按鈕"""
if str(e) == "Unknown platform: darwin":
logger.info("該報(bào)錯可能因?yàn)槟褂玫氖?macOS 操作系統(tǒng),需先下載模型至本地后執(zhí)行 Web UI,具體方法請參考項(xiàng)目 README 中本地部署方法及常見問題:"
" https://github.com/imClumsyPanda/langchain-ChatGLM")
else:
logger.info(reply)
return reply
模型重加載
- load_model_button.click動作綁定的函數(shù)
def reinit_model(llm_model, embedding_model, llm_history_len, no_remote_model, use_ptuning_v2, use_lora, top_k,
history):
try:
llm_model_ins = shared.loaderLLM(llm_model, no_remote_model, use_ptuning_v2)
llm_model_ins.history_len = llm_history_len
local_doc_qa.init_cfg(llm_model=llm_model_ins,
embedding_model=embedding_model,
top_k=top_k)
model_status = """模型已成功重新加載,可以開始對話,或從右側(cè)選擇模式后開始對話"""
logger.info(model_status)
except Exception as e:
logger.error(e)
model_status = """模型未成功重新加載,請到頁面左上角"模型配置"選項(xiàng)卡中重新選擇后點(diǎn)擊"加載模型"按鈕"""
logger.info(model_status)
# 更新chatbot的值
return history + [[None, model_status]]
文件向量化
- load_file_button.click和load_folder_button.click動作綁定的函數(shù)
def get_vector_store(vs_id, files, sentence_size, history, one_conent, one_content_segmentation):
vs_path = os.path.join(KB_ROOT_PATH, vs_id, "vector_store")
filelist = []
if local_doc_qa.llm_model_chain and local_doc_qa.embeddings:
if isinstance(files, list):
for file in files:
filename = os.path.split(file.name)[-1]
shutil.move(file.name, os.path.join(KB_ROOT_PATH, vs_id, "content", filename))
filelist.append(os.path.join(KB_ROOT_PATH, vs_id, "content", filename))
vs_path, loaded_files = local_doc_qa.init_knowledge_vector_store(filelist, vs_path, sentence_size)
else:
vs_path, loaded_files = local_doc_qa.one_knowledge_add(vs_path, files, one_conent, one_content_segmentation,
sentence_size)
if len(loaded_files):
file_status = f"已添加 {'、'.join([os.path.split(i)[-1] for i in loaded_files if i])} 內(nèi)容至知識庫,并已加載知識庫,請開始提問"
else:
file_status = "文件未成功加載,請重新上傳文件"
else:
file_status = "模型未完成加載,請先在加載模型后再導(dǎo)入文件"
vs_path = None
logger.info(file_status)
return vs_path, None, history + [[None, file_status]], \
gr.update(choices=local_doc_qa.list_file_from_vector_store(vs_path) if vs_path else [])
選擇知識庫
- select_vs.change和select_vs_test.change動作所綁定的函數(shù),如果刷新知識庫會有bug
def change_vs_name_input(vs_id, history):
if vs_id == "新建知識庫":
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), None, history, \
gr.update(choices=[]), gr.update(visible=False)
else:
# 刷新時這地方有bug,直接傳了個列表過去,逆天
vs_path = os.path.join(KB_ROOT_PATH, vs_id, "vector_store")
if "index.faiss" in os.listdir(vs_path):
file_status = f"已加載知識庫{vs_id},請開始提問"
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), \
vs_path, history + [[None, file_status]], \
gr.update(choices=local_doc_qa.list_file_from_vector_store(vs_path), value=[]), \
gr.update(visible=True)
else:
file_status = f"已選擇知識庫{vs_id},當(dāng)前知識庫中未上傳文件,請先上傳文件后,再開始提問"
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), \
vs_path, history + [[None, file_status]], \
gr.update(choices=[], value=[]), gr.update(visible=True, value=[])
knowledge_base_test_mode_info = ("【注意】\n\n"
"1. 您已進(jìn)入知識庫測試模式,您輸入的任何對話內(nèi)容都將用于進(jìn)行知識庫查詢,"
"并僅輸出知識庫匹配出的內(nèi)容及相似度分值和及輸入的文本源路徑,查詢的內(nèi)容并不會進(jìn)入模型查詢。\n\n"
"2. 知識相關(guān)度 Score 經(jīng)測試,建議設(shè)置為 500 或更低,具體設(shè)置情況請結(jié)合實(shí)際使用調(diào)整。"
"""3. 使用"添加單條數(shù)據(jù)"添加文本至知識庫時,內(nèi)容如未分段,則內(nèi)容越多越會稀釋各查詢內(nèi)容與之關(guān)聯(lián)的score閾值。\n\n"""
"4. 單條內(nèi)容長度建議設(shè)置在100-150左右。\n\n"
"5. 本界面用于知識入庫及知識匹配相關(guān)參數(shù)設(shè)定,但當(dāng)前版本中,"
"本界面中修改的參數(shù)并不會直接修改對話界面中參數(shù),仍需前往`configs/model_config.py`修改后生效。"
"相關(guān)參數(shù)將在后續(xù)版本中支持本界面直接修改。")
切換模型
- mode.change動作綁定的函數(shù)
def change_mode(mode, history):
# 調(diào)整vs_setting, knowledge_set, chatbot的可見性
if mode == "知識庫問答":
return gr.update(visible=True), gr.update(visible=False), history
# + [[None, "【注意】:您已進(jìn)入知識庫問答模式,您輸入的任何查詢都將進(jìn)行知識庫查詢,然后會自動整理知識庫關(guān)聯(lián)內(nèi)容進(jìn)入模型查詢?。?!"]]
elif mode == "知識庫測試":
return gr.update(visible=True), gr.update(visible=True), [[None,
knowledge_base_test_mode_info]]
else:
return gr.update(visible=False), gr.update(visible=False), history
啟用上下文
- chunk_conent.change動作綁定的函數(shù)
def change_chunk_conent(mode, label_conent, history):
# 更新chunk_sizes, chatbot
conent = ""
if "chunk_conent" in label_conent:
conent = "搜索結(jié)果上下文關(guān)聯(lián)"
elif "one_content_segmentation" in label_conent: # 這里沒用上,可以先留著
conent = "內(nèi)容分段入庫"
if mode:
return gr.update(visible=True), history + [[None, f"【已開啟{conent}】"]]
else:
return gr.update(visible=False), history + [[None, f"【已關(guān)閉{conent}】"]]
創(chuàng)建新的知識庫
- vs_add.click動作所綁定的函數(shù)
def add_vs_name(vs_name, chatbot):
if vs_name is None or vs_name.strip() == "":
vs_status = "知識庫名稱不能為空,請重新填寫知識庫名稱"
chatbot = chatbot + [[None, vs_status]]
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(
visible=False), chatbot, gr.update(visible=False)
elif vs_name in get_vs_list():
vs_status = "與已有知識庫名稱沖突,請重新選擇其他名稱后提交"
chatbot = chatbot + [[None, vs_status]]
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(
visible=False), chatbot, gr.update(visible=False)
else:
# 新建上傳文件存儲路徑
if not os.path.exists(os.path.join(KB_ROOT_PATH, vs_name, "content")):
os.makedirs(os.path.join(KB_ROOT_PATH, vs_name, "content"))
# 新建向量庫存儲路徑
if not os.path.exists(os.path.join(KB_ROOT_PATH, vs_name, "vector_store")):
os.makedirs(os.path.join(KB_ROOT_PATH, vs_name, "vector_store"))
vs_status = f"""已新增知識庫"{vs_name}",將在上傳文件并載入成功后進(jìn)行存儲。請?jiān)陂_始對話前,先完成文件上傳。 """
chatbot = chatbot + [[None, vs_status]]
# 更新select_vs, vs_name, vs_add, file2vs, chatbot, vs_delete這幾個組件
return gr.update(visible=True, choices=get_vs_list(), value=vs_name), gr.update(
visible=False), gr.update(visible=False), gr.update(visible=True), chatbot, gr.update(visible=True)
更新知識庫
- vs_refresh.click和demo.load動作綁定的事件
def refresh_vs_list():
# 更新select_vs, select_vs_test兩個組件
return gr.update(choices=get_vs_list()), gr.update(choices=get_vs_list())
刪除文件及整個知識庫
def delete_file(vs_id, files_to_delete, chatbot):
vs_path = os.path.join(KB_ROOT_PATH, vs_id, "vector_store")
content_path = os.path.join(KB_ROOT_PATH, vs_id, "content")
docs_path = [os.path.join(content_path, file) for file in files_to_delete]
status = local_doc_qa.delete_file_from_vector_store(vs_path=vs_path,
filepath=docs_path)
if "fail" not in status:
for doc_path in docs_path:
if os.path.exists(doc_path):
os.remove(doc_path)
rested_files = local_doc_qa.list_file_from_vector_store(vs_path)
if "fail" in status:
vs_status = "文件刪除失敗。"
elif len(rested_files) > 0:
vs_status = "文件刪除成功。"
else:
vs_status = f"文件刪除成功,知識庫{vs_id}中無已上傳文件,請先上傳文件后,再開始提問。"
logger.info(",".join(files_to_delete) + vs_status)
chatbot = chatbot + [[None, vs_status]]
return gr.update(choices=local_doc_qa.list_file_from_vector_store(vs_path), value=[]), chatbot
def delete_vs(vs_id, chatbot):
try:
shutil.rmtree(os.path.join(KB_ROOT_PATH, vs_id))
status = f"成功刪除知識庫{vs_id}"
logger.info(status)
chatbot = chatbot + [[None, status]]
return gr.update(choices=get_vs_list(), value=get_vs_list()[0]), gr.update(visible=True), gr.update(
visible=True), \
gr.update(visible=False), chatbot, gr.update(visible=False)
except Exception as e:
logger.error(e)
status = f"刪除知識庫{vs_id}失敗"
chatbot = chatbot + [[None, status]]
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), \
gr.update(visible=True), chatbot, gr.update(visible=True)
到了這里,關(guān)于langchain-ChatGLM源碼閱讀:webui.py的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!