ffreemt commited on
Commit
2493442
·
1 Parent(s): d9591bc

Update loguru

Browse files
Files changed (2) hide show
  1. app.py +128 -65
  2. requirements.txt +2 -1
app.py CHANGED
@@ -1,67 +1,102 @@
 
 
1
  import json
 
 
 
2
  import time
3
- import requests
4
- from flask import Flask, request, Response, stream_with_context
5
- from bs4 import BeautifulSoup
6
  from datetime import datetime, timedelta
7
- import logging
8
- import os
9
 
 
 
 
 
 
10
  from ycecream import y
 
11
  y.configure(sln=1)
12
 
13
  app = Flask(__name__)
14
 
15
  APP_SESSION_VALIDITY = timedelta(days=3)
16
  ACCESS_TOKEN_VALIDITY = timedelta(hours=1)
17
- USERNAME = os.environ.get('USERNAME', '')
18
- PASSWORD = os.environ.get('PASSWORD', '')
19
- AUTHKEY = os.environ.get('AUTHKEY', '')
20
 
21
  y(USERNAME[:3], PASSWORD[:2], AUTHKEY[:2])
22
 
23
- cache = {"app_session": None, "app_session_time": None, "access_token": None, "access_token_time": None}
 
 
 
 
 
24
 
25
  y(cache)
26
 
27
  # 配置日志记录
28
- logging.basicConfig(level=logging.DEBUG)
 
29
 
30
  def fetch_tokens():
31
  session = requests.Session()
32
 
33
  # 检查并获取 appSession
34
- if not cache["app_session_time"] or datetime.now() - cache["app_session_time"] >= APP_SESSION_VALIDITY:
35
- logging.info("Fetching new appSession")
36
- login_page_response = session.get('https://chat.reka.ai/bff/auth/login', allow_redirects=True)
 
 
 
 
 
37
  if login_page_response.status_code != 200:
38
- logging.error("Failed to load login page")
39
  return None
40
- soup = BeautifulSoup(login_page_response.text, 'html.parser')
41
- state_value = soup.find('input', {'name': 'state'})['value']
42
- session.post(f"https://auth.reka.ai/u/login?state={state_value}", data={
43
- 'state': state_value, 'username': USERNAME, 'password': PASSWORD, 'action': 'default'
44
- })
45
- cache["app_session"] = session.cookies.get('appSession')
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  cache["app_session_time"] = datetime.now()
47
 
48
  # 检查并获取 accessToken
49
- if not cache["access_token_time"] or datetime.now() - cache["access_token_time"] >= ACCESS_TOKEN_VALIDITY:
50
- logging.info("Fetching new accessToken")
51
- response = session.get('https://chat.reka.ai/bff/auth/access_token', headers={
52
- 'Cookie': f'appSession={cache["app_session"]}'
53
- })
 
 
 
 
54
  if response.status_code != 200:
55
- logging.error("Failed to get access token")
56
  return None
57
- cache["access_token"] = response.json().get('accessToken')
58
  cache["access_token_time"] = datetime.now()
59
 
60
  y(cache)
61
 
62
  return cache["access_token"]
63
 
64
- @app.route('/')
 
65
  def landing():
66
  return """
67
  query /hf/v1/chat/completions for a spin, e.g. curl -XPOST 127.0.0.1:7860/hf/v1/chat/completions -H "Authorization: Bearer Your_AUTHKEY"
@@ -71,33 +106,48 @@ curl -XPOST [127.0.0.1:7860|hf space url]/hf/v1/chat/completions -H "Authorizati
71
 
72
  """
73
 
74
- @app.route('/hf/v1/chat/completions', methods=['POST', 'OPTIONS'])
 
75
  def chat_completions():
76
  if request.method == "OPTIONS":
77
- return Response("", status=204, headers={
78
- 'Access-Control-Allow-Origin': '*',
79
- 'Access-Control-Allow-Headers': '*'
80
- })
81
-
82
- if request.method != 'POST' or request.path != '/hf/v1/chat/completions' or request.headers.get('Authorization') != f'Bearer {AUTHKEY}':
83
- logging.error("Unauthorized access attempt")
84
- return Response('Unauthorized', status=401)
 
 
 
 
 
 
 
 
85
 
86
  access_token = fetch_tokens()
87
  if not access_token:
