20 Commits

Author SHA1 Message Date
Clivia
6483e64460 feat flask直接启动,解决部分机cpu占用过大问题 2024-03-08 21:34:03 +08:00
Clivia
07aa5ec83b feat simply flask run 2024-03-08 14:29:23 +08:00
Clivia
0f4ab22273 feat simply flask run 2024-03-08 14:28:37 +08:00
Clivia
ba4e89101f Update xyhelper-deploy.yml 2024-03-04 15:09:48 +08:00
Clivia
876417a9d1 Update ninja-image.yml 2024-03-04 15:09:29 +08:00
Yanyutin753
0564b10550 支持填错gpt-4-gizmo-XXX,回退成gpt-3.5-turbo 2024-03-04 14:53:01 +08:00
Clivia
148e96108c 优化部署说明 2024-03-04 09:40:57 +08:00
Clivia
afcca06c9d 修改部署说明 2024-03-03 23:45:50 +08:00
Clivia
f5b5592f66 修改部署说明 2024-02-27 22:54:38 +08:00
Clivia
81ff100e9c 优化部署说明 2024-02-27 22:46:17 +08:00
Clivia
256e6dbce6 fix gpts.json is not accessible 2024-02-27 17:28:04 +08:00
Clivia
7ce92ae642 优化请求 2024-02-26 21:52:23 +08:00
Clivia
d0cc050a51 优化部署说明 2024-02-26 15:36:22 +08:00
Clivia
05d5a1a13e 修改配置说明 2024-02-26 15:25:34 +08:00
Clivia
bd0e470427 适配GPTs 2024-02-26 14:42:54 +08:00
Clivia
3d3d939e3c 支持gpt-4-gizmo-XXX,动态配置GPTS 2024-02-26 14:13:27 +08:00
Yanyutin753
fa971cf108 支持动态适配gpts 2024-02-26 13:08:45 +08:00
Clivia
10ae0b415c 优化非流式回复空的问题 2024-02-22 00:04:26 +08:00
Clivia
b850592a57 修改部署说明 2024-02-21 18:51:12 +08:00
Clivia
719e6f83a9 Update start.sh 2024-02-21 18:50:15 +08:00
10 changed files with 158 additions and 71 deletions

View File

@@ -42,5 +42,6 @@ jobs:
push: true
tags: |
yangclivia/pandora-to-api:${{ steps.tag_name.outputs.tag }}
yangclivia/pandora-to-api:0.7.7
platforms: linux/amd64,linux/arm64
build-args: TARGETPLATFORM=${{ matrix.platform }}

View File

@@ -42,5 +42,6 @@ jobs:
push: true
tags: |
yangclivia/pandora-to-api:${{ steps.tag_name.outputs.tag }}
yangclivia/pandora-to-api:0.7.8
platforms: linux/amd64,linux/arm64
build-args: TARGETPLATFORM=${{ matrix.platform }}

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
*.json
*.log
*.json
*.log

6
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/log/access.log" charset="GBK" />
</component>
</project>

View File

@@ -10,15 +10,13 @@ COPY . /app
# 设置环境变量
ENV PYTHONUNBUFFERED=1
RUN chmod +x /app/start.sh
RUN apt update && apt install -y jq
RUN chmod +x /app/main.py
# # 设置 pip 源为清华大学镜像
# RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 安装任何所需的依赖项
RUN pip install --no-cache-dir flask flask_apscheduler gunicorn requests Pillow flask-cors tiktoken fake_useragent redis websocket-client pysocks requests[socks] websocket-client[optional]
RUN pip install --no-cache-dir flask flask_apscheduler requests Pillow flask-cors tiktoken fake_useragent redis websocket-client pysocks requests[socks] websocket-client[optional]
# 在容器启动时运行 Flask 应用
CMD ["/app/start.sh"]
CMD ["python3", "main.py"]

View File

