fix repeat history

This commit is contained in:
LanQian 2024-04-06 15:05:57 +08:00
parent 80eb04d646
commit 269b076de3
6 changed files with 45 additions and 94 deletions

View File

@ -1,17 +1,10 @@
FROM python:3.11-slim as builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM python:3.11-slim
FROM python:3.11-alpine
WORKDIR /app
COPY --from=builder /install /usr/local
COPY . /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 5005

View File

@ -1,8 +1,8 @@
# CHAT2API
免费的GPT3.5 api
🌟无需账号即可使用免费、无限的gpt3.5目前只能转gpt3.5
### 注仅ip属地支持免登录使用ChatGpt可以使用
🔍以假乱真回复格式与真实api完全一致支持max_tokensstream等参数
## Deploy
@ -52,6 +52,10 @@ curl --location 'http://127.0.0.1:5005/v1/chat/completions' \
"stream": true
}'
```
## 常见问题
- 当返回错误代码`403`时这意味着当前IP地址被 CF 盾拦截请尝试更换IP地址或者在环境变量 `PROXY_URL` 中设置代理。
- 来自`Xiaofei`的礼物:将环境变量设置为 `CHATGPT_BASE_URL=http://api.angelxf.me:8080/api` 可无视CF盾和IP问题。
## 高级设置

View File

@ -1,12 +1,9 @@
import warnings
from fastapi import FastAPI, Request, Depends
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse, JSONResponse
from chatgpt.ChatService import ChatService
from utils.shared_session import create_shared_async_session
warnings.filterwarnings('ignore')
app = FastAPI()
@ -15,13 +12,16 @@ chat_requirements_token_list = []
@app.post("/v1/chat/completions")
# async def send_conversation(request: Request, session=Depends(create_shared_async_session)):
async def send_conversation(request: Request):
data = await request.json()
chat_service = ChatService()
try:
data = await request.json()
except Exception:
return JSONResponse({"error": "Invalid JSON body"}, status_code=400)
try:
chat_service = ChatService()
await chat_service.get_chat_requirements()
except:
chat_service = ChatService()
await chat_service.get_chat_requirements()
chat_service.prepare_send_conversation(data)
stream = data.get("stream", False)

View File

