diff --git a/.env.example b/.env.example index 98172a4..e0f91b0 100644 --- a/.env.example +++ b/.env.example @@ -3,5 +3,6 @@ CHATGPT_BASE_URL=https://chatgpt.com HISTORY_DISABLED=true PROXY_URL=your_first_proxy, your_second_proxy ARKOSE_TOKEN_URL=https://arkose.example.com/token -POW_DIFFICULTY=4 +POW_DIFFICULTY=000032 RETRY_TIMES=3 +ENABLE_GATEWAY=true \ No newline at end of file diff --git a/.github/workflows/build_docker.yml b/.github/workflows/build_docker.yml index 10ebbf7..9544ea9 100644 --- a/.github/workflows/build_docker.yml +++ b/.github/workflows/build_docker.yml @@ -35,7 +35,7 @@ jobs: images: lanqian528/chat2api tags: | type=raw,value=latest,enable={{is_default_branch}} - type=raw,value=v1.0.2 + type=raw,value=v1.0.4 - name: Build and push uses: docker/build-push-action@v5 diff --git a/README.md b/README.md index ab3d321..89f5929 100644 --- a/README.md +++ b/README.md @@ -156,8 +156,9 @@ CHATGPT_BASE_URL=https://chatgpt.com // ChatGPT网关地址, HISTORY_DISABLED=true // 是否不保存聊天记录并返回 conversation_id,true为不保存且不返回 PROXY_URL=your_first_proxy, your_second_proxy // 代理url,多个代理用逗号分隔 ARKOSE_TOKEN_URL=https://arkose.example.com/token // 获取Arkose token的地址,上文有提供说明 -POW_DIFFICULTY=4 // 要解决的工作量证明难度,数值越大,计算时间越长,建议3或者4 +POW_DIFFICULTY=000032 // 要解决的工作量证明难度,字符串越小,计算时间越长,建议000032 RETRY_TIMES=3 // 出错重试次数 +ENABLE_GATEWAY=true // 是否启用网关模式(WEBUI),true为启用 ``` ## License diff --git a/chatgpt/ChatService.py b/chatgpt/ChatService.py index ab5289c..2629dc8 100644 --- a/chatgpt/ChatService.py +++ b/chatgpt/ChatService.py @@ -118,7 +118,7 @@ class ChatService: proofofwork_required = proofofwork.get('required') if proofofwork_required: proofofwork_diff = proofofwork.get("difficulty") - if proofofwork_diff.startswith("0" * (pow_difficulty + 1)): + if proofofwork_diff <= pow_difficulty: raise HTTPException(status_code=403, detail=f"Proof of work difficulty too high: {proofofwork_diff}") proofofwork_seed = proofofwork.get("seed") self.proof_token = await run_in_threadpool(get_answer_token, proofofwork_seed, proofofwork_diff, config) @@ -207,6 +207,7 @@ class ChatService: "force_paragen_model_slug": "", "force_nulligen": False, "force_rate_limit": False, + "force_ues_sse": True, "websocket_request_id": f"{uuid.uuid4()}" } if self.conversation_id: diff --git a/chatgpt/proofofWork.py b/chatgpt/proofofWork.py index 50289f4..99258ea 100644 --- a/chatgpt/proofofWork.py +++ b/chatgpt/proofofWork.py @@ -6,6 +6,8 @@ import time from datetime import datetime, timedelta, timezone from html.parser import HTMLParser +import pybase64 + from utils.Logger import logger cores = [16, 24, 32] @@ -294,7 +296,8 @@ async def get_dpl(service): return True headers = service.base_headers.copy() if len(cached_scripts) == 0: - cached_scripts.append("https://cdn.oaistatic.com/_next/static/cXh69klOLzS0Gy2joLDRS/_ssgManifest.js?dpl=453ebaec0d44c2decab71692e1bfe39be35a24b3") + cached_scripts.append( + "https://cdn.oaistatic.com/_next/static/cXh69klOLzS0Gy2joLDRS/_ssgManifest.js?dpl=453ebaec0d44c2decab71692e1bfe39be35a24b3") cached_dpl = "453ebaec0d44c2decab71692e1bfe39be35a24b3" cached_time = int(time.time()) try: @@ -345,20 +348,34 @@ def generate_answer(seed, diff, config): diff_len = len(diff) seed_encoded = seed.encode() + static_config_part1 = (json.dumps(config[:3], separators=(',', ':'))[:-1] + ',').encode() + static_config_part2 = (',' + json.dumps(config[4:9], separators=(',', ':'))[1:-1] + ',').encode() + static_config_part3 = (',' + json.dumps(config[10:], separators=(',', ':'))[1:]).encode() + + target_diff = bytes.fromhex(diff) + for i in range(500000): - config[3] = i - config[9] = i - json_data = json.dumps(config, separators=(',', ':'), ensure_ascii=False) - base = base64.b64encode(json_data.encode()).decode() - hasher = hashlib.sha3_512() - hasher.update(seed_encoded + base.encode()) - hash_value = hasher.digest() - if hash_value.hex()[:diff_len] <= diff: - return base + dynamic_json_i = str(i).encode() + final_json_bytes = static_config_part1 + dynamic_json_i + static_config_part2 + dynamic_json_i + static_config_part3 + base_encode = pybase64.b64encode(final_json_bytes) + hash_value = hashlib.sha3_512(seed_encoded + base_encode).digest() + if hash_value[:diff_len] <= target_diff: + return base_encode.decode() return "wQ8Lk5FbGpA2NcR9dShT6gYjU7VxZ4D" + base64.b64encode(f'"{seed}"'.encode()).decode() def get_requirements_token(config): - require_token = generate_answer(format(random.random()), "0", config) + require_token = generate_answer(format(random.random()), "0fffff", config) return 'gAAAAAC' + require_token + + +if __name__ == "__main__": + cached_scripts.append( + "https://cdn.oaistatic.com/_next/static/cXh69klOLzS0Gy2joLDRS/_ssgManifest.js?dpl=453ebaec0d44c2decab71692e1bfe39be35a24b3") + cached_dpl = "453ebaec0d44c2decab71692e1bfe39be35a24b3" + cached_time = int(time.time()) + seed = format(random.random()) + diff = "0fffff" + config = get_config("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome") + answer = get_answer_token(seed, diff, config) diff --git a/chatgpt/reverseProxy.py b/chatgpt/reverseProxy.py index de0dd99..9de9faa 100644 --- a/chatgpt/reverseProxy.py +++ b/chatgpt/reverseProxy.py @@ -5,7 +5,7 @@ from fastapi.responses import StreamingResponse, Response from starlette.background import BackgroundTask from utils.Client import Client -from utils.config import chatgpt_base_url_list, proxy_url_list +from utils.config import chatgpt_base_url_list, proxy_url_list, enable_gateway headers_reject_list = [ "x-real-ip", @@ -60,6 +60,8 @@ headers_reject_list = [ async def chatgpt_reverse_proxy(request: Request, path: str): + if not enable_gateway: + raise HTTPException(status_code=404, detail="Gateway is disabled") try: origin_host = request.url.netloc if ":" in origin_host: diff --git a/requirements.txt b/requirements.txt index 8e0d960..a8957b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ uvicorn tiktoken python-dotenv websockets -pillow \ No newline at end of file +pillow +pybase64 \ No newline at end of file diff --git a/utils/config.py b/utils/config.py index 138bc1e..389f02d 100644 --- a/utils/config.py +++ b/utils/config.py @@ -7,11 +7,13 @@ from utils.Logger import logger load_dotenv(encoding="ascii") -def is_true(stream): - if isinstance(stream, str): - return stream.lower() in ['true', '1', 't', 'y', 'yes'] - elif isinstance(stream, int): - return stream == 1 +def is_true(x): + if isinstance(x, bool): + return x + if isinstance(x, str): + return x.lower() in ['true', '1', 't', 'y', 'yes'] + elif isinstance(x, int): + return x == 1 else: return False @@ -21,10 +23,10 @@ authorization = os.getenv('AUTHORIZATION', '').replace(' ', '') chatgpt_base_url = os.getenv('CHATGPT_BASE_URL', 'https://chatgpt.com').replace(' ', '') arkose_token_url = os.getenv('ARKOSE_TOKEN_URL', '').replace(' ', '') proxy_url = os.getenv('PROXY_URL', '').replace(' ', '') -history_disabled_str = os.getenv('HISTORY_DISABLED', 'true').replace(' ', '') -history_disabled = is_true(history_disabled_str) -pow_difficulty = int(os.getenv('POW_DIFFICULTY', 4)) +history_disabled = is_true(os.getenv('HISTORY_DISABLED', True)) +pow_difficulty = os.getenv('POW_DIFFICULTY', '000032') retry_times = int(os.getenv('RETRY_TIMES', 3)) +enable_gateway = is_true(os.getenv('ENABLE_GATEWAY', True)) authorization_list = authorization.split(',') if authorization else [] chatgpt_base_url_list = chatgpt_base_url.split(',') if chatgpt_base_url else [] @@ -32,7 +34,7 @@ arkose_token_url_list = arkose_token_url.split(',') if arkose_token_url else [] proxy_url_list = proxy_url.split(',') if proxy_url else [] logger.info("-" * 60) -logger.info("Chat2Api v1.0.2 | https://github.com/lanqian528/chat2api") +logger.info("Chat2Api v1.0.4 | https://github.com/lanqian528/chat2api") logger.info("-" * 60) logger.info("Environment variables:") logger.info("API_PREFIX: " + str(api_prefix)) @@ -43,4 +45,5 @@ logger.info("PROXY_URL: " + str(proxy_url_list)) logger.info("HISTORY_DISABLED: " + str(history_disabled)) logger.info("POW_DIFFICULTY: " + str(pow_difficulty)) logger.info("RETRY_TIMES: " + str(retry_times)) +logger.info("ENABLE_GATEWAY: " + str(enable_gateway)) logger.info("-" * 60)