game-wake-wolf commited on
Commit
84c8b89
·
verified ·
1 Parent(s): 9f3bc9f

Upload 5 files

Browse files
Files changed (5) hide show
  1. Dockerfile +14 -0
  2. README.md +6 -11
  3. api/chat.go +347 -0
  4. go.mod +5 -0
  5. go.sum +2 -0
Dockerfile ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM golang:1.22-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ COPY go.mod go.sum ./
6
+ RUN go mod download
7
+
8
+ COPY . .
9
+
10
+ RUN go build -o main .
11
+
12
+ EXPOSE 8080
13
+
14
+ CMD ["./main"]
README.md CHANGED
@@ -1,11 +1,6 @@
1
- ---
2
- title: Dev
3
- emoji: 🏆
4
- colorFrom: blue
5
- colorTo: green
6
- sdk: docker
7
- pinned: false
8
- license: apache-2.0
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ## 开始使用
2
+
3
+ 1. 点击右侧按钮开始部署:
4
+ [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3a%2f%2fgithub.com%2fSMNETSTUDIO%2fGetMerlin2Api&env=UUID&env=AUTH_TOKEN&project-name=getmerlin2api&repository-name=getmerlin2api)
5
+ 2. 在环境变量页填入UUID & AUTH_TOKEN
6
+ 3. 部署完毕后,即可开始使用
 
 
 
 
 