@ -3,9 +3,8 @@ import random
import string
import time
import uuid
from contextlib import aclosing
from curl_cffi import requests
import httpx
from fastapi import HTTPException
from api.chat_completions import num_tokens_from_messages, model_system_fingerprint, model_proxy, \
@ -18,27 +17,22 @@ async def stream_response(response, model, max_tokens):
chat_id = f"chatcmpl-{''.join(random.choice(string.ascii_letters + string.digits) for _ in range(29))}"
system_fingerprint_list = model_system_fingerprint.get(model, None)
system_fingerprint = random.choice(system_fingerprint_list) if system_fingerprint_list else None
created_time = int(time.time())
completion_tokens = -1
len_last_content = 0
end = False
status = None
async for chunk in response.aiter_lines():
if end:
yield f"data: [DONE]\n\n"
break
try:
chunk = chunk.decode("utf-8")
if chunk == "data: [DONE]":
yield f"data: [DONE]\n\n"
elif not chunk.startswith("data: "):
continue
else:
chunk_old_data = json.loads(chunk[6:])
if chunk_old_data["message"]["status"] == "in_progress":
status = "in_progress"
if status != "in_progress":
continue
if not chunk_old_data["message"]["author"]["role"] == "assistant":
if not chunk_old_data["message"]["status"] == "in_progress" and not chunk_old_data["message"]["metadata"].get("finish_details", {}):
continue
content = chunk_old_data["message"]["content"]["parts"][0]
if not content:
@ -47,7 +41,7 @@ async def stream_response(response, model, max_tokens):
delta = {"content": content[len_last_content:]}
len_last_content = len(content)
finish_reason = None
if chunk_old_data["message"]["end_turn"]:
if chunk_old_data["message"]["metadata"].get("finish_details", {}):
delta = {}
finish_reason = "stop"
end = True
@ -55,13 +49,10 @@ async def stream_response(response, model, max_tokens):
delta = {}
finish_reason = "length"
end = True
if completion_tokens > max_tokens:
yield f"data: [DONE]\n\n"
break
chunk_new_data = {
"id": chat_id,
"object": "chat.completion.chunk",
"created": int(time.time()),
"created": created_time,
"model": model,
"choices": [
{
@ -83,9 +74,10 @@ async def stream_response(response, model, max_tokens):
async def chat_response(resp, model, prompt_tokens, max_tokens):
last_resp = None
for i in resp:
for i in reversed(resp):
if i != "" and i != "data: [DONE]" and i.startswith("data: "):
last_resp = i
break
resp = json.loads(last_resp[6:])
chat_id = f"chatcmpl-{''.join(random.choice(string.ascii_letters + string.digits) for _ in range(29))}"
@ -143,11 +135,7 @@ def api_messages_to_chat(api_messages):
class ChatService:
def __init__(self, session=None):
self.session = session
self.proxies = {
"http": proxy_url,
"https": proxy_url,
}
self.s = httpx.AsyncClient(proxies=proxy_url)
self.user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/"
self.oai_device_id = str(uuid.uuid4())
self.chat_token = None
@ -170,16 +158,14 @@ class ChatService:
'sec-fetch-site': 'same-origin',
'user-agent': self.user_agent
}
# r = await self.session.post(url, headers=headers, json={}, proxies=self.proxies)
async with requests.AsyncSession() as s:
r = await s.post(url, headers=headers, json={}, proxies=self.proxies)
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
else:
self.chat_token = r.json().get('token')
if not self.chat_token:
raise HTTPException(status_code=500, detail="Chat token not found")
return self.chat_token
r = await self.s.post(url, headers=headers, json={})
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
else:
self.chat_token = r.json().get('token')
if not self.chat_token:
raise HTTPException(status_code=500, detail="Chat token not found")
return self.chat_token
def prepare_send_conversation(self, data):
self.headers = {
@ -225,21 +211,12 @@ class ChatService:
model = model_proxy.get(model, model)
max_tokens = data.get("max_tokens", 2147483647)
# async with aclosing(await self.session.post(url, headers=self.headers, json=self.chat_request, proxies=self.proxies, stream=True)) as r:
# async with self.session.stream("POST", url, headers=self.headers, json=self.chat_request, proxies=self.proxies) as r:
# async for chunk in r.aiter_content():
# print("Status: ", r.status_code)
# assert r.status_code == 200
# print("CHUNK", chunk)
# yield chunk
async with requests.AsyncSession() as s:
r = await s.post(url, headers=self.headers, json=self.chat_request, proxies=self.proxies, stream=True)
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
async for chunk in stream_response(r, model, max_tokens):
yield chunk
r = await self.s.send(
self.s.build_request("POST", url, headers=self.headers, json=self.chat_request, timeout=600), stream=True)
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
async for chunk in stream_response(r, model, max_tokens):
yield chunk
async def send_conversation(self, data):
url = f'{chatgpt_base_url}/conversation'
@ -249,9 +226,9 @@ class ChatService:
prompt_tokens = num_tokens_from_messages(api_messages, model)
max_tokens = data.get("max_tokens", 2147483647)
async with requests.AsyncSession() as s:
r = await s.post(url, headers=self.headers, json=self.chat_request, proxies=self.proxies, stream=True)
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
resp = (await r.atext()).split("\n")
return await chat_response(resp, model, prompt_tokens, max_tokens)
r = await self.s.send(
self.s.build_request("POST", url, headers=self.headers, json=self.chat_request, timeout=600), stream=False)
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
resp = r.text.split("\n")
return await chat_response(resp, model, prompt_tokens, max_tokens)

View File

@ -1,4 +1,4 @@
fastapi
curl_cffi
httpx
uvicorn
tiktoken

View File

@ -1,23 +0,0 @@
import random
import time
from curl_cffi import CurlHttpVersion, requests
from curl_cffi.requests import AsyncSession
async def create_shared_async_session():
browsers = ["chrome120", "chrome99_android"]
selected_browsers = random.choice(browsers)
async with AsyncSession(
impersonate=selected_browsers,
http_version=CurlHttpVersion.V2TLS, timeout=600) as session:
yield session
def create_shared_session():
random.seed(int(time.time()))
browsers = ["chrome120", "chrome99_android"]
selected_browsers = random.choice(browsers)
session = requests.Session(impersonate=selected_browsers,
http_version=CurlHttpVersion.V2TLS, timeout=600)
return session