22 Commits

Author SHA1 Message Date
cookeem
1d4ffa603d 基于最新的gpt-3.5-turbo-0301模型 2023-03-04 07:28:34 +08:00
cookeem
b461c75222 支持gpt-3.5-turbo-0301语言模型 2023-03-03 23:07:59 +08:00
cookeem
e2fd28897c 支持gpt-3.5-turbo-0301 2023-03-03 22:42:06 +08:00
cookeem
bf908be12e text-davinci-003 2023-03-03 22:28:02 +08:00
cookeem
dc4ffb96b3 使用gpt-3.5-turbo优化模型 2023-03-03 22:12:46 +08:00
cookeem
39cbed1853 解决收取websocket消息没有响应问题 2023-02-24 18:45:09 +08:00
cookeem
8d82c1b930 更新启动服务说明 2023-02-24 11:31:02 +08:00
cookeem
9d3c30785e 更新docker-compose 2023-02-15 18:42:42 +08:00
cookeem
f5068c3a58 新增.gitignore 2023-02-15 11:01:18 +08:00
cookeem
df71f28edf 移除go.sum 2023-02-15 11:00:32 +08:00
cookeem
6bb73cf30b 假如接收的不是text消息,返回错误提示 2023-02-15 10:57:03 +08:00
cookeem
37d888228c go-gpt3 升级为v1.1.0 2023-02-15 10:51:44 +08:00
cookeem
4291a95e27 回退 2023-02-13 11:10:46 +08:00
cookeem
5df6c92050 Revert "stream.Recv()会导致cpu 100的问题,升级gpt-3依赖库"
This reverts commit d7dfa7b216.
2023-02-13 11:10:09 +08:00
cookeem
d7dfa7b216 stream.Recv()会导致cpu 100的问题,升级gpt-3依赖库 2023-02-13 11:05:52 +08:00
cookeem
f09b7c8d95 问题反馈的超时时间设置为180秒 2023-02-13 10:40:51 +08:00
cookeem
be04f67050 设置会话超时,避免出现cpu 100% 2023-02-13 10:34:02 +08:00
cookeem
1b9d4b5e65 支持设置问题反馈的超时时间 2023-02-13 10:22:09 +08:00
cookeem
c37db35a33 死循环bug 2023-02-13 10:04:08 +08:00
cookeem
062645499b readme 更新git clone链接 2023-02-10 18:41:16 +08:00
cookeem
ccdb3baa0d 更新readme 2023-02-10 14:44:55 +08:00
cookeem
6de5909c48 MIT License 2023-02-10 14:22:29 +08:00
8 changed files with 88 additions and 69 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
go.sum
chatgpt-service

View File

