game-wake-wolf commited on
Commit
5930f40
·
verified ·
1 Parent(s): 5034bd3

Update api/chat.go

Browse files
Files changed (1) hide show
  1. api/chat.go +348 -347
api/chat.go CHANGED
@@ -1,347 +1,348 @@
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)
 
 
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
+ Id: generateUUID(),
306
+ Object: "chat.completion.chunk",
307
+ Created: getCurrentTimestamp(),
308
+ Model: openAIReq.Model,
309
+ Choices: []struct {
310
+ Delta struct {
311
+ Content string `json:"content"`
312
+ } `json:"delta"`
313
+ Index int `json:"index"`
314
+ FinishReason string `json:"finish_reason"`
315
+ }{{
316
+ Delta: struct {
317
+ Content string `json:"content"`
318
+ }{Content: ""},
319
+ Index: 0,
320
+ FinishReason: "stop",
321
+ }},
322
+ }
323
+ respData, _ := json.Marshal(finalResp)
324
+ fmt.Fprintf(w, "data: %s\n\n", string(respData))
325
+ fmt.Fprintf(w, "data: [DONE]\n\n")
326
+ }
327
+
328
+ func generateUUID() string {
329
+ return uuid.New().String()
330
+ }
331
+
332
+ func generateV1UUID() string {
333
+ uuidObj := uuid.Must(uuid.NewUUID())
334
+ return uuidObj.String()
335
+ }
336
+
337
+ func getCurrentTimestamp() int64 {
338
+ return time.Now().Unix()
339
+ }
340
+
341
+ func main() {
342
+ port := getEnvOrDefault("PORT", "8080")
343
+ http.HandleFunc("/", Handler)
344
+ fmt.Printf("Server starting on port %s...\n", port)
345
+ if err := http.ListenAndServe(":"+port, nil); err != nil {
346
+ fmt.Printf("Error starting server: %v\n", err)
347
+ }
348
+ }