mirror of
https://github.com/lanqian528/chat2api.git
synced 2026-06-13 21:02:46 +08:00
commit
95f4f5720c
@ -2,12 +2,13 @@ import asyncio
|
||||
import types
|
||||
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from fastapi import Request, Depends, HTTPException, Form
|
||||
from fastapi import Request, HTTPException, Form, Security
|
||||
from fastapi.responses import HTMLResponse, StreamingResponse, JSONResponse
|
||||
from fastapi.security import HTTPAuthorizationCredentials
|
||||
from starlette.background import BackgroundTask
|
||||
|
||||
import utils.globals as globals
|
||||
from app import templates, oauth2_scheme, app
|
||||
from app import app, templates, security_scheme
|
||||
from chatgpt.ChatService import ChatService
|
||||
from chatgpt.authorization import refresh_all_tokens
|
||||
from utils.Logger import logger
|
||||
@ -49,7 +50,8 @@ async def process(request_data, req_token):
|
||||
|
||||
|
||||
@app.post(f"/{api_prefix}/v1/chat/completions" if api_prefix else "/v1/chat/completions")
|
||||
async def send_conversation(request: Request, req_token: str = Depends(oauth2_scheme)):
|
||||
async def send_conversation(request: Request, credentials: HTTPAuthorizationCredentials = Security(security_scheme)):
|
||||
req_token = credentials.credentials
|
||||
try:
|
||||
request_data = await request.json()
|
||||
except Exception:
|
||||
@ -87,7 +89,7 @@ async def upload_post(text: str = Form(...)):
|
||||
for line in lines:
|
||||
if line.strip() and not line.startswith("#"):
|
||||
globals.token_list.append(line.strip())
|
||||
with open("../data/token.txt", "a", encoding="utf-8") as f:
|
||||
with open(globals.TOKENS_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(line.strip() + "\n")
|
||||
logger.info(f"Token count: {len(globals.token_list)}, Error token count: {len(globals.error_token_list)}")
|
||||
tokens_count = len(set(globals.token_list) - set(globals.error_token_list))
|
||||
@ -98,7 +100,7 @@ async def upload_post(text: str = Form(...)):
|
||||
async def upload_post():
|
||||
globals.token_list.clear()
|
||||
globals.error_token_list.clear()
|
||||
with open("../data/token.txt", "w", encoding="utf-8") as f:
|
||||
with open(globals.TOKENS_FILE, "w", encoding="utf-8") as f:
|
||||
pass
|
||||
logger.info(f"Token count: {len(globals.token_list)}, Error token count: {len(globals.error_token_list)}")
|
||||
tokens_count = len(set(globals.token_list) - set(globals.error_token_list))
|
||||
@ -115,7 +117,7 @@ async def error_tokens():
|
||||
async def add_token(token: str):
|
||||
if token.strip() and not token.startswith("#"):
|
||||
globals.token_list.append(token.strip())
|
||||
with open("../data/token.txt", "a", encoding="utf-8") as f:
|
||||
with open(globals.TOKENS_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(token.strip() + "\n")
|
||||
logger.info(f"Token count: {len(globals.token_list)}, Error token count: {len(globals.error_token_list)}")
|
||||
tokens_count = len(set(globals.token_list) - set(globals.error_token_list))
|
||||
|
||||
32
app.py
32
app.py
@ -1,11 +1,13 @@
|
||||
import warnings
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from utils.configs import enable_gateway, api_prefix
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
@ -15,7 +17,11 @@ access_format = r'%(asctime)s | %(levelname)s | %(client_addr)s: %(request_line)
|
||||
log_config["formatters"]["default"]["fmt"] = default_format
|
||||
log_config["formatters"]["access"]["fmt"] = access_format
|
||||
|
||||
app = FastAPI()
|
||||
app = FastAPI(
|
||||
docs_url=f"/{api_prefix}/docs", # 设置 Swagger UI 文档路径
|
||||
redoc_url=f"/{api_prefix}/redoc", # 设置 Redoc 文档路径
|
||||
openapi_url=f"/{api_prefix}/openapi.json" # 设置 OpenAPI JSON 路径
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
@ -26,12 +32,26 @@ app.add_middleware(
|
||||
)
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token", auto_error=False)
|
||||
security_scheme = HTTPBearer()
|
||||
|
||||
from app import app
|
||||
|
||||
import gateway.backend
|
||||
import gateway.share
|
||||
import api.chat2api
|
||||
|
||||
if enable_gateway:
|
||||
import gateway.share
|
||||
import gateway.login
|
||||
import gateway.chatgpt
|
||||
import gateway.gpts
|
||||
import gateway.admin
|
||||
import gateway.v1
|
||||
import gateway.backend
|
||||
else:
|
||||
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"])
|
||||
async def reverse_proxy():
|
||||
raise HTTPException(status_code=404, detail="Gateway is disabled")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run("app:app", host="0.0.0.0", port=5005)
|
||||
# uvicorn.run("app:app", host="0.0.0.0", port=5005, ssl_keyfile="key.pem", ssl_certfile="cert.pem")
|
||||
|
||||
@ -105,6 +105,9 @@ async def verify_token(req_token):
|
||||
return access_token
|
||||
elif len(req_token) == 45:
|
||||
try:
|
||||
if req_token in globals.error_token_list:
|
||||
raise HTTPException(status_code=401, detail="Error RefreshToken")
|
||||
|
||||
access_token = await rt2ac(req_token, force_refresh=False)
|
||||
return access_token
|
||||
except HTTPException as e:
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
0
gateway/admin.py
Normal file
0
gateway/admin.py
Normal file
@ -1,150 +1,149 @@
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from fastapi import Request, HTTPException
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse, Response
|
||||
from fastapi.responses import RedirectResponse, StreamingResponse, Response
|
||||
from starlette.background import BackgroundTask
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
|
||||
import utils.globals as globals
|
||||
from app import app, templates
|
||||
from gateway.reverseProxy import chatgpt_reverse_proxy
|
||||
from utils.configs import enable_gateway
|
||||
from app import app
|
||||
from chatgpt.authorization import verify_token, get_fp
|
||||
from chatgpt.proofofWork import get_answer_token, get_config, get_requirements_token
|
||||
from gateway.chatgpt import chatgpt_html
|
||||
from gateway.reverseProxy import chatgpt_reverse_proxy, content_generator, get_real_req_token, headers_reject_list
|
||||
from utils.Client import Client
|
||||
from utils.Logger import logger
|
||||
from utils.configs import x_sign, turnstile_solver_url, chatgpt_base_url_list, no_sentinel
|
||||
|
||||
with open("templates/remix_context.json", "r", encoding="utf-8") as f:
|
||||
remix_context = json.load(f)
|
||||
banned_paths = [
|
||||
"backend-api/accounts/logout_all",
|
||||
"backend-api/accounts/deactivate",
|
||||
"backend-api/user_system_messages",
|
||||
"backend-api/memories",
|
||||
"backend-api/settings/clear_account_user_memory",
|
||||
"backend-api/conversations/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
|
||||
"backend-api/accounts/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/invites",
|
||||
"admin",
|
||||
]
|
||||
redirect_paths = ["auth/logout"]
|
||||
chatgpt_paths = ["c/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"]
|
||||
|
||||
|
||||
def set_value_for_key(data, target_key, new_value):
|
||||
if isinstance(data, dict):
|
||||
for key, value in data.items():
|
||||
if key == target_key:
|
||||
data[key] = new_value
|
||||
else:
|
||||
set_value_for_key(value, target_key, new_value)
|
||||
elif isinstance(data, list):
|
||||
for item in data:
|
||||
set_value_for_key(item, target_key, new_value)
|
||||
@app.get("/backend-api/accounts/check/v4-2023-04-27")
|
||||
async def check_account(request: Request):
|
||||
token = request.headers.get("Authorization").replace("Bearer ", "")
|
||||
check_account_response = await chatgpt_reverse_proxy(request, "backend-api/accounts/check/v4-2023-04-27")
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return check_account_response
|
||||
else:
|
||||
check_account_str = check_account_response.body.decode('utf-8')
|
||||
check_account_info = json.loads(check_account_str)
|
||||
for key in check_account_info.get("accounts", {}).keys():
|
||||
account_id = check_account_info["accounts"][key]["account"]["account_id"]
|
||||
globals.seed_map[token]["user_id"] = \
|
||||
check_account_info["accounts"][key]["account"]["account_user_id"].split("__")[0]
|
||||
check_account_info["accounts"][key]["account"]["account_user_id"] = f"user-chatgpt__{account_id}"
|
||||
with open(globals.SEED_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(globals.seed_map, f, indent=4)
|
||||
return check_account_info
|
||||
|
||||
|
||||
if enable_gateway:
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def chatgpt_html(request: Request):
|
||||
token = request.query_params.get("token")
|
||||
if not token:
|
||||
token = request.cookies.get("token")
|
||||
if not token:
|
||||
return await login_html(request)
|
||||
|
||||
user_remix_context = remix_context.copy()
|
||||
set_value_for_key(user_remix_context, "user", {"id": "user-chatgpt"})
|
||||
set_value_for_key(user_remix_context, "accessToken", token)
|
||||
|
||||
response = templates.TemplateResponse("chatgpt.html", {"request": request, "remix_context": user_remix_context})
|
||||
response.set_cookie("token", value=token, expires="Thu, 01 Jan 2099 00:00:00 GMT")
|
||||
return response
|
||||
|
||||
|
||||
# @app.get("/backend-api/accounts/check/v4-2023-04-27")
|
||||
# async def check_account(request: Request):
|
||||
# token = request.headers.get("Authorization").replace("Bearer ", "")
|
||||
# check_account_response = await chatgpt_reverse_proxy(request, "backend-api/accounts/check/v4-2023-04-27")
|
||||
# if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
# return check_account_response
|
||||
# else:
|
||||
# check_account_str = check_account_response.body.decode('utf-8')
|
||||
# check_account_info = json.loads(check_account_str)
|
||||
# for key in check_account_info.get("accounts", {}).keys():
|
||||
# account_id = check_account_info["accounts"][key]["account"]["account_id"]
|
||||
# globals.seed_map[token]["user_id"] = check_account_info["accounts"][key]["account"]["account_user_id"].split("__")[0]
|
||||
# check_account_info["accounts"][key]["account"]["account_user_id"] = f"user-chatgpt__{account_id}"
|
||||
# with open(globals.SEED_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
# json.dump(globals.seed_map, f, indent=4)
|
||||
# return check_account_info
|
||||
|
||||
@app.get("/login", response_class=HTMLResponse)
|
||||
async def login_html(request: Request):
|
||||
response = templates.TemplateResponse("login.html", {"request": request})
|
||||
return response
|
||||
|
||||
|
||||
@app.get("/gpts")
|
||||
async def get_gpts():
|
||||
return {"kind": "store"}
|
||||
|
||||
|
||||
@app.get("/backend-api/gizmos/bootstrap")
|
||||
async def get_gizmos_bootstrap():
|
||||
@app.get("/backend-api/gizmos/bootstrap")
|
||||
async def get_gizmos_bootstrap(request: Request):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return await chatgpt_reverse_proxy(request, "backend-api/gizmos/bootstrap")
|
||||
else:
|
||||
return {"gizmos": []}
|
||||
|
||||
|
||||
@app.get("/backend-api/conversations")
|
||||
async def get_conversations(request: Request):
|
||||
limit = int(request.query_params.get("limit", 28))
|
||||
offset = int(request.query_params.get("offset", 0))
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return await chatgpt_reverse_proxy(request, "backend-api/conversations")
|
||||
else:
|
||||
items = []
|
||||
for conversation_id in globals.seed_map.get(token, {}).get("conversations", []):
|
||||
conversation = globals.conversation_map.get(conversation_id, None)
|
||||
if conversation:
|
||||
items.append(conversation)
|
||||
items = items[int(offset):int(offset) + int(limit)]
|
||||
conversations = {
|
||||
"items": items,
|
||||
"total": len(items),
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
"has_missing_conversations": False
|
||||
}
|
||||
return Response(content=json.dumps(conversations, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
@app.get("/backend-api/conversation/{conversation_id}")
|
||||
async def update_conversation(request: Request, conversation_id: str):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
conversation_details_response = await chatgpt_reverse_proxy(request, f"backend-api/conversation/{conversation_id}")
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return conversation_details_response
|
||||
else:
|
||||
conversation_details_str = conversation_details_response.body.decode('utf-8')
|
||||
conversation_details = json.loads(conversation_details_str)
|
||||
if conversation_id in globals.seed_map[token]["conversations"] and conversation_id in globals.conversation_map:
|
||||
globals.conversation_map[conversation_id]["title"] = conversation_details.get("title", None)
|
||||
globals.conversation_map[conversation_id]["is_archived"] = conversation_details.get("is_archived", False)
|
||||
globals.conversation_map[conversation_id]["conversation_template_id"] = conversation_details.get("conversation_template_id", None)
|
||||
globals.conversation_map[conversation_id]["gizmo_id"] = conversation_details.get("gizmo_id", None)
|
||||
globals.conversation_map[conversation_id]["async_status"] = conversation_details.get("async_status", None)
|
||||
with open(globals.CONVERSATION_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(globals.conversation_map, f, indent=4)
|
||||
return conversation_details_response
|
||||
|
||||
|
||||
@app.patch("/backend-api/conversation/{conversation_id}")
|
||||
async def patch_conversation(request: Request, conversation_id: str):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
patch_response = (await chatgpt_reverse_proxy(request, f"backend-api/conversation/{conversation_id}"))
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return patch_response
|
||||
else:
|
||||
data = await request.json()
|
||||
if conversation_id in globals.seed_map[token][
|
||||
"conversations"] and conversation_id in globals.conversation_map:
|
||||
if not data.get("is_visible", True):
|
||||
globals.conversation_map.pop(conversation_id)
|
||||
globals.seed_map[token]["conversations"].remove(conversation_id)
|
||||
with open(globals.SEED_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(globals.seed_map, f, indent=4)
|
||||
@app.get("/backend-api/conversations")
|
||||
async def get_conversations(request: Request):
|
||||
limit = int(request.query_params.get("limit", 28))
|
||||
offset = int(request.query_params.get("offset", 0))
|
||||
is_archived = request.query_params.get("is_archived", None)
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return await chatgpt_reverse_proxy(request, "backend-api/conversations")
|
||||
else:
|
||||
items = []
|
||||
for conversation_id in globals.seed_map.get(token, {}).get("conversations", []):
|
||||
conversation = globals.conversation_map.get(conversation_id, None)
|
||||
if conversation:
|
||||
if is_archived == "true":
|
||||
if conversation.get("is_archived", False):
|
||||
items.append(conversation)
|
||||
else:
|
||||
globals.conversation_map[conversation_id].update(data)
|
||||
with open(globals.CONVERSATION_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(globals.conversation_map, f, indent=4)
|
||||
return patch_response
|
||||
if not conversation.get("is_archived", False):
|
||||
items.append(conversation)
|
||||
items = items[int(offset):int(offset) + int(limit)]
|
||||
conversations = {
|
||||
"items": items,
|
||||
"total": len(items),
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
"has_missing_conversations": False
|
||||
}
|
||||
return Response(content=json.dumps(conversations, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
@app.get("/backend-api/me")
|
||||
async def get_me(request: Request):
|
||||
@app.get("/backend-api/conversation/{conversation_id}")
|
||||
async def update_conversation(request: Request, conversation_id: str):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
conversation_details_response = await chatgpt_reverse_proxy(request,
|
||||
f"backend-api/conversation/{conversation_id}")
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return conversation_details_response
|
||||
else:
|
||||
conversation_details_str = conversation_details_response.body.decode('utf-8')
|
||||
conversation_details = json.loads(conversation_details_str)
|
||||
if conversation_id in globals.seed_map[token][
|
||||
"conversations"] and conversation_id in globals.conversation_map:
|
||||
globals.conversation_map[conversation_id]["title"] = conversation_details.get("title", None)
|
||||
globals.conversation_map[conversation_id]["is_archived"] = conversation_details.get("is_archived",
|
||||
False)
|
||||
globals.conversation_map[conversation_id]["conversation_template_id"] = conversation_details.get(
|
||||
"conversation_template_id", None)
|
||||
globals.conversation_map[conversation_id]["gizmo_id"] = conversation_details.get("gizmo_id", None)
|
||||
globals.conversation_map[conversation_id]["async_status"] = conversation_details.get("async_status",
|
||||
None)
|
||||
with open(globals.CONVERSATION_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(globals.conversation_map, f, indent=4)
|
||||
return conversation_details_response
|
||||
|
||||
|
||||
@app.patch("/backend-api/conversation/{conversation_id}")
|
||||
async def patch_conversation(request: Request, conversation_id: str):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
patch_response = (await chatgpt_reverse_proxy(request, f"backend-api/conversation/{conversation_id}"))
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return patch_response
|
||||
else:
|
||||
data = await request.json()
|
||||
if conversation_id in globals.seed_map[token][
|
||||
"conversations"] and conversation_id in globals.conversation_map:
|
||||
if not data.get("is_visible", True):
|
||||
globals.conversation_map.pop(conversation_id)
|
||||
globals.seed_map[token]["conversations"].remove(conversation_id)
|
||||
with open(globals.SEED_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(globals.seed_map, f, indent=4)
|
||||
else:
|
||||
globals.conversation_map[conversation_id].update(data)
|
||||
with open(globals.CONVERSATION_MAP_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(globals.conversation_map, f, indent=4)
|
||||
return patch_response
|
||||
|
||||
|
||||
@app.get("/backend-api/me")
|
||||
async def get_me(request: Request):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
if len(token) == 45 or token.startswith("eyJhbGciOi"):
|
||||
return await chatgpt_reverse_proxy(request, "backend-api/me")
|
||||
else:
|
||||
me = {
|
||||
"object": "user",
|
||||
"id": "org-chatgpt",
|
||||
@ -188,50 +187,136 @@ if enable_gateway:
|
||||
},
|
||||
"has_payg_project_spend_limit": True
|
||||
}
|
||||
return me
|
||||
return Response(content=json.dumps(me, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
banned_paths = [
|
||||
"backend-api/accounts/logout_all",
|
||||
"backend-api/accounts/deactivate",
|
||||
"backend-api/user_system_messages",
|
||||
"backend-api/memories",
|
||||
"backend-api/settings/clear_account_user_memory",
|
||||
"backend-api/conversations/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
|
||||
"backend-api/accounts/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/invites",
|
||||
"admin",
|
||||
]
|
||||
redirect_paths = ["auth/logout"]
|
||||
chatgpt_paths = ["c/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"]
|
||||
@app.post("/backend-api/edge")
|
||||
async def edge():
|
||||
return Response(status_code=204)
|
||||
|
||||
|
||||
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"])
|
||||
async def reverse_proxy(request: Request, path: str):
|
||||
if re.match("/v1/rgstr", path):
|
||||
return Response(status_code=202, content=b'{"success":true}')
|
||||
if no_sentinel:
|
||||
@app.post("/backend-api/sentinel/chat-requirements")
|
||||
async def sentinel_chat_conversations():
|
||||
return {
|
||||
"arkose": {
|
||||
"dx": None,
|
||||
"required": False
|
||||
},
|
||||
"persona": "chatgpt-paid",
|
||||
"proofofwork": {
|
||||
"difficulty": None,
|
||||
"required": False,
|
||||
"seed": None
|
||||
},
|
||||
"token": str(uuid.uuid4()),
|
||||
"turnstile": {
|
||||
"dx": None,
|
||||
"required": False
|
||||
}
|
||||
}
|
||||
|
||||
if re.match("ces/v1", path):
|
||||
return {"success": True}
|
||||
|
||||
if re.match("backend-api/edge", path):
|
||||
return Response(status_code=204)
|
||||
@app.post("/backend-api/conversation")
|
||||
async def chat_conversations(request: Request):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
req_token = await get_real_req_token(token)
|
||||
access_token = await verify_token(req_token)
|
||||
fp = get_fp(req_token)
|
||||
proxy_url = fp.pop("proxy_url", None)
|
||||
impersonate = fp.pop("impersonate", "safari15_3")
|
||||
user_agent = fp.get("user-agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0")
|
||||
|
||||
for chatgpt_path in chatgpt_paths:
|
||||
if re.match(chatgpt_path, path):
|
||||
return await chatgpt_html(request)
|
||||
host_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com"
|
||||
proof_token = None
|
||||
turnstile_token = None
|
||||
|
||||
headers = {
|
||||
key: value for key, value in request.headers.items()
|
||||
if (key.lower() not in ["host", "origin", "referer", "priority",
|
||||
"oai-device-id"] and key.lower() not in headers_reject_list)
|
||||
}
|
||||
headers.update(fp)
|
||||
headers.update({
|
||||
"authorization": f"Bearer {access_token}",
|
||||
"oai-device-id": fp.get("oai-device-id", str(uuid.uuid4()))
|
||||
})
|
||||
|
||||
client = Client(proxy=proxy_url, impersonate=impersonate)
|
||||
|
||||
config = get_config(user_agent)
|
||||
p = get_requirements_token(config)
|
||||
data = {'p': p}
|
||||
r = await client.post(f'{host_url}/backend-api/sentinel/chat-requirements', headers=headers, json=data,
|
||||
timeout=10)
|
||||
resp = r.json()
|
||||
turnstile = resp.get('turnstile', {})
|
||||
turnstile_required = turnstile.get('required')
|
||||
if turnstile_required:
|
||||
turnstile_dx = turnstile.get("dx")
|
||||
try:
|
||||
if turnstile_solver_url:
|
||||
res = await client.post(turnstile_solver_url,
|
||||
json={"url": "https://chatgpt.com", "p": p, "dx": turnstile_dx})
|
||||
turnstile_token = res.json().get("t")
|
||||
except Exception as e:
|
||||
logger.info(f"Turnstile ignored: {e}")
|
||||
|
||||
proofofwork = resp.get('proofofwork', {})
|
||||
proofofwork_required = proofofwork.get('required')
|
||||
if proofofwork_required:
|
||||
proofofwork_diff = proofofwork.get("difficulty")
|
||||
proofofwork_seed = proofofwork.get("seed")
|
||||
proof_token, solved = await run_in_threadpool(
|
||||
get_answer_token, proofofwork_seed, proofofwork_diff, config
|
||||
)
|
||||
if not solved:
|
||||
raise HTTPException(status_code=403, detail="Failed to solve proof of work")
|
||||
chat_token = resp.get('token')
|
||||
headers.update({
|
||||
"openai-sentinel-chat-requirements-token": chat_token,
|
||||
"openai-sentinel-proof-token": proof_token,
|
||||
"openai-sentinel-turnstile-token": turnstile_token,
|
||||
})
|
||||
|
||||
params = dict(request.query_params)
|
||||
data = await request.body()
|
||||
request_cookies = dict(request.cookies)
|
||||
background = BackgroundTask(client.close)
|
||||
r = await client.post_stream(f"{host_url}/backend-api/conversation", params=params, headers=headers,
|
||||
cookies=request_cookies, data=data, stream=True, allow_redirects=False)
|
||||
rheaders = r.headers
|
||||
if x_sign:
|
||||
rheaders.update({"x-sign": x_sign})
|
||||
if 'stream' in rheaders.get("content-type", ""):
|
||||
logger.info(f"Request token: {req_token}")
|
||||
logger.info(f"Request proxy: {proxy_url}")
|
||||
logger.info(f"Request UA: {user_agent}")
|
||||
logger.info(f"Request impersonate: {impersonate}")
|
||||
return StreamingResponse(content_generator(r, token), headers=rheaders,
|
||||
media_type=rheaders.get("content-type"), background=background)
|
||||
else:
|
||||
return Response(content=(await r.atext()), headers=rheaders, media_type=rheaders.get("content-type"),
|
||||
status_code=r.status_code, background=background)
|
||||
|
||||
|
||||
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"])
|
||||
async def reverse_proxy(request: Request, path: str):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
if len(token) != 45 and not token.startswith("eyJhbGciOi"):
|
||||
for banned_path in banned_paths:
|
||||
if re.match(banned_path, path):
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
for redirect_path in redirect_paths:
|
||||
if re.match(redirect_path, path):
|
||||
redirect_url = str(request.base_url)
|
||||
response = RedirectResponse(url=f"{redirect_url}login", status_code=302)
|
||||
return response
|
||||
for chatgpt_path in chatgpt_paths:
|
||||
if re.match(chatgpt_path, path):
|
||||
return await chatgpt_html(request)
|
||||
|
||||
return await chatgpt_reverse_proxy(request, path)
|
||||
else:
|
||||
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"])
|
||||
async def reverse_proxy():
|
||||
raise HTTPException(status_code=404, detail="Gateway is disabled")
|
||||
for redirect_path in redirect_paths:
|
||||
if re.match(redirect_path, path):
|
||||
redirect_url = str(request.base_url)
|
||||
response = RedirectResponse(url=f"{redirect_url}login", status_code=302)
|
||||
return response
|
||||
|
||||
return await chatgpt_reverse_proxy(request, path)
|
||||
|
||||
28
gateway/chatgpt.py
Normal file
28
gateway/chatgpt.py
Normal file
@ -0,0 +1,28 @@
|
||||
import json
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
from app import app, templates
|
||||
from gateway.login import login_html
|
||||
from utils.kv_utils import set_value_for_key
|
||||
|
||||
with open("templates/chatgpt_context.json", "r", encoding="utf-8") as f:
|
||||
chatgpt_context = json.load(f)
|
||||
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def chatgpt_html(request: Request):
|
||||
token = request.query_params.get("token")
|
||||
if not token:
|
||||
token = request.cookies.get("token")
|
||||
if not token:
|
||||
return await login_html(request)
|
||||
|
||||
user_remix_context = chatgpt_context.copy()
|
||||
set_value_for_key(user_remix_context, "user", {"id": "user-chatgpt"})
|
||||
set_value_for_key(user_remix_context, "accessToken", token)
|
||||
|
||||
response = templates.TemplateResponse("chatgpt.html", {"request": request, "remix_context": user_remix_context})
|
||||
response.set_cookie("token", value=token, expires="Thu, 01 Jan 2099 00:00:00 GMT")
|
||||
return response
|
||||
24
gateway/gpts.py
Normal file
24
gateway/gpts.py
Normal file
@ -0,0 +1,24 @@
|
||||
import json
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.responses import Response
|
||||
|
||||
from app import app
|
||||
from gateway.chatgpt import chatgpt_html
|
||||
|
||||
with open("templates/gpts_context.json", "r", encoding="utf-8") as f:
|
||||
gpts_context = json.load(f)
|
||||
|
||||
|
||||
@app.get("/gpts")
|
||||
async def get_gpts():
|
||||
return {"kind": "store"}
|
||||
|
||||
|
||||
@app.get("/g/g-{gizmo_id}")
|
||||
async def get_gizmo_json(request: Request, gizmo_id: str):
|
||||
params = request.query_params
|
||||
if params.get("_data") == "routes/g.$gizmoId._index":
|
||||
return Response(content=json.dumps(gpts_context, indent=4), media_type="application/json")
|
||||
else:
|
||||
return await chatgpt_html(request)
|
||||
10
gateway/login.py
Normal file
10
gateway/login.py
Normal file
@ -0,0 +1,10 @@
|
||||
from fastapi import Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
from app import app, templates
|
||||
|
||||
|
||||
@app.get("/login", response_class=HTMLResponse)
|
||||
async def login_html(request: Request):
|
||||
response = templates.TemplateResponse("login.html", {"request": request})
|
||||
return response
|
||||
@ -2,25 +2,25 @@ import json
|
||||
import random
|
||||
import time
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import Request, HTTPException
|
||||
from fastapi.responses import StreamingResponse, Response
|
||||
from starlette.background import BackgroundTask
|
||||
|
||||
from chatgpt.authorization import verify_token, get_req_token, get_fp
|
||||
import utils.globals as globals
|
||||
from chatgpt.authorization import verify_token, get_req_token, get_fp
|
||||
from utils.Client import Client
|
||||
from utils.Logger import logger
|
||||
from utils.configs import chatgpt_base_url_list, proxy_url_list
|
||||
from utils.configs import chatgpt_base_url_list
|
||||
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
def generate_current_time():
|
||||
current_time = datetime.now(timezone.utc)
|
||||
formatted_time = current_time.isoformat(timespec='microseconds').replace('+00:00', 'Z')
|
||||
return formatted_time
|
||||
|
||||
|
||||
headers_reject_list = [
|
||||
"x-real-ip",
|
||||
"x-forwarded-for",
|
||||
@ -159,7 +159,8 @@ async def chatgpt_reverse_proxy(request: Request, path: str):
|
||||
|
||||
headers = {
|
||||
key: value for key, value in request.headers.items()
|
||||
if (key.lower() not in ["host", "origin", "referer", "priority", "oai-device-id"] and key.lower() not in headers_reject_list)
|
||||
if (key.lower() not in ["host", "origin", "referer", "priority",
|
||||
"oai-device-id"] and key.lower() not in headers_reject_list)
|
||||
}
|
||||
|
||||
base_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com"
|
||||
@ -173,9 +174,9 @@ async def chatgpt_reverse_proxy(request: Request, path: str):
|
||||
token = request.cookies.get("token", "")
|
||||
req_token = await get_real_req_token(token)
|
||||
fp = get_fp(req_token)
|
||||
proxy_url = fp.get("proxy_url")
|
||||
proxy_url = fp.pop("proxy_url", None)
|
||||
impersonate = fp.pop("impersonate", "safari15_3")
|
||||
user_agent = fp.get("user-agent")
|
||||
impersonate = fp.get("impersonate", "safari15_3")
|
||||
headers.update(fp)
|
||||
|
||||
headers.update({
|
||||
@ -185,12 +186,13 @@ async def chatgpt_reverse_proxy(request: Request, path: str):
|
||||
"referer": f"{base_url}/"
|
||||
})
|
||||
if "ab.chatgpt.com" in base_url:
|
||||
headers.update({
|
||||
"statsig-sdk-type": "js-client",
|
||||
"statsig-api-key": "client-tnE5GCU2F2cTxRiMbvTczMDT1jpwIigZHsZSdqiy4u",
|
||||
"statsig-sdk-version": "5.1.0",
|
||||
"statsig-client-time": int(time.time() * 1000)
|
||||
})
|
||||
if "statsig-api-key" not in headers:
|
||||
headers.update({
|
||||
"statsig-sdk-type": "js-client",
|
||||
"statsig-api-key": "client-tnE5GCU2F2cTxRiMbvTczMDT1jpwIigZHsZSdqiy4u",
|
||||
"statsig-sdk-version": "5.1.0",
|
||||
"statsig-client-time": int(time.time() * 1000)
|
||||
})
|
||||
|
||||
token = headers.get("authorization", "").replace("Bearer ", "")
|
||||
if token:
|
||||
@ -208,14 +210,11 @@ async def chatgpt_reverse_proxy(request: Request, path: str):
|
||||
background = BackgroundTask(client.close)
|
||||
r = await client.request(request.method, f"{base_url}/{path}", params=params, headers=headers,
|
||||
cookies=request_cookies, data=data, stream=True, allow_redirects=False)
|
||||
if r.status_code == 307:
|
||||
if "bing" in path:
|
||||
return Response(status_code=307,
|
||||
headers={"Location": r.headers.get("Location").replace("chatgpt.com", origin_host)
|
||||
.replace("https", petrol)}, background=background)
|
||||
if r.status_code == 302:
|
||||
return Response(status_code=302,
|
||||
headers={"Location": r.headers.get("Location").replace("chatgpt.com", origin_host)
|
||||
if r.status_code == 307 or r.status_code == 302 or r.status_code == 301:
|
||||
return Response(status_code=307,
|
||||
headers={"Location": r.headers.get("Location")
|
||||
.replace("ab.chatgpt.com", origin_host)
|
||||
.replace("chatgpt.com", origin_host)
|
||||
.replace("cdn.oaistatic.com", origin_host)
|
||||
.replace("https", petrol)}, background=background)
|
||||
elif 'stream' in r.headers.get("content-type", ""):
|
||||
|
||||
0
gateway/route.py
Normal file
0
gateway/route.py
Normal file
164
gateway/share.py
164
gateway/share.py
@ -1,22 +1,19 @@
|
||||
import json
|
||||
import random
|
||||
import uuid
|
||||
import time
|
||||
|
||||
from fastapi import Request, HTTPException
|
||||
import jwt
|
||||
from fastapi import Request, HTTPException, Security
|
||||
from fastapi.responses import Response
|
||||
from starlette.background import BackgroundTask
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
from starlette.responses import StreamingResponse
|
||||
from fastapi.security import HTTPAuthorizationCredentials
|
||||
|
||||
import utils.globals as globals
|
||||
from app import app
|
||||
from app import app, security_scheme
|
||||
from chatgpt.authorization import get_fp, verify_token
|
||||
from chatgpt.proofofWork import get_config, get_requirements_token, get_answer_token
|
||||
from gateway.reverseProxy import get_real_req_token, content_generator
|
||||
from gateway.reverseProxy import get_real_req_token
|
||||
from utils.Client import Client
|
||||
from utils.Logger import logger
|
||||
from utils.configs import proxy_url_list, chatgpt_base_url_list, turnstile_solver_url, x_sign, no_sentinel, \
|
||||
authorization_list
|
||||
from utils.configs import proxy_url_list, chatgpt_base_url_list, authorization_list
|
||||
|
||||
base_headers = {
|
||||
'accept': '*/*',
|
||||
@ -31,18 +28,16 @@ base_headers = {
|
||||
}
|
||||
|
||||
|
||||
def verify_authorization(request: Request):
|
||||
auth_header = request.headers.get("Authorization").replace("Bearer ", "")
|
||||
|
||||
if not auth_header:
|
||||
def verify_authorization(bearer_token):
|
||||
if not bearer_token:
|
||||
raise HTTPException(status_code=401, detail="Authorization header is missing")
|
||||
if auth_header not in authorization_list:
|
||||
if bearer_token not in authorization_list:
|
||||
raise HTTPException(status_code=401, detail="Invalid authorization")
|
||||
|
||||
|
||||
@app.get("/seedtoken")
|
||||
async def get_seedtoken(request: Request):
|
||||
verify_authorization(request)
|
||||
async def get_seedtoken(request: Request, credentials: HTTPAuthorizationCredentials = Security(security_scheme)):
|
||||
verify_authorization(credentials.credentials)
|
||||
try:
|
||||
params = request.query_params
|
||||
seed = params.get("seed")
|
||||
@ -69,8 +64,8 @@ async def get_seedtoken(request: Request):
|
||||
|
||||
|
||||
@app.post("/seedtoken")
|
||||
async def set_seedtoken(request: Request):
|
||||
verify_authorization(request)
|
||||
async def set_seedtoken(request: Request, credentials: HTTPAuthorizationCredentials = Security(security_scheme)):
|
||||
verify_authorization(credentials.credentials)
|
||||
data = await request.json()
|
||||
|
||||
seed = data.get("seed")
|
||||
@ -91,8 +86,8 @@ async def set_seedtoken(request: Request):
|
||||
|
||||
|
||||
@app.delete("/seedtoken")
|
||||
async def delete_seedtoken(request: Request):
|
||||
verify_authorization(request)
|
||||
async def delete_seedtoken(request: Request, credentials: HTTPAuthorizationCredentials = Security(security_scheme)):
|
||||
verify_authorization(credentials.credentials)
|
||||
|
||||
try:
|
||||
data = await request.json()
|
||||
@ -129,17 +124,18 @@ async def chatgpt_account_check(access_token):
|
||||
auth_info = {}
|
||||
client = Client(proxy=random.choice(proxy_url_list) if proxy_url_list else None)
|
||||
try:
|
||||
proxy_url = random.choice(proxy_url_list) if proxy_url_list else None
|
||||
host_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com"
|
||||
req_token = await get_real_req_token(access_token)
|
||||
access_token = await verify_token(req_token)
|
||||
fp = get_fp(req_token)
|
||||
proxy_url = fp.pop("proxy_url", None)
|
||||
impersonate = fp.pop("impersonate", "safari15_3")
|
||||
|
||||
headers = base_headers.copy()
|
||||
headers.update({"authorization": f"Bearer {access_token}"})
|
||||
headers.update(fp)
|
||||
|
||||
client = Client(proxy=proxy_url, impersonate=fp.get("impersonate", "safari15_3"))
|
||||
client = Client(proxy=proxy_url, impersonate=impersonate)
|
||||
r = await client.get(f"{host_url}/backend-api/models?history_and_training_disabled=false", headers=headers,
|
||||
timeout=10)
|
||||
if r.status_code != 200:
|
||||
@ -225,14 +221,17 @@ async def refresh(request: Request):
|
||||
if not refresh_token and not access_token:
|
||||
raise HTTPException(status_code=401, detail="refresh_token or access_token is required")
|
||||
|
||||
need_refresh = True
|
||||
if access_token:
|
||||
account_check_info = await chatgpt_account_check(access_token)
|
||||
if account_check_info:
|
||||
auth_info.update(account_check_info)
|
||||
auth_info.update({"accessToken": access_token})
|
||||
return Response(content=json.dumps(auth_info), media_type="application/json")
|
||||
try:
|
||||
access_token_info = jwt.decode(access_token, options={"verify_signature": False})
|
||||
exp = access_token_info.get("exp", 0)
|
||||
if exp > int(time.time()) + 60 * 60 * 24 * 5:
|
||||
need_refresh = False
|
||||
except Exception as e:
|
||||
logger.error(f"access_token: {e}")
|
||||
|
||||
if refresh_token:
|
||||
if refresh_token and need_refresh:
|
||||
chatgpt_refresh_info = await chatgpt_refresh(refresh_token)
|
||||
if chatgpt_refresh_info:
|
||||
auth_info.update(chatgpt_refresh_info)
|
||||
@ -242,106 +241,13 @@ async def refresh(request: Request):
|
||||
auth_info.update(account_check_info)
|
||||
auth_info.update({"accessToken": access_token})
|
||||
return Response(content=json.dumps(auth_info), media_type="application/json")
|
||||
elif access_token:
|
||||
account_check_info = await chatgpt_account_check(access_token)
|
||||
if account_check_info:
|
||||
auth_info.update(account_check_info)
|
||||
auth_info.update({"accessToken": access_token})
|
||||
return Response(content=json.dumps(auth_info), media_type="application/json")
|
||||
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
if no_sentinel:
|
||||
@app.post("/backend-api/sentinel/chat-requirements")
|
||||
async def sentinel_chat_conversations():
|
||||
return {
|
||||
"arkose": {
|
||||
"dx": None,
|
||||
"required": False
|
||||
},
|
||||
"persona": "chatgpt-paid",
|
||||
"proofofwork": {
|
||||
"difficulty": None,
|
||||
"required": False,
|
||||
"seed": None
|
||||
},
|
||||
"token": str(uuid.uuid4()),
|
||||
"turnstile": {
|
||||
"dx": None,
|
||||
"required": False
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@app.post("/backend-api/conversation")
|
||||
async def chat_conversations(request: Request):
|
||||
token = request.headers.get("Authorization", "").replace("Bearer ", "")
|
||||
req_token = await get_real_req_token(token)
|
||||
access_token = await verify_token(req_token)
|
||||
fp = get_fp(req_token)
|
||||
proxy_url = fp.get("proxy_url", None)
|
||||
user_agent = fp.get("user-agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0")
|
||||
impersonate = fp.get("impersonate", "safari15_3")
|
||||
|
||||
host_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com"
|
||||
proof_token = None
|
||||
turnstile_token = None
|
||||
|
||||
headers = base_headers.copy()
|
||||
headers.update(fp)
|
||||
headers.update({
|
||||
"authorization": f"Bearer {access_token}",
|
||||
"oai-device-id": fp.get("oai-device-id", str(uuid.uuid4()))
|
||||
})
|
||||
|
||||
client = Client(proxy=proxy_url, impersonate=impersonate)
|
||||
|
||||
config = get_config(user_agent)
|
||||
p = get_requirements_token(config)
|
||||
data = {'p': p}
|
||||
r = await client.post(f'{host_url}/backend-api/sentinel/chat-requirements', headers=headers, json=data,
|
||||
timeout=10)
|
||||
resp = r.json()
|
||||
turnstile = resp.get('turnstile', {})
|
||||
turnstile_required = turnstile.get('required')
|
||||
if turnstile_required:
|
||||
turnstile_dx = turnstile.get("dx")
|
||||
try:
|
||||
if turnstile_solver_url:
|
||||
res = await client.post(turnstile_solver_url,
|
||||
json={"url": "https://chatgpt.com", "p": p, "dx": turnstile_dx})
|
||||
turnstile_token = res.json().get("t")
|
||||
except Exception as e:
|
||||
logger.info(f"Turnstile ignored: {e}")
|
||||
|
||||
proofofwork = resp.get('proofofwork', {})
|
||||
proofofwork_required = proofofwork.get('required')
|
||||
if proofofwork_required:
|
||||
proofofwork_diff = proofofwork.get("difficulty")
|
||||
proofofwork_seed = proofofwork.get("seed")
|
||||
proof_token, solved = await run_in_threadpool(
|
||||
get_answer_token, proofofwork_seed, proofofwork_diff, config
|
||||
)
|
||||
if not solved:
|
||||
raise HTTPException(status_code=403, detail="Failed to solve proof of work")
|
||||
chat_token = resp.get('token')
|
||||
headers.update({
|
||||
"openai-sentinel-chat-requirements-token": chat_token,
|
||||
"openai-sentinel-proof-token": proof_token,
|
||||
"openai-sentinel-turnstile-token": turnstile_token,
|
||||
})
|
||||
|
||||
params = dict(request.query_params)
|
||||
data = await request.body()
|
||||
request_cookies = dict(request.cookies)
|
||||
background = BackgroundTask(client.close)
|
||||
r = await client.post_stream(f"{host_url}/backend-api/conversation", params=params, headers=headers,
|
||||
cookies=request_cookies, data=data, stream=True, allow_redirects=False)
|
||||
rheaders = r.headers
|
||||
if x_sign:
|
||||
rheaders.update({"x-sign": x_sign})
|
||||
if 'stream' in rheaders.get("content-type", ""):
|
||||
logger.info(f"Request token: {req_token}")
|
||||
logger.info(f"Request proxy: {proxy_url}")
|
||||
logger.info(f"Request UA: {user_agent}")
|
||||
logger.info(f"Request impersonate: {impersonate}")
|
||||
return StreamingResponse(content_generator(r, token), headers=rheaders,
|
||||
media_type=rheaders.get("content-type"), background=background)
|
||||
else:
|
||||
return Response(content=(await r.atext()), headers=rheaders, media_type=rheaders.get("content-type"),
|
||||
status_code=r.status_code, background=background)
|
||||
|
||||
28
gateway/v1.py
Normal file
28
gateway/v1.py
Normal file
@ -0,0 +1,28 @@
|
||||
import json
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.responses import Response
|
||||
|
||||
from app import app
|
||||
from gateway.reverseProxy import chatgpt_reverse_proxy
|
||||
from utils.kv_utils import set_value_for_key
|
||||
|
||||
|
||||
@app.post("/v1/initialize")
|
||||
async def initialize(request: Request):
|
||||
initialize_response = (await chatgpt_reverse_proxy(request, f"/v1/initialize"))
|
||||
initialize_str = initialize_response.body.decode('utf-8')
|
||||
initialize_json = json.loads(initialize_str)
|
||||
set_value_for_key(initialize_json, "ip", "8.8.8.8")
|
||||
set_value_for_key(initialize_json, "country", "US")
|
||||
return Response(content=json.dumps(initialize_json, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
@app.post("/v1/rgstr")
|
||||
async def rgstr():
|
||||
return Response(status_code=202, content=json.dumps({"success": True}, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
@app.post("/ces/v1/{path:path}")
|
||||
async def ces_v1():
|
||||
return Response(status_code=202, content=json.dumps({"success": True}, indent=4), media_type="application/json")
|
||||
@ -10,3 +10,4 @@ pybase64
|
||||
jinja2
|
||||
APScheduler
|
||||
ua-generator
|
||||
pyjwt
|
||||
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html data-build="prod-bf34a49b1a069459615ed830ce45441d6b9a54ee" dir="ltr" class="">
|
||||
<html data-build="prod-ecc0207d57b2a1317adeee3f3b5e693f287547aa" dir="ltr" class="">
|
||||
<head>
|
||||
<meta charSet="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
@ -18,55 +18,54 @@
|
||||
<meta property="og:title" content="ChatGPT"/>
|
||||
<meta property="og:image" content="/assets/chatgpt-share-og-u7j5uyao.webp"/>
|
||||
<meta property="og:url" content="https://chatgpt.com"/>
|
||||
<link rel="modulepreload" href="/assets/manifest-3ade92e0.js"/>
|
||||
<link rel="modulepreload" href="/assets/d9z3tlgc2shput1x.js"/>
|
||||
<link rel="modulepreload" href="/assets/jipkz7wahhvzzuqx.js"/>
|
||||
<link rel="modulepreload" href="/assets/36ro7pf3i6oxqv6i.js"/>
|
||||
<link rel="modulepreload" href="/assets/n5nz8vnsxibd6bik.js"/>
|
||||
<link rel="modulepreload" href="/assets/mdo2ehpmzqbbrcw9.js"/>
|
||||
<link rel="modulepreload" href="/assets/bvxb7ko3h6ykpbi0.js"/>
|
||||
<link rel="modulepreload" href="/assets/e6zhtx99a7i1g9zc.js"/>
|
||||
<link rel="modulepreload" href="/assets/npl77qwfuvi2jyha.js"/>
|
||||
<link rel="modulepreload" href="/assets/fwm14uzkyzsxflxc.js"/>
|
||||
<link rel="modulepreload" href="/assets/lbv1zpv4g2ap41f2.js"/>
|
||||
<link rel="modulepreload" href="/assets/hu4ya3hu1q2mtj3c.js"/>
|
||||
<link rel="modulepreload" href="/assets/fqai4h0y4a7y6yiz.js"/>
|
||||
<link rel="modulepreload" href="/assets/kgz011geyku0c84g.js"/>
|
||||
<link rel="modulepreload" href="/assets/lb2bw82esu8k4ire.js"/>
|
||||
<link rel="modulepreload" href="/assets/j625ckqact10y3my.js"/>
|
||||
<link rel="modulepreload" href="/assets/it892upc0b17konk.js"/>
|
||||
<link rel="modulepreload" href="/assets/ojtyfghvwqol77ni.js"/>
|
||||
<link rel="modulepreload" href="/assets/gf1rzma6lb3hhiaa.js"/>
|
||||
<link rel="modulepreload" href="/assets/n7shmditr84egzzk.js"/>
|
||||
<link rel="modulepreload" href="/assets/ncnmvo4fatoh9z2b.js"/>
|
||||
<link rel="modulepreload" href="/assets/efad9c3t7hoskfux.js"/>
|
||||
<link rel="modulepreload" href="/assets/erjy4zyeqfne1prk.js"/>
|
||||
<link rel="modulepreload" href="/assets/i21elbjdr0dt7siq.js"/>
|
||||
<link rel="modulepreload" href="/assets/nh5giofbgo8o5iz3.js"/>
|
||||
<link rel="modulepreload" href="/assets/hz1kryv1rsw2w11f.js"/>
|
||||
<link rel="modulepreload" href="/assets/m02oxzinki55f1a4.js"/>
|
||||
<link rel="modulepreload" href="/assets/c78o8wyvzedeoudw.js"/>
|
||||
<link rel="modulepreload" href="/assets/gecwa6udk6b6d8e5.js"/>
|
||||
<link rel="modulepreload" href="/assets/g70459ispqthxwkc.js"/>
|
||||
<link rel="modulepreload" href="/assets/kl3gqai6eyrksb78.js"/>
|
||||
<link rel="modulepreload" href="/assets/l6n2tuza1m4x9jmr.js"/>
|
||||
<link rel="modulepreload" href="/assets/jwoa39qbou2pb90k.js"/>
|
||||
<link rel="modulepreload" href="/assets/lxkd2uemxq651aut.js"/>
|
||||
<link rel="modulepreload" href="/assets/f2w9prfaqv5jn6b6.js"/>
|
||||
<link rel="modulepreload" href="/assets/dp98tj9u73hn9ufz.js"/>
|
||||
<link rel="modulepreload" href="/assets/k5lnvw1mrt1nlhku.js"/>
|
||||
<link rel="modulepreload" href="/assets/nsw6odx5xh6i9cc3.js"/>
|
||||
<link rel="modulepreload" href="/assets/dp2xls1tq8hl6hdd.js"/>
|
||||
<link rel="modulepreload" href="/assets/o8ne9dgj82ugno4a.js"/>
|
||||
<link rel="modulepreload" href="/assets/hpwzwf5t45kgizxl.js"/>
|
||||
<link rel="modulepreload" href="/assets/fcr06eqoxz5nj0zr.js"/>
|
||||
<link rel="modulepreload" href="/assets/cyzxbqfgo2fnhaph.js"/>
|
||||
<link rel="modulepreload" href="/assets/f1ccpn6bozgd3iqc.js"/>
|
||||
<link rel="modulepreload" href="/assets/m5dixe5n71jzyt0l.js"/>
|
||||
<link rel="modulepreload" href="/assets/ifx68p1cwmj10rjy.js"/>
|
||||
<link rel="modulepreload" href="/assets/koa1s917opmrb6zb.js"/>
|
||||
<link rel="modulepreload" href="/assets/manifest-317e0442.js"/>
|
||||
<link rel="modulepreload" href="/assets/l0flmalf4tyvsm1b.js"/>
|
||||
<link rel="modulepreload" href="/assets/cenhwbprxai3toix.js"/>
|
||||
<link rel="modulepreload" href="/assets/mej6dcn3epzdp940.js"/>
|
||||
<link rel="modulepreload" href="/assets/lzqwtbp50roqvxnh.js"/>
|
||||
<link rel="modulepreload" href="/assets/esp1o2lmeinam0sh.js"/>
|
||||
<link rel="modulepreload" href="/assets/wg6ecvahwsvfbs7t.js"/>
|
||||
<link rel="modulepreload" href="/assets/bomvf441parvbl6l.js"/>
|
||||
<link rel="modulepreload" href="/assets/jyh9xl3syf7yrebg.js"/>
|
||||
<link rel="modulepreload" href="/assets/jth9gz8y4nfsu03x.js"/>
|
||||
<link rel="modulepreload" href="/assets/h0w2cfyxquh3a88t.js"/>
|
||||
<link rel="modulepreload" href="/assets/i2mam4exf28ww00h.js"/>
|
||||
<link rel="modulepreload" href="/assets/kp41qb109q7zsu08.js"/>
|
||||
<link rel="modulepreload" href="/assets/e3lzzvpbrfw34hi0.js"/>
|
||||
<link rel="modulepreload" href="/assets/s26g8cj5crlmzrhm.js"/>
|
||||
<link rel="modulepreload" href="/assets/cd7rmveqys68yu6w.js"/>
|
||||
<link rel="modulepreload" href="/assets/hn586u5on2jlex6e.js"/>
|
||||
<link rel="modulepreload" href="/assets/hn877s1av7risab0.js"/>
|
||||
<link rel="modulepreload" href="/assets/c657bb6sfxb67al1.js"/>
|
||||
<link rel="modulepreload" href="/assets/i5dl7qcorvwptxtt.js"/>
|
||||
<link rel="modulepreload" href="/assets/j72yt11gyo474tkr.js"/>
|
||||
<link rel="modulepreload" href="/assets/d01hwntyf2775ji3.js"/>
|
||||
<link rel="modulepreload" href="/assets/kcdclgxeuzpy449e.js"/>
|
||||
<link rel="modulepreload" href="/assets/bh0hpeydruybhwyo.js"/>
|
||||
<link rel="modulepreload" href="/assets/ghlhzub07tt8683j.js"/>
|
||||
<link rel="modulepreload" href="/assets/er1c9qkbvqkr07px.js"/>
|
||||
<link rel="modulepreload" href="/assets/f994slaknt0q0gbk.js"/>
|
||||
<link rel="modulepreload" href="/assets/id6ryfq9914uxpp5.js"/>
|
||||
<link rel="modulepreload" href="/assets/oc6674sla3qapg4k.js"/>
|
||||
<link rel="modulepreload" href="/assets/olbio5uf8m7nh5z5.js"/>
|
||||
<link rel="modulepreload" href="/assets/if0s6lpo3mwf7mho.js"/>
|
||||
<link rel="modulepreload" href="/assets/jmi851zx6qdtjhdj.js"/>
|
||||
<link rel="modulepreload" href="/assets/i51i3k321hvaxal9.js"/>
|
||||
<link rel="modulepreload" href="/assets/lfvhb0nf0ozjlpqm.js"/>
|
||||
<link rel="modulepreload" href="/assets/lwsvc0prcm5qybau.js"/>
|
||||
<link rel="modulepreload" href="/assets/dmau43v1lisg5o8k.js"/>
|
||||
<link rel="modulepreload" href="/assets/leqgnttd8q44vj5y.js"/>
|
||||
<link rel="modulepreload" href="/assets/opnnku3lurllu7tw.js"/>
|
||||
<link rel="modulepreload" href="/assets/bj8mbuhov5xcqf0f.js"/>
|
||||
<link rel="modulepreload" href="/assets/kehs2ll784eynnt2.js"/>
|
||||
<link rel="modulepreload" href="/assets/fxwpnfsczjkyx99q.js"/>
|
||||
<link rel="modulepreload" href="/assets/cw70vbnpved29h73.js"/>
|
||||
<link rel="modulepreload" href="/assets/hibtdcbfc20dw1xa.js"/>
|
||||
<link rel="modulepreload" href="/assets/jrixumr7y4kpqw3k.js"/>
|
||||
<link rel="modulepreload" href="/assets/lrh8wz5t6uhmx4c9.js"/>
|
||||
<link rel="modulepreload" href="/assets/fnze8ev0ssatnf92.js"/>
|
||||
<link rel="modulepreload" href="/assets/jjr9on9cxlrbskjq.js"/>
|
||||
<link rel="stylesheet" href="/assets/root-fm8m2265.css"/>
|
||||
<link rel="stylesheet" href="/assets/root-o2r7uhf3.css"/>
|
||||
<link rel="stylesheet" href="/assets/conversation-small-cll5buey.css"/>
|
||||
</head>
|
||||
<body class="">
|
||||
@ -96,7 +95,7 @@
|
||||
}()
|
||||
</script>
|
||||
<div class="relative flex h-full w-full overflow-hidden transition-colors z-0">
|
||||
<div class="z-[1] flex-shrink-0 overflow-x-hidden bg-token-sidebar-surface-primary max-md:!w-0" style="width:260px">
|
||||
<div class="z-[21] flex-shrink-0 overflow-x-hidden bg-token-sidebar-surface-primary max-md:!w-0" style="width:260px">
|
||||
<div class="h-full w-[260px]">
|
||||
<div class="flex h-full min-h-0 flex-col">
|
||||
<div class="draggable relative h-full w-full flex-1 items-start border-white/20">
|
||||
@ -194,7 +193,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<form class="w-full" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:Rpn99iii4lj5:" data-state="closed">
|
||||
<form class="w-full" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:Rdf99iii4lj5:" data-state="closed">
|
||||
<div class="relative flex h-full max-w-full flex-1 flex-col">
|
||||
<div class="relative h-0"></div>
|
||||
<div class="group relative flex w-full items-center">
|
||||
@ -203,7 +202,7 @@
|
||||
<div class="flex min-w-0 flex-1 flex-col">
|
||||
<div class="_prosemirror-parent_15ceg_1 text-token-text-primary max-h-[25dvh] max-h-52 overflow-auto default-browser">
|
||||
<textarea class="block h-10 w-full resize-none border-0 bg-transparent px-0 py-2 text-token-text-primary placeholder:text-token-text-secondary" autofocus="" placeholder="Message ChatGPT"></textarea>
|
||||
<script nonce="2887053f-167d-4b8d-b616-8ea78c3e74b7">
|
||||
<script nonce="c5a3ef22-c71c-4ae3-9939-b19d1edaee92">
|
||||
window.__oai_logHTML ? window.__oai_logHTML() : window.__oai_SSR_HTML = window.__oai_SSR_HTML || Date.now();
|
||||
requestAnimationFrame((function() {
|
||||
window.__oai_logTTI ? window.__oai_logTTI() : window.__oai_SSR_TTI = window.__oai_SSR_TTI || Date.now()
|
||||
@ -257,7 +256,7 @@
|
||||
<div aria-live="assertive" aria-atomic="true" class="sr-only"></div>
|
||||
<div aria-live="polite" aria-atomic="true" class="sr-only"></div>
|
||||
<audio class="fixed bottom-0 left-0 hidden h-0 w-0" autoPlay="" crossorigin="anonymous"></audio>
|
||||
<script nonce="2887053f-167d-4b8d-b616-8ea78c3e74b7">
|
||||
<script nonce="c5a3ef22-c71c-4ae3-9939-b19d1edaee92">
|
||||
window.__remixContext = {{ remix_context|tojson }};
|
||||
__remixContext.p = function(v, e, p, x) {
|
||||
if (typeof e !== 'undefined') {
|
||||
@ -312,10 +311,10 @@
|
||||
Object.assign(__remixContext.state.loaderData["routes/_conversation"], {});
|
||||
__remixContext.a = 1;
|
||||
</script>
|
||||
<script nonce="2887053f-167d-4b8d-b616-8ea78c3e74b7" type="module" async="">
|
||||
import "/assets/manifest-3ade92e0.js";
|
||||
import*as route0 from "/assets/mdo2ehpmzqbbrcw9.js";
|
||||
import*as route1 from "/assets/koa1s917opmrb6zb.js";
|
||||
<script nonce="c5a3ef22-c71c-4ae3-9939-b19d1edaee92" type="module" async="">
|
||||
import "/assets/manifest-317e0442.js";
|
||||
import*as route0 from "/assets/esp1o2lmeinam0sh.js";
|
||||
import*as route1 from "/assets/fnze8ev0ssatnf92.js";
|
||||
import*as route2 from "/assets/jjr9on9cxlrbskjq.js";
|
||||
|
||||
window.__remixRouteModules = {
|
||||
@ -324,7 +323,46 @@
|
||||
"routes/_conversation._index": route2
|
||||
};
|
||||
|
||||
import("/assets/d9z3tlgc2shput1x.js");
|
||||
import("/assets/l0flmalf4tyvsm1b.js");
|
||||
</script>
|
||||
<script nonce="c5a3ef22-c71c-4ae3-9939-b19d1edaee92">
|
||||
$RC = function(b, c, e) {
|
||||
c = document.getElementById(c);
|
||||
c.parentNode.removeChild(c);
|
||||
var a = document.getElementById(b);
|
||||
if (a) {
|
||||
b = a.previousSibling;
|
||||
if (e)
|
||||
b.data = "$!",
|
||||
a.setAttribute("data-dgst", e);
|
||||
else {
|
||||
e = b.parentNode;
|
||||
a = b.nextSibling;
|
||||
var f = 0;
|
||||
do {
|
||||
if (a && 8 === a.nodeType) {
|
||||
var d = a.data;
|
||||
if ("/$" === d)
|
||||
if (0 === f)
|
||||
break;
|
||||
else
|
||||
f--;
|
||||
else
|
||||
"$" !== d && "$?" !== d && "$!" !== d || f++
|
||||
}
|
||||
d = a.nextSibling;
|
||||
e.removeChild(a);
|
||||
a = d
|
||||
} while (a);
|
||||
for (; c.firstChild; )
|
||||
e.insertBefore(c.firstChild, a);
|
||||
b.data = "$"
|
||||
}
|
||||
b._reactRetry && b._reactRetry()
|
||||
}
|
||||
}
|
||||
;
|
||||
$RC("B:0", "S:0")
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
5510
templates/gpts_context.json
Normal file
5510
templates/gpts_context.json
Normal file
File diff suppressed because it is too large
Load Diff
10
utils/kv_utils.py
Normal file
10
utils/kv_utils.py
Normal file
@ -0,0 +1,10 @@
|
||||
def set_value_for_key(data, target_key, new_value):
|
||||
if isinstance(data, dict):
|
||||
for key, value in data.items():
|
||||
if key == target_key:
|
||||
data[key] = new_value
|
||||
else:
|
||||
set_value_for_key(value, target_key, new_value)
|
||||
elif isinstance(data, list):
|
||||
for item in data:
|
||||
set_value_for_key(item, target_key, new_value)
|
||||
@ -1 +1 @@
|
||||
1.6.9
|
||||
1.7.0-beta3
|
||||
Loading…
Reference in New Issue
Block a user