由于 OpenAI的 API 会限制访问 IP,除了在本地访问时开启代理外,还可以使用代理链接的方式。
本片教程需要国外服务器,请大家自备。国外服务器的作用:
参考文章:
配置 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 证书后,将其放在 your_cert_path
和 your_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脚本进行请求转发,这样的好处是还能监测和处理数据的交互。
编写 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']
将请求转发到 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 配置文件,当访问该域名时,自动转发到相应的端口。
在 /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;
}
}
example.pem
和 example.key
。/etc/nginx/cert
目录下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 端口。
powered by kaifamiao