FastGPT+ChatGLM3-6b搭建知识库

前言:我用fastgpt直接连接chatglm3,没有使用oneai,不是很复杂,只需要对chatglm3项目代码做少量修改就能支持使用embeddings,向量模型用的m3e,效果还可以

我的配置:
处理器:i5-13500
显卡:RTX 4060Ti 16GB
内存:64GB
本文只是记录本人搭建过程,避免遗忘,写的不清楚望理解!

以下文件全部传至阿里云盘
1.ChatGLM3-6b代码
https://github.com/THUDM/ChatGLM3
模型很大,建议云盘下载
2.FastGPT
https://github.com/labring/FastGPT
3.向量模型m3e
https://huggingface.co/moka-ai/m3e-base

https://modelscope.cn/models/xrunda/m3e-base/files

注意:先安装合适的cuda和cudnn版本
cuda下载地址
https://developer.nvidia.com/cuda-toolkit-archive
cudnn下载地址
https://developer.nvidia.com/cudnn
安装步骤请参考
https://blog.csdn.net/Mind_programmonkey/article/details/99688839

部署步骤:

1.下载Anaconda

清华大学镜像网站速度很快
https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/?C=M&O=D
在这里插入图片描述
找到适合你系统的文件下载,我用的最新的
安装anaconda
执行以下命令创建chatglm3-6b的conda环境

conda create -n chatglm3-demo python=3.10
conda activate chatglm3-demo

请注意,chatglm3-6b项目需要 Python 3.10 或更高版本
创建完成后进入ChatGLM3-main\composite_demo目录中
在这里插入图片描述

注意:建议把requirements.txt中的torch删掉,稍后重新安装,这个torch会下载成cpu版本的,用gpu运行会报错

然后执行

pip install -r requirements.txt

此外,使用 Code Interpreter 还需要安装 Jupyter 内核:

ipython kernel install --name chatglm3-demo --user

安装torch和torchvision

注意版本!!!
刚刚创建的conda环境是python3.10版本,torch和torchvision要和python版本对应
torch-2.0.0+cu117-cp310-cp310-win_amd64.whl
torchvision-0.15.0+cu117-cp310-cp310-win_amd64.whl
文件已传云盘
如果你需要的torch和torchvision不是这两个,请到下面网站查询下载
https://download.pytorch.org/whl/

在conda环境中安装torch和torchvision
进入torch和torchvision所在路径下
执行

pip install torch-2.0.0+cu117-cp310-cp310-win_amd64.whl
pip install torchvision-0.15.0+cu117-cp310-cp310-win_amd64.whl

我把模型和代码放在同级目录下
在这里插入图片描述
然后配置系统环境变量,新建两个环境变量,如下,MODEL_PATH填写你模型的路径
在这里插入图片描述
在这里插入图片描述
然后打开client.py修改下处
在这里插入图片描述修改完
运行以下命令在本地加载模型并启动 demo:

streamlit run main.py

如果正常启动,证明环境和代码没有问题!
接下来配置openai_api.py实现知识库

2.配置openai_api.py实现知识库

1.修改openai_api.py在这里插入图片描述
2.进入D:\AI\ChatGLM3-main\openai_api_demo
在这里插入图片描述
执行代码

python openai_api.py

会报错,提示缺少loguru或者sse_starlette或者fastapi等等等
缺少哪个包执行哪个包的安装语句就可,如下

pip install 包名
例如:pip install fastapi

等待安装完成再次运行python openai_api.py,安装完缺少的包就可运行成功了
在这里插入图片描述
打开postman进行测试
在这里插入图片描述
请求体代码

{
  "model": "string",
  "messages": [
    {
      "role": "user",
      "content": "你好",
      "name": "string",
      "function_call": {
        "name": "string",
        "arguments": "string"
      }
    }
  ],
  "temperature": 0.8,
  "top_p": 0.8,
  "max_tokens": 0,
  "stream": false,
  "functions": {},
  "repetition_penalty": 1.1
}

运行成功
3.接下来修改openai_api.py代码,建议直接复制以下代码替换openai_api.py中所有代码


import time
from contextlib import asynccontextmanager
from typing import List, Literal, Optional, Union

import os
import torch
import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from loguru import logger
from pydantic import BaseModel, Field
from sse_starlette.sse import EventSourceResponse
from transformers import AutoTokenizer, AutoModel
import numpy as np
import tiktoken
from sentence_transformers import SentenceTransformer
from sklearn.preprocessing import PolynomialFeatures

