xxyy95 commited on
Commit
5333aaa
·
verified ·
1 Parent(s): 60a6ae6

Rename index.html to app.py

Browse files
Files changed (2) hide show
  1. app.py +179 -0
  2. index.html +0 -19
app.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, Response, stream_with_context
2
+ import requests
3
+ import json
4
+ import uuid
5
+ import time
6
+ import random
7
+ import os
8
+
9
+ app = Flask(__name__)
10
+
11
+ def get_token():
12
+ with open("token.txt", encoding="utf-8") as f:
13
+ return random.choice(f.read().split("\n"))
14
+
15
+ def create_merlin_request(openai_req):
16
+ messages = openai_req['messages']
17
+ context_messages = [
18
+ f"{msg['role']}: {msg['content']}"
19
+ for msg in messages[:-1]
20
+ ]
21
+
22
+ return {
23
+ "attachments": [],
24
+ "chatId": str(uuid.uuid1()),
25
+ "language": "AUTO",
26
+ "message": {
27
+ "content": messages[-1]['content'],
28
+ "context": "\n".join(context_messages),
29
+ "childId": str(uuid.uuid4()),
30
+ "id": str(uuid.uuid4()),
31
+ "parentId": "root"
32
+ },
33
+ "mode": "UNIFIED_CHAT",
34
+ "model": openai_req.get('model', 'claude-3-haiku'),
35
+ "metadata": {
36
+ "largeContext": False,
37
+ "merlinMagic": False,
38
+ "proFinderMode": False,
39
+ "webAccess": False
40
+ }
41
+ }
42
+
43
+ def process_merlin_response(response_text):
44
+ try:
45
+ merlin_resp = json.loads(response_text[6:])
46
+ content = merlin_resp['data']['content']
47
+ if isinstance(content, str):
48
+ content = content.encode('latin1').decode('utf-8')
49
+ return content
50
+ return content
51
+ except Exception:
52
+ return ""
53
+
54
+ def process_non_stream_response(response):
55
+ try:
56
+ full_content = ""
57
+ for line in response.text.split('\n'):
58
+ if line.startswith('data: '):
59
+ content = process_merlin_response(line)
60
+ if content and content != " ":
61
+ full_content += content
62
+
63
+ if not full_content:
64
+ return Response("Empty response from server", status=500)
65
+
66
+ return {
67
+ "id": str(uuid.uuid4()),
68
+ "object": "chat.completion",
69
+ "created": int(time.time()),
70
+ "model": "claude-3-haiku",
71
+ "choices": [{
72
+ "message": {
73
+ "role": "assistant",
74
+ "content": full_content
75
+ },
76
+ "finish_reason": "stop",
77
+ "index": 0
78
+ }]
79
+ }
80
+ except Exception as e:
81
+ print(f"Error processing response: {str(e)}")
82
+ return Response("Failed to process response", status=500)
83
+
84
+ @app.route('/', methods=['GET'])
85
+ def home():
86
+ return {"status": "GetMerlin2Api Service Running...", "message": "MoLoveSze..."}
87
+
88
+ @app.route('/v1/chat/completions', methods=['POST'])
89
+ def chat():
90
+ try:
91
+ auth_token = os.getenv('AUTH_TOKEN')
92
+ if auth_token:
93
+ request_token = request.headers.get('Authorization', '')
94
+ if request_token != f"Bearer {auth_token}":
95
+ return Response("Unauthorized", status=401)
96
+
97
+ token = get_token()
98
+ if not token:
99
+ return Response("Failed to get token", status=500)
100
+
101
+ openai_req = request.json
102
+ merlin_req = create_merlin_request(openai_req)
103
+
104
+ headers = {
105
+ "Content-Type": "application/json",
106
+ "Accept": "text/event-stream",
107
+ "Authorization": f"Bearer {token}",
108
+ "x-merlin-version": "web-merlin",
109
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
110
+ "host": "arcane.getmerlin.in"
111
+ }
112
+
113
+ response = requests.post(
114
+ "https://arcane.getmerlin.in/v1/thread/unified",
115
+ json=merlin_req,
116
+ headers=headers,
117
+ stream=True
118
+ )
119
+
120
+ if response.status_code != 200:
121
+ return Response(f"Merlin API error: {response.text}", status=response.status_code)
122
+
123
+ if not openai_req.get('stream', False):
124
+ return process_non_stream_response(response)
125
+
126
+ def generate():
127
+ try:
128
+ buffer = ""
129
+ for chunk in response.iter_content(chunk_size=1024, decode_unicode=True):
130
+ if chunk:
131
+ buffer += chunk
132
+ while '\n' in buffer:
133
+ line, buffer = buffer.split('\n', 1)
134
+ if line.startswith('data: '):
135
+ try:
136
+ content = process_merlin_response(line)
137
+ if content:
138
+ openai_resp = {
139
+ "id": str(uuid.uuid4()),
140
+ "object": "chat.completion.chunk",
141
+ "created": int(time.time()),
142
+ "model": openai_req.get('model', 'claude-3-haiku'),
143
+ "choices": [{
144
+ "delta": {
145
+ "content": content
146
+ },
147
+ "index": 0,
148
+ "finish_reason": None
149
+ }]
150
+ }
151
+ yield f"data: {json.dumps(openai_resp, ensure_ascii=False)}\n\n"
152
+ except Exception as e:
153
+ print(f"Error processing chunk: {str(e)}")
154
+ continue
155
+
156
+ final_resp = {
157
+ "choices": [{
158
+ "delta": {"content": ""},
159
+ "index": 0,
160
+ "finish_reason": "stop"
161
+ }]
162
+ }
163
+ yield f"data: {json.dumps(final_resp)}\n\n"
164
+ yield "data: [DONE]\n\n"
165
+ except Exception as e:
166
+ print(f"Error in generate: {str(e)}")
167
+ return
168
+
169
+ return Response(
170
+ stream_with_context(generate()),
171
+ content_type='text/event-stream'
172
+ )
173
+ except Exception as e:
174
+ print(f"Error in chat endpoint: {str(e)}")
175
+ return Response(f"Internal server error: {str(e)}", status=500)
176
+
177
+ if __name__ == '__main__':
178
+ port = int(os.getenv('PORT', 7860)) # HF Spaces 默认端口
179
+ app.run(host='0.0.0.0', port=port)
index.html DELETED
@@ -1,19 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>