开发个人Go-ChatGPT--5 模型管理 (一)

news2024/9/22 15:25:46

开发个人Go-ChatGPT–5 模型管理 (一)

背景

开发一个chatGPT的网站,后端服务如何实现与大模型的对话?是整个项目中开发困难较大的点。
chat-GPT

如何实现上图的聊天对话功能?在开发后端的时候,如何实现stream的响应呢?本文就先介绍后端的原理,逐步攻克这个课题。

环境部署

  • 启动ollamadocker run -d -p 3000:8080 -p 11434:11434 -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ollama/ollama

  • ollama 下载对话模型: docker exec -it open-webui ollama run gemma:2b

    pulling manifest 
    pulling c1864a5eb193... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏ 1.7 GB                         
    pulling 097a36493f71... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏ 8.4 KB                         
    pulling 109037bec39c... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏  136 B                         
    pulling 22a838ceb7fb... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏   84 B                         
    pulling 887433b89a90... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏  483 B                         
    verifying sha256 digest 
    writing manifest 
    removing any unused layers 
    success
    

Stream reponse

前端

        ....
        const [res, controller] = await generateChatCompletion(localStorage.token, {
            model: model,
            messages: messagesBody,
            options: {
                ...($settings.options ?? {})
            },
            format: $settings.requestFormat ?? undefined,
            keep_alive: $settings.keepAlive ?? undefined,
            docs: docs.length > 0 ? docs : undefined
        });

        if (res && res.ok) {
            console.log('controller', controller);

            const reader = res.body
                .pipeThrough(new TextDecoderStream())
                .pipeThrough(splitStream('\n'))
                .getReader();
        ...

ollamaopen-webui 前端项目实现和人类一样沟通的方法,使用的是stream监听 messages事件收到的响应,保持长连接的状态,逐渐将收到的消息显示到前端,直到后端响应结束。

后端

  • gin.Stream
...
    c.Stream(func(w io.Writer) bool {
        select {
        case msg, ok := <-msgChan:
            if !ok {
                // 如果msgChan被关闭,则结束流式传输
                return false
            }
            fmt.Print(msg)
            // 流式响应,发送给 messages 事件,和前端进行交互
            c.SSEvent("messages", msg)
            return true
        case <-c.Done():
            // 如果客户端连接关闭,则结束流式传输
            return false
        }
    })
...
  • ollama 响应
...
    // llms.WithStreamingFunc 将ollama api 的响应内容逐渐返回,而不是一次性全部返回
    callOp := llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
        select {
        case msgChan <- string(chunk):
        case <-ctx.Done():
            return ctx.Err() // 返回上下文的错误
        }
        return nil
    })

    _, err := llaClient.Call(context.Background(), prompt, callOp)
    if err != nil {
        log.Fatalf("Call failed: %v", err) // 处理错误,而不是 panic
    }
...
  • 完整代码
package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "net/http"

    "github.com/gin-gonic/gin"
    "github.com/tmc/langchaingo/llms"
    "github.com/tmc/langchaingo/llms/ollama"
)

func main() {
    router := gin.Default()

    router.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "OK",
        })
    })

    router.POST("/chat", chat)

    router.Run(":8083")
}

type Prompt struct {
    Text string `json:"text"`
}

func chat(c *gin.Context) {
    var prompt Prompt
    if err := c.BindJSON(&prompt); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return


    }

    var msgChan = make(chan string)
    // 通过chan 将ollama 响应返回给前端
    go Generate(prompt.Text, msgChan)

    c.Stream(func(w io.Writer) bool {
        select {
        case msg, ok := <-msgChan:
            if !ok {
                // 如果msgChan被关闭,则结束流式传输
                return false
            }
            // fmt.Print(msg)
            c.SSEvent("messages", msg)
            return true
        case <-c.Done():
            // 如果客户端连接关闭,则结束流式传输
            return false
        }
    })
}

var llaClient *ollama.LLM

func init() {
    // Create a new Ollama instance
    // The model is set to "gemma:2b"
    // remote url is set to "http://ollama-ip:11434"
    url := ollama.WithServerURL("http://ollama-ip:11434")
    lla, err := ollama.New(ollama.WithModel("gemma:2b"), url)
    if err != nil {
        panic(err)
    }

    llaClient = lla

    fmt.Println("connect to ollama server successfully")
}