from utils import process_response, generate_chatglm3, generate_stream_chatglm3


@asynccontextmanager
async def lifespan(app: FastAPI):  # collects GPU memory
    yield
    if torch.cuda.is_available():
        torch.cuda.empty_cache()
        torch.cuda.ipc_collect()


app = FastAPI(lifespan=lifespan)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


class ModelCard(BaseModel):
    id: str
    object: str = "model"
    created: int = Field(default_factory=lambda: int(time.time()))
    owned_by: str = "owner"
    root: Optional[str] = None
    parent: Optional[str] = None
    permission: Optional[list] = None


class ModelList(BaseModel):
    object: str = "list"
    data: List[ModelCard] = []


class FunctionCallResponse(BaseModel):
    name: Optional[str] = None
    arguments: Optional[str] = None


class ChatMessage(BaseModel):
    role: Literal["user", "assistant", "system", "function"]
    content: str = None
    name: Optional[str] = None
    function_call: Optional[FunctionCallResponse] = None


class DeltaMessage(BaseModel):
    role: Optional[Literal["user", "assistant", "system"]] = None
    content: Optional[str] = None
    function_call: Optional[FunctionCallResponse] = None

class ChatCompletionRequest(BaseModel):
    model: str
    messages: List[ChatMessage]
    temperature: Optional[float] = 0.8
    top_p: Optional[float] = 0.8
    max_tokens: Optional[int] = None
    stream: Optional[bool] = False
    functions: Optional[Union[dict, List[dict]]] = None
    # Additional parameters
    repetition_penalty: Optional[float] = 1.1


class ChatCompletionResponseChoice(BaseModel):
    index: int
    message: ChatMessage
    finish_reason: Literal["stop", "length", "function_call"]


class ChatCompletionResponseStreamChoice(BaseModel):
    index: int
    delta: DeltaMessage
    finish_reason: Optional[Literal["stop", "length", "function_call"]]


class UsageInfo(BaseModel):
    prompt_tokens: int = 0
    total_tokens: int = 0
    completion_tokens: Optional[int] = 0


class ChatCompletionResponse(BaseModel):
    model: str
    object: Literal["chat.completion", "chat.completion.chunk"]
    choices: List[Union[ChatCompletionResponseChoice, ChatCompletionResponseStreamChoice]]
    created: Optional[int] = Field(default_factory=lambda: int(time.time()))
    usage: Optional[UsageInfo] = None


@app.get("/v1/models", response_model=ModelList)
async def list_models():
    model_card = ModelCard(id="chatglm3-6b")
    return ModelList(data=[model_card])


@app.post("/v1/chat/completions", response_model=ChatCompletionResponse)
async def create_chat_completion(request: ChatCompletionRequest):
    global model, tokenizer

    if len(request.messages) < 1 or request.messages[-1].role == "assistant":
        raise HTTPException(status_code=400, detail="Invalid request")

    gen_params = dict(
        messages=request.messages,
        temperature=request.temperature,
        top_p=request.top_p,
        max_tokens=request.max_tokens or 1024,
        echo=False,
        stream=request.stream,
        repetition_penalty=request.repetition_penalty,
        functions=request.functions,
    )

    logger.debug(f"==== request ====\n{gen_params}")

    if request.stream:
        generate = predict(request.model, gen_params)
        return EventSourceResponse(generate, media_type="text/event-stream")

    response = generate_chatglm3(model, tokenizer, gen_params)
    usage = UsageInfo()

    function_call, finish_reason = None, "stop"
    if request.functions:
        try:
            function_call = process_response(response["text"], use_tool=True)
        except:
            logger.warning("Failed to parse tool call")

    if isinstance(function_call, dict):
        finish_reason = "function_call"
        function_call = FunctionCallResponse(**function_call)

    message = ChatMessage(
        role="assistant",
        content=response["text"],
        function_call=function_call if isinstance(function_call, FunctionCallResponse) else None,
    )

    choice_data = ChatCompletionResponseChoice(
        index=0,
        message=message,
        finish_reason=finish_reason,
    )

    task_usage = UsageInfo.parse_obj(response["usage"])
    for usage_key, usage_value in task_usage.dict().items():
        setattr(usage, usage_key, getattr(usage, usage_key) + usage_value)

    return ChatCompletionResponse(model=request.model, choices=[choice_data], object="chat.completion", usage=usage)


