Niansuh commited on
Commit
7d06702
·
verified ·
1 Parent(s): 7993f4b

Upload 19 files

Browse files
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .idea/
2
+ .env
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM golang:1.21 AS builder
2
+
3
+ WORKDIR /app
4
+
5
+ COPY go.mod go.sum ./
6
+
7
+ RUN go mod download
8
+
9
+ COPY . .
10
+
11
+ RUN CGO_ENABLED=0 go build -o /app/free-chat-to-api .
12
+
13
+ FROM alpine:latest
14
+
15
+ WORKDIR /app
16
+
17
+ COPY --from=builder /app/free-chat-to-api /app/free-chat-to-api
18
+
19
+ EXPOSE 8484
20
+
21
+ CMD [ "/app/free-chat-to-api" ]
chat/api.go ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package chat
2
+
3
+ import (
4
+ "encoding/json"
5
+ "errors"
6
+ "fmt"
7
+ "github.com/gin-gonic/gin"
8
+ "github.com/google/uuid"
9
+ "github.com/launchdarkly/eventsource"
10
+ "github.com/zbronya/free-chat-to-api/config"
11
+ "github.com/zbronya/free-chat-to-api/httpclient"
12
+ "github.com/zbronya/free-chat-to-api/logger"
13
+ "github.com/zbronya/free-chat-to-api/model"
14
+ "github.com/zbronya/free-chat-to-api/model/request"
15
+ "github.com/zbronya/free-chat-to-api/model/response"
16
+ "github.com/zbronya/free-chat-to-api/proofofwork"
17
+ "github.com/zbronya/free-chat-to-api/utils"
18
+ "io"
19
+ "net/http"
20
+ "strings"
21
+ "time"
22
+ )
23
+
24
+ func Completions(c *gin.Context) {
25
+ req := &request.ChatRequest{}
26
+ err := c.BindJSON(req)
27
+ if err != nil {
28
+ utils.ErrorResp(c, http.StatusBadRequest, "Invalid parameter", nil)
29
+ return
30
+ }
31
+
32
+ ua := "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
33
+ client := httpclient.NewReqClient()
34
+ pConfig := proofofwork.GetConfig(ua)
35
+ chatRequirementReq := proofofwork.GetChatRequirementReq(pConfig)
36
+ deviceId := uuid.NewString()
37
+
38
+ requirement, err := getChatRequirement(c, client, chatRequirementReq, ua, deviceId)
39
+ if err != nil {
40
+ return
41
+ }
42
+
43
+ if requirement.ForceLogin {
44
+ utils.ErrorResp(c, http.StatusForbidden, "force login", nil)
45
+ return
46
+ }
47
+
48
+ token := "gAAAAAB" + proofofwork.CalcProofToken(pConfig, requirement.Proof.Seed, requirement.Proof.Difficulty)
49
+
50
+ doConversation(c, client, req, requirement, ua, deviceId, token)
51
+ }
52
+
53
+ func doConversation(c *gin.Context, client *httpclient.ReqClient, req *request.ChatRequest, requirement *model.ChatRequirementRes, ua string, deviceId string, token string) {
54
+ completionReq := model.ApiReqToChatReq(req)
55
+ url := config.GatewayUrl + "/backend-anon/conversation"
56
+
57
+ header := map[string]string{
58
+ "Accept": "text/event-stream",
59
+ "Accept-Encoding": "gzip, deflate, br",
60
+ "Accept-Language": "en-US,en;q=0.9",
61
+ "Content-Type": "application/json",
62
+ "Oai-Device-Id": deviceId,
63
+ "Oai-Language": "en-US",
64
+ "Openai-Sentinel-Chat-Requirements-Token": requirement.Token,
65
+ "Openai-Sentinel-Proof-Token": token,
66
+ "Origin": "https://chatgpt.com",
67
+ "Priority": "u=1, i",
68
+ "Referer": "https://chatgpt.com/?oai-dm=1",
69
+ "User-Agent": ua,
70
+ "Cookie": "__Secure-next-auth.callback-url=https%3A%2F%2Fchatgpt.com;",
71
+ }
72
+
73
+ j, _ := json.Marshal(completionReq)
74
+
75
+ resp, err := client.Post(url, header, j)
76
+
77
+ if err != nil {
78
+ utils.ErrorResp(c, http.StatusInternalServerError, "fail to completions", nil)
79
+ return
80
+ }
81
+
82
+ if resp.StatusCode != 200 {
83
+ body, _ := io.ReadAll(resp.Body)
84
+ utils.ErrorResp(c, resp.StatusCode, string(body), nil)
85
+ return
86
+ }
87
+
88
+ if req.Stream {
89
+ conversationStream(c, req, resp)
90
+ } else {
91
+ conversation(c, req, resp)
92
+ }
93
+
94
+ }
95
+
96
+ func getChatRequirement(c *gin.Context, client httpclient.HttpClient, req model.ChatRequirementReq, ua string, deviceId string) (*model.ChatRequirementRes, error) {
97
+ url := config.GatewayUrl + "/backend-anon/sentinel/chat-requirements"
98
+ header := map[string]string{
99
+ "Accept": "*/*",
100
+ "Accept-Language": "en-US,en;q=0.9",
101
+ "Content-Type": "application/json",
102
+ "Oai-Device-Id": deviceId,
103
+ "Oai-Language": "en-US",
104
+ "Origin": "https://chatgpt.com",
105
+ "Referer": "https://chatgpt.com/?oai-dm=1",
106
+ "User-Agent": ua,
107
+ }
108
+
109
+ j, _ := json.Marshal(req)
110
+
111
+ resp, err := client.Post(url, header, j)
112
+ if err != nil {
113
+ utils.ErrorResp(c, http.StatusInternalServerError, "fail to get chat requirements", nil)
114
+ return nil, err
115
+ }
116
+
117
+ if resp.StatusCode != 200 {
118
+ body, _ := io.ReadAll(resp.Body)
119
+ utils.ErrorResp(c, resp.StatusCode, string(body), nil)
120
+ return nil, errors.New("fail to get chat requirements")
121
+ }
122
+
123
+ defer resp.Body.Close()
124
+
125
+ var chatRequirementRes model.ChatRequirementRes
126
+
127
+ err = json.NewDecoder(resp.Body).Decode(&chatRequirementRes)
128
+ return &chatRequirementRes, err
129
+ }
130
+
131
+ func conversationStream(c *gin.Context, req *request.ChatRequest, resp *http.Response) {
132
+ messageTemp := ""
133
+ decoder := eventsource.NewDecoder(resp.Body)
134
+ defer func(decoder *eventsource.Decoder) {
135
+ _, _ = decoder.Decode()
136
+ }(decoder)
137
+ id := utils.GenerateID(29)
138
+ handlingSigns := false
139
+ for {
140
+ event, err := decoder.Decode()
141
+ if err != nil {
142
+ logger.GetLogger().Error(err.Error())
143
+ utils.ErrorResp(c, http.StatusInternalServerError, "", nil)
144
+ break
145
+ }
146
+ name := event.Event()
147
+ data := event.Data()
148
+ if data == "" {
149
+ continue
150
+ }
151
+ if data == "[DONE]" {
152
+ result := &response.Stream{}
153
+ result.ID = id
154
+ result.Created = time.Now().Unix()
155
+ result.Object = "chat.completion.chunk"
156
+ delta := response.StreamDelta{
157
+ Content: "",
158
+ }
159
+ choices := response.StreamChoice{
160
+ Delta: delta,
161
+ FinishReason: "stop",
162
+ }
163
+ result.Choices = append(result.Choices, choices)
164
+ result.Model = req.Model
165
+ bytes, err := json.Marshal(result)
166
+ if err != nil {
167
+ logger.GetLogger().Error(err.Error())
168
+ continue
169
+ }
170
+ c.SSEvent(name, fmt.Sprint(" ", string(bytes)))
171
+ c.SSEvent(name, " [DONE]")
172
+ break
173
+ }
174
+ chatResp := &model.ChatCompletionResp{}
175
+ err = json.Unmarshal([]byte(data), chatResp)
176
+ if chatResp.Error != nil && !handlingSigns {
177
+ logger.GetLogger().Error(fmt.Sprint(chatResp.Error))
178
+ utils.ErrorResp(c, http.StatusInternalServerError, "", nil)
179
+ return
180
+ }
181
+ if err != nil {
182
+ continue
183
+ }
184
+
185
+ if chatResp.Message.Author.Role == "assistant" && (chatResp.Message.Status == "in_progress" || handlingSigns) {
186
+ handlingSigns = true
187
+ parts := chatResp.Message.Content.Parts[0]
188
+ content := strings.Replace(parts, messageTemp, "", 1)
189
+ messageTemp = parts
190
+ if content == "" {
191
+ continue
192
+ }
193
+ apiResp := &response.Stream{}
194
+ apiResp.ID = id
195
+ apiResp.Created = time.Now().Unix()
196
+ apiResp.Object = "chat.completion.chunk"
197
+ delta := response.StreamDelta{
198
+ Content: content,
199
+ }
200
+ choices := response.StreamChoice{
201
+ Delta: delta,
202
+ }
203
+ apiResp.Choices = append(apiResp.Choices, choices)
204
+ apiResp.Model = req.Model
205
+
206
+ bytes, err := json.Marshal(apiResp)
207
+ if err != nil {
208
+ logger.GetLogger().Error(err.Error())
209
+ continue
210
+ }
211
+ c.SSEvent(name, fmt.Sprint(" ", string(bytes)))
212
+ continue
213
+ }
214
+ }
215
+ }
216
+
217
+ func conversation(c *gin.Context, req *request.ChatRequest, resp *http.Response) {
218
+ content := ""
219
+ decoder := eventsource.NewDecoder(resp.Body)
220
+ defer func(decoder *eventsource.Decoder) {
221
+ _, _ = decoder.Decode()
222
+ }(decoder)
223
+
224
+ handlingSigns := false
225
+ for {
226
+ event, err := decoder.Decode()
227
+ if err != nil {
228
+ logger.GetLogger().Error(err.Error())
229
+ utils.ErrorResp(c, http.StatusInternalServerError, "", nil)
230
+ break
231
+ }
232
+ data := event.Data()
233
+ if data == "" {
234
+ continue
235
+ }
236
+ if data == "[DONE]" {
237
+ result := &response.ChatResponse{}
238
+ result.ID = utils.GenerateID(29)
239
+ result.Created = time.Now().Unix()
240
+ result.Object = "chat.completion"
241
+ result.Model = req.Model
242
+ usage := response.Usage{
243
+ PromptTokens: 0,
244
+ CompletionTokens: 0,
245
+ TotalTokens: 0,
246
+ }
247
+ result.Usage = usage
248
+ message := response.Message{
249
+ Role: "assistant",
250
+ Content: content,
251
+ }
252
+ choice := response.Choice{
253
+ Message: message,
254
+ FinishReason: "stop",
255
+ Index: 0,
256
+ }
257
+ result.Choices = append(result.Choices, choice)
258
+ c.JSON(http.StatusOK, result)
259
+ break
260
+ }
261
+
262
+ chatResp := &model.ChatCompletionResp{}
263
+ err = json.Unmarshal([]byte(data), chatResp)
264
+ if chatResp.Error != nil && !handlingSigns {
265
+ logger.GetLogger().Error(fmt.Sprint(chatResp.Error))
266
+ utils.ErrorResp(c, http.StatusInternalServerError, "", nil)
267
+ return
268
+ }
269
+ if err != nil {
270
+ continue
271
+ }
272
+
273
+ if chatResp.Message.Author.Role == "assistant" && (chatResp.Message.Status == "in_progress" || handlingSigns) {
274
+ handlingSigns = true
275
+ if !strings.Contains(chatResp.Message.Content.Parts[0], content) {
276
+ continue
277
+ }
278
+ content = chatResp.Message.Content.Parts[0]
279
+ if content == "" {
280
+ continue
281
+ }
282
+ continue
283
+ }
284
+ }
285
+ }
chat/proxy.go ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package chat
2
+
3
+ import (
4
+ "github.com/gin-gonic/gin"
5
+ "github.com/zbronya/free-chat-to-api/httpclient"
6
+ "github.com/zbronya/free-chat-to-api/utils"
7
+ "io"
8
+ "net/url"
9
+ "strings"
10
+ )
11
+
12
+ var client = httpclient.NewReqClient()
13
+
14
+ var headersFilterList = map[string]bool{
15
+ "x-real-ip": true, "x-forwarded-for": true, "x-forwarded-proto": true,
16
+ "x-forwarded-port": true, "x-forwarded-host": true, "x-forwarded-server": true,
17
+ "cf-warp-tag-id": true, "cf-visitor": true, "cf-ray": true,
18
+ "cf-connecting-ip": true, "cf-ipcountry": true, "cdn-loop": true,
19
+ "remote-host": true, "x-frame-options": true, "x-xss-protection": true,
20
+ "x-content-type-options": true, "content-security-policy": true,
21
+ "host": true, "cookie": true, "connection": true,
22
+ "content-length": true, "content-encoding": true,
23
+ "x-middleware-prefetch": true, "x-nextjs-data": true, "purpose": true,
24
+ "x-forwarded-uri": true, "x-forwarded-path": true,
25
+ "x-forwarded-method": true, "x-forwarded-protocol": true,
26
+ "x-forwarded-scheme": true, "cf-request-id": true,
27
+ "cf-worker": true, "cf-access-client-id": true,
28
+ "cf-access-client-device-type": true, "cf-access-client-device-model": true,
29
+ "cf-access-client-device-name": true, "cf-access-client-device-brand": true,
30
+ }
31
+
32
+ func ReverseProxy(c *gin.Context) {
33
+ var targetURL, _ = url.Parse("https://chatgpt.com")
34
+ targetURL.Path = c.Request.URL.Path
35
+ targetURL.RawQuery = c.Request.URL.RawQuery
36
+
37
+ headers := make(map[string]string)
38
+ for k, v := range c.Request.Header {
39
+ if _, found := headersFilterList[strings.ToLower(k)]; !found {
40
+ headers[k] = v[0]
41
+ }
42
+ }
43
+
44
+ headers["Host"] = targetURL.Host
45
+
46
+ body, _ := io.ReadAll(c.Request.Body)
47
+ resp, err := client.Post(targetURL.String(), headers, body)
48
+
49
+ if err != nil {
50
+ utils.ErrorResp(c, 500, "fail to proxy", err)
51
+ return
52
+ }
53
+
54
+ for k, v := range resp.Header {
55
+ c.Writer.Header()[k] = v
56
+ }
57
+
58
+ c.Writer.WriteHeader(resp.StatusCode)
59
+ io.Copy(c.Writer, resp.Body)
60
+
61
+ }
config/config.go ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package config
2
+
3
+ import (
4
+ "github.com/joho/godotenv"
5
+ "os"
6
+ "strings"
7
+ )
8
+
9
+ var (
10
+ Bind string
11
+ Port string
12
+ ProxyUrl string
13
+ GatewayUrl string
14
+ )
15
+
16
+ func init() {
17
+ _ = godotenv.Load()
18
+ Bind = os.Getenv("BIND")
19
+ if Bind == "" {
20
+ Bind = "0.0.0.0"
21
+ }
22
+
23
+ Port = os.Getenv("PORT")
24
+ if Port == "" {
25
+ Port = "8484"
26
+ }
27
+
28
+ ProxyUrl = os.Getenv("PROXY_URL")
29
+
30
+ GatewayUrl = os.Getenv("GATEWAY_URL")
31
+ if GatewayUrl == "" {
32
+ GatewayUrl = "https://chatgpt.com"
33
+ } else {
34
+ GatewayUrl = strings.TrimRight(GatewayUrl, "/")
35
+ }
36
+ }
go.mod ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ module github.com/zbronya/free-chat-to-api
2
+
3
+ go 1.21
4
+
5
+ require (
6
+ github.com/gin-gonic/gin v1.9.1
7
+ github.com/google/uuid v1.6.0
8
+ github.com/imroc/req/v3 v3.43.3
9
+ github.com/joho/godotenv v1.5.1
10
+ github.com/launchdarkly/eventsource v1.7.1
11
+ github.com/sirupsen/logrus v1.9.3
12
+ golang.org/x/crypto v0.22.0
13
+ )
14
+
15
+ require (
16
+ github.com/andybalholm/brotli v1.1.0 // indirect
17
+ github.com/bytedance/sonic v1.9.1 // indirect
18
+ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
19
+ github.com/cloudflare/circl v1.3.8 // indirect
20
+ github.com/gabriel-vasile/mimetype v1.4.2 // indirect
21
+ github.com/gin-contrib/sse v0.1.0 // indirect
22
+ github.com/go-playground/locales v0.14.1 // indirect
23
+ github.com/go-playground/universal-translator v0.18.1 // indirect
24
+ github.com/go-playground/validator/v10 v10.14.0 // indirect
25
+ github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
26
+ github.com/goccy/go-json v0.10.2 // indirect
27
+ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
28
+ github.com/hashicorp/errwrap v1.1.0 // indirect
29
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
30
+ github.com/json-iterator/go v1.1.12 // indirect
31
+ github.com/klauspost/compress v1.17.8 // indirect
32
+ github.com/klauspost/cpuid/v2 v2.2.4 // indirect
33
+ github.com/kr/pretty v0.3.1 // indirect
34
+ github.com/leodido/go-urn v1.2.4 // indirect
35
+ github.com/mattn/go-isatty v0.0.19 // indirect
36
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
37
+ github.com/modern-go/reflect2 v1.0.2 // indirect
38
+ github.com/onsi/ginkgo/v2 v2.17.2 // indirect
39
+ github.com/pelletier/go-toml/v2 v2.0.8 // indirect
40
+ github.com/quic-go/qpack v0.4.0 // indirect
41
+ github.com/quic-go/quic-go v0.43.0 // indirect
42
+ github.com/refraction-networking/utls v1.6.3 // indirect
43
+ github.com/rogpeppe/go-internal v1.12.0 // indirect
44
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
45
+ github.com/ugorji/go/codec v1.2.11 // indirect
46
+ go.uber.org/mock v0.4.0 // indirect
47
+ golang.org/x/arch v0.3.0 // indirect
48
+ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
49
+ golang.org/x/mod v0.17.0 // indirect
50
+ golang.org/x/net v0.24.0 // indirect
51
+ golang.org/x/sys v0.19.0 // indirect
52
+ golang.org/x/text v0.14.0 // indirect
53
+ golang.org/x/tools v0.20.0 // indirect
54
+ google.golang.org/protobuf v1.33.0 // indirect
55
+ gopkg.in/yaml.v3 v3.0.1 // indirect
56
+ )
go.sum ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
2
+ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
3
+ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
4
+ github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
5
+ github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
6
+ github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
7
+ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
8
+ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
9
+ github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
10
+ github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
11
+ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
12
+ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
13
+ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
14
+ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
15
+ github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
16
+ github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
17
+ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
18
+ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
19
+ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
20
+ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
21
+ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
22
+ github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
23
+ github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
24
+ github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
25
+ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
26
+ github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
27
+ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
28
+ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
29
+ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
30
+ github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
31
+ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
32
+ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
33
+ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
34
+ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
35
+ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
36
+ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
37
+ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
38
+ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
39
+ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
40
+ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
41
+ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
42
+ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
43
+ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
44
+ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
45
+ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
46
+ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
47
+ github.com/imroc/req/v3 v3.43.3 h1:WdZhpUev9THtuwEZsW2LOYacl12fm7IkB7OgACv40+k=
48
+ github.com/imroc/req/v3 v3.43.3/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8ToyQc2xA=
49
+ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
50
+ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
51
+ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
52
+ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
53
+ github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
54
+ github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
55
+ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
56
+ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
57
+ github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
58
+ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
59
+ github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
60
+ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
61
+ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
62
+ github.com/launchdarkly/eventsource v1.7.1 h1:StoRQeiPyrcQIXjlQ7b5jWMzHW4p+GGczN2r2oBhujg=
63
+ github.com/launchdarkly/eventsource v1.7.1/go.mod h1:LHxSeb4OnqznNZxCSXbFghxS/CjIQfzHovNoAqbO/Wk=
64
+ github.com/launchdarkly/go-test-helpers/v2 v2.2.0 h1:L3kGILP/6ewikhzhdNkHy1b5y4zs50LueWenVF0sBbs=
65
+ github.com/launchdarkly/go-test-helpers/v2 v2.2.0/go.mod h1:L7+th5govYp5oKU9iN7To5PgznBuIjBPn+ejqKR0avw=
66
+ github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
67
+ github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
68
+ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
69
+ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
70
+ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
71
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
72
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
73
+ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
74
+ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
75
+ github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
76
+ github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
77
+ github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
78
+ github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
79
+ github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
80
+ github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
81
+ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
82
+ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
83
+ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
84
+ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
85
+ github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
86
+ github.com/quic-go/quic-go v0.43.0 h1:sjtsTKWX0dsHpuMJvLxGqoQdtgJnbAPWY+W+5vjYW/g=
87
+ github.com/quic-go/quic-go v0.43.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
88
+ github.com/refraction-networking/utls v1.6.3 h1:MFOfRN35sSx6K5AZNIoESsBuBxS2LCgRilRIdHb6fDc=
89
+ github.com/refraction-networking/utls v1.6.3/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs=
90
+ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
91
+ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
92
+ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
93
+ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
94
+ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
95
+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
96
+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
97
+ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
98
+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
99
+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
100
+ github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
101
+ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
102
+ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
103
+ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
104
+ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
105
+ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
106
+ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
107
+ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
108
+ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
109
+ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
110
+ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
111
+ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
112
+ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
113
+ go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
114
+ go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
115
+ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
116
+ golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
117
+ golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
118
+ golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
119
+ golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
120
+ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
121
+ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
122
+ golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
123
+ golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
124
+ golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
125
+ golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
126
+ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
127
+ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
128
+ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
129
+ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
130
+ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
131
+ golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
132
+ golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
133
+ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
134
+ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
135
+ golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
136
+ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
137
+ golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
138
+ golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
139
+ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
140
+ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
141
+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
142
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
143
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
144
+ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
145
+ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
146
+ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
147
+ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
148
+ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
149
+ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
httpclient/client.go ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ package httpclient
2
+
3
+ import "net/http"
4
+
5
+ type HttpClient interface {
6
+ Get(url string, headers map[string]string) (*http.Response, error)
7
+ Post(url string, headers map[string]string, body []byte) (*http.Response, error)
8
+ }
httpclient/reqclient.go ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package httpclient
2
+
3
+ import (
4
+ "github.com/imroc/req/v3"
5
+ "github.com/zbronya/free-chat-to-api/config"
6
+ "net/http"
7
+ )
8
+
9
+ type ReqClient struct {
10
+ client *req.Client
11
+ }
12
+
13
+ func NewReqClient() *ReqClient {
14
+ return &ReqClient{
15
+ client: req.C().
16
+ ImpersonateChrome().SetProxyURL(config.ProxyUrl),
17
+ }
18
+ }
19
+
20
+ func (r *ReqClient) Get(url string, headers map[string]string) (*http.Response, error) {
21
+ resp, err := r.client.R().
22
+ SetHeaders(headers).
23
+ Get(url)
24
+
25
+ if err != nil {
26
+ return nil, err
27
+ }
28
+
29
+ return resp.Response, nil
30
+ }
31
+
32
+ func (r *ReqClient) Post(url string, headers map[string]string, body []byte) (*http.Response, error) {
33
+ resp, err := r.client.R().
34
+ SetHeaders(headers).
35
+ SetBody(body).
36
+ Post(url)
37
+
38
+ if err != nil {
39
+ return nil, err
40
+ }
41
+ return resp.Response, nil
42
+ }
logger/logger.go ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package logger
2
+
3
+ import (
4
+ "github.com/sirupsen/logrus"
5
+ "sync"
6
+ )
7
+
8
+ var (
9
+ once sync.Once
10
+ instance *LogrusLogger
11
+ )
12
+
13
+ type Logger interface {
14
+ Debug(args ...interface{})
15
+ Info(args ...interface{})
16
+ Warn(args ...interface{})
17
+ Error(args ...interface{})
18
+ }
19
+
20
+ type LogrusLogger struct {
21
+ *logrus.Logger
22
+ }
logger/logrus.go ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package logger
2
+
3
+ import (
4
+ "github.com/sirupsen/logrus"
5
+ "os"
6
+ )
7
+
8
+ func init() {
9
+ once.Do(func() {
10
+ l := logrus.New()
11
+ l.SetOutput(os.Stdout)
12
+ l.SetLevel(logrus.DebugLevel)
13
+ l.SetFormatter(&logrus.TextFormatter{
14
+ FullTimestamp: true,
15
+ })
16
+
17
+ instance = &LogrusLogger{
18
+ Logger: l,
19
+ }
20
+ })
21
+ }
22
+
23
+ func GetLogger() Logger {
24
+ return instance
25
+ }
26
+
27
+ func (l *LogrusLogger) Debug(args ...interface{}) {
28
+ l.Logger.Debug(args...)
29
+ }
30
+
31
+ func (l *LogrusLogger) Info(args ...interface{}) {
32
+ l.Logger.Info(args...)
33
+ }
34
+
35
+ func (l *LogrusLogger) Warn(args ...interface{}) {
36
+ l.Logger.Warn(args...)
37
+ }
38
+
39
+ func (l *LogrusLogger) Error(args ...interface{}) {
40
+ l.Logger.Error(args...)
41
+ }
main.go ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "github.com/gin-gonic/gin"
6
+ "github.com/zbronya/free-chat-to-api/config"
7
+ "github.com/zbronya/free-chat-to-api/logger"
8
+ "github.com/zbronya/free-chat-to-api/router"
9
+ )
10
+
11
+ func main() {
12
+ gin.SetMode(gin.ReleaseMode)
13
+ g := gin.New()
14
+ g.Use(gin.Recovery())
15
+ router.InitRouter(g)
16
+ host := config.Bind
17
+ logger.GetLogger().Info(fmt.Sprint("Server started on http://", host, ":", config.Port))
18
+ _ = g.Run(fmt.Sprint(config.Bind, ":", config.Port))
19
+ }
model/model.go ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package model
2
+
3
+ import (
4
+ "github.com/google/uuid"
5
+ "github.com/zbronya/free-chat-to-api/model/request"
6
+ "github.com/zbronya/free-chat-to-api/utils"
7
+ )
8
+
9
+ type ChatRequirementReq struct {
10
+ P string `json:"p"`
11
+ }
12
+
13
+ type ProofWork struct {
14
+ Difficulty string `json:"difficulty"`
15
+ Required bool `json:"required"`
16
+ Seed string `json:"seed"`
17
+ }
18
+
19
+ type ChatRequirementRes struct {
20
+ Token string `json:"token"`
21
+ Proof ProofWork `json:"proofofwork"`
22
+ Arkose struct {
23
+ Required bool `json:"required"`
24
+ DX string `json:"dx"`
25
+ } `json:"arkose"`
26
+ ForceLogin bool `json:"force_login"`
27
+ }
28
+
29
+ type ChatAuthor struct {
30
+ Role string `json:"role"`
31
+ }
32
+
33
+ type ChatContent struct {
34
+ ContentType string `json:"content_type"`
35
+ Parts []string `json:"parts"`
36
+ }
37
+
38
+ type ChatMessages struct {
39
+ Author ChatAuthor `json:"author"`
40
+ Content ChatContent `json:"content"`
41
+ }
42
+
43
+ type ChatConversationMode struct {
44
+ Kind string `json:"kind"`
45
+ }
46
+
47
+ type ChatCompletionRequest struct {
48
+ Action string `json:"action"`
49
+ Messages []ChatMessages `json:"messages"`
50
+ ParentMessageId string `json:"parent_message_id"`
51
+ Model string `json:"model"`
52
+ TimeZoneOffsetMin int `json:"timezone_offset_min"`
53
+ Suggestions []string `json:"suggestions"`
54
+ HistoryAndTrainingDisabled bool `json:"history_and_training_disabled"`
55
+ ConversationMode ChatConversationMode `json:"conversation_mode"`
56
+ WebsocketRequestId string `json:"websocket_request_id"`
57
+ }
58
+
59
+ func ApiReqToChatReq(req *request.ChatRequest) (chatReq *ChatCompletionRequest) {
60
+ messages := make([]ChatMessages, 0)
61
+ for _, apiMessage := range req.Messages {
62
+ chatMessage := ChatMessages{
63
+ Author: ChatAuthor{
64
+ Role: apiMessage.Role,
65
+ },
66
+ Content: ChatContent{
67
+ ContentType: "text",
68
+ Parts: []string{apiMessage.Content},
69
+ },
70
+ }
71
+ messages = append(messages, chatMessage)
72
+ }
73
+
74
+ chatReq = &ChatCompletionRequest{
75
+ Action: "next",
76
+ Messages: messages,
77
+ ParentMessageId: uuid.New().String(),
78
+ Model: utils.MappingModel(req.Model),
79
+ TimeZoneOffsetMin: -180,
80
+ Suggestions: make([]string, 0),
81
+ HistoryAndTrainingDisabled: true,
82
+ ConversationMode: ChatConversationMode{
83
+ Kind: "primary_assistant",
84
+ },
85
+ WebsocketRequestId: uuid.New().String(),
86
+ }
87
+ return chatReq
88
+ }
89
+
90
+ type ChatCompletionResp struct {
91
+ Message struct {
92
+ Id string `json:"id"`
93
+ Author struct {
94
+ Role string `json:"role"`
95
+ Name interface{} `json:"name"`
96
+ Metadata struct {
97
+ } `json:"metadata"`
98
+ } `json:"author"`
99
+ CreateTime float64 `json:"create_time"`
100
+ UpdateTime interface{} `json:"update_time"`
101
+ Content struct {
102
+ ContentType string `json:"content_type"`
103
+ Parts []string `json:"parts"`
104
+ } `json:"content"`
105
+ Status string `json:"status"`
106
+ EndTurn interface{} `json:"end_turn"`
107
+ Weight float64 `json:"weight"`
108
+ Metadata struct {
109
+ Citations []interface{} `json:"citations"`
110
+ GizmoId interface{} `json:"gizmo_id"`
111
+ MessageType string `json:"message_type"`
112
+ ModelSlug string `json:"model_slug"`
113
+ DefaultModelSlug string `json:"default_model_slug"`
114
+ Pad string `json:"pad"`
115
+ ParentId string `json:"parent_id"`
116
+ } `json:"metadata"`
117
+ Recipient string `json:"recipient"`
118
+ } `json:"message"`
119
+ ConversationId string `json:"conversation_id"`
120
+ Error interface{} `json:"error"`
121
+ }
model/request/request.go ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package request
2
+
3
+ type ChatMessage struct {
4
+ Role string `json:"role"`
5
+ Content string `json:"content"`
6
+ }
7
+
8
+ type ChatRequest struct {
9
+ Messages []ChatMessage `json:"messages"`
10
+ Model string `json:"model"`
11
+ Stream bool `json:"stream"`
12
+ }
model/response/response.go ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package response
2
+
3
+ type ChatResponse struct {
4
+ ID string `json:"id"`
5
+ Object string `json:"object"`
6
+ Created int64 `json:"created"`
7
+ Model string `json:"model"`
8
+ Usage Usage `json:"usage"`
9
+ Choices []Choice `json:"choices"`
10
+ }
11
+
12
+ type Message struct {
13
+ Role string `json:"role"`
14
+ Content string `json:"content"`
15
+ }
16
+
17
+ type Choice struct {
18
+ Message Message `json:"message"`
19
+ FinishReason string `json:"finish_reason"`
20
+ Index int `json:"index"`
21
+ }
22
+
23
+ type Usage struct {
24
+ PromptTokens int `json:"prompt_tokens"`
25
+ CompletionTokens int `json:"completion_tokens"`
26
+ TotalTokens int `json:"total_tokens"`
27
+ }
model/response/stream.go ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package response
2
+
3
+ type Stream struct {
4
+ ID string `json:"id"`
5
+ Object string `json:"object"`
6
+ Created int64 `json:"created"`
7
+ Model string `json:"model"`
8
+ Choices []StreamChoice `json:"choices"`
9
+ }
10
+
11
+ type StreamChoice struct {
12
+ Delta StreamDelta `json:"delta"`
13
+ Index int `json:"index"`
14
+ FinishReason string `json:"finish_reason"`
15
+ }
16
+
17
+ type StreamDelta struct {
18
+ Content string `json:"content"`
19
+ }
proofofwork/proofofwork.go ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package proofofwork
2
+
3
+ import (
4
+ "encoding/base64"
5
+ "encoding/hex"
6
+ "encoding/json"
7
+ "github.com/google/uuid"
8
+ "github.com/zbronya/free-chat-to-api/model"
9
+ "golang.org/x/crypto/sha3"
10
+ "math/rand"
11
+ "time"
12
+ _ "time/tzdata"
13
+ )
14
+
15
+ var (
16
+ cores = []int{1, 2, 4, 8}
17
+ screens = []int{3000, 4000, 6000}
18
+ script = "https://cdn.oaistatic.com/_next/static/chunks/2565-9cf19ba0b7d24a5d.js?dpl=4811fd1c94b550c8f03fcc863ee6c1a99940efc5"
19
+
20
+ dpl = "4811fd1c94b550c8f03fcc863ee6c1a99940efc5"
21
+
22
+ errorPrefix = "gAAAAABwQ8Lk5FbGpA2NcR9dShT6gYjU7VxZ4D"
23
+ )
24
+
25
+ func getParseTime() string {
26
+ loc, _ := time.LoadLocation("America/Los_Angeles")
27
+ now := time.Now().In(loc)
28
+ return now.Format("Mon Jan 02 2006 15:04:05") + " GMT-0800 (Pacific Time)"
29
+ }
30
+
31
+ func GetConfig(ua string) []interface{} {
32
+ rand.New(rand.NewSource(time.Now().UnixNano()))
33
+ core := cores[rand.Intn(4)]
34
+ rand.New(rand.NewSource(time.Now().UnixNano()))
35
+ screen := screens[rand.Intn(3)]
36
+ rand.New(rand.NewSource(time.Now().UnixNano()))
37
+ return []interface{}{core + screen,
38
+ getParseTime(),
39
+ int64(4294705152),
40
+ 0,
41
+ ua,
42
+ script,
43
+ dpl,
44
+ "en-US",
45
+ "en-US,en",
46
+ 0,
47
+ "updateAdInterestGroups−function updateAdInterestGroups() { [native code] }",
48
+ "location",
49
+ "__NEXT_PRELOADREADY",
50
+ 885.6999999880791,
51
+ }
52
+ }
53
+
54
+ func GetChatRequirementReq(config []interface{}) model.ChatRequirementReq {
55
+ //randomFloat := rand.Float64()
56
+ //seed := fmt.Sprintf("%.6f", randomFloat)
57
+ //token := CalcProofToken(config, seed, "0")
58
+ return model.ChatRequirementReq{
59
+ P: "hello openai" + uuid.NewString(),
60
+ }
61
+
62
+ }
63
+
64
+ func CalcProofToken(config []interface{}, seed string, diff string) string {
65
+
66
+ diffLen := len(diff) / 2
67
+ hasher := sha3.New512()
68
+ startTime := time.Now()
69
+ for i := 0; i < 1000000; i++ {
70
+ config[3] = i
71
+ endTime := time.Now()
72
+ elapsed := endTime.Sub(startTime)
73
+ config[9] = elapsed.Milliseconds()
74
+ j, _ := json.Marshal(config)
75
+ base := base64.StdEncoding.EncodeToString(j)
76
+ hasher.Write([]byte(seed + base))
77
+ hash := hasher.Sum(nil)
78
+ hasher.Reset()
79
+ if hex.EncodeToString(hash[:diffLen]) <= diff {
80
+ return base
81
+ }
82
+ }
83
+ return errorPrefix + base64.StdEncoding.EncodeToString([]byte(`"`+seed+`"`))
84
+ }
router/router.go ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package router
2
+
3
+ import (
4
+ "fmt"
5
+ "github.com/gin-gonic/gin"
6
+ "github.com/zbronya/free-chat-to-api/chat"
7
+ "github.com/zbronya/free-chat-to-api/logger"
8
+ "net/http"
9
+ )
10
+
11
+ func Cors(c *gin.Context) {
12
+ c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
13
+ c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
14
+ c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
15
+ c.Writer.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept")
16
+ c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
17
+ if c.Request.Method == "OPTIONS" {
18
+ c.AbortWithStatus(204)
19
+ return
20
+ }
21
+ c.Next()
22
+ }
23
+
24
+ func RequestLogger(c *gin.Context) {
25
+ c.Next()
26
+
27
+ logger.GetLogger().Info(fmt.Sprintf("IP: %s, Method: %s, UserAgent: %s, URL: %s, Status: %d",
28
+ c.Request.RemoteAddr,
29
+ c.Request.Method,
30
+ c.Request.UserAgent(),
31
+ c.Request.URL.Path,
32
+ c.Writer.Status()))
33
+ }
34
+
35
+ func InitRouter(g *gin.Engine) {
36
+ g.GET("/", func(c *gin.Context) {
37
+ c.String(http.StatusOK,
38
+ "This is Free Chat To API Service \n"+
39
+ "https://github.com/zbronya/free-chat-to-api")
40
+ })
41
+
42
+ g.GET("/ping", func(c *gin.Context) {
43
+ c.JSON(200, gin.H{
44
+ "message": "pong",
45
+ })
46
+ })
47
+
48
+ g.Use(Cors)
49
+ g.Use(RequestLogger)
50
+ g.OPTIONS("/v1/chat/completions")
51
+ g.POST("/v1/chat/completions", chat.Completions)
52
+ g.POST("/backend-anon/sentinel/chat-requirements", chat.ReverseProxy)
53
+ g.POST("/backend-anon/conversation", chat.ReverseProxy)
54
+ }
utils/util.go ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package utils
2
+
3
+ import (
4
+ "github.com/gin-gonic/gin"
5
+ "math/rand"
6
+ )
7
+
8
+ func MappingModel(model string) string {
9
+ var modelMapping = map[string]string{
10
+ "gpt-3.5-turbo": "text-davinci-002-render-sha",
11
+ "gpt-3.5-turbo-16k": "text-davinci-002-render-sha",
12
+ "gpt-3.5-turbo-16k-0613": "text-davinci-002-render-sha",
13
+ "gpt-3.5-turbo-0301": "text-davinci-002-render-sha",
14
+ "gpt-3.5-turbo-0613": "text-davinci-002-render-sha",
15
+ "gpt-3.5-turbo-1106": "text-davinci-002-render-sha",
16
+ }
17
+ if model == "" {
18
+ return "text-davinci-002-render-sha"
19
+ }
20
+ if v, ok := modelMapping[model]; ok {
21
+ return v
22
+ }
23
+ return "text-davinci-002-render-sha"
24
+ }
25
+
26
+ func GenerateID(length int) string {
27
+ const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
28
+ id := "chatcmpl-"
29
+ for i := 0; i < length; i++ {
30
+ id += string(charset[rand.Intn(len(charset))])
31
+ }
32
+ return id
33
+ }
34
+
35
+ func ErrorResp(c *gin.Context, code int, msg interface{}, err interface{}) {
36
+ c.AbortWithStatusJSON(code, gin.H{
37
+ "code": code,
38
+ "msg": msg,
39
+ "error": err,
40
+ })
41
+ return
42
+ }