Niansuh commited on
Commit
a088f99
1 Parent(s): 24092aa

Update main.go

Browse files
Files changed (1) hide show
  1. main.go +80 -52
main.go CHANGED
@@ -5,19 +5,11 @@ import (
5
  "bytes"
6
  "encoding/json"
7
  "io"
8
- "log"
9
  "net/http"
10
- "time"
11
 
12
  "github.com/gin-gonic/gin"
13
  )
14
 
15
- const (
16
- statusURL = "https://duckduckgo.com/duckchat/v1/status"
17
- chatURL = "https://duckduckgo.com/duckchat/v1/chat"
18
- userAgent = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0"
19
- )
20
-
21
  type OpenAIRequest struct {
22
  Model string `json:"model"`
23
  Messages []struct {
@@ -74,58 +66,77 @@ func chatWithDuckDuckGo(c *gin.Context, messages []struct {
74
  Role string `json:"role"`
75
  Content string `json:"content"`
76
  }, stream bool) {
77
- client := &http.Client{Timeout: 10 * time.Second}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- // Get vqd_4
80
  req, err := http.NewRequest("GET", statusURL, nil)
81
  if err != nil {
82
- log.Println(err)
83
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request"})
84
  return
85
  }
 
86
  req.Header.Set("x-vqd-accept", "1")
87
- setHeaders(req, userAgent)
 
 
88
 
89
- resp, err := client.Do(req)
90
  if err != nil {
91
- log.Println(err)
92
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get vqd_4"})
93
  return
94
  }
95
  defer resp.Body.Close()
96
 
97
  vqd4 := resp.Header.Get("x-vqd-4")
98
 
99
- // Send chat request
100
  payload := map[string]interface{}{
101
  "model": "gpt-3.5-turbo-0125",
102
  "messages": messages,
103
  }
 
104
  payloadBytes, err := json.Marshal(payload)
105
  if err != nil {
106
- log.Println(err)
107
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal payload"})
108
  return
109
  }
110
 
111
  req, err = http.NewRequest("POST", chatURL, bytes.NewBuffer(payloadBytes))
112
  if err != nil {
113
- log.Println(err)
114
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request"})
115
  return
116
  }
 
117
  req.Header.Set("x-vqd-4", vqd4)
118
- setHeaders(req, userAgent)
 
 
119
 
120
- resp, err = client.Do(req)
121
  if err != nil {
122
- log.Println(err)
123
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send chat request"})
124
  return
125
  }
126
  defer resp.Body.Close()
127
 
128
- // Process response
129
  reader := bufio.NewReader(resp.Body)
130
  c.Header("Content-Type", "text/event-stream")
131
  c.Header("Cache-Control", "no-cache")
@@ -135,7 +146,9 @@ func chatWithDuckDuckGo(c *gin.Context, messages []struct {
135
  flusher, _ := c.Writer.(http.Flusher)
136
 
137
  var response OpenAIResponse
 
138
  response.Choices = make([]OpenAIChoice, 1)
 
139
 
140
  var responseContent string
141
 
@@ -153,12 +166,36 @@ func chatWithDuckDuckGo(c *gin.Context, messages []struct {
153
  chunk := line[6:]
154
 
155
  if bytes.HasPrefix(chunk, []byte("[DONE]")) {
156
- response.Choices[0].Delta.Content = responseContent
157
- response.Choices[0].Delta.Role = "assistant"
158
- response.Choices[0].FinishReason = new(string)
159
- *response.Choices[0].FinishReason = "stop"
160
- c.JSON(http.StatusOK, response)
161
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
 
164
  var data DuckDuckGoResponse
@@ -174,6 +211,10 @@ func chatWithDuckDuckGo(c *gin.Context, messages []struct {
174
  response.Object = "chat.completion"
175
  response.Created = data.Created
176
  response.Model = data.Model
 
 
 
 
177
  responseContent += data.Message
178
 
179
  if stream {
@@ -195,21 +236,8 @@ func chatWithDuckDuckGo(c *gin.Context, messages []struct {
195
  }
196
  }
197
 
198
- func setHeaders(req *http.Request, userAgent string) {
199
- req.Header.Set("User-Agent", userAgent)
200
- req.Header.Set("Accept", "text/event-stream")
201
- req.Header.Set("Accept-Language", "de,en-US;q=0.7,en;q=0.3")
202
- req.Header.Set("Accept-Encoding", "gzip, deflate, br")
203
- req.Header.Set("Referer", "https://duckduckgo.com/")
204
- req.Header.Set("Content-Type", "application/json")
205
- req.Header.Set("Origin", "https://duckduckgo.com")
206
- req.Header.Set("Connection", "keep-alive")
207
- req.Header.Set("Cookie", "dcm=1")
208
- req.Header.Set("Sec-Fetch-Dest", "empty")
209
- req.Header.Set("Sec-Fetch-Mode", "cors")
210
- req.Header.Set("Sec-Fetch-Site", "same-origin")
211
- req.Header.Set("Pragma", "no-cache")
212
- req.Header.Set("TE", "trailers")
213
  }
214
 
215
  func main() {
@@ -221,13 +249,13 @@ func main() {
221
  "message": "Hello! Thank you for using FreeDuckDuckGo. Made by Vincent Yang. Repo: https://github.com/missuo/FreeDuckDuckGo",
222
  })
223
  })
224
-
225
  r.OPTIONS("/v1/chat/completions", func(c *gin.Context) {
226
- c.Header("Access-Control-Allow-Origin", "*")
227
- c.Header("Access-Control-Allow-Methods", "POST, OPTIONS")
228
- c.Header("Access-Control-Allow-Headers", "Content-Type, Accept, Origin, X-Requested-With")
229
- c.Status(http.StatusOK)
230
  })
 
231
 
232
  r.POST("/v1/chat/completions", func(c *gin.Context) {
233
  var req OpenAIRequest
 
5
  "bytes"
6
  "encoding/json"
7
  "io"
 
8
  "net/http"
 
9
 
10
  "github.com/gin-gonic/gin"
11
  )
12
 
 
 
 
 
 
 
13
  type OpenAIRequest struct {
14
  Model string `json:"model"`
15
  Messages []struct {
 
66
  Role string `json:"role"`
67
  Content string `json:"content"`
68
  }, stream bool) {
69
+ userAgent := "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0"
70
+ headers := map[string]string{
71
+ "User-Agent": userAgent,
72
+ "Accept": "text/event-stream",
73
+ "Accept-Language": "de,en-US;q=0.7,en;q=0.3",
74
+ "Accept-Encoding": "gzip, deflate, br",
75
+ "Referer": "https://duckduckgo.com/",
76
+ "Content-Type": "application/json",
77
+ "Origin": "https://duckduckgo.com",
78
+ "Connection": "keep-alive",
79
+ "Cookie": "dcm=1",
80
+ "Sec-Fetch-Dest": "empty",
81
+ "Sec-Fetch-Mode": "cors",
82
+ "Sec-Fetch-Site": "same-origin",
83
+ "Pragma": "no-cache",
84
+ "TE": "trailers",
85
+ }
86
+
87
+ statusURL := "https://duckduckgo.com/duckchat/v1/status"
88
+ chatURL := "https://duckduckgo.com/duckchat/v1/chat"
89
 
90
+ // get vqd_4
91
  req, err := http.NewRequest("GET", statusURL, nil)
92
  if err != nil {
93
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
 
94
  return
95
  }
96
+
97
  req.Header.Set("x-vqd-accept", "1")
98
+ for key, value := range headers {
99
+ req.Header.Set(key, value)
100
+ }
101
 
102
+ resp, err := http.DefaultClient.Do(req)
103
  if err != nil {
104
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
 
105
  return
106
  }
107
  defer resp.Body.Close()
108
 
109
  vqd4 := resp.Header.Get("x-vqd-4")
110
 
 
111
  payload := map[string]interface{}{
112
  "model": "gpt-3.5-turbo-0125",
113
  "messages": messages,
114
  }
115
+
116
  payloadBytes, err := json.Marshal(payload)
117
  if err != nil {
118
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
 
119
  return
120
  }
121
 
122
  req, err = http.NewRequest("POST", chatURL, bytes.NewBuffer(payloadBytes))
123
  if err != nil {
124
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
 
125
  return
126
  }
127
+
128
  req.Header.Set("x-vqd-4", vqd4)
129
+ for key, value := range headers {
130
+ req.Header.Set(key, value)
131
+ }
132
 
133
+ resp, err = http.DefaultClient.Do(req)
134
  if err != nil {
135
+ c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
 
136
  return
137
  }
138
  defer resp.Body.Close()
139
 
 
140
  reader := bufio.NewReader(resp.Body)
141
  c.Header("Content-Type", "text/event-stream")
142
  c.Header("Cache-Control", "no-cache")
 
146
  flusher, _ := c.Writer.(http.Flusher)
147
 
148
  var response OpenAIResponse
149
+ var nonStreamResponse OpenAINonStreamResponse
150
  response.Choices = make([]OpenAIChoice, 1)
151
+ nonStreamResponse.Choices = make([]OpenAINonStreamChoice, 1)
152
 
153
  var responseContent string
154
 
 
166
  chunk := line[6:]
167
 
168
  if bytes.HasPrefix(chunk, []byte("[DONE]")) {
169
+ if !stream {
170
+ nonStreamResponse.Choices[0].Message.Content = responseContent
171
+ nonStreamResponse.Choices[0].Message.Role = "assistant"
172
+ nonStreamResponse.Choices[0].FinishReason = new(string)
173
+ *nonStreamResponse.Choices[0].FinishReason = "stop"
174
+ c.JSON(http.StatusOK, nonStreamResponse)
175
+ return
176
+ } else {
177
+ stopData := OpenAIResponse{
178
+ ID: "chatcmpl-9HOzx2PhnYCLPxQ3Dpa2OKoqR2lgl",
179
+ Object: "chat.completion",
180
+ Created: 1713934697,
181
+ Model: "gpt-3.5-turbo-0125",
182
+ Choices: []OpenAIChoice{
183
+ {
184
+ Index: 0,
185
+ FinishReason: stringPtr("stop"),
186
+ },
187
+ },
188
+ }
189
+ stopDataBytes, _ := json.Marshal(stopData)
190
+ c.Data(http.StatusOK, "application/json", []byte("data: "))
191
+ c.Data(http.StatusOK, "application/json", stopDataBytes)
192
+ c.Data(http.StatusOK, "application/json", []byte("\n\n"))
193
+ flusher.Flush()
194
+
195
+ c.Data(http.StatusOK, "application/json", []byte("data: [DONE]\n\n"))
196
+ flusher.Flush()
197
+ return
198
+ }
199
  }
200
 
201
  var data DuckDuckGoResponse
 
211
  response.Object = "chat.completion"
212
  response.Created = data.Created
213
  response.Model = data.Model
214
+ nonStreamResponse.ID = data.ID
215
+ nonStreamResponse.Object = "chat.completion"
216
+ nonStreamResponse.Created = data.Created
217
+ nonStreamResponse.Model = data.Model
218
  responseContent += data.Message
219
 
220
  if stream {
 
236
  }
237
  }
238
 
239
+ func stringPtr(s string) *string {
240
+ return &s
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  }
242
 
243
  func main() {
 
249
  "message": "Hello! Thank you for using FreeDuckDuckGo. Made by Vincent Yang. Repo: https://github.com/missuo/FreeDuckDuckGo",
250
  })
251
  })
252
+
253
  r.OPTIONS("/v1/chat/completions", func(c *gin.Context) {
254
+ c.JSON(http.StatusOK, gin.H{
255
+ "message": "ok",
256
+ })
 
257
  })
258
+
259
 
260
  r.POST("/v1/chat/completions", func(c *gin.Context) {
261
  var req OpenAIRequest