88
- logging.error("Failed to obtain access token")
89
  return Response("Failed to obtain access token.", status=500)
90
 
91
  try:
92
  request_body = request.json
93
  except Exception as e:
94
- logging.error(f"Error parsing JSON body: {e}")
95
  return Response("Error parsing JSON body", status=400)
96
 
97
  messages = request_body.get("messages", [])
98
  model = request_body.get("model", "reka-core")
99
 
100
- conversation_history = [{"type": "human" if msg["role"] in ["user", "system"] else "model", "text": msg["content"]} for msg in messages]
 
 
 
 
 
 
101
 
102
  if conversation_history and conversation_history[0]["type"] != "human":
103
  conversation_history.insert(0, {"type": "human", "text": ""})
@@ -107,7 +157,15 @@ def chat_completions():
107
  i = 0
108
  while i < len(conversation_history) - 1:
109
  if conversation_history[i]["type"] == conversation_history[i + 1]["type"]:
110
- conversation_history.insert(i + 1, {"type": "model" if conversation_history[i]["type"] == "human" else "human", "text": ""})
 
 
 
 
 
 
 
 
111
  i += 1
112
 
113
  new_request_body = {
@@ -116,21 +174,22 @@ def chat_completions():
116
  "use_search_engine": False,
117
  "use_code_interpreter": False,
118
  "model_name": "reka-core",
119
- "random_seed": int(time.time())
120
  }
121
 
122
  response = requests.post(
123
  "https://chat.reka.ai/api/chat",
124
  headers={
125
  "authorization": f"bearer {access_token}",
126
- "content-type": "application/json"
127
  },
128
  data=json.dumps(new_request_body),
129
- stream=True
 
130
  )
131
 
132
  if response.status_code != 200:
133
- logging.error(f"Error from external API: {response.status_code} {response.text}")
134
  return Response(response.text, status=response.status_code)
135
 
136
  created = int(time.time())
@@ -145,11 +204,11 @@ def chat_completions():
145
 
146
  for line in response.iter_lines():
147
  if line:
148
- content_buffer += line.decode('utf-8') + "\n"
149
  while "\n" in content_buffer:
150
  newline_index = content_buffer.index("\n")
151
  line = content_buffer[:newline_index]
152
- content_buffer = content_buffer[newline_index + 1:]
153
 
154
  if not line.startswith("data:"):
155
  continue
@@ -164,25 +223,29 @@ def chat_completions():
164
  last_four_texts.pop(0)
165
 
166
  if len(last_four_texts) == 4 and (
167
- len(last_four_texts[3]) < len(last_four_texts[2])
168
- or last_four_texts[3].endswith("<sep")
169
- or last_four_texts[3].endswith("<")):
 
170
  break
171
 
172
  full_content = data["text"]
173
- new_content = full_content[len(prev_content):]
174
  prev_content = full_content
175
 
176
  formatted_data = {
177
- "id": "chatcmpl-" + "".join([str(time.time()), str(hash(new_content))]),
 
178
  "object": "chat.completion.chunk",
179
  "created": created,
180
  "model": model,
181
- "choices": [{
182
- "index": 0,
183
- "delta": {"content": new_content},
184
- "finish_reason": None
185
- }]
 
 
186
  }
187
  yield f"data: {encoder.encode(formatted_data)}\n\n"
188
 
@@ -191,16 +254,16 @@ def chat_completions():
191
  "object": "chat.completion.chunk",
192
  "created": created,
193
  "model": model,
194
- "choices": [{
195
- "index": 0,
196
- "delta": {},
197
- "finish_reason": "stop"
198
- }]
199
  }
200
  yield f"data: {json.dumps(done_data)}\n\n"
201
  yield "data: [DONE]\n\n"
202
 
203
- return Response(stream_with_context(generate_stream()), headers={"Content-Type": "text/event-stream"})
 
 
 
 
204
 
205
- if __name__ == '__main__':
206
- app.run(host='0.0.0.0', port=7860)
 
1
+ # pylint: disable=line-too-long, missing-module-docstring, missing-function-docstring,broad-exception-caught, too-many-statements
2
+
3
  import json
4
+
5
+ import os
6
+ import re
7
  import time
 
 
 
8
  from datetime import datetime, timedelta
 
 
9
 