async def predict(model_id: str, params: dict):
    global model, tokenizer

    choice_data = ChatCompletionResponseStreamChoice(
        index=0,
        delta=DeltaMessage(role="assistant"),
        finish_reason=None
    )
    chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
    yield "{}".format(chunk.json(exclude_unset=True))

    previous_text = ""
    for new_response in generate_stream_chatglm3(model, tokenizer, params):
        decoded_unicode = new_response["text"]
        delta_text = decoded_unicode[len(previous_text):]
        previous_text = decoded_unicode

        finish_reason = new_response["finish_reason"]
        if len(delta_text) == 0 and finish_reason != "function_call":
            continue

        function_call = None
        if finish_reason == "function_call":
            try:
                function_call = process_response(decoded_unicode, use_tool=True)
            except:
                print("Failed to parse tool call")

        if isinstance(function_call, dict):
            function_call = FunctionCallResponse(**function_call)

        delta = DeltaMessage(
            content=delta_text,
            role="assistant",
            function_call=function_call if isinstance(function_call, FunctionCallResponse) else None,
        )

        choice_data = ChatCompletionResponseStreamChoice(
            index=0,
            delta=delta,
            finish_reason=finish_reason
        )
        chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
        yield "{}".format(chunk.json(exclude_unset=True))

    choice_data = ChatCompletionResponseStreamChoice(
        index=0,
        delta=DeltaMessage(),
        finish_reason="stop"
    )
    chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
    yield "{}".format(chunk.json(exclude_unset=True))
    yield '[DONE]'

class EmbeddingRequest(BaseModel):
    input: List[str]
    model: str

def num_tokens_from_string(string: str) -> int:
    """Returns the number of tokens in a text string."""
    encoding = tiktoken.get_encoding('cl100k_base')
    num_tokens = len(encoding.encode(string))
    return num_tokens

def expand_features(embedding, target_length):
    poly = PolynomialFeatures(degree=2)
    expanded_embedding = poly.fit_transform(embedding.reshape(1, -1))
    expanded_embedding = expanded_embedding.flatten()
    if len(expanded_embedding) > target_length:
        # 如果扩展后的特征超过目标长度,可以通过截断或其他方法来减少维度
        expanded_embedding = expanded_embedding[:target_length]
    elif len(expanded_embedding) < target_length:
        # 如果扩展后的特征少于目标长度,可以通过填充或其他方法来增加维度
        expanded_embedding = np.pad(
            expanded_embedding, (0, target_length - len(expanded_embedding))
        )
    return expanded_embedding

@app.post("/v1/embeddings")
async def get_embeddings(
    request: EmbeddingRequest
):
    # 计算嵌入向量和tokens数量
    embeddings = [embeddings_model.encode(text) for text in request.input]

    # 如果嵌入向量的维度不为1536,则使用插值法扩展至1536维度
    embeddings = [
        expand_features(embedding, 1536) if len(embedding) < 1536 else embedding
        for embedding in embeddings
    ]

    # Min-Max normalization 归一化
    embeddings = [embedding / np.linalg.norm(embedding) for embedding in embeddings]

    # 将numpy数组转换为列表
    embeddings = [embedding.tolist() for embedding in embeddings]
    prompt_tokens = sum(len(text.split()) for text in request.input)
    total_tokens = sum(num_tokens_from_string(text) for text in request.input)

    response = {
        "data": [
            {"embedding": embedding, "index": index, "object": "embedding"}
            for index, embedding in enumerate(embeddings)
        ],
        "model": request.model,
        "object": "list",
        "usage": {
            "prompt_tokens": prompt_tokens,
            "total_tokens": total_tokens,
        },
    }

    return response

if __name__ == "__main__":

    # model_path = "THUDM/chatglm3-6b"
    model_path = os.environ.get('MODEL_PATH', 'chatglm3-6b')
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    model = AutoModel.from_pretrained(model_path, trust_remote_code=True).cuda()

    # 多显卡支持,使用下面两行代替上面一行,将num_gpus改为你实际的显卡数量
    # from utils import load_model_on_gpus
    # model = load_model_on_gpus("D:\AI\chatglm3-6b", num_gpus=2)
    model = model.eval()
    embeddings_model = SentenceTransformer('D:\AI\m3e-base', device='cpu')

    uvicorn.run(app, host='0.0.0.0', port=8000, workers=1)