@@ -1,5 +1,5 @@
## 项目简介
## 0.7.8 xyhelper项目简介
![Docker Image Size (tag)](https://img.shields.io/docker/image-size/yangclivia/pandora-to-api/0.7.8)![Docker Pulls](https://img.shields.io/docker/pulls/yangclivia/pandora-to-api)[![GitHub Repo stars](https://img.shields.io/github/stars/Yanyutin753/RefreshToV1Api?style=social)](https://github.com/Yanyutin753/refresh-gpt-chat/stargazers)
> [!IMPORTANT]
>
> Respect `xyhelper` ,Respect `ninja` , Respect `Wizerd`
@@ -14,7 +14,7 @@
3. 支持直接把refresh_token作为请求key方便接入one_api
4. 支持 gpt-4-mobile 、gpt-4-s 、基本所有的GPTS
4. 支持 gpt-4-mobile 、gpt-4-s 、动态支持所有的gpt-4-gizmo-XXX模型
* **xyhelper 的 免费 backend-api 接口,无需打码**
@@ -99,9 +99,9 @@
- `need_log_to_file`: 用于设置是否需要将日志输出到文件,可选值为:`true``false`,默认为 `true`,日志文件路径为:`./log/access.log`,默认每天会自动分割日志文件。
- `process_workers`: 用于设置进程数,如果不需要设置,可以保持不变,如果需要设置,可以设置为需要设置的值,如果设置`1`,则会强制设置为单进程模式
- `process_workers`: 用于设置进程数,如果不需要设置,可以保持不变,如果需要设置,可以设置为需要设置的值,默认`2`
- `process_threads`: 用于设置线程数,如果不需要设置,可以保持不变,如果需要设置,可以设置为需要设置的值,如果设置`1`,则会强制设置为单线程模式
- `process_threads`: 用于设置线程数,如果不需要设置,可以保持不变,如果需要设置,可以设置为需要设置的值,默认`2`
- `upstream_base_url`: xyhelper 的免费接口地址,如:`https://demo.xyhelper.cn`,注意:不要以 `/` 结尾。
@@ -166,7 +166,9 @@ PS. 注意arkose_urls中的地址需要支持PandoraNext的Arkose Token获取
## GPTS配置说明
如果需要使用 GPTS需要修改 `gpts.json` 文件其中每个对象的key即为调用对应 GPTS 的时候使用的模型名称,而 `id` 则为对应的模型id`id` 对应每个 GPTS 的链接的后缀。配置多个GPTS的时候用逗号隔开。
### 使用 GPTS
1. 可修改 `gpts.json` 文件其中每个对象的key即为调用对应 GPTS 的时候使用的模型名称,而 `id` 则为对应的模型id`id` 对应每个 GPTS 的链接的后缀。配置多个GPTS的时候用逗号隔开。
例如PandoraNext的官方 GPTS 的链接为:`https://chat.oaifree.com/g/g-CFsXuTRfy-pandoranextzhu-shou`,则该模型的 `id` 的值应为 `g-CFsXuTRfy-pandoranextzhu-shou`,而模型名可以自定义。
@@ -183,7 +185,16 @@ PS. 注意arkose_urls中的地址需要支持PandoraNext的Arkose Token获取
}
```
注意:使用该配置的时候需要保证正确填写 `docker-compose.yml` 的环境变量 `KEY_FOR_GPTS_INFO`,同时该变量设置的 `key` 允许访问所有配置的 GPTS。
2. 可直接请求的时候加上相应的gpt-4-gizmo-XXX
```json
{
"stream":true,
"model":"gpt-4-gizmo-XXXX",
"messages": [{"role": "user", "content": "你是什么模型"}]
}
```
注意:使用该配置的时候需要保证正确填写 `config.json` 文件的环境变量 `KEY_FOR_GPTS_INFO`,同时该变量设置的 `key` 允许访问所有配置的 GPTS。
## 绘图接口使用说明
@@ -324,19 +335,20 @@ PS. 注意arkose_urls中的地址需要支持PandoraNext的Arkose Token获取
## 示例
以ChatGPT-Next-Web项目的docker-compose部署为例这里提供一个简单的部署配置文件示例
[ChatGPT-Next-Web](https://github.com/Yanyutin753/ChatGPT-Next-Web-LangChain-Gpt-4-All)项目插件版的docker-compose部署为例支持完全适配项目,这里提供一个简单的部署配置文件示例:
```
version: '3'
services:
chatgpt-next-web:
image: yidadaa/chatgpt-next-web
image: yangclivia/chatgpt-next-web-langchain
ports:
- "50013:3000"
environment:
- CUSTOM_MODELS=-all,+gpt-3.5-turbo,+gpt-4-s,+gpt-4-mobile,+gpt-4-vision-preview,+gpt-4-gizmo-XXX
- OPENAI_API_KEY=<正确的refresh_token>
- BASE_URL=<backend-to-api容器地址>
- CUSTOM_MODELS=+gpt-4-s,+gpt-4-mobile,+<gpts.json 中的模型名>
- CUSTOM_MODELS=-gpt-4-0613,-gpt-4-32k,-gpt-4-32k-0613,-gpt-4-turbo-preview,-gpt-4-1106-preview,-gpt-4-0125-preview,-gpt-3.5-turbo-0125,-gpt-3.5-turbo-0613,-gpt-3.5-turbo-1106,-gpt-3.5-turbo-16k,-gpt-3.5-turbo-16k-0613,+gpt-3.5-turbo,+gpt-4,+gpt-4-mobile,+gpt-4-vision-preview,+gpt-4-mobile,+<gpts.json 中的模型名>
```
@@ -351,17 +363,20 @@ services:
![api-2](https://github.com/Ink-Osier/PandoraToV1Api/assets/133617214/37c0381f-a70a-42bb-83f1-1491053240b7)
### 读文件
![api-3](https://github.com/Yanyutin753/xyhelperToV1Api_refresh/assets/132346501/e1f2e770-cd33-4af0-a0c7-5ddabf1c076d)
### 绘图
![api-3](https://github.com/Ink-Osier/PandoraToV1Api/assets/133617214/8eea9436-12ee-46b1-86c1-67e7e97da83a)
![api-4](https://github.com/Ink-Osier/PandoraToV1Api/assets/133617214/8eea9436-12ee-46b1-86c1-67e7e97da83a)
### GPT-4-Mobile
![api-4](https://github.com/Ink-Osier/PandoraToV1Api/assets/133617214/2eb4fd4f-7c66-4a1f-a54a-3c280a36e509)
![api-5](https://github.com/Ink-Osier/PandoraToV1Api/assets/133617214/2eb4fd4f-7c66-4a1f-a54a-3c280a36e509)
### GPTS
![api-5](https://github.com/Ink-Osier/PandoraToV1Api/assets/133617214/299df56a-d245-4920-8892-94e1a9cc644a)
![api-6](https://github.com/Ink-Osier/PandoraToV1Api/assets/133617214/299df56a-d245-4920-8892-94e1a9cc644a)
### Bot 模式

View File

@@ -26,7 +26,7 @@
},
"refresh_ToAccess": {
"stream_sleep_time": 0,
"enableOai":"true",
"enableOai":"false",
"xyhelper_refreshToAccess_Url": "https://demo.xyhelper.cn/applelogin"
},
"redis": {

0
log/access.log Normal file
View File

160
main.py
View File

@@ -202,7 +202,7 @@ def oaiGetAccessToken(refresh_token):
def xyhelperGetAccessToken(getAccessTokenUrl, refresh_token):
try:
logger.info("将通过这个网址请求access_token" + getAccessTokenUrl)
data = {
'refresh_token': refresh_token,
}
@@ -255,7 +255,7 @@ def fetch_gizmo_info(base_url, proxy_api_prefix, model_id):
# 将配置添加到全局列表
def add_config_to_global_list(base_url, proxy_api_prefix, gpts_data):
global gpts_configurations
updateGptsKey()
updateGptsKey() # cSpell:ignore Gpts
# print(f"gpts_data: {gpts_data}")
for model_name, model_info in gpts_data.items():
# print(f"model_name: {model_name}")
@@ -271,22 +271,20 @@ def add_config_to_global_list(base_url, proxy_api_prefix, gpts_data):
else:
logger.info(f"Fetching gpts info for {model_name}, {model_id}")
gizmo_info = fetch_gizmo_info(base_url, proxy_api_prefix, model_id)
# 如果成功获取到数据,则将其存入 Redis
if gizmo_info:
redis_client.set(model_id, str(gizmo_info))
logger.info(f"Cached gizmo info for {model_name}, {model_id}")
if gizmo_info:
# 检查模型名称是否已经在列表中
if not any(d['name'] == model_name for d in gpts_configurations):
gpts_configurations.append({
'name': model_name,
'id': model_id,
'config': gizmo_info
})
else:
logger.info(f"Model already exists in the list, skipping...")
# 检查模型名称是否已经在列表中
if gizmo_info and not any(d['name'] == model_name for d in gpts_configurations):
gpts_configurations.append({
'name': model_name,
'id': model_id,
'config': gizmo_info
})
else:
logger.info(f"Model already exists in the list, skipping...")
def generate_gpts_payload(model, messages):
@@ -324,9 +322,11 @@ scheduler.start()
# PANDORA_UPLOAD_URL = 'files.pandoranext.com'
VERSION = '0.7.8'
VERSION = '0.7.8.3'
# VERSION = 'test'
UPDATE_INFO = '项目将脱离ninja使用xyhelperxyhelper_refreshToAccess_Url等配置需修改'
UPDATE_INFO = 'flask直接启动解决部分机cpu占用过大问题'
# UPDATE_INFO = '【仅供临时测试使用】 '
# 解析响应中的信息
@@ -864,10 +864,14 @@ def send_text_prompt_and_get_response(messages, api_key, stream, model):
# 查找模型配置
model_config = find_model_config(model)
if model_config:
if model_config or 'gpt-4-gizmo-' in model:
# 检查是否有 ori_name
ori_model_name = model_config.get('ori_name', model)
logger.info(f"原模型名: {ori_model_name}")
if model_config:
ori_model_name = model_config.get('ori_name', model)
logger.info(f"原模型名: {ori_model_name}")
else:
ori_model_name = model
logger.info(f"请求模型名: {model}")
if ori_model_name == 'gpt-4-s':
payload = {
# 构建 payload
@@ -918,6 +922,54 @@ def send_text_prompt_and_get_response(messages, api_key, stream, model):
"force_paragen": False,
"force_rate_limit": False
}
elif 'gpt-4-gizmo-' in model:
payload = generate_gpts_payload(model, formatted_messages)
if not payload:
global gpts_configurations
# 假设 model是 'gpt-4-gizmo-123'
split_name = model.split('gpt-4-gizmo-')
model_id = split_name[1] if len(split_name) > 1 else None
gizmo_info = fetch_gizmo_info(BASE_URL, PROXY_API_PREFIX, model_id)
logging.info(gizmo_info)
# 如果成功获取到数据,则将其存入 Redis
if gizmo_info:
redis_client.set(model_id, str(gizmo_info))
logger.info(f"Cached gizmo info for {model}, {model_id}")
# 检查模型名称是否已经在列表中
if not any(d['name'] == model for d in gpts_configurations):
gpts_configurations.append({
'name': model,
'id': model_id,
'config': gizmo_info
})
else:
logger.info(f"Model already exists in the list, skipping...")
payload = generate_gpts_payload(model, formatted_messages)
else:
payload = {
# 构建 payload
"action": "next",
"messages": formatted_messages,
"parent_message_id": str(uuid.uuid4()),
"model": "text-davinci-002-render-sha",
"timezone_offset_min": -480,
"suggestions": [
"What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter.",
"I want to cheer up my friend who's having a rough day. Can you suggest a couple short and sweet text messages to go with a kitten gif?",
"Come up with 5 concepts for a retro-style arcade game.",
"I have a photoshoot tomorrow. Can you recommend me some colors and outfit options that will look good on camera?"
],
"history_and_training_disabled": False,
"arkose_token": None,
"conversation_mode": {
"kind": "primary_assistant"
},
"force_paragen": False,
"force_rate_limit": False
}
logger.debug('KEY_FOR_GPTS_INFO Or Request Model is not accessible')
else:
payload = generate_gpts_payload(model, formatted_messages)
if not payload:
@@ -1093,7 +1145,7 @@ def replace_sandbox(text, conversation_id, message_id, api_key):
sandbox_path = match.group(1)
download_url = get_download_url(conversation_id, message_id, sandbox_path)
if download_url == None:
return "\n```\nError: 沙箱文件下载失败,这可能是因为您启用了隐私模式\n```"
return "\n```\nError: 沙箱文件下载失败,这可能是因为您的帐号启用了隐私模式\n```"
file_name = extract_filename(download_url)
timestamped_file_name = timestamp_filename(file_name)
if USE_OAIUSERCONTENT_URL == False:
@@ -1161,7 +1213,7 @@ def generate_actions_allow_payload(author_role, author_name, target_message_id,
"action": "next",
"messages": [
{
"id": generate_custom_uuid_v4(),
"id": str(uuid.uuid4()),
"author": {
"role": author_role,
"name": author_name
@@ -2012,7 +2064,7 @@ def old_data_fetcher(upstream_response, data_queue, stop_event, last_data_time,
"id": chat_message_id,
"object": "chat.completion.chunk",
"created": timestamp,
"model": message.get("metadata", {}).get("model_slug"),
"model": model,
"choices": [
{
"index": 0,
@@ -2248,8 +2300,10 @@ def chat_completions():
messages = data.get('messages')
model = data.get('model')
accessible_model_list = get_accessible_model_list()
if model not in accessible_model_list:
if model not in accessible_model_list and not 'gpt-4-gizmo-' in model:
return jsonify({"error": "model is not accessible"}), 401
elif 'gpt-4-gizmo-' in model and not KEY_FOR_GPTS_INFO:
return jsonify({"error": "key_for_gpts_info is not accessible"}), 400
stream = data.get('stream', False)
@@ -2368,32 +2422,36 @@ def chat_completions():
ori_model_name = model_config.get('ori_name', model)
input_tokens = count_total_input_words(messages, ori_model_name)
comp_tokens = count_tokens(all_new_text, ori_model_name)
response_json = {
"id": generate_unique_id("chatcmpl"),
"object": "chat.completion",
"created": int(time.time()), # 使用当前时间戳
"model": model, # 使用请求中指定的模型
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": all_new_text # 使用累积的文本
},
"finish_reason": "stop"
}
],
"usage": {
# 这里的 token 计数需要根据实际情况计算
"prompt_tokens": input_tokens,
"completion_tokens": comp_tokens,
"total_tokens": input_tokens + comp_tokens
},
"system_fingerprint": None
}
# 返回 JSON 响应
return jsonify(response_json)
if input_tokens >= 100 and comp_tokens <= 0:
# 返回错误消息和状态码429
error_response = {"error": "空回复"}
return jsonify(error_response), 429
else:
response_json = {
"id": generate_unique_id("chatcmpl"),
"object": "chat.completion",
"created": int(time.time()), # 使用当前时间戳
"model": model, # 使用请求中指定的模型
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": all_new_text # 使用累积的文本
},
"finish_reason": "stop"
}
],
"usage": {
# 这里的 token 计数需要根据实际情况计算
"prompt_tokens": input_tokens,
"completion_tokens": comp_tokens,
"total_tokens": input_tokens + comp_tokens
},
"system_fingerprint": None
}
# 返回 JSON 响应
return jsonify(response_json)
else:
return Response(generate(), mimetype='text/event-stream')
@@ -2406,8 +2464,10 @@ def images_generations():
# messages = data.get('messages')
model = data.get('model')
accessible_model_list = get_accessible_model_list()
if model not in accessible_model_list:
if model not in accessible_model_list and not 'gpt-4-gizmo-' in model:
return jsonify({"error": "model is not accessible"}), 401
elif 'gpt-4-gizmo-' in model and not KEY_FOR_GPTS_INFO:
return jsonify({"error": "key_for_gpts_info is not accessible"}), 400
prompt = data.get('prompt', '')
@@ -2639,4 +2699,4 @@ scheduler.add_job(id='updateRefresh_run', func=updateRefresh_dict, trigger='cron
# 运行 Flask 应用
if __name__ == '__main__':
app.run(host='0.0.0.0')
app.run(host='0.0.0.0', port=33333, threaded=True)

View File

@@ -11,7 +11,7 @@ if [ -z "$PROCESS_WORKERS" ]; then
export PROCESS_WORKERS
if [ -z "$PROCESS_WORKERS" ]; then
PROCESS_WORKERS=1
PROCESS_WORKERS=2
fi
fi
@@ -31,4 +31,5 @@ echo "PROCESS_WORKERS: ${PROCESS_WORKERS}"
echo "PROCESS_THREADS: ${PROCESS_THREADS}"
# 启动 Gunicorn 并使用 tee 命令同时输出日志到文件和控制台
exec gunicorn -w ${PROCESS_WORKERS} --threads ${PROCESS_THREADS} --bind 0.0.0.0:33333 main:app --access-logfile - --error-logfile -
exec gunicorn -w ${PROCESS_WORKERS} --threads ${PROCESS_THREADS} --bind 0.0.0.0:33333 main:app --access-logfile - --error-logfile - --timeout 60