func Generate(prompt string, msgChan chan string) {
    // ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) // 设置超时
    // defer cancel()                                                          // 确保在函数结束时取消上下文

    callOp := llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
        select {
        case msgChan <- string(chunk):
        case <-ctx.Done():
            return ctx.Err() // 返回上下文的错误
        }
        return nil
    })

    _, err := llaClient.Call(context.Background(), prompt, callOp)
    if err != nil {
        log.Fatalf("Call failed: %v", err) // 处理错误,而不是 panic
    }

    // 确保在所有数据处理完毕后关闭 msgChan
    close(msgChan)
}

项目地址

jackwillsmith/openui-svelte-build (github.com)

GitHub - jackwillsmith/openui-backend-go: openui-backend-go

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JRE、JVM、JDK分别是什么。

JDK JDK的英文全称是Java Development Kit。JDK是用于制作程序和Java应用程序的软件开发环境。JDK 是 Java 开发工具包&#xff0c;它是 Java 开发者用来编写、编译、调试和运行 Java 程序的集合。JDK 包括了 Java 编译器&#xff08;javac&#xff09;、Java 运行时环境&…

SLAM相关知识

目前在SLAM上的传感器主要分为两大类&#xff1a;激光雷达和摄像头 激光雷达&#xff1a;单线、多线 摄像头&#xff1a;单目相机&#xff08;普通USB相机&#xff09;、双目相机&#xff08;2个普通的USB相机&#xff09;、单目结构光&#xff08;深度相机&#xff09;、双目…

编辑器 goland 和 visual studio code

goland 编辑器做的真是太好了&#xff0c;面向 go 代码的定制设计&#xff0c;但它是收费软件&#xff0c;价格还贵的超出了自己的经济能力范围。有时候想打几行代码&#xff0c;却没有趁手的兵器&#xff0c;真是难受。但求助免费破解版吧&#xff0c;又需要关注公众号&#x…

用流式数据库解决「自动化检测服务器性能异常」难题

对 DevOps 团队来说&#xff0c;检测大量服务器的性能异常并尽快响应一直是个挑战。他们设置了各种指标来监控服务器性能&#xff0c;但诊断性能问题复杂且耗时&#xff0c;因为诊断数据的量可能非常大。越来越多的人认为这个过程应该自动化。但怎么做呢&#xff1f; 流式系统…

@Slf4j idea标红Cannot resolve symbol ‘log‘

一、背景 时间久了没有应用idea,打开工程后项目 log 提示报红&#xff0c;未能解析&#xff0c;Cannot resolve symbol log &#xff0c;Slf4j 注解正常&#xff0c;应用的lombok插件。 检查lombok插件安装情况&#xff0c;发现未安装&#xff0c;重新安装重启idea后正常。 二…

pdf容量大小怎么改,pdf容量太大怎么变小

在数字化时代&#xff0c;pdf文件因其稳定性和跨平台兼容性而成为工作、学习和生活中不可或缺的文件格式。然而&#xff0c;随着文件内容的丰富&#xff0c;pdf文件的体积也日益增大&#xff0c;给存储和传输带来了不少困扰。本文将为你详细介绍多种实用的pdf文件压缩方法&…

怎样在 PostgreSQL 中优化对 UUID 数据类型的索引和查询?

文章目录 一、UUID 数据类型概述二、UUID 索引和查询的性能问题三、优化方案&#xff08;一&#xff09;选择合适的索引类型&#xff08;二&#xff09;压缩 UUID&#xff08;三&#xff09;拆分 UUID&#xff08;四&#xff09;使用覆盖索引&#xff08;五&#xff09;优化查询…

AutoHotKey自动热键(五)添加WINDOWS秘笈指令-输入瞬间启动功能

在AUTOHOTKEY的使用中,不仅仅可以监听组合热键,还可以监听正常文本击键录入,这是另一种监听方式,比如依次击键jsq之后直接弹出<计算器>工具,或者依次击键sj之后直接输出135****5564的手机号码,等等,这就是autohotkey的录入击键监听,以双冒号为开头:: 因这种录入监听像极了…

Vue3使用ref绑定组件获取valueRef.value为null的解决

