Upload 24 files
Browse files- app.py +1 -0
- chat2api.py +36 -15
- chatgpt/ChatService.py +30 -30
- chatgpt/authorization.py +24 -9
- chatgpt/globals.py +8 -8
- chatgpt/reverseProxy.py +21 -20
- templates/chatgpt.html +0 -0
- utils/config.py +1 -1
app.py
CHANGED
|
@@ -7,3 +7,4 @@ log_config["formatters"]["default"]["fmt"] = default_format
|
|
| 7 |
log_config["formatters"]["access"]["fmt"] = access_format
|
| 8 |
|
| 9 |
uvicorn.run("chat2api:app", host="0.0.0.0", port=5005)
|
|
|
|
|
|
| 7 |
log_config["formatters"]["access"]["fmt"] = access_format
|
| 8 |
|
| 9 |
uvicorn.run("chat2api:app", host="0.0.0.0", port=5005)
|
| 10 |
+
# uvicorn.run("chat2api:app", host="0.0.0.0", port=5005, ssl_keyfile="key.pem", ssl_certfile="cert.pem")
|
chat2api.py
CHANGED
|
@@ -131,19 +131,33 @@ async def error_tokens():
|
|
| 131 |
return {"status": "success", "error_tokens": error_tokens_list}
|
| 132 |
|
| 133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
if enable_gateway:
|
| 135 |
@app.get("/", response_class=HTMLResponse)
|
| 136 |
-
async def
|
| 137 |
-
|
| 138 |
-
if not
|
| 139 |
-
|
| 140 |
-
if not
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
response
|
| 146 |
-
|
|
|
|
|
|
|
|
|
|
| 147 |
return response
|
| 148 |
|
| 149 |
|
|
@@ -205,8 +219,13 @@ if enable_gateway:
|
|
| 205 |
}
|
| 206 |
|
| 207 |
|
| 208 |
-
banned_paths = [
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
redirect_paths = ["auth/logout"]
|
| 211 |
chatgpt_paths = ["c/"]
|
| 212 |
|
|
@@ -215,7 +234,7 @@ if enable_gateway:
|
|
| 215 |
async def reverse_proxy(request: Request, path: str):
|
| 216 |
for chatgpt_path in chatgpt_paths:
|
| 217 |
if chatgpt_path in path:
|
| 218 |
-
return await
|
| 219 |
|
| 220 |
for banned_path in banned_paths:
|
| 221 |
if banned_path in path:
|
|
@@ -224,7 +243,9 @@ if enable_gateway:
|
|
| 224 |
for redirect_path in redirect_paths:
|
| 225 |
if redirect_path in path:
|
| 226 |
redirect_url = str(request.base_url)
|
| 227 |
-
|
|
|
|
|
|
|
| 228 |
|
| 229 |
return await chatgpt_reverse_proxy(request, path)
|
| 230 |
else:
|
|
|
|
| 131 |
return {"status": "success", "error_tokens": error_tokens_list}
|
| 132 |
|
| 133 |
|
| 134 |
+
@app.get(f"/{api_prefix}/tokens/add/{{token}}" if api_prefix else "/tokens/add/{token}")
|
| 135 |
+
async def add_token(token: str):
|
| 136 |
+
if token.strip() and not token.startswith("#"):
|
| 137 |
+
globals.token_list.append(token.strip())
|
| 138 |
+
with open("data/token.txt", "a", encoding="utf-8") as f:
|
| 139 |
+
f.write(token.strip() + "\n")
|
| 140 |
+
logger.info(f"Token count: {len(globals.token_list)}, Error token count: {len(globals.error_token_list)}")
|
| 141 |
+
tokens_count = len(set(globals.token_list) - set(globals.error_token_list))
|
| 142 |
+
return {"status": "success", "tokens_count": tokens_count}
|
| 143 |
+
|
| 144 |
+
|
| 145 |
if enable_gateway:
|
| 146 |
@app.get("/", response_class=HTMLResponse)
|
| 147 |
+
async def chatgpt_html(request: Request):
|
| 148 |
+
token = request.query_params.get("token")
|
| 149 |
+
if not token:
|
| 150 |
+
token = request.cookies.get("token")
|
| 151 |
+
if not token:
|
| 152 |
+
return await login_html(request)
|
| 153 |
+
|
| 154 |
+
response = templates.TemplateResponse("chatgpt.html", {"request": request, "token": token})
|
| 155 |
+
response.set_cookie("token", value=token)
|
| 156 |
+
return response
|
| 157 |
+
|
| 158 |
+
@app.get("/login", response_class=HTMLResponse)
|
| 159 |
+
async def login_html(request: Request):
|
| 160 |
+
response = templates.TemplateResponse("login.html", {"request": request})
|
| 161 |
return response
|
| 162 |
|
| 163 |
|
|
|
|
| 219 |
}
|
| 220 |
|
| 221 |
|
| 222 |
+
banned_paths = [
|
| 223 |
+
"backend-api/accounts/logout_all",
|
| 224 |
+
"backend-api/accounts/deactivate",
|
| 225 |
+
"backend-api/user_system_messages",
|
| 226 |
+
"backend-api/memories",
|
| 227 |
+
"backend-api/settings/clear_account_user_memory"
|
| 228 |
+
]
|
| 229 |
redirect_paths = ["auth/logout"]
|
| 230 |
chatgpt_paths = ["c/"]
|
| 231 |
|
|
|
|
| 234 |
async def reverse_proxy(request: Request, path: str):
|
| 235 |
for chatgpt_path in chatgpt_paths:
|
| 236 |
if chatgpt_path in path:
|
| 237 |
+
return await chatgpt_html(request)
|
| 238 |
|
| 239 |
for banned_path in banned_paths:
|
| 240 |
if banned_path in path:
|
|
|
|
| 243 |
for redirect_path in redirect_paths:
|
| 244 |
if redirect_path in path:
|
| 245 |
redirect_url = str(request.base_url)
|
| 246 |
+
response = RedirectResponse(url=f"{redirect_url}", status_code=302)
|
| 247 |
+
response.delete_cookie("token")
|
| 248 |
+
return response
|
| 249 |
|
| 250 |
return await chatgpt_reverse_proxy(request, path)
|
| 251 |
else:
|
chatgpt/ChatService.py
CHANGED
|
@@ -37,7 +37,7 @@ class ChatService:
|
|
| 37 |
self.req_token = get_req_token(origin_token)
|
| 38 |
self.ua = get_ua(self.req_token)
|
| 39 |
self.user_agent = self.ua.get(
|
| 40 |
-
"
|
| 41 |
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
|
| 42 |
)
|
| 43 |
self.chat_token = "gAAAAAB"
|
|
@@ -95,22 +95,22 @@ class ChatService:
|
|
| 95 |
self.chat_request = None
|
| 96 |
|
| 97 |
self.base_headers = {
|
| 98 |
-
'
|
| 99 |
-
'
|
| 100 |
-
'
|
| 101 |
-
'
|
| 102 |
-
'
|
| 103 |
-
'
|
| 104 |
-
'
|
| 105 |
-
'
|
| 106 |
-
'
|
| 107 |
-
'
|
| 108 |
-
'
|
| 109 |
-
'
|
| 110 |
-
'
|
| 111 |
-
'
|
| 112 |
-
'
|
| 113 |
-
'
|
| 114 |
}
|
| 115 |
if self.access_token:
|
| 116 |
self.base_url = self.host_url + "/backend-api"
|
|
@@ -281,22 +281,22 @@ class ChatService:
|
|
| 281 |
self.chat_headers = self.base_headers.copy()
|
| 282 |
self.chat_headers.update(
|
| 283 |
{
|
| 284 |
-
'
|
| 285 |
-
'
|
| 286 |
-
'
|
| 287 |
}
|
| 288 |
)
|
| 289 |
if self.ark0se_token:
|
| 290 |
-
self.chat_headers['
|
| 291 |
|
| 292 |
if self.turnstile_token:
|
| 293 |
-
self.chat_headers['
|
| 294 |
|
| 295 |
if conversation_only:
|
| 296 |
-
self.chat_headers.pop('
|
| 297 |
-
self.chat_headers.pop('
|
| 298 |
-
self.chat_headers.pop('
|
| 299 |
-
self.chat_headers.pop('
|
| 300 |
|
| 301 |
if "gpt-4-gizmo" in self.origin_model:
|
| 302 |
gizmo_id = self.origin_model.split("gpt-4-gizmo-")[-1]
|
|
@@ -429,10 +429,10 @@ class ChatService:
|
|
| 429 |
headers = self.base_headers.copy()
|
| 430 |
headers.update(
|
| 431 |
{
|
| 432 |
-
'
|
| 433 |
-
'
|
| 434 |
-
'
|
| 435 |
-
'
|
| 436 |
}
|
| 437 |
)
|
| 438 |
headers.pop('Authorization', None)
|
|
|
|
| 37 |
self.req_token = get_req_token(origin_token)
|
| 38 |
self.ua = get_ua(self.req_token)
|
| 39 |
self.user_agent = self.ua.get(
|
| 40 |
+
"user-agent",
|
| 41 |
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
|
| 42 |
)
|
| 43 |
self.chat_token = "gAAAAAB"
|
|
|
|
| 95 |
self.chat_request = None
|
| 96 |
|
| 97 |
self.base_headers = {
|
| 98 |
+
'accept': '*/*',
|
| 99 |
+
'accept-encoding': 'gzip, deflate, br, zstd',
|
| 100 |
+
'accept-language': 'en-US,en;q=0.9',
|
| 101 |
+
'content-type': 'application/json',
|
| 102 |
+
'oai-device-id': self.oai_device_id,
|
| 103 |
+
'oai-language': 'en-US',
|
| 104 |
+
'origin': self.host_url,
|
| 105 |
+
'priority': 'u=1, i',
|
| 106 |
+
'referer': f'{self.host_url}/',
|
| 107 |
+
'sec-ch-ua': self.ua.get("sec-ch-ua", '"Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"'),
|
| 108 |
+
'sec-ch-ua-mobile': self.ua.get("sec-ch-ua-mobile", "?0"),
|
| 109 |
+
'sec-ch-ua-platform': self.ua.get("sec-ch-ua-platform", '"Windows"'),
|
| 110 |
+
'sec-fetch-dest': 'empty',
|
| 111 |
+
'sec-fetch-mode': 'cors',
|
| 112 |
+
'sec-fetch-site': 'same-origin',
|
| 113 |
+
'user-agent': self.user_agent
|
| 114 |
}
|
| 115 |
if self.access_token:
|
| 116 |
self.base_url = self.host_url + "/backend-api"
|
|
|
|
| 281 |
self.chat_headers = self.base_headers.copy()
|
| 282 |
self.chat_headers.update(
|
| 283 |
{
|
| 284 |
+
'accept': 'text/event-stream',
|
| 285 |
+
'openai-sentinel-chat-requirements-token': self.chat_token,
|
| 286 |
+
'openai-sentinel-proof-token': self.proof_token,
|
| 287 |
}
|
| 288 |
)
|
| 289 |
if self.ark0se_token:
|
| 290 |
+
self.chat_headers['openai-sentinel-ark' + 'ose-token'] = self.ark0se_token
|
| 291 |
|
| 292 |
if self.turnstile_token:
|
| 293 |
+
self.chat_headers['openai-sentinel-turnstile-token'] = self.turnstile_token
|
| 294 |
|
| 295 |
if conversation_only:
|
| 296 |
+
self.chat_headers.pop('openai-sentinel-chat-requirements-token', None)
|
| 297 |
+
self.chat_headers.pop('openai-sentinel-proof-token', None)
|
| 298 |
+
self.chat_headers.pop('openai-sentinel-ark' + 'ose-token', None)
|
| 299 |
+
self.chat_headers.pop('openai-sentinel-turnstile-token', None)
|
| 300 |
|
| 301 |
if "gpt-4-gizmo" in self.origin_model:
|
| 302 |
gizmo_id = self.origin_model.split("gpt-4-gizmo-")[-1]
|
|
|
|
| 429 |
headers = self.base_headers.copy()
|
| 430 |
headers.update(
|
| 431 |
{
|
| 432 |
+
'accept': 'application/json, text/plain, */*',
|
| 433 |
+
'content-type': mime_type,
|
| 434 |
+
'x-ms-blob-type': 'BlockBlob',
|
| 435 |
+
'x-ms-version': '2020-04-08',
|
| 436 |
}
|
| 437 |
)
|
| 438 |
headers.pop('Authorization', None)
|
chatgpt/authorization.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import asyncio
|
|
|
|
| 2 |
import os
|
| 3 |
import random
|
| 4 |
|
|
@@ -40,16 +41,30 @@ def get_req_token(req_token, seed=None):
|
|
| 40 |
|
| 41 |
def get_ua(req_token):
|
| 42 |
user_agent = globals.user_agent_map.get(req_token, "")
|
| 43 |
-
|
| 44 |
if not user_agent:
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
else:
|
| 54 |
return user_agent
|
| 55 |
|
|
|
|
| 1 |
import asyncio
|
| 2 |
+
import json
|
| 3 |
import os
|
| 4 |
import random
|
| 5 |
|
|
|
|
| 41 |
|
| 42 |
def get_ua(req_token):
|
| 43 |
user_agent = globals.user_agent_map.get(req_token, "")
|
| 44 |
+
user_agent = {k.lower(): v for k, v in user_agent.items()}
|
| 45 |
if not user_agent:
|
| 46 |
+
if not req_token:
|
| 47 |
+
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'), platform=('windows', 'macos'))
|
| 48 |
+
return {
|
| 49 |
+
"user-agent": ua.text,
|
| 50 |
+
"sec-ch-ua-platform": ua.platform,
|
| 51 |
+
"sec-ch-ua": ua.ch.brands,
|
| 52 |
+
"sec-ch-ua-mobile": ua.ch.mobile,
|
| 53 |
+
"impersonate": random.choice(globals.impersonate_list),
|
| 54 |
+
}
|
| 55 |
+
else:
|
| 56 |
+
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'), platform=('windows', 'macos'))
|
| 57 |
+
user_agent = {
|
| 58 |
+
"user-agent": ua.text,
|
| 59 |
+
"sec-ch-ua-platform": ua.platform,
|
| 60 |
+
"sec-ch-ua": ua.ch.brands,
|
| 61 |
+
"sec-ch-ua-mobile": ua.ch.mobile,
|
| 62 |
+
"impersonate": random.choice(globals.impersonate_list),
|
| 63 |
+
}
|
| 64 |
+
globals.user_agent_map[req_token] = user_agent
|
| 65 |
+
with open(globals.USER_AGENTS_FILE, "a", encoding="utf-8") as f:
|
| 66 |
+
f.write(json.dumps({req_token: user_agent}, indent=4))
|
| 67 |
+
return user_agent
|
| 68 |
else:
|
| 69 |
return user_agent
|
| 70 |
|
chatgpt/globals.py
CHANGED
|
@@ -78,10 +78,10 @@ if os.path.exists(USER_AGENTS_FILE):
|
|
| 78 |
for token in new_tokens:
|
| 79 |
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'), platform=('windows', 'macos'))
|
| 80 |
ua_dict = {
|
| 81 |
-
"
|
| 82 |
-
"
|
| 83 |
-
"
|
| 84 |
-
"
|
| 85 |
"impersonate": random.choice(impersonate_list),
|
| 86 |
}
|
| 87 |
user_agent_map[token] = ua_dict
|
|
@@ -91,10 +91,10 @@ else:
|
|
| 91 |
for token in token_list:
|
| 92 |
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'), platform=('windows', 'macos'))
|
| 93 |
ua_dict = {
|
| 94 |
-
"
|
| 95 |
-
"
|
| 96 |
-
"
|
| 97 |
-
"
|
| 98 |
"impersonate": random.choice(impersonate_list),
|
| 99 |
}
|
| 100 |
user_agent_map[token] = ua_dict
|
|
|
|
| 78 |
for token in new_tokens:
|
| 79 |
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'), platform=('windows', 'macos'))
|
| 80 |
ua_dict = {
|
| 81 |
+
"user-agent": ua.text,
|
| 82 |
+
"sec-ch-ua-platform": ua.platform,
|
| 83 |
+
"sec-ch-ua": ua.ch.brands,
|
| 84 |
+
"sec-ch-ua-mobile": ua.ch.mobile,
|
| 85 |
"impersonate": random.choice(impersonate_list),
|
| 86 |
}
|
| 87 |
user_agent_map[token] = ua_dict
|
|
|
|
| 91 |
for token in token_list:
|
| 92 |
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'), platform=('windows', 'macos'))
|
| 93 |
ua_dict = {
|
| 94 |
+
"user-agent": ua.text,
|
| 95 |
+
"sec-ch-ua-platform": ua.platform,
|
| 96 |
+
"sec-ch-ua": ua.ch.brands,
|
| 97 |
+
"sec-ch-ua-mobile": ua.ch.mobile,
|
| 98 |
"impersonate": random.choice(impersonate_list),
|
| 99 |
}
|
| 100 |
user_agent_map[token] = ua_dict
|
chatgpt/reverseProxy.py
CHANGED
|
@@ -5,7 +5,7 @@ from fastapi import Request, HTTPException
|
|
| 5 |
from fastapi.responses import StreamingResponse, Response
|
| 6 |
from starlette.background import BackgroundTask
|
| 7 |
|
| 8 |
-
from chatgpt.authorization import verify_token, get_req_token
|
| 9 |
from utils.Client import Client
|
| 10 |
from utils.config import chatgpt_base_url_list, proxy_url_list, enable_gateway
|
| 11 |
|
|
@@ -61,6 +61,15 @@ headers_reject_list = [
|
|
| 61 |
]
|
| 62 |
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
async def chatgpt_reverse_proxy(request: Request, path: str):
|
| 65 |
try:
|
| 66 |
origin_host = request.url.netloc
|
|
@@ -79,7 +88,7 @@ async def chatgpt_reverse_proxy(request: Request, path: str):
|
|
| 79 |
|
| 80 |
headers = {
|
| 81 |
key: value for key, value in request.headers.items()
|
| 82 |
-
if (key.lower() not in ["host", "origin", "referer"] and key.lower() not in headers_reject_list)
|
| 83 |
}
|
| 84 |
|
| 85 |
base_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com"
|
|
@@ -88,31 +97,23 @@ async def chatgpt_reverse_proxy(request: Request, path: str):
|
|
| 88 |
if "file-" in path and "backend-api" not in path:
|
| 89 |
base_url = "https://files.oaiusercontent.com"
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
|
|
|
|
|
|
| 94 |
headers.update({
|
| 95 |
"accept-language": "en-US,en;q=0.9",
|
| 96 |
"host": base_url.replace("https://", "").replace("http://", ""),
|
| 97 |
"origin": base_url,
|
| 98 |
-
"referer": f"{base_url}/"
|
| 99 |
-
"sec-fetch-dest": "empty",
|
| 100 |
-
"sec-fetch-mode": "cors",
|
| 101 |
-
"sec-fetch-site": "same-origin",
|
| 102 |
})
|
| 103 |
|
| 104 |
-
|
| 105 |
-
if
|
| 106 |
-
req_token =
|
| 107 |
access_token = await verify_token(req_token)
|
| 108 |
-
|
| 109 |
-
headers.update({"authorization": access_token})
|
| 110 |
-
else:
|
| 111 |
-
req_token = get_req_token(None, seed_token)
|
| 112 |
-
access_token = await verify_token(req_token)
|
| 113 |
-
headers.update({"authorization": access_token})
|
| 114 |
-
else:
|
| 115 |
-
headers.pop("authorization", None)
|
| 116 |
|
| 117 |
data = await request.body()
|
| 118 |
|
|
|
|
| 5 |
from fastapi.responses import StreamingResponse, Response
|
| 6 |
from starlette.background import BackgroundTask
|
| 7 |
|
| 8 |
+
from chatgpt.authorization import verify_token, get_req_token, get_ua
|
| 9 |
from utils.Client import Client
|
| 10 |
from utils.config import chatgpt_base_url_list, proxy_url_list, enable_gateway
|
| 11 |
|
|
|
|
| 61 |
]
|
| 62 |
|
| 63 |
|
| 64 |
+
async def get_real_req_token(token):
|
| 65 |
+
req_token = get_req_token(token)
|
| 66 |
+
if len(req_token) == 45 or req_token.startswith("eyJhbGciOi"):
|
| 67 |
+
return req_token
|
| 68 |
+
else:
|
| 69 |
+
req_token = get_req_token(None, token)
|
| 70 |
+
return req_token
|
| 71 |
+
|
| 72 |
+
|
| 73 |
async def chatgpt_reverse_proxy(request: Request, path: str):
|
| 74 |
try:
|
| 75 |
origin_host = request.url.netloc
|
|
|
|
| 88 |
|
| 89 |
headers = {
|
| 90 |
key: value for key, value in request.headers.items()
|
| 91 |
+
if (key.lower() not in ["host", "origin", "referer", "priority", "oai-device-id"] and key.lower() not in headers_reject_list)
|
| 92 |
}
|
| 93 |
|
| 94 |
base_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com"
|
|
|
|
| 97 |
if "file-" in path and "backend-api" not in path:
|
| 98 |
base_url = "https://files.oaiusercontent.com"
|
| 99 |
|
| 100 |
+
token = request.cookies.get("token")
|
| 101 |
+
req_token = await get_real_req_token(token)
|
| 102 |
+
ua = get_ua(req_token)
|
| 103 |
+
headers.update(ua)
|
| 104 |
+
|
| 105 |
headers.update({
|
| 106 |
"accept-language": "en-US,en;q=0.9",
|
| 107 |
"host": base_url.replace("https://", "").replace("http://", ""),
|
| 108 |
"origin": base_url,
|
| 109 |
+
"referer": f"{base_url}/"
|
|
|
|
|
|
|
|
|
|
| 110 |
})
|
| 111 |
|
| 112 |
+
token = headers.get("authorization", "").replace("Bearer ", "")
|
| 113 |
+
if token:
|
| 114 |
+
req_token = await get_real_req_token(token)
|
| 115 |
access_token = await verify_token(req_token)
|
| 116 |
+
headers.update({"authorization": access_token})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
data = await request.body()
|
| 119 |
|
templates/chatgpt.html
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
utils/config.py
CHANGED
|
@@ -52,7 +52,7 @@ proxy_url_list = proxy_url.split(',') if proxy_url else []
|
|
| 52 |
user_agents_list = ast.literal_eval(user_agents)
|
| 53 |
|
| 54 |
logger.info("-" * 60)
|
| 55 |
-
logger.info("Chat2Api 1.5.
|
| 56 |
logger.info("-" * 60)
|
| 57 |
logger.info("Environment variables:")
|
| 58 |
logger.info("API_PREFIX: " + str(api_prefix))
|
|
|
|
| 52 |
user_agents_list = ast.literal_eval(user_agents)
|
| 53 |
|
| 54 |
logger.info("-" * 60)
|
| 55 |
+
logger.info("Chat2Api 1.5.10 | https://github.com/lanqian528/chat2api")
|
| 56 |
logger.info("-" * 60)
|
| 57 |
logger.info("Environment variables:")
|
| 58 |
logger.info("API_PREFIX: " + str(api_prefix))
|