@@ -2,11 +2,11 @@ FROM alpine:3.15.3
LABEL maintainer="cookeem"
LABEL email="cookeem@qq.com"
LABEL version="v1.0.0"
LABEL version="v1.0.1"
RUN adduser -h /chatgpt-service -u 1000 -D dory
COPY chatgpt-service /chatgpt-service/
WORKDIR /chatgpt-service
USER dory
# docker build -t doryengine/chatgpt-service:v1.0.0-alpine .
# docker build -t doryengine/chatgpt-service:v1.0.1-alpine .

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 SeeFlowerX
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,4 +1,4 @@
# 实时ChatGPT服务
# 实时ChatGPT服务基于最新的gpt-3.5-turbo-0301模型
## chatGPT-service和chatGPT-stream
@@ -7,6 +7,11 @@
- chatGPT-stream: [https://github.com/cookeem/chatgpt-stream](https://github.com/cookeem/chatgpt-stream)
- chatGPT-stream是一个前端服务以websocket的方式实时接收chatGPT-service返回的消息
## gitee传送门
- [https://gitee.com/cookeem/chatgpt-service](https://gitee.com/cookeem/chatgpt-service)
- [https://gitee.com/cookeem/chatgpt-stream](https://gitee.com/cookeem/chatgpt-stream)
## 效果图
![](chatgpt-service.gif)
@@ -16,7 +21,7 @@
```bash
# 拉取代码
git clone https://github.com/chatgpt-service.git
git clone https://github.com/cookeem/chatgpt-service.git
cd chatgpt-service
# chatGPT的注册页面: https://beta.openai.com/signup
@@ -29,7 +34,10 @@ vi config.yaml
appKey: "xxxxxx"
# 使用docker启动服务
# 使用docker-compose启动服务
docker-compose up -d
# 查看服务状态
docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------

View File

@@ -2,17 +2,16 @@ package chat
import (
"context"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/gorilla/websocket"
gogpt "github.com/sashabaranov/go-gpt3"
"io"
"net/http"
"strings"
"sync"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/gorilla/websocket"
gogpt "github.com/sashabaranov/go-gpt3"
)
type Api struct {
@@ -45,25 +44,6 @@ func (api *Api) responseFunc(c *gin.Context, startTime time.Time, status, msg st
c.JSON(httpStatus, ar)
}
func (api *Api) wsCheckConnectStatus(conn *websocket.Conn, chClose chan int) {
var err error
defer func() {
conn.Close()
}()
conn.SetReadDeadline(time.Now().Add(pingWait))
conn.SetPongHandler(func(s string) error {
conn.SetReadDeadline(time.Now().Add(pingWait))
return nil
})
for {
_, _, err = conn.ReadMessage()
if err != nil {
chClose <- 0
return
}
}
}
func (api *Api) wsPingMsg(conn *websocket.Conn, chClose, chIsCloseSet chan int) {
var err error
ticker := time.NewTicker(pingPeriod)
@@ -93,21 +73,27 @@ func (api *Api) wsPingMsg(conn *websocket.Conn, chClose, chIsCloseSet chan int)
}
func (api *Api) GetChatMessage(conn *websocket.Conn, cli *gogpt.Client, mutex *sync.Mutex, requestMsg string) {
var err error
var strResp string
req := gogpt.CompletionRequest{
Model: gogpt.GPT3TextDavinci003,
MaxTokens: api.Config.MaxLength,
Temperature: 0.6,
Prompt: requestMsg,
req := gogpt.ChatCompletionRequest{
Model: gogpt.GPT3Dot5Turbo0301,
MaxTokens: api.Config.MaxLength,
Temperature: 1.0,
Messages: []gogpt.ChatCompletionMessage{
{
Role: "user",
Content: requestMsg,
},
},
Stream: true,
Stop: []string{"\n\n\n"},
TopP: 1,
FrequencyPenalty: 0.1,
PresencePenalty: 0.1,
}
ctx := context.Background()
stream, err := cli.CreateCompletionStream(ctx, req)
stream, err := cli.CreateChatCompletionStream(ctx, req)
if err != nil {
err = fmt.Errorf("[ERROR] create chatGPT stream error: %s", err.Error())
chatMsg := Message{
@@ -128,7 +114,7 @@ func (api *Api) GetChatMessage(conn *websocket.Conn, cli *gogpt.Client, mutex *s
var i int
for {
response, err := stream.Recv()
if errors.Is(err, io.EOF) {
if err != nil {
var s string
var kind string
if i == 0 {
@@ -147,25 +133,8 @@ func (api *Api) GetChatMessage(conn *websocket.Conn, cli *gogpt.Client, mutex *s
mutex.Lock()
_ = conn.WriteJSON(chatMsg)
mutex.Unlock()
if kind == "retry" {
api.Logger.LogError(s)
}
break
}
if err != nil {
err = fmt.Errorf("[ERROR] receive chatGPT stream error: %s", err.Error())
chatMsg := Message{
Kind: "error",
Msg: err.Error(),
MsgId: id,
CreateTime: time.Now().Format("2006-01-02 15:04:05"),
}
mutex.Lock()
_ = conn.WriteJSON(chatMsg)
mutex.Unlock()
api.Logger.LogError(err.Error())
return
}
if len(response.Choices) > 0 {
var s string
@@ -173,7 +142,7 @@ func (api *Api) GetChatMessage(conn *websocket.Conn, cli *gogpt.Client, mutex *s
s = fmt.Sprintf(`%s# %s`, s, requestMsg)
}
for _, choice := range response.Choices {
s = s + choice.Text
s = s + choice.Delta.Content
}
strResp = strResp + s
chatMsg := Message{
@@ -189,7 +158,7 @@ func (api *Api) GetChatMessage(conn *websocket.Conn, cli *gogpt.Client, mutex *s
i = i + 1
}
if strResp != "" {
api.Logger.LogInfo(fmt.Sprintf("[RESPONSE] %s%s", requestMsg, strResp))
api.Logger.LogInfo(fmt.Sprintf("[RESPONSE] %s\n", strResp))
}
}
@@ -210,7 +179,7 @@ func (api *Api) WsChat(c *gin.Context) {
mutex := &sync.Mutex{}
conn, err := wsupgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
err = fmt.Errorf("failed to upgrade websocket %s", err.Error())
err = fmt.Errorf("[ERROR] failed to upgrade websocket %s", err.Error())
msg = err.Error()
api.responseFunc(c, startTime, status, msg, httpStatus, data)
return
@@ -219,13 +188,18 @@ func (api *Api) WsChat(c *gin.Context) {
_ = conn.Close()
}()
_ = conn.SetReadDeadline(time.Now().Add(pingWait))
conn.SetPongHandler(func(s string) error {
_ = conn.SetReadDeadline(time.Now().Add(pingWait))
return nil
})
var isClosed bool
chClose := make(chan int)
chIsCloseSet := make(chan int)
defer func() {
conn.Close()
}()
go api.wsCheckConnectStatus(conn, chClose)
go api.wsPingMsg(conn, chClose, chIsCloseSet)
go func() {
for {
@@ -248,7 +222,7 @@ func (api *Api) WsChat(c *gin.Context) {
// read in a message
messageType, bs, err := conn.ReadMessage()
if err != nil {
err = fmt.Errorf("read message error: %s", err.Error())
err = fmt.Errorf("[ERROR] read message error: %s", err.Error())
api.Logger.LogError(err.Error())
return
}
@@ -262,7 +236,7 @@ func (api *Api) WsChat(c *gin.Context) {
ok = true
} else {
if time.Since(latestRequestTime) < time.Second*time.Duration(api.Config.IntervalSeconds) {
err = fmt.Errorf("please wait %d seconds for next query", api.Config.IntervalSeconds)
err = fmt.Errorf("[ERROR] please wait %d seconds for next query", api.Config.IntervalSeconds)
chatMsg := Message{
Kind: "error",
Msg: err.Error(),
@@ -280,7 +254,7 @@ func (api *Api) WsChat(c *gin.Context) {
}
if ok {
if len(strings.Trim(requestMsg, " ")) < 2 {
err = fmt.Errorf("message too short")
err = fmt.Errorf("[ERROR] message too short")
chatMsg := Message{
Kind: "error",
Msg: err.Error(),
@@ -292,7 +266,6 @@ func (api *Api) WsChat(c *gin.Context) {
mutex.Unlock()
api.Logger.LogError(err.Error())
} else {
chatMsg := Message{
Kind: "receive",
Msg: requestMsg,
@@ -309,9 +282,23 @@ func (api *Api) WsChat(c *gin.Context) {
isClosed = true
api.Logger.LogInfo("[CLOSED] websocket receive closed message")
case websocket.PingMessage:
_ = conn.SetReadDeadline(time.Now().Add(pingWait))
api.Logger.LogInfo("[PING] websocket receive ping message")
case websocket.PongMessage:
_ = conn.SetReadDeadline(time.Now().Add(pingWait))
api.Logger.LogInfo("[PONG] websocket receive pong message")
default:
api.Logger.LogError("websocket receive message type error")
err = fmt.Errorf("[ERROR] websocket receive message type not text")
chatMsg := Message{
Kind: "error",
Msg: err.Error(),
MsgId: uuid.New().String(),
CreateTime: time.Now().Format("2006-01-02 15:04:05"),
}
mutex.Lock()
_ = conn.WriteJSON(chatMsg)
mutex.Unlock()
api.Logger.LogError(err.Error())
return
}
}

View File

@@ -5,6 +5,7 @@ port: 9000
# 问题发送的时间间隔不能小于多长时间,单位:秒
intervalSeconds: 5
# 返回答案的最大长度
maxLength: 1500
maxLength: 2000
# 是否允许cors跨域
cors: true

View File

@@ -1,7 +1,7 @@
version: "3"
services:
chatgpt-stream:
image: "doryengine/chatgpt-stream:v1.0.0"
image: "doryengine/chatgpt-stream:v1.0.1"
hostname: chatgpt-stream
container_name: chatgpt-stream
ports:
@@ -11,11 +11,11 @@ services:
- chatgpt-service
restart: always
chatgpt-service:
image: "doryengine/chatgpt-service:v1.0.0-alpine"
image: "doryengine/chatgpt-service:v1.0.1-alpine"
hostname: chatgpt-service
container_name: chatgpt-service
ports:
- "9000"
- "9000:9000"
volumes:
- ./config.yaml:/chatgpt-service/config.yaml
command: /chatgpt-service/chatgpt-service

2
go.mod
View File

@@ -7,7 +7,7 @@ require (
github.com/gin-gonic/gin v1.8.2
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0
github.com/sashabaranov/go-gpt3 v1.0.0
github.com/sashabaranov/go-gpt3 v1.3.3
github.com/sirupsen/logrus v1.9.0
gopkg.in/yaml.v3 v3.0.1
)