10
+ import requests
11
+
12
+ # from bs4 import BeautifulSoup
13
+ from flask import Flask, Response, request, stream_with_context
14
+ from loguru import logger
15
  from ycecream import y
16
+
17
  y.configure(sln=1)
18
 
19
  app = Flask(__name__)
20
 
21
  APP_SESSION_VALIDITY = timedelta(days=3)
22
  ACCESS_TOKEN_VALIDITY = timedelta(hours=1)
23
+ USERNAME = os.environ.get("USERNAME", "")
24
+ PASSWORD = os.environ.get("PASSWORD", "")
25
+ AUTHKEY = os.environ.get("AUTHKEY", "")
26
 
27
  y(USERNAME[:3], PASSWORD[:2], AUTHKEY[:2])
28
 
29
+ cache = {
30
+ "app_session": None,
31
+ "app_session_time": None,
32
+ "access_token": None,
33
+ "access_token_time": None,
34
+ }
35
 
36
  y(cache)
37
 
38
  # 配置日志记录
39
+ # logging.basicConfig(level=logging.DEBUG)
40
+
41
 
42
  def fetch_tokens():
43
  session = requests.Session()
44
 
45
  # 检查并获取 appSession
46
+ if (
47
+ not cache["app_session_time"]
48
+ or datetime.now() - cache["app_session_time"] >= APP_SESSION_VALIDITY
49
+ ):
50
+ logger.info("Fetching new appSession")
51
+ login_page_response = session.get(
52
+ "https://chat.reka.ai/bff/auth/login", allow_redirects=True
53
+ )
54
  if login_page_response.status_code != 200:
55
+ logger.error("Failed to load login page")
56
  return None
57
+
58
+ # soup = BeautifulSoup(login_page_response.text, "html.parser")
59
+ # state_value = soup.find("input", {"name": "state"})["value"]
60
+
61
+ state_value = ""
62
+ _ = re.search(r"\w{20,}", login_page_response.text)
63
+ if _:
64
+ state_value = _.group()
65
+
66
+ session.post(
67
+ "https://auth.reka.ai/u/login",
68
+ data={
69
+ "state": state_value,
70
+ "username": USERNAME,
71
+ "password": PASSWORD,
72
+ "action": "default",
73
+ },
74
+ )
75
+ cache["app_session"] = session.cookies.get("appSession")
76
  cache["app_session_time"] = datetime.now()
77
 
78
  # 检查并获取 accessToken
79
+ if (
80
+ not cache["access_token_time"]
81
+ or datetime.now() - cache["access_token_time"] >= ACCESS_TOKEN_VALIDITY
82
+ ):
83
+ logger.info("Fetching new accessToken")
84
+ response = session.get(
85
+ "https://chat.reka.ai/bff/auth/access_token",
86
+ headers={"Cookie": f'appSession={cache["app_session"]}'},
87
+ )
88
  if response.status_code != 200:
89
+ logger.error("Failed to get access token")
90
  return None
91
+ cache["access_token"] = response.json().get("accessToken")
92
  cache["access_token_time"] = datetime.now()
93
 
94
  y(cache)
95
 
96
  return cache["access_token"]
97
 
98
+
99
+ @app.route("/")
100
  def landing():
101
  return """
102
  query /hf/v1/chat/completions for a spin, e.g. curl -XPOST 127.0.0.1:7860/hf/v1/chat/completions -H "Authorization: Bearer Your_AUTHKEY"
 
106
 
107
  """
108
 
109
+
110
+ @app.route("/hf/v1/chat/completions", methods=["POST", "OPTIONS"])
111
  def chat_completions():
112
  if request.method == "OPTIONS":
113
+ return Response(
114
+ "",
115
+ status=204,
116
+ headers={
117
+ "Access-Control-Allow-Origin": "*",
118
+ "Access-Control-Allow-Headers": "*",
119
+ },
120
+ )
121
+
122
+ if (
123
+ request.method != "POST"
124
+ or request.path != "/hf/v1/chat/completions"
125
+ or request.headers.get("Authorization") != f"Bearer {AUTHKEY}"
126
+ ):
127
+ logger.error("Unauthorized access attempt")
128
+ return Response("Unauthorized", status=401)
129
 
130
  access_token = fetch_tokens()
131
  if not access_token:
