如果说部署
这里不得不提一下:
本笔记是ChatGLM2-6B - xiaodu114.github.io的后续,还是先根据这篇准备好环境吧!机器必须还是我的老朋友。
上篇已经下载。对,这里使用的还是量化版:chatglm2-6b-int4
虽然这只是一扇窗,但是咱还得在说一下: 互链高科
这里将下载的Embedding 模型
这里将下载的仓库放到
说明:这里的仓库是今天(2023-10-17)在GitHub获取的。
项目的配置在根目录的
这里就是对LLM 模型、Embedding 模型等配置的地方了,具体修改了哪些,你可以看下面的截图:
# 示例:LLM模型的绝对路径
# model_config.py
# MODEL_ROOT_PATH 字符串变量
# MODEL_PATH 字典变量
# LLM_MODEL 字符串变量 默认使用哪个模型
MODEL_ROOT_PATH + MODEL_PATH["llm_model"][LLM_MODEL]
跑通之后发现,该项目有很多API的调用,启动了好几个服务器……这里应该是关于Web服务器的配置,修改如下图:
# 创建虚拟环境
python -m venv venv
# 激活虚拟环境
.\venv\scripts\activate
# 我这里设置全局的清华镜像源
pip install -r requirements.txt
# 如果你不想全局设置,也可以仅本次安装时使用镜像源(如下面的截图)
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
因为我们这是第一次部署,可以直接初始化知识库。其他的可以看官方文档。
# 初始化或重建知识库
python init_database.py --recreate-vs
你可能发现了,这里还有对拥抱脸
# 一键启动脚本 startup.py,一键启动所有 FastChat 服务、API 服务、WebUI 服务
python startup.py -a
不出意外,还是出意外了,出现了一大推错误,并没有看到想看到的WebUI页面。这个问题,弄了好几天,试了N种方式,最后发现是
# 查看被占用端口对应的 PID
netstat -aon|findstr 20001
# 查看指定 PID 的进程
tasklist|findstr 7836
郁闷的是这进程还干不掉(内部问题,具体的原因就不和大家说了啊)。于是我只能修改代码了,文件为
# fastchat controller server
FSCHAT_CONTROLLER = {
"host": DEFAULT_BIND_HOST,
"port": 30001,
"dispatch_method": "shortest_queue",
}
修改完之后继续一键启动,需要耐心等待。没想到啊!就这么一点一点的成功了。这你妹的绝对不按套路出牌啊!这时你就问了:怎么成功了,怎么还这样说啊?曰:“客官,你听我细细道来。前几天也跑通了,但是可不是就这么简简单单的,那真是废了九牛二虎之力啊!前几次的一键启动失败,我认为可能是CPU太弱,内存太小,多进程或者什么原因之类,我就将 startup.py 拷贝了五份,当然我修改其中的代码了啊!每一个文件只启动一个服务,最后开五个命令行依次执行这五个文件。你还别说,利用这种方式还真的跑通了。但是今天写部署文档时想着在重新来一遍,结果你也看到了……”。都是泪啊!
下面已修改其中一个文件为例,其他的类似,如下图:
LLM 直接对话正常。下面测试一下知识库,在网上找了两个2023年的PDF,看一下成功添加的截图:
再来试一下:知识库问答。请她帮忙分析一下,结果如下图:
看着界面效果,确实是针对本地文件的回答,但是好像没有回答完?确实是这样的,命令行显示超时了。如下图:
针对上面的超时问题,我在
这里使用
# 进入Python项目目录
$projectPath = "E:\llm\Langchain-Chatchat-master"
Set-Location -Path $projectPath
# 激活虚拟环境
$venvPath = ".\venv\Scripts\Activate.ps1"
if (Test-Path $venvPath) {
& $venvPath
} else {
Write-Host "Python Virtual environment not found."
}
# 执行Python脚本
$pythonScript = ".\startup.py"
if (Test-Path $pythonScript) {
python $pythonScript -a
} else {
Write-Host "Python script not found."
}
Read-Host | Out-Null
关于执行脚本策略和默认执行程序你可以参考:PowerShell - xiaodu114.github.io
这里使用
#!/bin/bash
# 打开一个新的终端,并在指定目录进入虚拟环境venv
gnome-terminal --working-directory=/home/xxx/llm/2-code/Langchain-Chatchat-master -- /bin/bash -c 'source ./venv/bin/activate; python startup.py -a'
exit
如果这个脚本文件你是在Windows下创建编辑的,一定要注意换行符 Windows(CR LF)和 Unix(LF)。如果使用的是Windows(CR LF),那么在 Ubuntu 下执行时会报错。参考:$'\r': 未找到命令的解决办法 - 菜鸟辉哥 - 博客园
右键“*.sh”文件->属性->“权限”页签->勾中“允许执行文件”
右键“*.sh”文件->作为程序运行即可
你有这样的需求吗?我们想看一下他拆分之后的文档怎样的……于是写了两个扩展方法:添加和删除
修改的文件为:
下面是新增的两个方法:
# 保存拆分后的内容
def extend_add_split_docs_to_file(self, kb_file: KnowledgeFile, docs: List[Document] = []):
print("-"*50 +" ddz extend_add_split_docs_to_file " +"-"*50)
# self.kb_name : 知识库名称 ,例如:ddz002
# self.kb_info : 知识库知识库介绍 ,例如:关于ddz002的知识库
# self.kb_path : 知识库绝对路径 ,例如:D:\2-code\Langchain-Chatchat-0.2.6\knowledge_base\ddz002
# self.doc_path : 知识库文档绝对路径 ,例如:D:\2-code\Langchain-Chatchat-0.2.6\knowledge_base\ddz002\content
if(kb_file is None or kb_file.filepath is None): return
if(docs is None or len(docs) == 0): return
fileName = os.path.basename(kb_file.filepath)
split_docs_folder_name = "split_docs_content"
split_docs_path = os.path.join(self.kb_path, split_docs_folder_name)
if not os.path.exists(split_docs_path):
os.makedirs(split_docs_path)
with open(os.path.join(split_docs_path, fileName + ".txt"), "a", encoding="utf-8") as file:
counter = 0
for doc in docs:
counter = counter + 1
file.write("-"*10 + ">【程序添加】 第 " + str(counter) + " 块 【程序添加】<" + "-"*10+"\n")
file.write(doc.page_content)
file.write("\n")
print("-"*50 +" ddz extend_add_split_docs_to_file " +"-"*50)
return
# 删除
def extend_delele_split_docs_file(self, kb_file: KnowledgeFile, delete_content: bool = False):
print("-"*50 +" ddz extend_delele_split_docs_file " +"-"*50)
# self.kb_name : 知识库名称 ,例如:ddz002
# self.kb_info : 知识库知识库介绍 ,例如:关于ddz002的知识库
# self.kb_path : 知识库绝对路径 ,例如:D:\2-code\Langchain-Chatchat-0.2.6\knowledge_base\ddz002
# self.doc_path : 知识库文档绝对路径 ,例如:D:\2-code\Langchain-Chatchat-0.2.6\knowledge_base\ddz002\content
if(kb_file is None or kb_file.filepath is None): return
fileName = os.path.basename(kb_file.filepath)
split_docs_folder_name = "split_docs_content"
split_docs_path = os.path.join(self.kb_path, split_docs_folder_name)
filePath = os.path.join(split_docs_path, fileName + ".txt")
if delete_content and os.path.exists(filePath):
os.remove(filePath)
print("-"*50 +" ddz extend_delele_split_docs_file " +"-"*50)
return
调用两个新增的方法:
# 添加时调用 extend_add_split_docs_to_file
def add_doc(self, kb_file: KnowledgeFile, docs: List[Document] = [], **kwargs):
"""
向知识库添加文件
如果指定了docs,则不再将文本向量化,并将数据库对应条目标为custom_docs=True
"""
if docs:
custom_docs = True
for doc in docs:
doc.metadata.setdefault("source", kb_file.filepath)
else:
docs = kb_file.file2text()
custom_docs = False
if docs:
self.delete_doc(kb_file)
doc_infos = self.do_add_doc(docs, **kwargs)
# ddz 添加
self.extend_add_split_docs_to_file(kb_file, docs)
status = add_file_to_db(kb_file,
custom_docs=custom_docs,
docs_count=len(docs),
doc_infos=doc_infos)
else:
status = False
return status
# 删除时同步删除
def delete_doc(self, kb_file: KnowledgeFile, delete_content: bool = False, **kwargs):
"""
从知识库删除文件
"""
self.do_delete_doc(kb_file, **kwargs)
status = delete_file_from_db(kb_file)
if delete_content and os.path.exists(kb_file.filepath):
os.remove(kb_file.filepath)
self.extend_delele_split_docs_file(kb_file,delete_content)
return status
WebUI采用的
虽然不建议,又没说不行,还是试了一下,这里修改的文件是项目根目录下的
# https相关证书文件了解的不太多,这里测试的是下面的两种类型
def run_webui(started_event: mp.Event = None):
from server.utils import set_httpx_config
set_httpx_config()
host = WEBUI_SERVER["host"]
port = WEBUI_SERVER["port"]
p = subprocess.Popen(["streamlit", "run", "webui.py",
"--server.address", host,
"--server.port", str(port),
"--server.sslCertFile", "C:/*.crt", # HTTPS 看这里
"--server.sslKeyFile", "C:/*.key", # 请您再看一眼
"--theme.base", "light",
"--theme.primaryColor", "#165dff",
"--theme.secondaryBackgroundColor", "#f5f5f5",
"--theme.textColor", "#000000",
])
started_event.set()
p.wait()