问题&#xff1a; onMounted(() > {nextTick(()>{console.log(treeselectRef, treeselectRef.value);console.log(treeselectRef.value, treeselectRef.value);}); });输出&#xff1a; 查看绑定和定义都没有问题&#xff0c;还是获取不到 解决&#xff1a;使用getCur…

transformer网络学习

Transformer encoder-decoder模型之间共享的是Encoder最后一层输出的hidden-state。 GitHub - huggingface/transformers: &#x1f917; Transformers: State-of-the-art Machine Learning for Pytorch, TensorFlow, and JAX. Bert2Bert中&#xff0c;Encoder的hidden-state同…

变阻器的分类

变阻器作为用于调节电路中电阻值的电子元件&#xff0c;在电子电路中具有广泛的应用。根据不同的工作原理和结构形式&#xff0c;变阻器可以分为多种类型。以下是对变阻器分类的详细阐述&#xff1a; 一、按工作原理分类 电位器是一种通过滑动端位置调节电阻值的变阻器&#x…

移动公厕有无人显示屏为何多采用RS485、IO信号通讯方式

在户外活动、临时集会或是应急情况下&#xff0c;移动公厕作为解决人们生理需求的重要设施&#xff0c;发挥着不可替代的作用。然而&#xff0c;随着人口密度的增加和对公共卫生要求的提高&#xff0c;如何确保移动公厕的高效利用和良好维护&#xff0c;成为了组织者和管理者面…

大模型2024的问题在哪里?

自从大模型吹响新一轮技术革命的号角后&#xff0c;整个行业各个层次都面临大模型带来的范式转换。我今年在 4 月份上海举办的全球机器学习技术大会上演讲时曾提出&#xff0c;大模型为计算产业带来了计算范式、开发范式、交互范式的三大范式改变。今天是软件研发技术大会&…

使用jdk11运行javafx程序和jdk11打包jre包含javafx模块

我们都知道jdk11是移除了javafx的,如果需要使用javafx,需要单独下载。 这就导致我们使用javafx开发的桌面程序使用jdk11时提示缺少javafx依赖。但这是可以通过下面的方法解决。 一,使用jdk11运行javafx程序 我们可以通过设置vmOptions来使用jdk11运行javafx程序 1,添加j…

uniapp版即时通讯软件 IM社交交友聊天系统 语音视频通话双端APP 聊天交友APP源码 (含搭建教程)

修复音视频&#xff08;官方团队插件&#xff0c;无二次费用&#xff09;&#xff0c;文件发送&#xff0c;公告&#xff0c;签到&#xff0c;发现页&#xff0c;朋友圈删除&#xff0c;轮询客服&#xff0c;马甲等 可内嵌第三方网页连接&#xff0c;后台添加&#xff0c;带完…

Monaco 中添加 CodeLens

CodeLens 会在指定代码行上添加一行可点击的文字&#xff0c;点击时可以触发定义的命令&#xff0c;效果如下&#xff1a; 通过调用 API 注册 LensProvider&#xff0c;点击时触发 Command&#xff0c;首先要注册命令&#xff0c;通过 editor.addCommand () 方法进行注册。三个…

22.状态机设计--可乐机设计(投币三元出一瓶可乐)

理论知识&#xff1a; &#xff08;1&#xff09;状态机简写为FSM&#xff08;Finite State Machine&#xff09;&#xff0c;也称为同步有限状态机。同步是指状态的变化都是在时钟的边沿发送变化&#xff0c;有限值得是状态的个数是可数的。 &#xff08;2&#xff09;分类&…

springboot封装请求参数json的源码解析

源码位置&#xff1a; org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(org.springframework.http.HttpInputMessage, org.springframework.core.MethodParameter, java.lang.reflect.Type…

计算机视觉研究方向初学习,计算机视觉都有什么方向??!到底是干什么的?!

计算机视觉研究方向初学习&#xff0c;计算机视觉都有什么方向&#xff1f;&#xff1f;&#xff01;到底是干什么的&#xff1f;&#xff01; 语义分割图像分类目标检测和定位实例分割、全景分割物体跟踪姿态估计人脸识别人体识别图像增强风格迁移图像生成视觉问答视频分析光学…