开发喵星球

ChatGPT API 代理转发

ChatGPT API 代理转发

由于 OpenAI的 API 会限制访问 IP,除了在本地访问时开启代理外,还可以使用代理链接的方式。

本片教程需要国外服务器,请大家自备。国外服务器的作用:

直接转发请求

参考文章:

设置 http 转发

配置 Nginx 信息如下,vim /etc/nginx/sites-enabled/default

server {
    listen 80;
    server_name {your_domain_name};
    location / {
        proxy_pass  https://api.openai.com/;
        proxy_ssl_server_name on;
        proxy_set_header Host api.openai.com;
        proxy_set_header Connection '';
        proxy_http_version 1.1;
        chunked_transfer_encoding off;
        proxy_buffering off;
        proxy_cache off;
        ; proxy_set_header X-Forwarded-For remote_addr;
        proxy_set_header X-Forwarded-Protoscheme;
    }
}

将第一处的 {your_domain_name} 替换为你的域名,保存退出。

参数说明:

设置 ssl 证书

申请 ssl 证书后,将其放在 your_cert_pathyour_cert_key_path 处,并修改 Nginx 配置文件:

server {
    listen 443 ssl;
    server_name {your_domain_name};
    ssl_certificate {your_cert_path};
    ssl_certificate_key {your_cert_key_path};
    ssl_session_cache shared:le_nginx_SSL:1m;
    ssl_session_timeout 1440m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;
    location / {
        proxy_pass  https://api.openai.com/;
        proxy_ssl_server_name on;
        proxy_set_header Host api.openai.com;
        proxy_set_header Connection '';
        proxy_http_version 1.1;
        chunked_transfer_encoding off;
        proxy_buffering off;
        proxy_cache off;
        # proxy_set_header X-Forwarded-For remote_addr;
        proxy_set_header X-Forwarded-Protoscheme;
    }
}

监测数据并转发

还可以通过Python脚本进行请求转发,这样的好处是还能监测和处理数据的交互。

flask 转发请求

编写 main.py 文件:

#!/usr/bin/env python
from flask import Flask, request, Response
import requests, random, os, datetime

app = Flask(__name__)

# file for saving API requests
home = os.path.expanduser("~")
api_path = os.path.join(home, '.chatlog/apilist.log')
logfile = 'chatdata-' + datetime.datetime.now().strftime("%Y-%m-%d") + '.log'
log_path = os.path.join(home, '.chatlog', logfile)
os.makedirs(os.path.dirname(log_path), exist_ok=True)
os.makedirs(os.path.dirname(api_path), exist_ok=True)

# real API keys
API_LIST = [ 'sk-real-1', 'sk-real-2', 'sk-real-3']
# fake API keys
fake_keys = [ 'sk-fake-1', 'sk-fake-2', 'sk-fake-3']

# wrap chat requests
@app.route('/v1/chat/completions', methods=['POST'])
def forward_request():
    try:
        # get request headers, body and query parameters
        api_key = request.headers.get('Authorization').strip("Bearer ").strip()
        url = 'https://api.openai.com/v1/chat/completions'
        data = request.get_json()
        params = request.args
        # If the API key starts with fake-, randomly select one key
        if api_key in fake_keys:
            api_key = random.choice(API_LIST)

        # Forward the data to the target API and get the response
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}"
        }
        response = requests.post(url, json=data, params=params, headers=headers)

        # Save API request log
        if not api_key in API_LIST:
            with open(api_path, 'a') as f:
                f.write(f'{api_key}\n\n')
        
        # Save request data
        with open(log_path, 'a', encoding="utf-8") as f:
            f.write(f'#Request\n{data}\n#Request\n')
            f.write(f'#Response\n{response.content}\n#Response\n\n')

        # return the response
        return Response(response.content, status=response.status_code)
    except Exception as e: # hide the error message
        return Response(f"invalid request!\n", status=400)

# wrap dashboard requests
@app.route('/<path:path>', methods=['GET'])
def handle_all(path):
    try:
        api_key = request.headers.get('Authorization').strip("Bearer ").strip()
        if api_key in fake_keys:
            api_key = random.choice(API_LIST)
        headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {api_key}"}
        # get recent usage
        if path == 'v1/dashboard/billing/usage':
            start_date = request.args.get('start_date')
            end_date = request.args.get('end_date')
            url = f'https://api.openai.com/v1/dashboard/billing/usage?start_date={start_date}&end_date={end_date}'
            response = requests.get(url, headers=headers)
            return Response(response.content, status=response.status_code)
        # get subscription info
        elif path == 'v1/dashboard/billing/subscription':
            url = 'https://api.openai.com/v1/dashboard/billing/subscription'
            response = requests.get(url, headers=headers)
            return Response(response.content, status=response.status_code)
        else:
            return Response(f"Unsupported url!\n", status=400)
    except Exception as e:
        return Response(f"invalid request!\n", status=400)

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=False, port=5000)