132
+ logger.error("Failed to obtain access token")
133
  return Response("Failed to obtain access token.", status=500)
134
 
135
  try:
136
  request_body = request.json
137
  except Exception as e:
138
+ logger.error(f"Error parsing JSON body: {e}")
139
  return Response("Error parsing JSON body", status=400)
140
 
141
  messages = request_body.get("messages", [])
142
  model = request_body.get("model", "reka-core")
143
 
144
+ conversation_history = [
145
+ {
146
+ "type": "human" if msg["role"] in ["user", "system"] else "model",
147
+ "text": msg["content"],
148
+ }
149
+ for msg in messages
150
+ ]
151
 
152
  if conversation_history and conversation_history[0]["type"] != "human":
153
  conversation_history.insert(0, {"type": "human", "text": ""})
 
157
  i = 0
158
  while i < len(conversation_history) - 1:
159
  if conversation_history[i]["type"] == conversation_history[i + 1]["type"]:
160
+ conversation_history.insert(
161
+ i + 1,
162
+ {
163
+ "type": "model"
164
+ if conversation_history[i]["type"] == "human"
165
+ else "human",
166
+ "text": "",
167
+ },
168
+ )
169
  i += 1
170
 
171
  new_request_body = {
 
174
  "use_search_engine": False,
175
  "use_code_interpreter": False,
176
  "model_name": "reka-core",
177
+ "random_seed": int(time.time()),
178
  }
179
 
180
  response = requests.post(
181
  "https://chat.reka.ai/api/chat",
182
  headers={
183
  "authorization": f"bearer {access_token}",
184
+ "content-type": "application/json",
185
  },
186
  data=json.dumps(new_request_body),
187
+ stream=True,
188
+ timeout=300,
189
  )
190
 
191
  if response.status_code != 200:
192
+ logger.error(f"Error from external API: {response.status_code} {response.text}")
193
  return Response(response.text, status=response.status_code)
194
 
195
  created = int(time.time())
 
204
 
205
  for line in response.iter_lines():
206
  if line:
207
+ content_buffer += line.decode("utf-8") + "\n"
208
  while "\n" in content_buffer:
209
  newline_index = content_buffer.index("\n")
210
  line = content_buffer[:newline_index]
211
+ content_buffer = content_buffer[newline_index + 1 :]
212
 
213
  if not line.startswith("data:"):
214
  continue
 
223
  last_four_texts.pop(0)
224
 
225
  if len(last_four_texts) == 4 and (
226
+ len(last_four_texts[3]) < len(last_four_texts[2])
227
+ or last_four_texts[3].endswith("<sep")
228
+ or last_four_texts[3].endswith("<")
229
+ ):
230
  break
231
 
232
  full_content = data["text"]
233
+ new_content = full_content[len(prev_content) :]
234
  prev_content = full_content
235
 
236
  formatted_data = {
237
+ "id": "chatcmpl-"
238
+ + "".join([str(time.time()), str(hash(new_content))]),
239
  "object": "chat.completion.chunk",
240
  "created": created,
241
  "model": model,
242
+ "choices": [
243
+ {
244
+ "index": 0,
245
+ "delta": {"content": new_content},
246
+ "finish_reason": None,
247
+ }
248
+ ],
249
  }
250
  yield f"data: {encoder.encode(formatted_data)}\n\n"
251
 
 
254
  "object": "chat.completion.chunk",
255
  "created": created,
256
  "model": model,
257
+ "choices": [{"index": 0, "delta": {}, "finish_reason": "stop"}],
 
 
 
 
258
  }
259
  yield f"data: {json.dumps(done_data)}\n\n"
260
  yield "data: [DONE]\n\n"
261
 
262
+ return Response(
263
+ stream_with_context(generate_stream()),
264
+ headers={"Content-Type": "text/event-stream"},
265
+ )
266
+
267
 
268
+ if __name__ == "__main__":
269
+ app.run(host="0.0.0.0", port=7860)
requirements.txt CHANGED
@@ -1,4 +1,5 @@
1
  Flask==3.0.3
2
  requests==2.31.0
3
  beautifulsoup4==4.12.3
4
- ycecream
 
 
1
  Flask==3.0.3
2
  requests==2.31.0
3
  beautifulsoup4==4.12.3
4
+ ycecream
5
+ loguru