req流式读取 #gin框架流式发送

欢迎来我的博客cjwblog.cn逛逛,虽然没什么内容x

场景
  • 部分大模型(如gpt)的流式读取,可以增加用户体验。
  • gin框架的流式问答,与前端交互。
使用方法
  1. 我在使用框架req 的时候,发现无法从resp.Body流式读取数据,只能完整读出来

原因是框架自动帮我们读取了resp,导致我们无法读取流式的消息。

正常我们获取返回值应该是这样的:

resp := c.c.Post(url).SetQueryParam("key", c.key).SetBody(msg).Do(ctx)
data := resp.String()

想要读取流式可以这么做:

resp := c.c.DisableAutoReadResponse().Post(url).SetQueryParam("key", c.key).SetBody(msg).Do(ctx)
defer resp.Body.Close()

scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
    line := scanner.Text()
    if strings.Contains(line, "text") {
        fmt.Println(line)
    }
}
  1. 现在我们知道了如何从外部读取流式数据,那么我们如何利用web框架发送流式数据呢?

下面以gin框架为例

可以使用func (c *Context) Stream(step func(w io.Writer) bool) bool函数

==具体使用方法如下==(这里我用了自己的代码做了演示):

如果前端有需求,需要加上Header

c.Header("Content-Type", "application/octet-stream")

用bufio缓冲区向前端写数据

stop := c.Stream(func(w io.Writer) bool {
    bw := bufio.NewWriter(w)
    if len(r.Choices) != 0 {
        gptResult.Detail = &r
        gptResult.Id = r.ID
        gptResult.Role = openai.ChatMessageRoleAssistant
        gptResult.Text += r.Choices[0].Delta.Content // 流传输
        marshal, _ := json.Marshal(gptResult)
        if _, err := fmt.Fprintf(bw, "%s\n", marshal); err != nil {
            fmt.Println(err)
            return true
        }
        bw.Flush()
    }
    return false
}) //stop
if stop {
    fmt.Println("stop")
    break
}

顺便讲一下flush吧,按官方文档来说,是为了将写好的数据发送给客户端。

// The Flusher interface is implemented by ResponseWriters that allow
// an HTTP handler to flush buffered data to the client.
type Flusher interface {
    // Flush sends any buffered data to the client.
    Flush()
}
本文由博客一文多发平台 OpenWrite 发布!

丿幻灬影丨
1 声望0 粉丝

« 上一篇
go mod tidy 报错