修改如下两处内容即可
在这里插入图片描述
然后再次执行

python openai_api.py

会提示缺包,按上面方法pip安装即可,执行成功即可开始部署FastGPT

3.部署FastGPT

1.需要Linux进行部署,windows有自带的虚拟化功能,可以安装Linux系统,参考
https://zhuanlan.zhihu.com/p/666301493
部署Ubuntu 20.04
因为我装的有Linux虚拟机,就直接在虚拟机上部署了
2.安装Docker、Docker-Compose
3.打开Fast-GPT代码,复制docker-compose.yml文件到Linux系统上
在这里插入图片描述
修改以下地方
在这里插入图片描述

pg的账号密码,我没改,和代码中一样,镜像用的阿里云
在这里插入图片描述
mongo的账号密码,我没改,和代码中一样,镜像用的阿里云
在这里插入图片描述
修改阿里云镜像和url地址
4.执行docker-compose.yml文件
在该文件目录下执行

docker compose up -d

在这里插入图片描述
成功后即可打开,默认3000端口
在这里插入图片描述
登录,默认root,密码1234
点击应用,新建
在这里插入图片描述
在这里插入图片描述
左边框框不用管,因为我们是直连ChatGLM3-6b,直接访问即可
在这里插入图片描述
执行成功!
在这里插入图片描述
知识库内容,新建数据,然后绑定到应用里即可,后续再详细写
在这里插入图片描述
在这里关联完即可问它知识库里的内容了

以上所用所有文件及程序:
https://www.alipan.com/s/Goc66oWkVEw
提取码: 8uv1
ChatGLM3-6b文件和模型不能分享,请到下面链接下载
链接:https://pan.baidu.com/s/1V_y-10Ixx7bFNUuQ9NhF9w
提取码:2s14

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/264314.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web前端html笔记2

