Repository: ultrasev/chatrapper
Branch: master
Commit: 46633bd3d406
Files: 5
Total size: 7.1 KB
Directory structure:
gitextract_s8xdcfmo/
├── LICENCE
├── README.md
├── chatrapper/
│ └── __init__.py
├── pyproject.toml
└── tests/
└── __init__.py
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENCE
================================================
MIT License
Copyright (c) 2023-2024 ultrasev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
ChatGPT API (W)rapper
把网页版 ChatGPT 封装为一个简单的 API,以便在代码中使用。
> OpenAI 对逆向的限制越来越严格,逆向难度越来越大,且各平台的 API 已经很便宜了,像 Groq 的 Llama 3 API 还一直是免费的,不太建议大家继续研究这类项目了。如果特别需要,可以参考作者的另一个项目 [juchats](https://github.com/ultrasev/juchats),有更多免费模型可以使用。
# Installation
```bash
pip3 install git+https://github.com/ultrasev/chatrapper.git
```
# Usage
环境变量中设置 `TOKEN`,然后调用 `chat` 函数即可。
```bash
export TOKEN="eyJhbGci..."
```
在代码中使用 `Rapper`:
```python
import os
from chatrapper import Rapper
token = os.environ.get("TOKEN")
rapper = Rapper(
access_token=token
model="text-davinci-002-render-sha"
)
rapper("鲁迅为什么打周树人?")
```
或者有异步需求的话,可以使用 `AsyncRapper`。这种情况下,最好有多个账号支持,单账号下,同一时间只支持一轮对话。
```python
import os
import asyncio
from chatrapper import AsyncRapper
token = os.environ.get("TOKEN")
rapper = AsyncRapper(
access_token=token
model="text-davinci-002-render-sha"
)
async def main():
print(await rapper("鲁迅为什么打周树人?"))
asyncio.run(main())
```
Demo:
# Notes
- 一定要保护好自己的 token,不要泄露给他人。
- 合理使用 API,调用频率不宜过高,树大易招风,避免触发风控。
================================================
FILE: chatrapper/__init__.py
================================================
#!/usr/bin/env python
import asyncio
import base64
import json
import typing
from uuid import uuid4
import httpx
import websockets
import logging
from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK
class MessageDeserializer(object):
def __init__(self, data: str) -> None:
self.data = data.lstrip("data: ").strip()
def __str__(self) -> str:
try:
js = json.loads(self.data)
return js['message']['content']['parts'][0]
except json.decoder.JSONDecodeError:
return ""
except KeyError:
logging.error(f"Error: {self.data}")
return ""
class AsyncRapper(object):
def __init__(self,
access_token: str,
model: str = "text-davinci-002-render-sha") -> None:
""" API (w)rapper for OpenAI's ChatGPT.
Args:
access_token (str): ChatGPT access token, acquired from https://chat.openai.com/api/auth/session
model (str): model name, options include:
- "text-davinci-002-render-sha", default model for ChatGPT-3.5
- "GPT-4", GPT-4 model
"""
self.access_token = access_token
self.model = model
async def _stream_from_wss(self, chunk: str) -> typing.AsyncGenerator[str, None]:
url = json.loads(chunk)['wss_url']
async with websockets.connect(url) as websocket:
while True:
try:
response = await websocket.recv()
body = json.loads(response)["body"]
body = base64.b64decode(body).decode('utf-8')
if 'DONE' in body:
break
yield body
except ConnectionClosedOK:
break
except ConnectionClosedError:
break
async def stream(self,
text: str) -> typing.AsyncGenerator[str, None]:
body = {
"action": "next",
"arkose_token": "null",
"conversation_mode": {"kind": "primary_assistant"},
"force_paragen": False,
"force_rate_limit": False,
"history_and_training_disabled": True,
"messages": [{
"metadata": {},
"author": {
"role": "user"
},
"content": {
"content_type": "text",
"parts": [text]
}
}],
"model": self.model,
"parent_message_id": str(uuid4()),
"timezone_offset_min": -330,
"stream": True
}
async with httpx.AsyncClient() as client:
async with client.stream(
'POST',
url="https://chat.openai.com/backend-api/conversation",
headers={
"accept": "text/event-stream",
"accept-language": "en-US",
"authorization": f"Bearer {self.access_token}",
"content-type": "application/json",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"Referer": "https://chat.openai.com/",
"Referrer-Policy": "strict-origin-when-cross-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
},
data=json.dumps(body)) as response:
async for chunk in response.aiter_text():
chunk = chunk.lstrip("data: ").strip()
if "wss_url" in chunk:
async for x in self._stream_from_wss(chunk):
yield str(MessageDeserializer(x))
else:
yield str(MessageDeserializer(chunk))
async def __call__(self, text: str) -> str:
prev = ""
async for x in self.stream(text):
print(x.replace(prev, ""), end="", flush=True)
prev = max(prev, x, key=len)
return prev
class Rapper(object):
def __init__(self,
access_token: str,
model: str = "text-davinci-002-render-sha") -> None:
self._proxy = AsyncRapper(access_token, model)
def __call__(self, text: str) -> str:
return asyncio.run(self._proxy(text))
================================================
FILE: pyproject.toml
================================================
[tool.poetry]
name = "chatrapper"
version = "0.1.0"
description = ""
authors = ["ultrasev "]
readme = "README.md"
packages = [{include = "chatrapper"}]
[tool.poetry.dependencies]
python = "^3.8"
uuid = "^1.30"
httpx = "^0.27.0"
websockets = "^12.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
================================================
FILE: tests/__init__.py
================================================