Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -28,6 +28,11 @@ _API_BASE_URL = "https://spuckhogycrxcbomznwo.supabase.co"
|
|
| 28 |
_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
|
| 29 |
_PASTE_API_URL = "https://page.zhoudan.icu/api/paste/b40v96oX"
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
app = Flask(__name__)
|
| 32 |
logging.basicConfig(level=logging.INFO)
|
| 33 |
logger = logging.getLogger(__name__)
|
|
@@ -42,6 +47,25 @@ if not NOTDIAMOND_IP:
|
|
| 42 |
logger.error("NOTDIAMOND_IP environment variable is not set!")
|
| 43 |
raise ValueError("NOTDIAMOND_IP must be set")
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
refresh_token_cache = TTLCache(maxsize=1000, ttl=3600)
|
| 46 |
headers_cache = TTLCache(maxsize=1, ttl=3600) # 1小时过期
|
| 47 |
token_refresh_lock = threading.Lock()
|
|
@@ -470,12 +494,16 @@ def before_request():
|
|
| 470 |
multi_auth_manager = None
|
| 471 |
|
| 472 |
@app.route('/', methods=['GET'])
|
|
|
|
| 473 |
def root():
|
| 474 |
return jsonify({
|
| 475 |
"service": "AI Chat Completion Proxy",
|
| 476 |
"usage": {
|
| 477 |
"endpoint": "/ai/v1/chat/completions",
|
| 478 |
"method": "POST",
|
|
|
|
|
|
|
|
|
|
| 479 |
"body": {
|
| 480 |
"model": "One of: " + ", ".join(MODEL_INFO.keys()),
|
| 481 |
"messages": [
|
|
@@ -487,10 +515,11 @@ def root():
|
|
| 487 |
}
|
| 488 |
},
|
| 489 |
"availableModels": list(MODEL_INFO.keys()),
|
| 490 |
-
"note": "
|
| 491 |
})
|
| 492 |
|
| 493 |
@app.route('/ai/v1/models', methods=['GET'])
|
|
|
|
| 494 |
def proxy_models():
|
| 495 |
"""返回可用模型列表。"""
|
| 496 |
models = [
|
|
@@ -510,6 +539,7 @@ def proxy_models():
|
|
| 510 |
})
|
| 511 |
|
| 512 |
@app.route('/ai/v1/chat/completions', methods=['POST'])
|
|
|
|
| 513 |
def handle_request():
|
| 514 |
global multi_auth_manager
|
| 515 |
if not multi_auth_manager:
|
|
|
|
| 28 |
_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
|
| 29 |
_PASTE_API_URL = "https://page.zhoudan.icu/api/paste/b40v96oX"
|
| 30 |
|
| 31 |
+
# 从环境变量获取API密钥
|
| 32 |
+
API_KEY = os.getenv('API_KEY')
|
| 33 |
+
if not API_KEY:
|
| 34 |
+
raise ValueError("API_KEY environment variable must be set")
|
| 35 |
+
|
| 36 |
app = Flask(__name__)
|
| 37 |
logging.basicConfig(level=logging.INFO)
|
| 38 |
logger = logging.getLogger(__name__)
|
|
|
|
| 47 |
logger.error("NOTDIAMOND_IP environment variable is not set!")
|
| 48 |
raise ValueError("NOTDIAMOND_IP must be set")
|
| 49 |
|
| 50 |
+
# API密钥验证装饰器
|
| 51 |
+
def require_api_key(f):
|
| 52 |
+
@wraps(f)
|
| 53 |
+
def decorated_function(*args, **kwargs):
|
| 54 |
+
auth_header = request.headers.get('Authorization')
|
| 55 |
+
if not auth_header:
|
| 56 |
+
return jsonify({'error': 'No API key provided'}), 401
|
| 57 |
+
|
| 58 |
+
try:
|
| 59 |
+
# 从 Bearer token 中提取API密钥
|
| 60 |
+
provided_key = auth_header.split('Bearer ')[-1].strip()
|
| 61 |
+
if provided_key != API_KEY:
|
| 62 |
+
return jsonify({'error': 'Invalid API key'}), 401
|
| 63 |
+
except Exception:
|
| 64 |
+
return jsonify({'error': 'Invalid Authorization header format'}), 401
|
| 65 |
+
|
| 66 |
+
return f(*args, **kwargs)
|
| 67 |
+
return decorated_function
|
| 68 |
+
|
| 69 |
refresh_token_cache = TTLCache(maxsize=1000, ttl=3600)
|
| 70 |
headers_cache = TTLCache(maxsize=1, ttl=3600) # 1小时过期
|
| 71 |
token_refresh_lock = threading.Lock()
|
|
|
|
| 494 |
multi_auth_manager = None
|
| 495 |
|
| 496 |
@app.route('/', methods=['GET'])
|
| 497 |
+
@require_api_key
|
| 498 |
def root():
|
| 499 |
return jsonify({
|
| 500 |
"service": "AI Chat Completion Proxy",
|
| 501 |
"usage": {
|
| 502 |
"endpoint": "/ai/v1/chat/completions",
|
| 503 |
"method": "POST",
|
| 504 |
+
"headers": {
|
| 505 |
+
"Authorization": "Bearer YOUR_API_KEY"
|
| 506 |
+
},
|
| 507 |
"body": {
|
| 508 |
"model": "One of: " + ", ".join(MODEL_INFO.keys()),
|
| 509 |
"messages": [
|
|
|
|
| 515 |
}
|
| 516 |
},
|
| 517 |
"availableModels": list(MODEL_INFO.keys()),
|
| 518 |
+
"note": "API key authentication is required for all endpoints."
|
| 519 |
})
|
| 520 |
|
| 521 |
@app.route('/ai/v1/models', methods=['GET'])
|
| 522 |
+
@require_api_key
|
| 523 |
def proxy_models():
|
| 524 |
"""返回可用模型列表。"""
|
| 525 |
models = [
|
|
|
|
| 539 |
})
|
| 540 |
|
| 541 |
@app.route('/ai/v1/chat/completions', methods=['POST'])
|
| 542 |
+
@require_api_key
|
| 543 |
def handle_request():
|
| 544 |
global multi_auth_manager
|
| 545 |
if not multi_auth_manager:
|