1、前言
我的ChatGPT 系列文章
GPT-4 API waitlist (openai.com) 有兴趣的赶紧申请一下吧。
- GPT-4更新最大的变化是可以输入并识别图片了,前两天写的这篇文章,算了,就这样赶紧发了 哈哈
- ChatGPT给人们日常生活带来的影响,尤其在软件科技圈,层出不穷的新品。
- 或与十多年前的iPhone非常的相似,带来一轮变革或新陈代谢。
- 必应日活最近也首次破亿,这一波微软真的是赢麻了。
- ChatGPT正式整合进Azure中,相信对于开发者来说是更大的利好。
即将到来的GPT-4是多模态模型,可能同时理解图像、声音、文本和视频。也就是说,万物皆可作为输入和输出。这个真的是太刺激了。就看接下来发布之后,api的开放程度了,拭目以待啊。
再来说一下,最近学习的GPT-3.5吧,由于种种原因,其实官网的功能也是足够的强大,只不过需要我们做到科学的上网才能使用。而在GPT-3.5之前开放的api,返回给我们的数据可以说是没什么参考价值吧。
在3月1日发布的GPT-3.5之后,api接口的返回数据质量,也发生了质的提升,种种迹象表明,现在的GPT模型势必会给各行各业产生不小的冲击,引领我们被动的进行变革,也许不是现在,但绝对已经在路上了,因为更强大的GPT-4.0也马上蓄势待发,看着这个趋势,作为一个程序员的我,是怎么也安耐不住的,必须参与其中,哪怕只是进行了解学习,对其接口数据组织进行提前的预热学习吧。
种种迹象表明,得好好学习一波了。
2、对接openai接口的全过程
可以按照这个顺序来尝试一下
- 科学上网这个有很多就不说了
- openai官网注册账号也有非常的多,也不提了
- openai官网创建apikey
- 本地开发可以使用代理进行开发
- 了解go语言初级开发
- 了解go语言的gin框架和fasthttp框架
- 了解openai官网的api
- 开干写代码,其实如果代码遇到了问题很大程度上你可以把代码发送给openai,大概率它可以帮你找到问题
这里着重说一下代理的问题,通过本地调试的时候应该是没有办法访问接口 api.openai.com
这里一种是nodejs实现的腾讯云函数,一种是go语言实现的云函数,这两种方式相对来说是最简单的,当然还可以有其他的方式了
3、go语言初级开发
由于年后时间相对充裕,所以在结合自身状况的前提下,我开启了go语言的学习,这期间真的好多的问题甚至是代码异常都是通过openai解决的, 也就是它能给予我莫大的帮助
说句不太好听的话:最近掘金好像没怎么使用了,而且连签到都经常忘记了,百度和谷歌也就更不用说了,一定程度上,改变了我处理问题的方式。不知道掘金通过后台的访问数据,能否看出一点问题。
所以最近我就通过go语言,算是原生的来调用了几个openai官网对外提供的接口。
这里也有go语言开发的类库,当然其他语言的也都有
- openai类库 github.com/sashabarano… ,目前1766个star
- python github.com/openai/open… 5863个star
- python github.com/acheong08/C… 20837个star
- C# github.com/betalgo/ope… 1071个star
- nodejs github.com/transitive-… 10980个star
- nodejs github.com/openai/open… 1890个star
- java github.com/TheoKanning… 1492个star
各个语言都有,发展可谓百家争鸣,当然自家的python可谓有得天独厚的优势
4、通过go对接openai
下面我简单说一下我通过go是如何来对接openai接口的,分为以下几个小节
4.1、gin框架
Gin 是一个使用 Go 语言编写的 Web 框架,具有轻量、快速和易于使用的特点。Gin 框架提供了许多 Web 开发中常用的功能和中间件,包括路由、请求参数解析、日志记录、错误处理、认证授权、Swagger 文档生成等,使得开发者可以更加方便快捷地进行 Web 开发。
- 已经使用强大的路由,对外对前端提供接口路由(路由可以分组,还可以继续分组真的很棒)
- 可以使用Swagger文档提供与前端交流的媒介(生成接口预览、参数说明、还可调试、返回数据等等)
- 将会使用中间件 验证token、日志记录、错误处理等
swagger如下,目前开发的接口就这几个而已,后续会慢慢的增加业务,不断优化。
这是我目前对接openai 的几个路由
4.2、fasthttp
在go中我主要是通过fasthttp类库来实现调用openai的接口的,没有使用上面说到的类库,主要是想学习一下通过fasthttp来调用接口
相对于标准库提供的net/http包,Fasthttp具有更高的性能和更低的内存占用。它也支持HTTP/1.x和HTTP/2协议。同样fasthttp也有极其强大的其他功能:
- 快速的路由匹配。Fasthttp使用高效的路由匹配算法来快速地匹配请求。
- 支持中间件。Fasthttp支持中间件,可以让开发人员在处理请求之前或之后添加自定义逻辑,例如身份验证、日志记录等。
- 支持文件服务器。Fasthttp可以快速地为静态文件提供服务,这对于处理大量静态内容的Web应用程序非常有用。
- 容易学习和使用。Fasthttp采用简单的API设计,并提供了丰富的文档和示例,使开发人员可以快速学习和使用。
4.3、代码实现
看openai官网可以发现,这个接口主要的参数就是model和messages,而messages中又嵌套了一个数组结构体
type ChatModel struct { Model string `json:"model"` Messages []Message `json:"messages"` } type Message struct { Role string `json:"role"` Content string `json:"content"` }
所以这里我通过struct创建两个结构体,来组装参数,并通过后面的json:"model"
设置被转换为json后对应的字段
接下来看看整个函数,其中我也添加了我对代码的理解注释,毕竟刚学习可能理解的不到位
func GetChatCompletions(ctx *gin.Context) dto.ResponseResult { // 通过GetRawData获取前端传递的JSON数据结构 data, _ := ctx.GetRawData() // 将data数据 包装成json数据 var m map[string]interface{} _ = json.Unmarshal(data, &m) // 这里我定义的参数是content获取传入的参数 content := m["content"].(string) // 组装openai 接口的参数实体 chatModel := ChatModel{ Model: "gpt-3.5-turbo", Messages: []Message{ {Role: "user", Content: content}, }, } // 将实体结构转换为byte数组 bytes, err := json.Marshal(chatModel) fmt.Println(string(bytes), "bytes") if err != nil { fmt.Println("error:", err) return dto.SetResponseFailure("数据转换错误") } // openai接口地址,可通过代理处理 url := utils.OpenAIUrl + `/v1/chat/completions` // 定义fasthttp请求对象 req := fasthttp.AcquireRequest() // 使用defer关键字可以确保在函数返回之前,即使出现了错误,也会释放请求对象的内存,从而避免内存泄漏和浪费。 // 当请求处理完成时,应该调用fasthttp.ReleaseRequest(req)来将请求对象返回给对象池。 defer fasthttp.ReleaseRequest(req) // 设置请求的url地址,请求头,以及通过SetBody设置请求的参数 req.SetRequestURI(url) req.Header.SetMethod("POST") req.Header.Set("Content-Type", "application/json") // req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Authorization", "Bearer "+utils.OpenAIAuthToken) //gpt-3.5-turbo-0301 req.SetBody(bytes) // 这里跟上面AcquireRequest 类似的,一个是请求对象,一个是返回对象 resp := fasthttp.AcquireResponse() defer fasthttp.ReleaseResponse(resp) // 通过fasthttp.Do真正的发起对象 if err := fasthttp.Do(req, resp); err != nil { fmt.Println("Error:", err) // return dto.SetResponseFailure("调用openai发生错误") ctx.JSON(200, gin.H{"data": "调用openai发生错误"}) } fmt.Println("Status:", resp.StatusCode()) // 将返回对象中的body数据转换为json数据 var obj map[string]interface{} if err := json.Unmarshal(resp.Body(), &obj); err != nil { panic(err) } fmt.Println("Body:", obj) // 最后我通过一个方法进行统一返回参数处理 return dto.SetResponseData(obj) }
4.4、调试效果
目前初步完成了五个接口,细节的参数可能在需要的时候还会添加,具体后端代码 github.com/aehyok/go-a…
4.5、前端展示效果
目前接口算是写好了,准备跟前端进行联调了,其实前端还有很多工作要做的,慢慢的把自己使用的这个工具好好优化。
5、总结
看似对接几个接口很简单,但是整个过程要学习的东西还是蛮多的,如果你也有兴趣学习,欢迎大家一起交流。
我的go代码仓库: github.com/aehyok/go-a…
我的个人博客:vue.tuokecat.com/blog
我的个人github:github.com/aehyok
我的前端项目:pnpm + monorepo + qiankun + vue3 + vite3 + 工具库、组件库 + 工程化 + 自动化
不断完善中,整体框架都有了
在线预览:vue.tuokecat.com
github源码:github.com/aehyok/vue-…