api/chat.go ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package api
2
+
3
+ import (
4
+ "bufio"
5
+ "encoding/json"
6
+ "fmt"
7
+ "io"
8
+ "net/http"
9
+ "os"
10
+ "strings"
11
+ "time"
12
+
13
+ "github.com/google/uuid"
14
+ )
15
+
16
+ type OpenAIRequest struct {
17
+ Messages []Message `json:"messages"`
18
+ Stream bool `json:"stream"`
19
+ Model string `json:"model"`
20
+ }
21
+
22
+ type Message struct {
23
+ Role string `json:"role"`
24
+ Content string `json:"content"`
25
+ }
26
+
27
+ type MerlinRequest struct {
28
+ Attachments []interface{} `json:"attachments"`
29
+ ChatId string `json:"chatId"`
30
+ Language string `json:"language"`
31
+ Message struct {
32
+ Content string `json:"content"`
33
+ Context string `json:"context"`
34
+ ChildId string `json:"childId"`
35
+ Id string `json:"id"`
36
+ ParentId string `json:"parentId"`
37
+ } `json:"message"`
38
+ Metadata struct {
39
+ LargeContext bool `json:"largeContext"`
40
+ MerlinMagic bool `json:"merlinMagic"`
41
+ ProFinderMode bool `json:"proFinderMode"`
42
+ WebAccess bool `json:"webAccess"`
43
+ } `json:"metadata"`
44
+ Mode string `json:"mode"`
45
+ Model string `json:"model"`
46
+ }
47
+
48
+ type MerlinResponse struct {
49
+ Data struct {
50
+ Content string `json:"content"`
51
+ } `json:"data"`
52
+ }
53
+
54
+ type OpenAIResponse struct {
55
+ Id string `json:"id"`
56
+ Object string `json:"object"`
57
+ Created int64 `json:"created"`
58
+ Model string `json:"model"`
59
+ Choices []struct {
60
+ Delta struct {
61
+ Content string `json:"content"`
62
+ } `json:"delta"`
63
+ Index int `json:"index"`
64
+ FinishReason string `json:"finish_reason"`
65
+ } `json:"choices"`
66
+ }
67
+
68
+ type TokenResponse struct {
69
+ IdToken string `json:"idToken"`
70
+ }
71
+
72
+ func getEnvOrDefault(key, defaultValue string) string {
73
+ if value := os.Getenv(key); value != "" {
74
+ return value
75
+ }
76
+ return defaultValue
77
+ }
78
+
79
+ func getToken() (string, error) {
80
+ tokenReq := struct {
81
+ UUID string `json:"uuid"`
82
+ }{
83
+ UUID: getEnvOrDefault("UUID", ""),
84
+ }
85
+
86
+ tokenReqBody, _ := json.Marshal(tokenReq)
87
+ resp, err := http.Post(
88
+ "https://getmerlin-main-server.vercel.app/generate",
89
+ "application/json",
90
+ strings.NewReader(string(tokenReqBody)),
91
+ )
92
+ if err != nil {
93
+ return "", err
94
+ }
95
+ defer resp.Body.Close()
96
+
97
+ var tokenResp TokenResponse
98
+ if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
99
+ return "", err
100
+ }
101
+
102
+ return tokenResp.IdToken, nil
103
+ }
104
+
105
+ func Handler(w http.ResponseWriter, r *http.Request) {
106
+ authToken := r.Header.Get("Authorization")
107
+ envToken := getEnvOrDefault("AUTH_TOKEN", "")
108
+
109
+ if envToken != "" && authToken != "Bearer "+envToken {
110
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
111
+ return
112
+ }
113
+
114
+ if r.URL.Path != "/v1/chat/completions" {
115
+ w.Header().Set("Content-Type", "application/json")
116
+ w.WriteHeader(http.StatusOK)
117
+ fmt.Fprintf(w, `{"status":"GetMerlin2Api Service Running...","message":"MoLoveSze..."}`)
118
+ return
119
+ }
120
+
121
+ if r.Method != http.MethodPost {
122
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
123
+ return
124
+ }
125
+
126
+ var openAIReq OpenAIRequest
127
+ if err := json.NewDecoder(r.Body).Decode(&openAIReq); err != nil {
128
+ http.Error(w, err.Error(), http.StatusBadRequest)
129
+ return
130
+ }
131
+ var contextMessages []string
132
+ for i := 0; i < len(openAIReq.Messages)-1; i++ {
133
+ msg := openAIReq.Messages[i]
134
+ contextMessages = append(contextMessages, fmt.Sprintf("%s: %s", msg.Role, msg.Content))
135
+ }
136
+ context := strings.Join(contextMessages, "\n")
137
+ merlinReq := MerlinRequest{
138
+ Attachments: make([]interface{}, 0),
139
+ ChatId: generateV1UUID(),
140
+ Language: "AUTO",
141
+ Message: struct {
142
+ Content string `json:"content"`
143
+ Context string `json:"context"`
144
+ ChildId string `json:"childId"`
145
+ Id string `json:"id"`
146
+ ParentId string `json:"parentId"`
147
+ }{
148
+ Content: openAIReq.Messages[len(openAIReq.Messages)-1].Content,
149
+ Context: context,
150
+ ChildId: generateUUID(),
151
+ Id: generateUUID(),
152
+ ParentId: "root",
153
+ },
154
+ Mode: "UNIFIED_CHAT",
155
+ Model: openAIReq.Model,
156
+ Metadata: struct {
157
+ LargeContext bool `json:"largeContext"`
158
+ MerlinMagic bool `json:"merlinMagic"`
159
+ ProFinderMode bool `json:"proFinderMode"`
160
+ WebAccess bool `json:"webAccess"`
161
+ }{
162
+ LargeContext: false,
163
+ MerlinMagic: false,
164
+ ProFinderMode: false,
165
+ WebAccess: false,
166
+ },
167
+ }
168
+ token, err := getToken()
169
+ if err != nil {
170
+ http.Error(w, "Failed to get token: "+err.Error(), http.StatusInternalServerError)
171
+ return
172
+ }
173
+ client := &http.Client{}
174
+ merlinReqBody, _ := json.Marshal(merlinReq)
175
+
176
+ req, _ := http.NewRequest("POST", "https://arcane.getmerlin.in/v1/thread/unified", strings.NewReader(string(merlinReqBody)))
177
+ req.Header.Set("Content-Type", "application/json")
178
+ req.Header.Set("Accept", "text/event-stream, text/event-stream")
179
+ req.Header.Set("Authorization", "Bearer "+token)
180
+ req.Header.Set("x-merlin-version", "web-merlin")
181
+ 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")
182
+ req.Header.Set("sec-ch-ua", `"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"`)
183
+ req.Header.Set("sec-ch-ua-mobile", "?0")
184
+ req.Header.Set("sec-ch-ua-platform", "Windows")
185
+ req.Header.Set("Sec-Fetch-Site", "same-site")
186
+ req.Header.Set("Sec-Fetch-Mode", "cors")
187
+ req.Header.Set("Sec-Fetch-Dest", "empty")
188
+ req.Header.Set("host", "arcane.getmerlin.in")
189
+ if openAIReq.Stream {
190
+ w.Header().Set("Content-Type", "text/event-stream")
191
+ w.Header().Set("Cache-Control", "no-cache")
192
+ w.Header().Set("Connection", "keep-alive")
193
+ w.Header().Set("X-Accel-Buffering", "no")
194
+ w.Header().Set("Transfer-Encoding", "chunked")
195
+ } else {
196
+ w.Header().Set("Content-Type", "application/json")
197
+ }
198
+
199
+ resp, err := client.Do(req)
200
+ if err != nil {
201
+ http.Error(w, err.Error(), http.StatusInternalServerError)
202
+ return
203
+ }
204
+ defer resp.Body.Close()
205
+
206
+ if !openAIReq.Stream {
207
+ var fullContent string
208
+ reader := bufio.NewReader(resp.Body)
209
+ for {
210
+ line, err := reader.ReadString('\n')
211
+ if err != nil {
212
+ if err == io.EOF {
213
+ break
214
+ }
215
+ continue
216
+ }
217
+
218
+ line = strings.TrimSpace(line)
219
+
220
+ if strings.HasPrefix(line, "event: message") {
221
+ dataLine, err := reader.ReadString('\n')
222
+ if err != nil {
223
+ continue
224
+ }
225
+ dataLine = strings.TrimSpace(dataLine)
226
+
227
+ if strings.HasPrefix(dataLine, "data: ") {
228
+ dataStr := strings.TrimPrefix(dataLine, "data: ")
229
+ var merlinResp MerlinResponse
230
+ if err := json.Unmarshal([]byte(dataStr), &merlinResp); err != nil {
231
+ continue
232
+ }
233
+ if merlinResp.Data.Content != " " {
234
+ fullContent += merlinResp.Data.Content
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ response := map[string]interface{}{
241
+ "id": generateUUID(),
242
+ "object": "chat.completion",
243
+ "created": getCurrentTimestamp(),
244
+ "model": openAIReq.Model,
245
+ "choices": []map[string]interface{}{
246
+ {
247
+ "message": map[string]interface{}{
248
+ "role": "assistant",
249
+ "content": fullContent,
250
+ },
251
+ "finish_reason": "stop",
252
+ "index": 0,
253
+ },
254
+ },
255
+ }
256
+ json.NewEncoder(w).Encode(response)
257
+ return
258
+ }
259
+
260
+ reader := bufio.NewReaderSize(resp.Body, 256)
261
+ for {
262
+ line, err := reader.ReadString('\n')
263
+ if err != nil {
264
+ if err == io.EOF {
265
+ break
266
+ }
267
+ continue
268
+ }
269
+
270
+ if strings.HasPrefix(line, "event: message") {
271
+ dataLine, _ := reader.ReadString('\n')
272
+ var merlinResp MerlinResponse
273
+ json.Unmarshal([]byte(strings.TrimPrefix(dataLine, "data: ")), &merlinResp)
274
+
275
+ if merlinResp.Data.Content != "" {
276
+ openAIResp := OpenAIResponse{
277
+ Id: generateUUID(),
278
+ Object: "chat.completion.chunk",
279
+ Created: getCurrentTimestamp(),
280
+ Model: openAIReq.Model,
281
+ Choices: []struct {
282
+ Delta struct {
283
+ Content string `json:"content"`
284
+ } `json:"delta"`
285
+ Index int `json:"index"`
286
+ FinishReason string `json:"finish_reason"`
287
+ }{{
288
+ Delta: struct {
289
+ Content string `json:"content"`
290
+ }{
291
+ Content: merlinResp.Data.Content,
292
+ },
293
+ Index: 0,
294
+ FinishReason: "",
295
+ }},
296
+ }
297
+
298
+ respData, _ := json.Marshal(openAIResp)
299
+ fmt.Fprintf(w, "data: %s\n\n", string(respData))
300
+ }
301
+ }
302
+ }
303
+
304
+ finalResp := OpenAIResponse{
305
+ Choices: []struct {
306
+ Delta struct {
307
+ Content string `json:"content"`
308
+ } `json:"delta"`
309
+ Index int `json:"index"`
310
+ FinishReason string `json:"finish_reason"`
311
+ }{{
312
+ Delta: struct {
313
+ Content string `json:"content"`
314
+ }{Content: ""},
315
+ Index: 0,
316
+ FinishReason: "stop",
317
+ }},
318
+ }
319
+ respData, _ := json.Marshal(finalResp)
320
+ fmt.Fprintf(w, "data: %s\n\n", string(respData))
321
+ fmt.Fprintf(w, "data: [DONE]\n\n")
322
+ }
323
+
324
+ func generateUUID() string {
325
+ return uuid.New().String()
326
+ }
327
+
328
+ func generateV1UUID() string {
329
+ uuidObj := uuid.Must(uuid.NewUUID())
330
+ return uuidObj.String()
331
+ }
332
+
333
+ func getCurrentTimestamp() int64 {
334
+ return time.Now().Unix()
335
+ }
336
+ <<<<<<< HEAD
337
+ =======
338
+
339
+ func main() {
340
+ port := getEnvOrDefault("PORT", "8080")
341
+ http.HandleFunc("/", Handler)
342
+ fmt.Printf("Server starting on port %s...\n", port)
343
+ if err := http.ListenAndServe(":"+port, nil); err != nil {
344
+ fmt.Printf("Error starting server: %v\n", err)
345
+ }
346
+ }
347
+ >>>>>>> e64d792 (MoLoveSze)
go.mod ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ module getmerlin2api
2
+
3
+ go 1.22.2
4
+
5
+ require github.com/google/uuid v1.6.0
go.sum ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
2
+ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=