diff --git a/README.md b/README.md index 16cc8ac..e3d090c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 🌟 无需账号即可使用免费、无限的 `GPT-3.5` -💥 支持 AccessToken 使用账号,支持 `O1-Preview/mini`、`GPT-4`、`GPT-4o/mini`、 `GPTs` +💥 支持 AccessToken 使用账号,支持 `O3-mini/high`、`O1/mini/Pro`、`GPT-4/4o/mini`、`GPTs` 🔍 回复格式与真实 API 完全一致,适配几乎所有客户端 @@ -43,25 +43,28 @@ > - [x] Tokens 管理,支持上传、清除 > - [x] 定时使用 `RefreshToken` 刷新 `AccessToken` / 每次启动将会全部非强制刷新一次,每4天晚上3点全部强制刷新一次。 > - [x] 支持文件下载,需要开启历史记录 -> - [x] 支持 `O1-Preview/mini` 模型推理过程输出 +> - [x] 支持 `O3-mini/high`、`O1/mini/Pro` 等模型推理过程输出 ### 官网镜像 功能 > - [x] 支持官网原生镜像 > - [x] 后台账号池随机抽取,`Seed` 设置随机账号 > - [x] 输入 `RefreshToken` 或 `AccessToken` 直接登录使用 -> - [x] 支持 O1-Preview/mini、GPT-4、GPT-4o/mini +> - [x] 支持 `O3-mini/high`、`O1/mini/Pro`、`GPT-4/4o/mini` > - [x] 敏感信息接口禁用、部分设置接口禁用 > - [x] /login 登录页面,注销后自动跳转到登录页面 > - [x] /?token=xxx 直接登录, xxx 为 `RefreshToken` 或 `AccessToken` 或 `SeedToken` (随机种子) +> - [x] 支持不同 SeedToken 会话隔离 +> - [x] 支持 `GPTs` 商店 +> - [x] 支持 `DeepReaserch`、`Canvas` 等官网独有功能 +> - [x] 支持切换各国语言 > TODO -> - [ ] 镜像支持 `GPTs` > - [ ] 暂无,欢迎提 `issue` ## 逆向API -完全 `OpenAI` 格式的 API ,支持传入 `AccessToken` 或 `RefreshToken`,可用 GPT-4, GPT-4o, GPTs, O1-Preview, O1-Mini: +完全 `OpenAI` 格式的 API ,支持传入 `AccessToken` 或 `RefreshToken`,可用 GPT-4, GPT-4o, GPT-4o-Mini, GPTs, O1-Pro, O1, O1-Mini, O3-Mini, O3-Mini-High: ```bash curl --location 'http://127.0.0.1:5005/v1/chat/completions' \ diff --git a/chatgpt/ChatService.py b/chatgpt/ChatService.py index aef2859..328eabb 100644 --- a/chatgpt/ChatService.py +++ b/chatgpt/ChatService.py @@ -1,4 +1,5 @@ import asyncio +import hashlib import json import random import uuid @@ -86,9 +87,12 @@ async def set_dynamic_data(self, data): self.host_url = random.choice(chatgpt_base_url_list) if chatgpt_base_url_list else "https://chatgpt.com" self.ark0se_token_url = random.choice(ark0se_token_url_list) if ark0se_token_url_list else None - self.s = Client(proxy=self.proxy_url, impersonate=self.impersonate) + session_id = hashlib.md5(self.req_token.encode()).hexdigest() + proxy_url = self.proxy_url.replace("{}", session_id) if self.proxy_url else None + self.s = Client(proxy=proxy_url, impersonate=self.impersonate) if sentinel_proxy_url_list: - self.ss = Client(proxy=random.choice(sentinel_proxy_url_list), impersonate=self.impersonate) + sentinel_proxy_url = (random.choice(sentinel_proxy_url_list)).replace("{}", session_id) if sentinel_proxy_url_list else None + self.ss = Client(proxy=sentinel_proxy_url, impersonate=self.impersonate) else: self.ss = self.s diff --git a/chatgpt/refreshToken.py b/chatgpt/refreshToken.py index 05ef321..a580a75 100644 --- a/chatgpt/refreshToken.py +++ b/chatgpt/refreshToken.py @@ -1,3 +1,4 @@ +import hashlib import json import random import time @@ -34,7 +35,9 @@ async def chat_refresh(refresh_token): "redirect_uri": "com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback", "refresh_token": refresh_token } - client = Client(proxy=random.choice(proxy_url_list) if proxy_url_list else None) + session_id = hashlib.md5(refresh_token.encode()).hexdigest() + proxy_url = random.choice(proxy_url_list).replace("{}", session_id) if proxy_url_list else None + client = Client(proxy=proxy_url) try: r = await client.post("https://auth0.openai.com/oauth/token", json=data, timeout=15) if r.status_code == 200: diff --git a/gateway/backend.py b/gateway/backend.py index 4f28276..635b7a1 100644 --- a/gateway/backend.py +++ b/gateway/backend.py @@ -1,3 +1,4 @@ +import hashlib import json import random import re @@ -295,9 +296,12 @@ async def sentinel_chat_conversations(request: Request): } headers.update(fp) headers.update({"authorization": f"Bearer {access_token}"}) + session_id = hashlib.md5(req_token.encode()).hexdigest() + proxy_url = proxy_url.replace("{}", session_id) if proxy_url else None client = Client(proxy=proxy_url, impersonate=impersonate) if sentinel_proxy_url_list: - clients = Client(proxy=random.choice(sentinel_proxy_url_list), impersonate=impersonate) + sentinel_proxy_url = random.choice(sentinel_proxy_url_list).replace("{}", session_id) if sentinel_proxy_url_list else None + clients = Client(proxy=sentinel_proxy_url, impersonate=impersonate) else: clients = client @@ -390,9 +394,12 @@ async def chat_conversations(request: Request): headers.update({"authorization": f"Bearer {access_token}"}) try: + session_id = hashlib.md5(req_token.encode()).hexdigest() + proxy_url = proxy_url.replace("{}", session_id) if proxy_url else None client = Client(proxy=proxy_url, impersonate=impersonate) if sentinel_proxy_url_list: - clients = Client(proxy=random.choice(sentinel_proxy_url_list), impersonate=impersonate) + sentinel_proxy_url = random.choice(sentinel_proxy_url_list).replace("{}", session_id) if sentinel_proxy_url_list else None + clients = Client(proxy=sentinel_proxy_url, impersonate=impersonate) else: clients = client diff --git a/gateway/chatgpt.py b/gateway/chatgpt.py index a10e590..4d20d7d 100644 --- a/gateway/chatgpt.py +++ b/gateway/chatgpt.py @@ -32,20 +32,29 @@ async def chatgpt_html(request: Request): set_value_for_key_list(user_chatgpt_context_1, "accessToken", token) if request.cookies.get("oai-locale"): set_value_for_key_list(user_chatgpt_context_1, "locale", request.cookies.get("oai-locale")) + else: + accept_language = request.headers.get("accept-language") + if accept_language: + set_value_for_key_list(user_chatgpt_context_1, "locale", accept_language.split(",")[0]) user_chatgpt_context_1 = json.dumps(user_chatgpt_context_1, separators=(',', ':'), ensure_ascii=False) user_chatgpt_context_2 = json.dumps(user_chatgpt_context_2, separators=(',', ':'), ensure_ascii=False) - escaped_context_1 = user_chatgpt_context_1.replace("\\", "\\\\") - escaped_context_2 = user_chatgpt_context_2.replace("\\", "\\\\") + escaped_context_1 = user_chatgpt_context_1.replace("\\", "\\\\").replace('"', '\\"') + escaped_context_2 = user_chatgpt_context_2.replace("\\", "\\\\").replace('"', '\\"') - escaped_context_1 = escaped_context_1.replace('"', '\\"') - escaped_context_2 = escaped_context_2.replace('"', '\\"') + clear_localstorage_script = """ + + """ response = templates.TemplateResponse("chatgpt.html", { - "request": request, + "request": request, "react_chatgpt_context_1": escaped_context_1, - "react_chatgpt_context_2": escaped_context_2 + "react_chatgpt_context_2": escaped_context_2, + "clear_localstorage_script": clear_localstorage_script }) response.set_cookie("token", value=token, expires="Thu, 01 Jan 2099 00:00:00 GMT") return response + diff --git a/gateway/reverseProxy.py b/gateway/reverseProxy.py index b9f16c0..510640e 100644 --- a/gateway/reverseProxy.py +++ b/gateway/reverseProxy.py @@ -1,3 +1,4 @@ +import hashlib import json import random import time @@ -211,6 +212,8 @@ async def chatgpt_reverse_proxy(request: Request, path: str): req_token = await get_real_req_token(cookie_token) fp = get_fp(req_token).copy() + session_id = hashlib.md5(req_token.encode()).hexdigest() + proxy_url = fp.pop("proxy_url", None) impersonate = fp.pop("impersonate", "safari15_3") user_agent = fp.get("user-agent") @@ -248,9 +251,11 @@ async def chatgpt_reverse_proxy(request: Request, path: str): data = json.dumps(req_json).encode("utf-8") - if sentinel_proxy_url_list and "backend-api/sentinel/chat-requirements" in path: - client = Client(proxy=random.choice(sentinel_proxy_url_list)) + if "backend-api/sentinel/chat-requirements" in path and sentinel_proxy_url_list: + sentinel_proxy_url = random.choice(sentinel_proxy_url_list).replace("{}", session_id) if sentinel_proxy_url_list else None + client = Client(proxy=sentinel_proxy_url) else: + proxy_url = proxy_url.replace("{}", session_id) if proxy_url else None client = Client(proxy=proxy_url, impersonate=impersonate) try: background = BackgroundTask(client.close) diff --git a/gateway/share.py b/gateway/share.py index 8ec36aa..aaf910e 100644 --- a/gateway/share.py +++ b/gateway/share.py @@ -1,3 +1,4 @@ +import hashlib import json import random import time @@ -136,6 +137,8 @@ async def chatgpt_account_check(access_token): headers.update(fp) headers.update({"authorization": f"Bearer {access_token}"}) + session_id = hashlib.md5(access_token.encode()).hexdigest() + proxy_url = random.choice(proxy_url_list).replace("{}", session_id) if proxy_url_list else None 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) @@ -182,7 +185,9 @@ async def chatgpt_account_check(access_token): async def chatgpt_refresh(refresh_token): - client = Client(proxy=random.choice(proxy_url_list) if proxy_url_list else None) + session_id = hashlib.md5(refresh_token.encode()).hexdigest() + proxy_url = random.choice(proxy_url_list).replace("{}", session_id) if proxy_url_list else None + client = Client(proxy=proxy_url) try: data = { "client_id": "pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh", diff --git a/gateway/v1.py b/gateway/v1.py index c0d5a01..4b17398 100644 --- a/gateway/v1.py +++ b/gateway/v1.py @@ -7,6 +7,9 @@ from gateway.reverseProxy import chatgpt_reverse_proxy from utils.kv_utils import set_value_for_key_dict +with open("templates/initialize.json", "r") as f: + initialize_json = json.load(f) + @app.post("/v1/initialize") async def initialize(request: Request): diff --git a/templates/chatgpt.html b/templates/chatgpt.html index dd551ef..30d6e60 100644 --- a/templates/chatgpt.html +++ b/templates/chatgpt.html @@ -82,6 +82,7 @@ } catch {} }(); +{{ clear_localstorage_script | safe }}