Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 完全一致,适配几乎所有客户端

Expand Down Expand Up @@ -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/miniGPT-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' \
Expand Down
8 changes: 6 additions & 2 deletions chatgpt/ChatService.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import hashlib
import json
import random
import uuid
Expand Down Expand Up @@ -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

Expand Down
5 changes: 4 additions & 1 deletion chatgpt/refreshToken.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import hashlib
import json
import random
import time
Expand Down Expand Up @@ -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:
Expand Down
11 changes: 9 additions & 2 deletions gateway/backend.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import hashlib
import json
import random
import re
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
21 changes: 15 additions & 6 deletions gateway/chatgpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = """
<script>
localStorage.clear();
</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

9 changes: 7 additions & 2 deletions gateway/reverseProxy.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import hashlib
import json
import random
import time
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion gateway/share.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import hashlib
import json
import random
import time
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions gateway/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
1 change: 1 addition & 0 deletions templates/chatgpt.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
} catch {}
}();
</script>
{{ clear_localstorage_script | safe }}
</head>
<body class="">
<script>
Expand Down
2 changes: 1 addition & 1 deletion templates/chatgpt_context_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
"userCountry",
"US",
"locale",
"zh-CN",
"",
"statsig",
{
"_65": 66
Expand Down
Loading
Loading