代码解析:

加载头部

导入必要的 Python 包

#!/usr/bin/env python
from flask import Flask, request, Response
import requests, random

app = Flask(__name__)

设置 API 请求日志的保存路径

# file for saving API requests
home = os.path.expanduser("~")
# api path
api_path = os.path.join(home, '.chatlog/apilist.log')
# request log
logfile = 'chatdata-' + datetime.datetime.now().strftime("%Y-%m-%d") + '.log'
log_path = os.path.join(home, '.chatlog', logfile)
os.makedirs(os.path.dirname(log_path), exist_ok=True)
os.makedirs(os.path.dirname(api_path), exist_ok=True)
替换密钥

API_LIST 中填写实际的 API 密钥,当请求密钥为 fake_keys 中的值时,会随机返回 API_LIST 中的一个密钥。

# real API keys
API_LIST = [ 'sk-real-1', 'sk-real-2', 'sk-real-3']
# fake API keys
fake_keys = [ 'sk-fake-1', 'sk-fake-2', 'sk-fake-3']
转发 chat 请求

将请求转发到 OpenAI,将返回结果保存到日志文件中。

# wrap chat requests
@app.route('/v1/chat/completions', methods=['POST'])
def forward_request():
    try:
        # get request headers, body and query parameters
        api_key = request.headers.get('Authorization').strip("Bearer ").strip()
        url = 'https://api.openai.com/v1/chat/completions'
        data = request.get_json()
        params = request.args
        # If the API key starts with fake-, randomly select one key
        if api_key in fake_keys:
            api_key = random.choice(API_LIST)

        # Forward the data to the target API and get the response
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}"
        }
        response = requests.post(url, json=data, params=params, headers=headers)

        # Save API request log
        if not api_key in API_LIST:
            with open(api_path, 'a') as f:
                f.write(f'{api_key}\n\n')
        
        # Save request data
        with open(log_path, 'a', encoding="utf-8") as f:
            f.write(f'#Request\n{data}\n#Request\n')
            f.write(f'#Response\n{response.content}\n#Response\n\n')

        # return the response
        return Response(response.content, status=response.status_code)
    except Exception as e: # hide the error message
        return Response(f"invalid request!\n", status=400)
转发其他请求

这部分用于获取 API 的使用信息。

# wrap dashboard requests
@app.route('/<path:path>', methods=['GET'])
def handle_all(path):
    try:
        api_key = request.headers.get('Authorization').strip("Bearer ").strip()
        if api_key in fake_keys:
            api_key = random.choice(API_LIST)
        headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {api_key}"}
        # get recent usage
        if path == 'v1/dashboard/billing/usage':
            start_date = request.args.get('start_date')
            end_date = request.args.get('end_date')
            url = f'https://api.openai.com/v1/dashboard/billing/usage?start_date={start_date}&end_date={end_date}'
            response = requests.get(url, headers=headers)
            return Response(response.content, status=response.status_code)
        # get subscription info
        elif path == 'v1/dashboard/billing/subscription':
            url = 'https://api.openai.com/v1/dashboard/billing/subscription'
            response = requests.get(url, headers=headers)
            return Response(response.content, status=response.status_code)
        else:
            return Response(f"Unsupported url!\n", status=400)
    except Exception as e:
        return Response(f"invalid request!\n", status=400)
启动服务

最后,加上启动服务的代码:

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=False, port=5000)

执行 python main.py 启动服务。

修改 Nginx 配置文件

这一步需要域名,根据监听的端口号编写 nginx 配置文件,当访问该域名时,自动转发到相应的端口。

/etc/nginx/sites-available/default 文件中,添加如下内容:

server {
    listen 80;
    server_name <域名地址>;

    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host host;
        proxy_set_header X-Real-IPremote_addr;
    }
}

设置 ssl 证书

  1. 在域名所在服务商申请证书后,下载 nginx 证书文件,如 example.pemexample.key
  2. 将证书文件上传到服务器,比如到 /etc/nginx/cert 目录下
  3. 修改 nginx 配置文件,追加下边内容:
server {
    listen 443 ssl;
    server_name <域名地址>;

    ssl_certificate /etc/nginx/cert/example.pem;
    ssl_certificate_key /etc/nginx/cert/example.key;

    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host host;
        proxy_set_header X-Real-IPremote_addr;
    }
}

注意:服务器需要开启 443 端口。

   
分类:玩技术 作者:荡荡, 浩浩 发表于:2024-03-27 12:58:21 阅读量:158
<<   >>


powered by kaifamiao