新增状态标签<meter><progress> <meter> 属性 值 描述 high 数值 规定高值 low 数值 规定低值 max 数值 规定最大值 min 数值 规定最小值 optimum 数值 规定最优值 value 数值 规定当前值 <body> <meter high"50" …

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之TextInput输入框组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之TextInput输入框组件 一、操作环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、TextInput 接口 TextInput(value?:{placeholder?: ResourceStr, tex…

NIO的实战教程(简单且高效)

1. 参考 建议按顺序阅读以下三篇文章 为什么NIO被称为同步非阻塞&#xff1f; Java IO 与 NIO&#xff1a;高效的输入输出操作探究 【Java.NIO】Selector&#xff0c;及SelectionKey 2. 实战 我们将模拟一个简单的HTTP服务器&#xff0c;它将响应客户端请求并返回一个固定的…

【EI会议征稿】2024年光电信息与光学工程国际学术会议(OIOE 2024)

2024年光电信息与光学工程国际学术会议&#xff08;OIOE 2024&#xff09; 2024 International Conference on Optoelectronic Information and Optical Engineering 光电信息技术和光学工程技术广泛应用于国民经济和国防建设的各行各业。近年来&#xff0c;随着相关产业的迅…

AcWing算法提高课-1.4.2股票买卖 IV

算法提高课整理 CSDN个人主页&#xff1a;更好的阅读体验 原题链接 题目描述 给定一个长度为 n n n 的数组&#xff0c;数组中的第 i i i 个数字表示一个给定股票在第 i i i 天的价格。 设计一个算法来计算你所能获取的最大利润&#xff0c;你最多可以完成 k k k 笔交易…

2024年你的年度目标OKR制定好了吗?

标题2023年余额见底&#xff0c;2024年的FLAG都制定好了吗&#xff1f; 目标很明确&#xff0c;计划很丰满&#xff0c;执行起来又处处透着一点点乏力&#xff0c;怎么办&#xff1f; 2024年可以尝试用OKR制定目标。 OKR目标管理方法&#xff0c;既适用于企业&#xff0c;也…

智能优化算法应用:基于卷尾猴算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于卷尾猴算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于卷尾猴算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.卷尾猴算法4.实验参数设定5.算法结果6.参考文…

前端案例—antdDesign的Select多选框组件加上全选功能

前端案例—antdDesign的Select多选框组件加上全选功能。 实现效果如下&#xff1a; Select 组件里有这个属性&#xff0c;可以利用这个对下拉菜单进行自定义。 const handleChange (e, value) > {setSelectState(e.target.checked)let arr productOptions?productOption…

嵌入式系统复习--ARM指令集(二)

文章目录 上一篇ARM指令详细介绍数据处理指令Load/Store指令转移指令异常中断指令协处理器指令下一篇 上一篇 嵌入式系统复习–ARM指令集&#xff08;一&#xff09; ARM指令详细介绍 分类 数据传送指令算术运算指令逻辑运算指令比较指令测试指令乘法指令 二进制编码格式 #…

Ubuntu 22.04 禁用(彻底移除)Snap

什么是Snaps Snaps 是 Ubuntu 的母公司 Canonical 于 2016 年 4 月发布 Ubuntu 16.04 LTS&#xff08;Long Term Support&#xff0c;长期支持版&#xff09;时引入的一种容器化的软件包格式。自 Ubuntu 16.04 LTS 起&#xff0c;Ubuntu 操作系统可以同时支持 Snap 及 Debian …

Python之Django项目的功能配置

1.创建Django项目 进入项目管理目录&#xff0c;比如&#xff1a;D盘 执行命令&#xff1a;diango-admin startproject demo1 创建项目 如果提示diango命令不存在&#xff0c;搜索diango-admin程序的位置&#xff0c;然后加入到环境变量path中。 进入项目&#xff0c;cd demo…

了解XSS、CSRF攻击这一篇就够了

目录 XSS攻击XSS概念XSS案例XSS攻击类型反射型存储型 总结 CSRFCSRF概念CSRF防御方式一&#xff1a;跨域禁止携带cookie方式二&#xff1a;设置SameSite属性为Strict方式三&#xff1a;验证Referer字段&#xff08;利用浏览器功能&#xff09;方式四&#xff1a;Token XSS攻击 …

深入理解 JavaScript 函数:提升编程技能的必备知识(中)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

WPF组合控件TreeView+DataGrid之DataGrid封装

&#xff08;关注博主后&#xff0c;在“粉丝专栏”&#xff0c;可免费阅读此文&#xff09; wpf的功能非常强大&#xff0c;很多控件都是原生的&#xff0c;但是要使用TreeViewDataGrid的组合&#xff0c;就需要我们自己去封装实现。 我们需要的效果如图所示&#x…

【MAC、IOS】charles抓包配置教程,亲测有效

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

4.3【共享源】克隆实战开发之截屏(一)

一,Screen截屏介绍 Screen的截屏是指从源读取像素,然后复制到缓冲区。然后可以根据需要操纵缓冲区;它可以简单地写入文件,也可以在其他窗口或显示器中使用。 Screen API从源中读取像素,并将其复制到提供的缓冲区中以捕获截屏。缓冲区可以是pixmap或窗口缓冲区,但必须设…

UE5 Landscape 制作GIS卫星图地形

1. 总体想法&#xff1a; 制作GIS地形&#xff0c;使用Landscaping MapBox是一个好方法&#xff0c;但是区域过大&#xff0c;会占用很多内存 https://blog.csdn.net/qq_17523181/article/details/135029614 如果采用QGis&#xff0c;导出卫星图&#xff0c;在UE5里拼合出地形…

趁网站还在!用python把次元岛COS小姐姐图集批量下载~

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 开发环境: Python 3.10 Pycharm 模块使用: requests >>> 数据请求模块 re >>> 匹配提取数据 os >>> 自动创建文件夹 如何安装python第三方模块: win R 输入 cmd 点击确定, 输入安装命令 p…

Codeforces Round 862 (Div. 2)

Problem - A - Codeforces AC代码: #include<bits/stdc.h> #define endl \n //#define int long long using namespace std; const int N1e310; int a[N]; int n; void solve() {cin>>n;int ans0;for(int i1;i<n;i) cin>>a[i],ans^a[i];if(n%21){for(in…

SQL布尔盲注 (Blind)基本原理及使用burpsuite进行暴力猜解

SQL布尔型盲注入是一种SQL注入攻击方式&#xff0c; 根据某个条件是否成立&#xff0c;来判断返回结果的真假&#xff0c;通过布尔型盲注&#xff0c;攻击者可以逐个字符地推断出数据库中存储的信息&#xff0c;如用户名、密码等&#xff0c;从而获取敏感信息或者执行非法操作。…