alcex commited on
Commit
efa5e41
·
verified ·
1 Parent(s): 0e5b89e

Create main.go

Browse files
Files changed (1) hide show
  1. main.go +332 -0
main.go ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package handler
2
+
3
+ import (
4
+ "bufio"
5
+ "bytes"
6
+ "encoding/json"
7
+ "fmt"
8
+ "io"
9
+ "net/http"
10
+ "os"
11
+ "strings"
12
+ "time"
13
+
14
+ "github.com/google/uuid"
15
+ )
16
+
17
+ var modelMapping = map[string]string{
18
+ "gpt-4o-mini": "GPT-4o mini",
19
+ "claude-haiku": "Claude Haiku",
20
+ "llama-3": "Llama 3",
21
+ "gemini-1.5": "Gemini 1.5",
22
+ "gemini-flash": "Gemini Flash",
23
+ "command-r": "Command R",
24
+ }
25
+
26
+ func getCurrentTimestamp() int64 {
27
+ return time.Now().Unix()
28
+ }
29
+
30
+ type OpenAIRequest struct {
31
+ Messages []Message `json:"messages"`
32
+ Model string `json:"model"`
33
+ Stream bool `json:"stream"`
34
+ }
35
+
36
+ type Message struct {
37
+ Role string `json:"role"`
38
+ Content string `json:"content"`
39
+ }
40
+
41
+ type OpenAIResponse struct {
42
+ Id string `json:"id"`
43
+ Object string `json:"object"`
44
+ Created int64 `json:"created"`
45
+ Model string `json:"model"`
46
+ Choices []Choice `json:"choices"`
47
+ }
48
+
49
+ type Choice struct {
50
+ Index int `json:"index"`
51
+ Message Message `json:"message"`
52
+ FinishReason string `json:"finish_reason"`
53
+ }
54
+
55
+ type ChatCompletionStreamResponse struct {
56
+ ID string `json:"id"`
57
+ Object string `json:"object"`
58
+ Created int64 `json:"created"`
59
+ Model string `json:"model"`
60
+ Choices []struct {
61
+ Delta struct {
62
+ Content string `json:"content"`
63
+ Role string `json:"role,omitempty"`
64
+ } `json:"delta"`
65
+ Index int `json:"index"`
66
+ FinishReason string `json:"finish_reason,omitempty"`
67
+ } `json:"choices"`
68
+ }
69
+
70
+ func Handler(w http.ResponseWriter, r *http.Request) {
71
+ authToken := os.Getenv("AUTH_TOKEN")
72
+ if authToken != "" {
73
+ requestToken := r.Header.Get("Authorization")
74
+ if requestToken == "" {
75
+ http.Error(w, "Access Denied", http.StatusUnauthorized)
76
+ return
77
+ }
78
+ requestToken = strings.TrimPrefix(requestToken, "Bearer ")
79
+ if requestToken != authToken {
80
+ http.Error(w, "Access Denied", http.StatusUnauthorized)
81
+ return
82
+ }
83
+ }
84
+
85
+ if r.URL.Path != "/v1/chat/completions" {
86
+ w.Header().Set("Content-Type", "application/json")
87
+ response := map[string]string{
88
+ "status": "Julius2Api Service Running...",
89
+ "message": "MoLoveSze...",
90
+ }
91
+ json.NewEncoder(w).Encode(response)
92
+ return
93
+ }
94
+
95
+ if r.Method != http.MethodPost {
96
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
97
+ return
98
+ }
99
+
100
+ var openAIReq OpenAIRequest
101
+ if err := json.NewDecoder(r.Body).Decode(&openAIReq); err != nil {
102
+ http.Error(w, err.Error(), http.StatusBadRequest)
103
+ return
104
+ }
105
+
106
+ if mappedModel, exists := modelMapping[openAIReq.Model]; exists {
107
+ openAIReq.Model = mappedModel
108
+ } else {
109
+ openAIReq.Model = "GPT-4o mini"
110
+ }
111
+
112
+ tempUserID, err := getTempUserID()
113
+ if err != nil {
114
+ http.Error(w, err.Error(), http.StatusInternalServerError)
115
+ return
116
+ }
117
+
118
+ juliusResp, err := sendToJulius(tempUserID, openAIReq.Messages[len(openAIReq.Messages)-1].Content, openAIReq.Model)
119
+ if err != nil {
120
+ http.Error(w, err.Error(), http.StatusInternalServerError)
121
+ return
122
+ }
123
+
124
+ isStream := openAIReq.Stream
125
+
126
+ respId := "chatcmpl-" + tempUserID
127
+ created := getCurrentTimestamp()
128
+
129
+ if isStream {
130
+ w.Header().Set("Content-Type", "text/event-stream")
131
+ w.Header().Set("Cache-Control", "no-cache")
132
+ w.Header().Set("Connection", "keep-alive")
133
+
134
+ chunks := splitIntoChunks(juliusResp, 50)
135
+ firstResponse := ChatCompletionStreamResponse{
136
+ ID: respId,
137
+ Object: "chat.completion.chunk",
138
+ Created: created,
139
+ Model: openAIReq.Model,
140
+ Choices: []struct {
141
+ Delta struct {
142
+ Content string `json:"content"`
143
+ Role string `json:"role,omitempty"`
144
+ } `json:"delta"`
145
+ Index int `json:"index"`
146
+ FinishReason string `json:"finish_reason,omitempty"`
147
+ }{
148
+ {
149
+ Delta: struct {
150
+ Content string `json:"content"`
151
+ Role string `json:"role,omitempty"`
152
+ }{
153
+ Role: "assistant",
154
+ },
155
+ Index: 0,
156
+ },
157
+ },
158
+ }
159
+
160
+ data, err := json.Marshal(firstResponse)
161
+ if err != nil {
162
+ http.Error(w, err.Error(), http.StatusInternalServerError)
163
+ return
164
+ }
165
+ fmt.Fprintf(w, "data: %s\n\n", string(data))
166
+
167
+ for i, chunk := range chunks {
168
+ response := ChatCompletionStreamResponse{
169
+ ID: respId,
170
+ Object: "chat.completion.chunk",
171
+ Created: created,
172
+ Model: openAIReq.Model,
173
+ Choices: []struct {
174
+ Delta struct {
175
+ Content string `json:"content"`
176
+ Role string `json:"role,omitempty"`
177
+ } `json:"delta"`
178
+ Index int `json:"index"`
179
+ FinishReason string `json:"finish_reason,omitempty"`
180
+ }{
181
+ {
182
+ Delta: struct {
183
+ Content string `json:"content"`
184
+ Role string `json:"role,omitempty"`
185
+ }{
186
+ Content: chunk,
187
+ },
188
+ Index: 0,
189
+ FinishReason: func() string {
190
+ if i == len(chunks)-1 {
191
+ return "stop"
192
+ }
193
+ return ""
194
+ }(),
195
+ },
196
+ },
197
+ }
198
+
199
+ data, err := json.Marshal(response)
200
+ if err != nil {
201
+ http.Error(w, err.Error(), http.StatusInternalServerError)
202
+ return
203
+ }
204
+ fmt.Fprintf(w, "data: %s\n\n", string(data))
205
+ }
206
+
207
+ fmt.Fprintf(w, "data: [DONE]\n\n")
208
+ } else {
209
+ w.Header().Set("Content-Type", "application/json")
210
+ response := OpenAIResponse{
211
+ Id: respId,
212
+ Object: "chat.completion",
213
+ Created: created,
214
+ Model: openAIReq.Model,
215
+ Choices: []Choice{
216
+ {
217
+ Index: 0,
218
+ Message: Message{
219
+ Role: "assistant",
220
+ Content: juliusResp,
221
+ },
222
+ FinishReason: "stop",
223
+ },
224
+ },
225
+ }
226
+ json.NewEncoder(w).Encode(response)
227
+ }
228
+ }
229
+
230
+ func splitIntoChunks(text string, chunkSize int) []string {
231
+ var chunks []string
232
+ runes := []rune(text)
233
+ for i := 0; i < len(runes); i += chunkSize {
234
+ end := i + chunkSize
235
+ if end > len(runes) {
236
+ end = len(runes)
237
+ }
238
+ chunks = append(chunks, string(runes[i:end]))
239
+ }
240
+ return chunks
241
+ }
242
+
243
+ func getTempUserID() (string, error) {
244
+ resp, err := http.Get("https://playground.julius.ai/api/temp_user_id")
245
+ if err != nil {
246
+ return "", err
247
+ }
248
+ defer resp.Body.Close()
249
+
250
+ var result struct {
251
+ Status string `json:"status"`
252
+ TempUserID string `json:"temp_user_id"`
253
+ }
254
+ if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
255
+ return "", err
256
+ }
257
+ return result.TempUserID, nil
258
+ //return "自定义ID", nil
259
+ }
260
+
261
+ func sendToJulius(tempUserID, message string, model string) (string, error) {
262
+ conversationID := uuid.New().String()
263
+
264
+ juliusReq := map[string]interface{}{
265
+ "message": map[string]interface{}{
266
+ "content": message,
267
+ "role": "user",
268
+ },
269
+ "provider": "default",
270
+ "chat_mode": "auto",
271
+ "client_version": "20240130",
272
+ "theme": "dark",
273
+ "new_images": nil,
274
+ "new_attachments": nil,
275
+ "dataframe_format": "json",
276
+ "selectedModels": []string{
277
+ model,
278
+ },
279
+ }
280
+
281
+ reqBody, err := json.Marshal(juliusReq)
282
+ if err != nil {
283
+ return "", err
284
+ }
285
+
286
+ req, err := http.NewRequest("POST", "https://playground.julius.ai/api/chat/message", bytes.NewBuffer(reqBody))
287
+ if err != nil {
288
+ return "", err
289
+ }
290
+ req.Header.Set("is-demo", tempUserID)
291
+ req.Header.Set("Content-Type", "application/json")
292
+ req.Header.Set("Platform", "web")
293
+ req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36")
294
+ req.Header.Set("conversation-id", conversationID)
295
+ req.Header.Set("interactive-charts", "true")
296
+ req.Header.Set("use-dict", "true")
297
+ req.Header.Set("Gcs", "true")
298
+ req.Header.Set("Is-Native", "false")
299
+ req.Header.Set("sec-ch-ua-platform", "Windows")
300
+ req.Header.Set("Accept", "*/*")
301
+ req.Header.Set("Sec-Fetch-Site", "same-site")
302
+ req.Header.Set("Sec-Fetch-Mode", "cors")
303
+ req.Header.Set("Sec-Fetch-Dest", "empty")
304
+
305
+ client := &http.Client{}
306
+ resp, err := client.Do(req)
307
+ if err != nil {
308
+ return "", err
309
+ }
310
+ defer resp.Body.Close()
311
+
312
+ var fullResponse strings.Builder
313
+ reader := bufio.NewReader(resp.Body)
314
+
315
+ for {
316
+ line, err := reader.ReadString('\n')
317
+ if err == io.EOF {
318
+ break
319
+ }
320
+ if err != nil {
321
+ return "", err
322
+ }
323
+ var jsonResp map[string]interface{}
324
+ if err := json.Unmarshal([]byte(line), &jsonResp); err != nil {
325
+ continue
326
+ }
327
+ if content, ok := jsonResp["content"].(string); ok {
328
+ fullResponse.WriteString(content)
329
+ }
330
+ }
331
+ return fullResponse.String(), nil
332
+ }