由于 OpenAI 的 API 会限制访问 IP,除了在本地访问时开启代理外,还可以使用代理链接的方式。
教程需要一台国外服务器,个人主要用 Azure,内容一览:
注:本篇配合 openai_api_call 工具使用更佳。
直接转发请求 参考知乎:Nginx 反向代理 OpenAI API
设置 http 转发 配置 Nginx 信息如下,vim /etc/nginx/sites-enabled/default
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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-Proto $scheme; } }
将第一处的 {your_domain_name}
替换为你的域名,保存退出。
参数说明:
proxy_pass
:转发的上游服务器地址
proxy_ssl_server_name on
和 SSL/TLS 握手相关(待了解)
proxy_set_header Host
,默认将上游地址作为 Host,这里手动设置为 api.openai.com
proxy_set_header X-Forwarded-For
,默认将客户端 IP 作为 X-Forwarded-For,这里注释掉,避免暴露实际 IP
proxy_set_header X-Forwarded-Proto
,默认将客户端协议作为 X-Forwarded-Proto
设置 ssl 证书 申请 ssl 证书后,将其放在 your_cert_path
和 your_cert_key_path
处,并修改 Nginx 配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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-Proto $scheme; } }
监测数据并转发 比起直接用 nginx 转发,我们通过 Python 脚本转发请求,这样可以监测和处理交互的数据。
flask 转发请求 编写 main.py
文件,下载链接:main.py 。
下边是对文件内容的解释。
加载头部 导入必要的 Python 包
1 2 3 4 5 from flask import Flask, request, Responseimport requests, randomapp = Flask(__name__)
设置 API 请求日志的保存路径
1 2 3 4 5 6 7 8 9 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 )
替换密钥 在 API_LIST
中填写实际的 API 密钥,当请求密钥为 fake_keys
中的值时,会随机返回 API_LIST
中的一个密钥。
1 2 3 4 API_LIST = [ 'sk-real-1' , 'sk-real-2' , 'sk-real-3' ] fake_keys = [ 'sk-fake-1' , 'sk-fake-2' , 'sk-fake-3' ]
转发 chat 请求 将请求转发到 OpenAI,将返回结果保存到日志文件中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @app.route('/v1/chat/completions' , methods=['POST' ] ) def forward_request (): try : 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 api_key in fake_keys: api_key = random.choice(API_LIST) headers = { "Content-Type" : "application/json" , "Authorization" : f"Bearer {api_key} " } response = requests.post(url, json=data, params=params, headers=headers) if not api_key in API_LIST: with open (api_path, 'a' ) as f: f.write(f'{api_key} \n\n' ) 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 Response(response.content, status=response.status_code) except Exception as e: return Response(f"invalid request!\n" , status=400 )
转发其他请求 这部分用于获取 API 的使用信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @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} " } 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) 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 )
启动服务 最后,加上启动服务的代码:
1 2 if __name__ == '__main__' : app.run(host='0.0.0.0' , debug=False , port=5000 )
执行 python main.py
启动服务。
修改 Nginx 配置文件 这一步需要域名,根据监听的端口号编写 nginx 配置文件,当访问该域名时,自动转发到相应的端口。
在 /etc/nginx/sites-available/default
文件中,添加如下内容:
1 2 3 4 5 6 7 8 9 10 server { listen 80; server_name <域名地址>; location / { proxy_pass http://localhost:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
设置 ssl 证书 在域名所在服务商申请证书后,下载 nginx 证书文件,如 example.pem
和 example.key
。
将证书文件上传到服务器,比如到 /etc/nginx/cert
目录下
修改 nginx 配置文件,追加下边内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 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-IP $remote_addr; } }
注意服务器需要开启 443 入站端口。
越过 Cloudflare 限制 借助 go-chatgpt-api 项目,只需要编写 docker-compose 文件:
1 2 3 4 5 6 7 8 9 10 version: "3" services: go-chatgpt-api: container_name: go-chatgpt-api image: linweiyuan/go-chatgpt-api:latest # 最新 ports: - 8080:8080 # 宿主机8080端口可按需改为其它端口 environment: - GIN_MODE=release restart: unless-stopped
然后编写 nginx 配置文件,设置反向代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 server { listen 80; server_name <域名地址>; location / { proxy_pass http://127.0.0.1:8080; 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-Proto $scheme; } }
443 端口类似配置。为避免代理被他人使用,这里也可以修改参数,比如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 server { listen 80; server_name <域名地址>; location /password { proxy_pass http://127.0.0.1:8080; 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-Proto $scheme; } }
另外,该项目不仅支持 API 代理,也支持 Access Token 代理,接口示例参看:
https://github.com/linweiyuan/go-chatgpt-api/blob/main/example/vscode