diff --git a/README.md b/README.md index 4b1c335f..1bfbeceb 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Create a fake API using ChatGPT's website ### Authentication +#### After 2024-04-02, accouts.txt is optional because no need authentication for gpt-3.5. + Access token and PUID(only for PLUS account) retrieval has been automated by [OpenAIAuth](https://github.com/xqdoo00o/OpenAIAuth/) with account email & password. `accounts.txt` - A list of accounts separated by new line @@ -23,7 +25,7 @@ email:password All authenticated access tokens and PUID will store in `access_tokens.json` -Auto renew access tokens and PUID after 7 days +Auto renew access tokens and PUID after 1 day Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. diff --git a/README_ZH.md b/README_ZH.md index 89efbbd7..bb896e4d 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -7,6 +7,8 @@ ### 设置 +#### 自2024-04-02起,可选配置accounts.txt,因为gpt-3.5无需登录了。 + 配置账户邮箱和密码,自动生成和更新Access tokens 和 PUID(仅PLUS账户)(使用[OpenAIAuth](https://github.com/xqdoo00o/OpenAIAuth/)) `accounts.txt` - 存放OpenAI账号邮箱和密码的文件 @@ -20,7 +22,7 @@ 所有登录后的Access tokens和PUID会存放在`access_tokens.json` -每7天自动更新Access tokens和PUID +每天自动更新Access tokens和PUID 注意! 请使用未封锁的ip登录账号,请先打开浏览器登录`https://chat.openai.com/`以检查ip是否可用 diff --git a/auth.go b/auth.go index c6483ffe..9348e3bd 100644 --- a/auth.go +++ b/auth.go @@ -20,7 +20,7 @@ var accounts []Account var validAccounts []string -const interval = time.Hour * 24 * 10 +const interval = time.Hour * 24 type Account struct { Email string `json:"username"` @@ -57,13 +57,13 @@ func AppendIfNone(slice []string, i string) []string { return append(slice, i) } -func getSecret() (string, string) { +func getSecret() (string, tokens.Secret) { if len(validAccounts) != 0 { account := validAccounts[0] validAccounts = append(validAccounts[1:], account) - return ACCESS_TOKENS.GetSecret(account) + return account, ACCESS_TOKENS.GetSecret(account) } else { - return "", "" + return "", tokens.Secret{} } } @@ -79,6 +79,9 @@ func readAccounts() { for scanner.Scan() { // Split by : line := strings.Split(scanner.Text(), ":") + if len(line) < 2 { + continue + } // Create an account account := Account{ Email: line[0], @@ -145,7 +148,7 @@ func scheduleTokenPUID() { } } tokenProcess: - token, _ = ACCESS_TOKENS.GetSecret(account.Email) + token = ACCESS_TOKENS.GetSecret(account.Email).Token expireTime, err := getTokenExpire(token) nowTime := time.Now() if err != nil { diff --git a/conversion/requests/chatgpt/convert.go b/conversion/requests/chatgpt/convert.go index 0ea83a46..342f39e2 100644 --- a/conversion/requests/chatgpt/convert.go +++ b/conversion/requests/chatgpt/convert.go @@ -2,6 +2,7 @@ package chatgpt import ( "fmt" + "freechatgpt/internal/tokens" chatgpt_types "freechatgpt/typings/chatgpt" official_types "freechatgpt/typings/official" "strings" @@ -9,10 +10,10 @@ import ( arkose "github.com/xqdoo00o/funcaptcha" ) -func ConvertAPIRequest(api_request official_types.APIRequest, puid string, requireArk bool, dx string, proxy string) chatgpt_types.ChatGPTRequest { +func ConvertAPIRequest(api_request official_types.APIRequest, account string, secret *tokens.Secret, deviceId string, requireArk bool, dx string, proxy string) chatgpt_types.ChatGPTRequest { chatgpt_request := chatgpt_types.NewChatGPTRequest() var api_version int - if puid == "" { + if secret.PUID == "" { api_request.Model = "gpt-3.5" } if strings.HasPrefix(api_request.Model, "gpt-3.5") { @@ -20,14 +21,10 @@ func ConvertAPIRequest(api_request official_types.APIRequest, puid string, requi chatgpt_request.Model = "text-davinci-002-render-sha" } else if strings.HasPrefix(api_request.Model, "gpt-4") { api_version = 4 - chatgpt_request.Model = api_request.Model - // Cover some models like gpt-4-32k - if len(api_request.Model) >= 7 && api_request.Model[6] >= 48 && api_request.Model[6] <= 57 { - chatgpt_request.Model = "gpt-4" - } + chatgpt_request.Model = "gpt-4" } if requireArk { - token, err := arkose.GetOpenAIToken(api_version, puid, dx, proxy) + token, err := arkose.GetOpenAIToken(api_version, secret.PUID, dx, proxy) if err == nil { chatgpt_request.ArkoseToken = token } else { @@ -38,11 +35,12 @@ func ConvertAPIRequest(api_request official_types.APIRequest, puid string, requi chatgpt_request.PluginIDs = api_request.PluginIDs chatgpt_request.Model = "gpt-4-plugins" } + ifMultimodel := api_version == 4 for _, api_message := range api_request.Messages { if api_message.Role == "system" { api_message.Role = "critic" } - chatgpt_request.AddMessage(api_message.Role, api_message.Content.(string)) + chatgpt_request.AddMessage(api_message.Role, api_message.Content, ifMultimodel, account, secret, deviceId, proxy) } return chatgpt_request } diff --git a/conversion/response/chatgpt/convert.go b/conversion/response/chatgpt/convert.go index ce7b0244..477300fa 100644 --- a/conversion/response/chatgpt/convert.go +++ b/conversion/response/chatgpt/convert.go @@ -11,8 +11,8 @@ func ConvertToString(chatgpt_response *chatgpt_types.ChatGPTResponse, previous_t translated_response := official_types.NewChatCompletionChunk(strings.Replace(chatgpt_response.Message.Content.Parts[0].(string), previous_text.Text, "", 1)) if role { translated_response.Choices[0].Delta.Role = chatgpt_response.Message.Author.Role - } else if translated_response.Choices[0].Delta.Content == "" || (strings.HasPrefix(chatgpt_response.Message.Metadata.ModelSlug, "gpt-4") && translated_response.Choices[0].Delta.Content == "【") { - return translated_response.Choices[0].Delta.Content + } else if translated_response.Choices[0].Delta.Content == "" { + return "" } previous_text.Text = chatgpt_response.Message.Content.Parts[0].(string) return "data: " + translated_response.String() + "\n\n" diff --git a/go.mod b/go.mod index 3c4c419d..9beaf957 100644 --- a/go.mod +++ b/go.mod @@ -6,34 +6,36 @@ toolchain go1.22.0 require ( github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd - github.com/bogdanfinn/fhttp v0.5.24 - github.com/bogdanfinn/tls-client v1.6.1 - github.com/gin-contrib/cors v1.7.0 + github.com/bogdanfinn/fhttp v0.5.28 + github.com/bogdanfinn/tls-client v1.7.4 + github.com/gin-contrib/cors v1.7.1 github.com/gin-gonic/gin v1.9.1 - github.com/go-resty/resty/v2 v2.7.0 - github.com/google/generative-ai-go v0.8.0 + github.com/go-resty/resty/v2 v2.12.0 + github.com/google/generative-ai-go v0.11.0 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 github.com/joho/godotenv v1.5.1 - github.com/sashabaranov/go-openai v1.20.3 - github.com/tidwall/gjson v1.14.4 + github.com/sashabaranov/go-openai v1.21.0 + github.com/tidwall/gjson v1.17.1 github.com/xqdoo00o/OpenAIAuth v0.0.0-20240403091529-7ef147706fc4 github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c - github.com/zhu327/gemini-openai-proxy v0.0.0-20240314045503-f6afa6badbd2 - google.golang.org/api v0.169.0 - k8s.io/apimachinery v0.27.2 + github.com/zhu327/gemini-openai-proxy v0.0.0-20240328042054-d2c6c4cdff01 + golang.org/x/image v0.15.0 + google.golang.org/api v0.172.0 + k8s.io/apimachinery v0.29.3 ) require ( - cloud.google.com/go/ai v0.3.2 // indirect - cloud.google.com/go/compute v1.24.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/longrunning v0.5.5 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect - github.com/bogdanfinn/utls v1.5.16 // indirect - github.com/bytedance/sonic v1.11.2 // indirect + cloud.google.com/go v0.112.2 // indirect + cloud.google.com/go/ai v0.4.0 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/longrunning v0.5.6 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/bogdanfinn/utls v1.6.1 // indirect + github.com/bytedance/sonic v1.11.3 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect + github.com/cloudflare/circl v1.3.7 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -44,44 +46,45 @@ require ( github.com/go-playground/validator/v10 v10.19.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.1.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.1 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/quic-go/quic-go v0.42.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect + go.opentelemetry.io/otel v1.25.0 // indirect + go.opentelemetry.io/otel/metric v1.25.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/oauth2 v0.19.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect - google.golang.org/grpc v1.62.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect + google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index f90a998e..41da1e43 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,27 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/ai v0.3.2 h1:swTIKSDnWHfgdI1dUh1cXKbhGPnTYk+h61DdBhFny/s= -cloud.google.com/go/ai v0.3.2/go.mod h1:y4G84zVohpvriIkoFsaQiPhJZzL6LyQMduOWxFSjwvA= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= -cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go v0.112.2 h1:ZaGT6LiG7dBzi6zNOvVZwacaXlmf3lRqnC4DQzqyRQw= +cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= +cloud.google.com/go/ai v0.4.0 h1:hoF8+joXKfW2Ug7MKssoffXCVUSxUqMUJL0hJxVtO1Q= +cloud.google.com/go/ai v0.4.0/go.mod h1:iX72tmUodGXVDxRDCGUZEPiB9HaMeERXkOdgCkUi8sA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/longrunning v0.5.6 h1:xAe8+0YaWoCKr9t1+aWe+OeQgN/iJK1fEgZSXmjuEaE= +cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd h1:oIpfrRhD7Jus41dotbK+SQjWSFRnf1cLZUYCZpF/o/4= github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd/go.mod h1:0yO7neMeJLvKk/B/fq5votDY8rByrOPDubpvU+6saKo= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/bogdanfinn/fhttp v0.5.24 h1:OlyBKjvJp6a3TotN3wuj4mQHHRbfK7QUMrzCPOZGhRc= -github.com/bogdanfinn/fhttp v0.5.24/go.mod h1:brqi5woc5eSCVHdKYBV8aZLbO7HGqpwyDLeXW+fT18I= -github.com/bogdanfinn/tls-client v1.6.1 h1:GTIqQssFoIvLaDf4btoYRzDhUzudLqYD4axvfUCXl3I= -github.com/bogdanfinn/tls-client v1.6.1/go.mod h1:FtwQ3DndVZ0xAOO704v4iNAgbHOcEc5kPk9tjICTNQ0= -github.com/bogdanfinn/utls v1.5.16 h1:NhhWkegEcYETBMj9nvgO4lwvc6NcLH+znrXzO3gnw4M= -github.com/bogdanfinn/utls v1.5.16/go.mod h1:mHeRCi69cUiEyVBkKONB1cAbLjRcZnlJbGzttmiuK4o= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/bogdanfinn/fhttp v0.5.28 h1:G6thT8s8v6z1IuvXMUsX9QKy3ZHseTQTzxuIhSiaaAw= +github.com/bogdanfinn/fhttp v0.5.28/go.mod h1:oJiYPG3jQTKzk/VFmogH8jxjH5yiv2rrOH48Xso2lrE= +github.com/bogdanfinn/tls-client v1.7.4 h1:8cn2/egs0LmqA7RFgrQh9Ww074lyQkeMKmsYl9JluTQ= +github.com/bogdanfinn/tls-client v1.7.4/go.mod h1:pQwF0eqfL0gf0mu8hikvu6deZ3ijSPruJDzEKEnnXjU= +github.com/bogdanfinn/utls v1.6.1 h1:dKDYAcXEyFFJ3GaWaN89DEyjyRraD1qb4osdEK89ass= +github.com/bogdanfinn/utls v1.6.1/go.mod h1:VXIbRZaiY/wHZc6Hu+DZ4O2CgTzjhjCg/Ou3V4r/39Y= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A= -github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA= +github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= @@ -31,6 +31,8 @@ github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLI github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -44,8 +46,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= -github.com/gin-contrib/cors v1.7.0 h1:wZX2wuZ0o7rV2/1i7gb4Jn+gW7HBqaP91fizJkBUJOA= -github.com/gin-contrib/cors v1.7.0/go.mod h1:cI+h6iOAyxKRtUtC6iF/Si1KSFvGm/gK+kshxlCi8ro= +github.com/gin-contrib/cors v1.7.1 h1:s9SIppU/rk8enVvkzwiC2VK3UZ/0NNGsWfUKvV55rqs= +github.com/gin-contrib/cors v1.7.1/go.mod h1:n/Zj7B4xyrgk/cX1WCX2dkzFfaNm/xJb6oIUk7WTtps= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= @@ -63,8 +65,10 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA= +github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -81,22 +85,21 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/generative-ai-go v0.8.0 h1:sbpEC4rdjby19jehqmQ5pF0eXDTGHmNhXuNN+elfC5I= -github.com/google/generative-ai-go v0.8.0/go.mod h1:8fXQk4w+eyTzFokGGJrBFL0/xwXqm3QNhTqOWyX11zs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/generative-ai-go v0.11.0 h1:+wL9xu5jVIgJKC6NmZOxZsBYWDtIap7DGUZ1diQSSnk= +github.com/google/generative-ai-go v0.11.0/go.mod h1:RauvbBjc+AzW0b1LV0VSlxHI5n2i3dz8oJfjboOSiWQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -104,22 +107,22 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= -github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -131,35 +134,44 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= -github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= +github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/sashabaranov/go-openai v1.20.3 h1:JMhaSfE1mLznYIvlf8odxbyWGiFFGnQjyLw00I9R4fU= -github.com/sashabaranov/go-openai v1.20.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= +github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/sashabaranov/go-openai v1.21.0 h1:isAf3zPSD3VLd0pC2/2Q6ZyRK7jzPAaz+X3rjsviaYQ= +github.com/sashabaranov/go-openai v1.21.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc= github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -169,33 +181,40 @@ github.com/xqdoo00o/OpenAIAuth v0.0.0-20240403091529-7ef147706fc4/go.mod h1:XHxG github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c h1:nj17XsSTwprsZUDXLldOUZmqz7VlHsLCeXXFOE6Q+Mk= github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c/go.mod h1:7aCyoW5MHDUsoooMVLqKe0F7W9HMPUvDG3bXqw++8XA= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zhu327/gemini-openai-proxy v0.0.0-20240314045503-f6afa6badbd2 h1:jt7dpvsz47vZU1FbHUBQQjTnXUj99NidNL8nYZ+ySNg= -github.com/zhu327/gemini-openai-proxy v0.0.0-20240314045503-f6afa6badbd2/go.mod h1:tL/SICLAKUSC5+ew0OhiW+ifcC8sEzQD7nnqL0I+Rm0= +github.com/zhu327/gemini-openai-proxy v0.0.0-20240328042054-d2c6c4cdff01 h1:oTKr6NUPO0Q/8eUPf75hpZrUYfP8eQLHdVbLTWVuf/c= +github.com/zhu327/gemini-openai-proxy v0.0.0-20240328042054-d2c6c4cdff01/go.mod h1:np6NnsU7xC3JTdGlOAOvWSudER6P43EnDhEvYrEL1Vc= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= +golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= +golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -204,39 +223,49 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -248,30 +277,29 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= -google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= +google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk= +google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9 h1:4++qSzdWBUy9/2x8L5KZgwZw+mjJZ2yDSCGMVM0YzRs= -google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:PVreiBMirk8ypES6aw9d4p6iiBNSIfZEBqr3UGoAi2E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -281,8 +309,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -293,7 +319,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= -k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= +k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/handlers.go b/handlers.go index 8c21a848..bb74477f 100644 --- a/handlers.go +++ b/handlers.go @@ -19,6 +19,10 @@ import ( "github.com/google/uuid" ) +var ( + uuidNamespace = uuid.MustParse("12345678-1234-5678-1234-567812345678") +) + func passwordHandler(c *gin.Context) { // Get the password from the request (json) and update the password type password_struct struct { @@ -90,6 +94,10 @@ func simulateModel(c *gin.Context) { }, }) } + +func generateUUID(name string) string { + return uuid.NewSHA1(uuidNamespace, []byte(name)).String() +} func nightmare(c *gin.Context) { var original_request official_types.APIRequest if c.Request.ContentLength == 0 { @@ -118,17 +126,17 @@ func nightmare(c *gin.Context) { } if original_request.Model == "gemini-pro-vision" { - api.VisionProxyHandler(c) + api.ChatProxyHandler(c) return } authHeader := c.GetHeader("Authorization") - token, puid := getSecret() + account, secret := getSecret() if authHeader != "" { customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1) // Check if customAccessToken starts with sk- if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiI") { - token = customAccessToken + secret.Token = customAccessToken } } @@ -141,24 +149,29 @@ func nightmare(c *gin.Context) { proxies = append(proxies[1:], proxies[0]) } uid := uuid.NewString() - if token == "" { + var deviceId string + if account == "" { + deviceId = uid chatgpt.SetOAICookie(uid) + } else { + deviceId = generateUUID(account) + chatgpt.SetOAICookie(deviceId) } var err error var chat_require *chatgpt.ChatRequire var wg sync.WaitGroup - if token == "" { + if secret.Token == "" { wg.Add(1) } else { wg.Add(2) go func() { defer wg.Done() - err = chatgpt.InitWSConn(token, uid, proxy_url) + err = chatgpt.InitWSConn(secret.Token, deviceId, uid, proxy_url) }() } go func() { defer wg.Done() - chat_require = chatgpt.CheckRequire(token, puid, proxy_url) + chat_require = chatgpt.CheckRequire(&secret, deviceId, proxy_url) }() wg.Wait() if err != nil { @@ -170,9 +183,9 @@ func nightmare(c *gin.Context) { return } // Convert the chat request to a ChatGPT request - translated_request := chatgpt_request_converter.ConvertAPIRequest(original_request, puid, chat_require.Arkose.Required, chat_require.Arkose.DX, proxy_url) + translated_request := chatgpt_request_converter.ConvertAPIRequest(original_request, account, &secret, deviceId, chat_require.Arkose.Required, chat_require.Arkose.DX, proxy_url) - response, err := chatgpt.POSTconversation(translated_request, token, puid, chat_require.Token, proxy_url) + response, err := chatgpt.POSTconversation(translated_request, &secret, deviceId, chat_require.Token, proxy_url) if err != nil { c.JSON(500, gin.H{ "error": "error sending request", @@ -187,7 +200,7 @@ func nightmare(c *gin.Context) { for i := 3; i > 0; i-- { var continue_info *chatgpt.ContinueInfo var response_part string - response_part, continue_info = chatgpt.Handler(c, response, token, puid, uid, translated_request, original_request.Stream) + response_part, continue_info = chatgpt.Handler(c, response, &secret, deviceId, uid, translated_request, original_request.Stream) full_response += response_part if continue_info == nil { break @@ -198,9 +211,9 @@ func nightmare(c *gin.Context) { translated_request.ConversationID = continue_info.ConversationID translated_request.ParentMessageID = continue_info.ParentID if chat_require.Arkose.Required { - chatgpt_request_converter.RenewTokenForRequest(&translated_request, puid, chat_require.Arkose.DX, proxy_url) + chatgpt_request_converter.RenewTokenForRequest(&translated_request, secret.PUID, chat_require.Arkose.DX, proxy_url) } - response, err = chatgpt.POSTconversation(translated_request, token, puid, chat_require.Token, proxy_url) + response, err = chatgpt.POSTconversation(translated_request, &secret, deviceId, chat_require.Token, proxy_url) if err != nil { c.JSON(500, gin.H{ "error": "error sending request", @@ -220,5 +233,5 @@ func nightmare(c *gin.Context) { } else { c.String(200, "data: [DONE]\n\n") } - chatgpt.UnlockSpecConn(token, uid) + chatgpt.UnlockSpecConn(secret.Token, uid) } diff --git a/internal/chatgpt/request.go b/internal/chatgpt/request.go index b9791615..6f654fab 100644 --- a/internal/chatgpt/request.go +++ b/internal/chatgpt/request.go @@ -6,6 +6,7 @@ import ( "context" "encoding/base64" "encoding/json" + "freechatgpt/internal/tokens" "freechatgpt/typings" chatgpt_types "freechatgpt/typings/chatgpt" "io" @@ -49,13 +50,14 @@ var ( userAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" ) -func getWSURL(token string, retry int) (string, error) { +func getWSURL(token string, deviceId string, retry int) (string, error) { request, err := http.NewRequest(http.MethodPost, "https://chat.openai.com/backend-api/register-websocket", nil) if err != nil { return "", err } request.Header.Set("User-Agent", userAgent) request.Header.Set("Accept", "*/*") + request.Header.Set("Oai-Device-Id", deviceId) request.Header.Set("Oai-Language", "en-US") if token != "" { request.Header.Set("Authorization", "Bearer "+token) @@ -66,7 +68,7 @@ func getWSURL(token string, retry int) (string, error) { return "", err } time.Sleep(time.Second) // wait 1s to get ws url - return getWSURL(token, retry+1) + return getWSURL(token, deviceId, retry+1) } defer response.Body.Close() var WSSResp chatgpt_types.ChatGPTWSSResponse @@ -134,7 +136,7 @@ func UnlockSpecConn(token string, uuid string) { } } } -func InitWSConn(token string, uuid string, proxy string) error { +func InitWSConn(token string, deviceId string, uuid string, proxy string) error { connInfo := findAvailConn(token, uuid) conn := connInfo.conn isExpired := connInfo.expire.IsZero() || time.Now().After(connInfo.expire) @@ -147,7 +149,7 @@ func InitWSConn(token string, uuid string, proxy string) error { conn.Close() connInfo.conn = nil } - wssURL, err := getWSURL(token, 0) + wssURL, err := getWSURL(token, deviceId, 0) if err != nil { return err } @@ -179,7 +181,7 @@ func InitWSConn(token string, uuid string, proxy string) error { conn.Close() connInfo.conn = nil connInfo.lock = false - return InitWSConn(token, uuid, proxy) + return InitWSConn(token, deviceId, uuid, proxy) case context.DeadlineExceeded: return nil default: @@ -206,13 +208,13 @@ type ChatRequire struct { } `json:"arkose"` } -func CheckRequire(access_token string, puid string, proxy string) *ChatRequire { +func CheckRequire(secret *tokens.Secret, deviceId string, proxy string) *ChatRequire { if proxy != "" { client.SetProxy(proxy) } var body *bytes.Buffer var apiUrl string - if access_token == "" { + if secret.Token == "" { body = bytes.NewBuffer([]byte(`{}`)) apiUrl = "https://chat.openai.com/backend-anon/sentinel/chat-requirements" } else { @@ -223,14 +225,15 @@ func CheckRequire(access_token string, puid string, proxy string) *ChatRequire { if err != nil { return nil } - if puid != "" { - request.Header.Set("Cookie", "_puid="+puid+";") + if secret.PUID != "" { + request.Header.Set("Cookie", "_puid="+secret.PUID+";") } request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", userAgent) + request.Header.Set("Oai-Device-Id", deviceId) request.Header.Set("Oai-Language", "en-US") - if access_token != "" { - request.Header.Set("Authorization", "Bearer "+access_token) + if secret.Token != "" { + request.Header.Set("Authorization", "Bearer "+secret.Token) } response, err := client.Do(request) if err != nil { @@ -252,19 +255,20 @@ type urlAttr struct { Attribution string `json:"attribution"` } -func getURLAttribution(access_token string, puid string, url string) string { +func getURLAttribution(secret *tokens.Secret, deviceId string, url string) string { request, err := http.NewRequest(http.MethodPost, "https://chat.openai.com/backend-api/attributions", bytes.NewBuffer([]byte(`{"urls":["`+url+`"]}`))) if err != nil { return "" } - if puid != "" { - request.Header.Set("Cookie", "_puid="+puid+";") + if secret.PUID != "" { + request.Header.Set("Cookie", "_puid="+secret.PUID+";") } request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", userAgent) + request.Header.Set("Oai-Device-Id", deviceId) request.Header.Set("Oai-Language", "en-US") - if access_token != "" { - request.Header.Set("Authorization", "Bearer "+access_token) + if secret.Token != "" { + request.Header.Set("Authorization", "Bearer "+secret.Token) } if err != nil { return "" @@ -282,7 +286,7 @@ func getURLAttribution(access_token string, puid string, url string) string { return attr.Attribution } -func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, puid string, chat_token string, proxy string) (*http.Response, error) { +func POSTconversation(message chatgpt_types.ChatGPTRequest, secret *tokens.Secret, deviceId string, chat_token string, proxy string) (*http.Response, error) { if proxy != "" { client.SetProxy(proxy) } @@ -305,15 +309,16 @@ func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, return &http.Response{}, err } // Clear cookies - if puid == "" { - puid = os.Getenv("PUID") + if secret.PUID == "" { + secret.PUID = os.Getenv("PUID") } - if puid != "" { - request.Header.Set("Cookie", "_puid="+puid+";") + if secret.PUID != "" { + request.Header.Set("Cookie", "_puid="+secret.PUID+";") } request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", userAgent) request.Header.Set("Accept", "text/event-stream") + request.Header.Set("Oai-Device-Id", deviceId) request.Header.Set("Oai-Language", "en-US") if arkoseToken != "" { request.Header.Set("Openai-Sentinel-Arkose-Token", arkoseToken) @@ -321,8 +326,8 @@ func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, if chat_token != "" { request.Header.Set("Openai-Sentinel-Chat-Requirements-Token", chat_token) } - if access_token != "" { - request.Header.Set("Authorization", "Bearer "+access_token) + if secret.Token != "" { + request.Header.Set("Authorization", "Bearer "+secret.Token) } if err != nil { return &http.Response{}, err @@ -370,23 +375,25 @@ type fileInfo struct { Status string `json:"status"` } -func GetImageSource(wg *sync.WaitGroup, url string, prompt string, token string, puid string, idx int, imgSource []string) { +func GetImageSource(wg *sync.WaitGroup, url string, prompt string, secret *tokens.Secret, deviceId string, idx int, imgSource []string) { defer wg.Done() request, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return } - if puid == "" { - puid = os.Getenv("PUID") + if secret.PUID == "" { + secret.PUID = os.Getenv("PUID") } // Clear cookies - if puid != "" { - request.Header.Set("Cookie", "_puid="+puid+";") + if secret.PUID != "" { + request.Header.Set("Cookie", "_puid="+secret.PUID+";") } request.Header.Set("User-Agent", userAgent) request.Header.Set("Accept", "*/*") - if token != "" { - request.Header.Set("Authorization", "Bearer "+token) + request.Header.Set("Oai-Device-Id", deviceId) + request.Header.Set("Oai-Language", "en-US") + if secret.Token != "" { + request.Header.Set("Authorization", "Bearer "+secret.Token) } response, err := client.Do(request) if err != nil { @@ -401,7 +408,7 @@ func GetImageSource(wg *sync.WaitGroup, url string, prompt string, token string, imgSource[idx] = "[![image](" + file_info.DownloadURL + " \"" + prompt + "\")](" + file_info.DownloadURL + ")" } -func Handler(c *gin.Context, response *http.Response, token string, puid string, uuid string, translated_request chatgpt_types.ChatGPTRequest, stream bool) (string, *ContinueInfo) { +func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, deviceId string, uuid string, translated_request chatgpt_types.ChatGPTRequest, stream bool) (string, *ContinueInfo) { max_tokens := false // Create a bufio.Reader from the response body @@ -419,7 +426,6 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, var previous_text typings.StringStruct var original_response chatgpt_types.ChatGPTResponse var isRole = true - var waitSource = false var isEnd = false var imgSource []string var isWSS = false @@ -433,7 +439,7 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, if !strings.Contains(response.Header.Get("Content-Type"), "text/event-stream") { isWSS = true - connInfo = findSpecConn(token, uuid) + connInfo = findSpecConn(secret.Token, uuid) if connInfo.conn == nil { c.JSON(500, gin.H{"error": "No websocket connection"}) return "", nil @@ -529,6 +535,7 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, // Check if line starts with [DONE] if !strings.HasPrefix(line, "[DONE]") { // Parse the line as JSON + original_response.Message.ID = "" err = json.Unmarshal([]byte(line), &original_response) if err != nil { continue @@ -537,6 +544,9 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, c.JSON(500, gin.H{"error": original_response.Error}) return "", nil } + if original_response.Message.ID == "" { + continue + } if original_response.ConversationID != convId { if convId == "" { convId = original_response.ConversationID @@ -547,27 +557,17 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, if !(original_response.Message.Author.Role == "assistant" || (original_response.Message.Author.Role == "tool" && original_response.Message.Content.ContentType != "text")) || original_response.Message.Content.Parts == nil { continue } - if original_response.Message.Metadata.MessageType == "" { + if original_response.Message.Metadata.MessageType == "" || original_response.Message.Recipient != "all" { continue } if original_response.Message.Metadata.MessageType != "next" && original_response.Message.Metadata.MessageType != "continue" || !strings.HasSuffix(original_response.Message.Content.ContentType, "text") { continue } if original_response.Message.EndTurn != nil { - if waitSource { - waitSource = false - } isEnd = true } if len(original_response.Message.Metadata.Citations) != 0 { r := []rune(original_response.Message.Content.Parts[0].(string)) - if waitSource { - if string(r[len(r)-1:]) == "】" { - waitSource = false - } else { - continue - } - } offset := 0 for _, citation := range original_response.Message.Metadata.Citations { rl := len(r) @@ -575,22 +575,18 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, baseURL := u.Scheme + "://" + u.Host + "/" attr := urlAttrMap[baseURL] if attr == "" { - attr = getURLAttribution(token, puid, baseURL) + attr = getURLAttribution(secret, deviceId, baseURL) if attr != "" { urlAttrMap[baseURL] = attr } } - original_response.Message.Content.Parts[0] = string(r[:citation.StartIx+offset]) + " ([" + attr + "](" + citation.Metadata.URL + " \"" + citation.Metadata.Title + "\"))" + string(r[citation.EndIx+offset:]) + u.Fragment = "" + original_response.Message.Content.Parts[0] = string(r[:citation.StartIx+offset]) + " ([" + attr + "](" + u.String() + " \"" + citation.Metadata.Title + "\"))" + string(r[citation.EndIx+offset:]) r = []rune(original_response.Message.Content.Parts[0].(string)) offset += len(r) - rl } - } else if waitSource { - continue } response_string := "" - if original_response.Message.Recipient != "all" { - continue - } if original_response.Message.Content.ContentType == "multimodal_text" { apiUrl := "https://chat.openai.com/backend-api/files/" if FILES_REVERSE_PROXY != "" { @@ -607,10 +603,10 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, } url := apiUrl + strings.Split(dalle_content.AssetPointer, "//")[1] + "/download" wg.Add(1) - go GetImageSource(&wg, url, dalle_content.Metadata.Dalle.Prompt, token, puid, index, imgSource) + go GetImageSource(&wg, url, dalle_content.Metadata.Dalle.Prompt, secret, deviceId, index, imgSource) } wg.Wait() - translated_response := official_types.NewChatCompletionChunk(strings.Join(imgSource, "")) + translated_response := official_types.NewChatCompletionChunk(strings.Join(imgSource, "") + "\n") if isRole { translated_response.Choices[0].Delta.Role = original_response.Message.Author.Role } @@ -626,10 +622,6 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, continue } } - if response_string == "【" { - waitSource = true - continue - } isRole = false if stream { _, err = c.Writer.WriteString(response_string) @@ -657,9 +649,9 @@ func Handler(c *gin.Context, response *http.Response, token string, puid string, } } if !max_tokens { - return strings.Join(imgSource, "") + previous_text.Text, nil + return strings.Join(imgSource, "") + "\n" + previous_text.Text, nil } - return strings.Join(imgSource, "") + previous_text.Text, &ContinueInfo{ + return strings.Join(imgSource, "") + "\n" + previous_text.Text, &ContinueInfo{ ConversationID: original_response.ConversationID, ParentID: original_response.Message.ID, } diff --git a/internal/gemini/api/handler.go b/internal/gemini/api/handler.go index dd2fa12d..25792f74 100644 --- a/internal/gemini/api/handler.go +++ b/internal/gemini/api/handler.go @@ -1,27 +1,20 @@ package api import ( - "bytes" "encoding/json" "errors" - "fmt" "io" "log" "math/rand" "net/http" "os" - "strings" "time" "github.com/gin-gonic/gin" "github.com/google/generative-ai-go/genai" openai "github.com/sashabaranov/go-openai" "github.com/zhu327/gemini-openai-proxy/pkg/adapter" - "google.golang.org/api/iterator" "google.golang.org/api/option" - - "freechatgpt/internal/gemini/pkg/protocol" - "freechatgpt/internal/gemini/pkg/util" ) func IndexHandler(c *gin.Context) { @@ -67,7 +60,8 @@ func ChatProxyHandler(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve API key from gemini-api-key.json file"}) return } - var req = &adapter.ChatCompletionRequest{} + + req := &adapter.ChatCompletionRequest{} // Bind the JSON data from the request to the struct if err := c.ShouldBindJSON(req); err != nil { c.JSON(http.StatusBadRequest, openai.APIError{ @@ -77,6 +71,23 @@ func ChatProxyHandler(c *gin.Context) { return } + // Model change logic based on the incoming model + switch req.Model { + case "gemini-pro": + req.Model = "gpt-3.5-turbo" + case "gemini-pro-vision": + req.Model = "gpt-4-vision-preview" + } + + messages, err := req.ToGenaiMessages() + if err != nil { + c.JSON(http.StatusBadRequest, openai.APIError{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + return + } + ctx := c.Request.Context() client, err := genai.NewClient(ctx, option.WithAPIKey(openaiAPIKey)) if err != nil { @@ -89,16 +100,11 @@ func ChatProxyHandler(c *gin.Context) { } defer client.Close() - var gemini adapter.GenaiModelAdapter - switch req.Model { - case openai.GPT4VisionPreview: - gemini = adapter.NewGeminiProVisionAdapter(client) - default: - gemini = adapter.NewGeminiProAdapter(client) - } + model := req.ToGenaiModel() + gemini := adapter.NewGeminiAdapter(client, model) if !req.Stream { - resp, err := gemini.GenerateContent(ctx, req) + resp, err := gemini.GenerateContent(ctx, req, messages) if err != nil { log.Printf("genai generate content error %v\n", err) c.JSON(http.StatusBadRequest, openai.APIError{ @@ -112,7 +118,7 @@ func ChatProxyHandler(c *gin.Context) { return } - dataChan, err := gemini.GenerateStreamContent(ctx, req) + dataChan, err := gemini.GenerateStreamContent(ctx, req, messages) if err != nil { log.Printf("genai generate content error %v\n", err) c.JSON(http.StatusBadRequest, openai.APIError{ @@ -170,134 +176,3 @@ func getRandomAPIKey() (string, error) { randomIndex := rng.Intn(len(keys)) return keys[randomIndex], nil } - -func VisionProxyHandler(c *gin.Context) { - openaiAPIKey, err := getRandomAPIKey() - if err != nil { - // Handle the error, for example, log it and return from the function - log.Printf("Error getting API key: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve API key from gemini-api-key.json file"}) - return - } - - println("use api key:" + openaiAPIKey) - - if openaiAPIKey == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "Api key not found!"}) - return - } - var req openai.ChatCompletionRequest - // Bind the JSON data from the request to the struct - if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - ctx := c.Request.Context() - client, err := genai.NewClient(ctx, option.WithAPIKey(openaiAPIKey)) - if err != nil { - log.Printf("new genai client error %v\n", err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - defer client.Close() - - texts := "" - image := []byte{} - for _, it := range req.Messages { - for _, ij := range it.MultiContent { - if strings.TrimSpace(ij.Text) != "" { - texts += ij.Text - continue - } - if ij.ImageURL == nil { - continue - } - link := strings.TrimSpace(ij.ImageURL.URL) - if link == "" { - continue - } - response, err := http.Get(link) - if err != nil { - log.Printf("new genai client error %v\n", err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - defer response.Body.Close() - buff := &bytes.Buffer{} - if _, err := io.Copy(buff, response.Body); err != nil { - log.Printf("new genai client error %v\n", err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - image = buff.Bytes() - } - } - - prompt := genai.Text(texts) - imageData := genai.ImageData("jpeg", image) - model := client.GenerativeModel(protocol.GeminiProVision) - protocol.SetGenaiModelByOpenaiRequest(model, req) - - cs := model.StartChat() - protocol.SetGenaiChatByOpenaiRequest(cs, req) - - if !req.Stream { - genaiResp, err := cs.SendMessage(ctx, prompt, imageData) - if err != nil { - log.Printf("genai send message error %v\n", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - openaiResp := protocol.GenaiResponseToOpenaiResponse(genaiResp) - c.JSON(http.StatusOK, openaiResp) - return - } - - iter := cs.SendMessageStream(ctx, prompt, imageData) - dataChan := make(chan string) - go func() { - defer close(dataChan) - - defer func() { - if r := recover(); r != nil { - log.Println("Recovered. Error:\n", r) - } - }() - - respID := util.GetUUID() - created := time.Now().Unix() - - for { - genaiResp, err := iter.Next() - if err == iterator.Done { - break - } - - if err != nil { - log.Printf("genai get stream message error %v\n", err) - dataChan <- fmt.Sprintf(`{"error": "%s"}`, err.Error()) - break - } - - openaiResp := protocol.GenaiResponseToStreamCompletionResponse(genaiResp, respID, created) - resp, _ := json.Marshal(openaiResp) - dataChan <- string(resp) - - if len(openaiResp.Choices) > 0 && openaiResp.Choices[0].FinishReason != nil { - break - } - } - }() - - setEventStreamHeaders(c) - c.Stream(func(w io.Writer) bool { - if data, ok := <-dataChan; ok { - c.Render(-1, protocol.Event{Data: "data: " + data}) - return true - } - c.Render(-1, protocol.Event{Data: "data: [DONE]"}) - return false - }) -} diff --git a/internal/tokens/tokens.go b/internal/tokens/tokens.go index 1cca6124..de7307fc 100644 --- a/internal/tokens/tokens.go +++ b/internal/tokens/tokens.go @@ -48,13 +48,12 @@ func (a *AccessToken) Save() bool { return err == nil } -func (a *AccessToken) GetSecret(account string) (string, string) { +func (a *AccessToken) GetSecret(account string) Secret { a.lock.Lock() defer a.lock.Unlock() if len(a.tokens) == 0 { - return "", "" + return Secret{} } - secret := a.tokens[account] - return secret.Token, secret.PUID + return a.tokens[account] } diff --git a/main.go b/main.go index 70052737..debe2cff 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,8 @@ import ( "os" "strings" + chatgpt_types "freechatgpt/typings/chatgpt" + "github.com/acheong08/endless" "github.com/gin-gonic/gin" "github.com/joho/godotenv" @@ -63,6 +65,7 @@ func init() { scheduleTokenPUID() } func main() { + defer chatgpt_types.SaveFileHash() router := gin.Default() router.Use(cors) diff --git a/typings/chatgpt/request.go b/typings/chatgpt/request.go index 9ff37b36..e50aba5b 100644 --- a/typings/chatgpt/request.go +++ b/typings/chatgpt/request.go @@ -1,25 +1,62 @@ package chatgpt import ( + "bytes" + "crypto/sha1" + "encoding/base64" + "encoding/hex" + "encoding/json" + "freechatgpt/internal/tokens" + "image" + "io" + "mime" + "net/url" "os" + "path" + "strconv" + "strings" + // 确保导入以下包以支持常见的图像格式 + _ "image/gif" + _ "image/jpeg" + _ "image/png" + + _ "golang.org/x/image/webp" + + http "github.com/bogdanfinn/fhttp" + + tls_client "github.com/bogdanfinn/tls-client" + "github.com/bogdanfinn/tls-client/profiles" "github.com/google/uuid" ) type chatgpt_message struct { - ID uuid.UUID `json:"id"` - Author chatgpt_author `json:"author"` - Content chatgpt_content `json:"content"` + ID uuid.UUID `json:"id"` + Author chatgpt_author `json:"author"` + Content chatgpt_content `json:"content"` + Metadata *Chatgpt_metadata `json:"metadata,omitempty"` +} + +type Chatgpt_metadata struct { + Attachments []ImgMeta `json:"attachments,omitempty"` } type chatgpt_content struct { - ContentType string `json:"content_type"` - Parts []string `json:"parts"` + ContentType string `json:"content_type"` + Parts []interface{} `json:"parts"` } type chatgpt_author struct { Role string `json:"role"` } +type Image_url struct { + Url string `json:"url"` +} +type Original_multimodel struct { + Type string `json:"type"` + Text string `json:"text,omitempty"` + Image Image_url `json:"image_url,omitempty"` +} type ChatGPTRequest struct { Action string `json:"action"` @@ -31,7 +68,153 @@ type ChatGPTRequest struct { ArkoseToken string `json:"arkose_token,omitempty"` PluginIDs []string `json:"plugin_ids,omitempty"` } +type FileResp struct { + File_id string `json:"file_id"` + Status string `json:"status"` + Upload_url string `json:"upload_url"` +} +type UploadResp struct { + Status string `json:"status"` + Download_url string `json:"download_url"` +} + +type FileResult struct { + Mime string + Filename string + Fileid string + Filesize int + Isimage bool + Bounds [2]int +} + +type ImgPart struct { + Asset_pointer string `json:"asset_pointer"` + Content_type string `json:"content_type"` + Size_bytes int `json:"size_bytes"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` +} + +type ImgMeta struct { + Id string `json:"id"` + MimeType string `json:"mimeType"` + Name string `json:"name"` + Size int `json:"size"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` +} +var ( + client, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), []tls_client.HttpClientOption{ + tls_client.WithCookieJar(tls_client.NewCookieJar()), + tls_client.WithTimeoutSeconds(600), + tls_client.WithClientProfile(profiles.Okhttp4Android13), + }...) + userAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" + fileHashPool = map[string]*FileResult{} +) + +func init() { + // from https://chromium.googlesource.com/chromium/src/+/HEAD/net/base/mime_util.cc + mimeMap := map[string]string{ + "webm": "video/webm", + "mp3": "audio/mpeg", + "wasm": "application/wasm", + "crx": "application/x-chrome-extension", + "xhtml,xht,xhtm": "application/xhtml+xml", + "flac": "audio/flac", + "ogg,oga,opus": "audio/ogg", + "wav": "audio/wav", + "m4a": "audio/x-m4a", + "avif": "image/avif", + "gif": "image/gif", + "jpeg,jpg": "image/jpeg", + "png": "image/png", + "png,apng": "image/apng", + "svg,svgz": "image/svg+xml", + "webp": "image/webp", + "mht,mhtml": "multipart/related", + "css": "text/css", + "html,htm,shtml,shtm": "text/html", + "js,mjs": "text/javascript", + "xml": "text/xml", + "mp4,m4v": "video/mp4", + "ogv,ogm": "video/ogg", + "csv": "text/csv", + "ico": "image/x-icon", + "epub": "application/epub+zip", + "woff": "application/font-woff", + "gz,tgz": "application/gzip", + "js": "application/javascript", + "json": "application/json", + "doc,dot": "application/msword", + "bin,exe,com": "application/octet-stream", + "pdf": "application/pdf", + "p7m,p7c,p7z": "application/pkcs7-mime", + "p7s": "application/pkcs7-signature", + "ps,eps,ai": "application/postscript", + "rdf": "application/rdf+xml", + "rss": "application/rss+xml", + "rtf": "application/rtf", + "apk": "application/vnd.android.package-archive", + "xul": "application/vnd.mozilla.xul+xml", + "xls": "application/vnd.ms-excel", + "ppt": "application/vnd.ms-powerpoint", + "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "m3u8": "application/x-mpegurl", + "swf,swl": "application/x-shockwave-flash", + "tar": "application/x-tar", + "cer,crt": "application/x-x509-ca-cert", + "zip": "application/zip", + "weba": "audio/webm", + "bmp": "image/bmp", + "jfif,pjpeg,pjp": "image/jpeg", + "tiff,tif": "image/tiff", + "xbm": "image/x-xbitmap", + "eml": "message/rfc822", + "ics": "text/calendar", + "ehtml": "text/html", + "txt,text": "text/plain", + "sh": "text/x-sh", + "xsl,xbl,xslt": "text/xml", + "mpeg,mpg": "video/mpeg", + } + for key, item := range mimeMap { + keyArr := strings.Split(key, ",") + if len(keyArr) == 1 { + mime.AddExtensionType("."+key, item) + } else { + for _, ext := range keyArr { + mime.AddExtensionType("."+ext, item) + } + } + } + file, err := os.Open("fileHashes.json") + if err != nil { + return + } + defer file.Close() + err = json.NewDecoder(file).Decode(&fileHashPool) + if err != nil { + return + } +} +func SaveFileHash() { + if len(fileHashPool) == 0 { + return + } + file, err := os.OpenFile("fileHashes.json", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return + } + defer file.Close() + err = json.NewEncoder(file).Encode(fileHashPool) + if err != nil { + return + } +} func NewChatGPTRequest() ChatGPTRequest { disable_history := os.Getenv("ENABLE_HISTORY") != "true" return ChatGPTRequest{ @@ -41,11 +224,232 @@ func NewChatGPTRequest() ChatGPTRequest { HistoryAndTrainingDisabled: disable_history, } } +func processUrl(urlstr string, account string, secret *tokens.Secret, deviceId string, proxy string) *FileResult { + if proxy != "" { + client.SetProxy(proxy) + } + u, err := url.Parse(urlstr) + if err != nil { + return nil + } + fileName := path.Base(u.Path) + extIndex := strings.Index(fileName, ".") + mimeType := mime.TypeByExtension(fileName[extIndex:]) + request, err := http.NewRequest(http.MethodGet, urlstr, nil) + if err != nil { + return nil + } + response, err := client.Do(request) + if err != nil { + return nil + } + defer response.Body.Close() + binary, err := io.ReadAll(response.Body) + if err != nil { + return nil + } + hasher := sha1.New() + hasher.Write(binary) + hash := account + hex.EncodeToString(hasher.Sum(nil)) + if fileHashPool[hash] != nil { + return fileHashPool[hash] + } + isImg := strings.HasPrefix(mimeType, "image") + var bounds [2]int + if isImg { + img, _, _ := image.Decode(bytes.NewReader(binary)) + if img != nil { + bounds[0] = img.Bounds().Dx() + bounds[1] = img.Bounds().Dy() + } + } + fileid := uploadBinary(binary, mimeType, fileName, isImg, secret, deviceId, proxy) + if fileid == "" { + return nil + } else { + result := FileResult{Mime: mimeType, Filename: fileName, Filesize: len(binary), Fileid: fileid, Isimage: isImg, Bounds: bounds} + fileHashPool[hash] = &result + return &result + } +} +func processDataUrl(data string, account string, secret *tokens.Secret, deviceId string, proxy string) *FileResult { + commaIndex := strings.Index(data, ",") + binary, err := base64.StdEncoding.DecodeString(data[commaIndex+1:]) + if err != nil { + return nil + } + hasher := sha1.New() + hasher.Write(binary) + hash := account + hex.EncodeToString(hasher.Sum(nil)) + if fileHashPool[hash] != nil { + return fileHashPool[hash] + } + startIdx := strings.Index(data, ":") + endIdx := strings.Index(data, ";") + mimeType := data[startIdx+1 : endIdx] + var fileName string + extensions, _ := mime.ExtensionsByType(mimeType) + if len(extensions) > 0 { + fileName = "file" + extensions[0] + } else { + index := strings.Index(mimeType, "/") + fileName = "file." + mimeType[index+1:] + } + isImg := strings.HasPrefix(mimeType, "image") + var bounds [2]int + if isImg { + img, _, _ := image.Decode(bytes.NewReader(binary)) + if img != nil { + bounds[0] = img.Bounds().Dx() + bounds[1] = img.Bounds().Dy() + } + } + fileid := uploadBinary(binary, mimeType, fileName, isImg, secret, deviceId, proxy) + if fileid == "" { + return nil + } else { + result := FileResult{Mime: mimeType, Filename: fileName, Filesize: len(binary), Fileid: fileid, Isimage: isImg, Bounds: bounds} + fileHashPool[hash] = &result + return &result + } +} +func uploadBinary(data []byte, mime string, name string, isImg bool, secret *tokens.Secret, deviceId string, proxy string) string { + if proxy != "" { + client.SetProxy(proxy) + } + var fileCase string + if isImg { + fileCase = "multimodal" + } else { + fileCase = "ace_upload" + } + dataLen := strconv.Itoa(len(data)) + request, err := http.NewRequest(http.MethodPost, "https://chat.openai.com/backend-api/files", bytes.NewBuffer([]byte(`{"file_name":"`+name+`","file_size":`+dataLen+`,"use_case":"`+fileCase+`"}`))) + if secret.PUID != "" { + request.Header.Set("Cookie", "_puid="+secret.PUID+";") + } + if secret.Token != "" { + request.Header.Set("Authorization", "Bearer "+secret.Token) + } + request.Header.Set("User-Agent", userAgent) + request.Header.Set("Accept", "*/*") + request.Header.Set("Oai-Device-Id", deviceId) + request.Header.Set("Oai-Language", "en-US") + if err != nil { + return "" + } + response, err := client.Do(request) + if err != nil { + return "" + } + defer response.Body.Close() + var fileResp FileResp + err = json.NewDecoder(response.Body).Decode(&fileResp) + if err != nil { + return "" + } + if fileResp.Status != "success" { + return "" + } + request, err = http.NewRequest(http.MethodPut, fileResp.Upload_url, bytes.NewReader(data)) + if err != nil { + return "" + } + request.Header.Set("X-Ms-Blob-Type", "BlockBlob") + request.Header.Set("X-Ms-Version", "2020-04-08") + response, err = client.Do(request) + if err != nil { + return "" + } + defer response.Body.Close() + if response.StatusCode != 201 { + return "" + } + request, err = http.NewRequest(http.MethodPost, "https://chat.openai.com/backend-api/files/"+fileResp.File_id+"/uploaded", bytes.NewBuffer([]byte(`{}`))) + if secret.PUID != "" { + request.Header.Set("Cookie", "_puid="+secret.PUID+";") + } + if secret.Token != "" { + request.Header.Set("Authorization", "Bearer "+secret.Token) + } + request.Header.Set("User-Agent", userAgent) + request.Header.Set("Accept", "*/*") + request.Header.Set("Oai-Device-Id", deviceId) + request.Header.Set("Oai-Language", "en-US") + if err != nil { + return "" + } + response, err = client.Do(request) + if err != nil { + return "" + } + defer response.Body.Close() + var uploadResp UploadResp + err = json.NewDecoder(response.Body).Decode(&uploadResp) + if err != nil { + return "" + } + return fileResp.File_id +} -func (c *ChatGPTRequest) AddMessage(role string, content string) { - c.Messages = append(c.Messages, chatgpt_message{ - ID: uuid.New(), - Author: chatgpt_author{Role: role}, - Content: chatgpt_content{ContentType: "text", Parts: []string{content}}, - }) +func (c *ChatGPTRequest) AddMessage(role string, content interface{}, multimodal bool, account string, secret *tokens.Secret, deviceId string, proxy string) { + parts := []interface{}{} + var result *FileResult + switch v := content.(type) { + case string: + parts = append(parts, v) + case []interface{}: + var items []Original_multimodel + for _, item := range v { + itemMap, ok := item.(map[string]interface{}) + if !ok { + continue + } + itemtype, _ := itemMap["type"].(string) + if itemtype == "text" { + text, _ := itemMap["text"].(string) + items = append(items, Original_multimodel{Type: itemtype, Text: text}) + } else { + imageMap, _ := itemMap["image_url"].(map[string]interface{}) + items = append(items, Original_multimodel{Type: itemtype, Image: Image_url{Url: imageMap["url"].(string)}}) + } + } + for _, item := range items { + if item.Type == "image_url" { + if !multimodal { + continue + } + data := item.Image.Url + if strings.HasPrefix(data, "data:") { + result = processDataUrl(data, account, secret, deviceId, proxy) + if result == nil { + continue + } + } else { + result = processUrl(data, account, secret, deviceId, proxy) + if result == nil { + continue + } + } + if result.Isimage { + parts = append(parts, ImgPart{Asset_pointer: "file-service://" + result.Fileid, Content_type: "image_asset_pointer", Size_bytes: result.Filesize, Width: result.Bounds[0], Height: result.Bounds[1]}) + } + } else { + parts = append(parts, item.Text) + } + } + } + var msg = chatgpt_message{ + ID: uuid.New(), + Author: chatgpt_author{Role: role}, + Content: chatgpt_content{ContentType: "text", Parts: parts}, + Metadata: nil, + } + if result != nil { + if result.Isimage { + msg.Content.ContentType = "multimodal_text" + } + msg.Metadata = &Chatgpt_metadata{Attachments: []ImgMeta{{Id: result.Fileid, Name: result.Filename, Size: result.Filesize, MimeType: result.Mime, Width: result.Bounds[0], Height: result.Bounds[1]}}} + } + c.Messages = append(c.Messages, msg) }