|
|
from flask import Flask, jsonify, request, Response, stream_with_context |
|
|
import requests |
|
|
import os |
|
|
import logging |
|
|
from dotenv import load_dotenv |
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
|
|
|
|
API_BASE_URL = os.getenv("API_BASE_URL", "") |
|
|
AUTH_KEY = os.getenv("AUTH_KEY", "callme") |
|
|
API_KEYS = os.getenv("API_KEYS") |
|
|
|
|
|
API_KEY_LIST = API_KEYS.split(",") if API_KEYS else [] |
|
|
|
|
|
key_index = 0 |
|
|
|
|
|
app = Flask(__name__) |
|
|
|
|
|
def getAPI_KEY(): |
|
|
global key_index |
|
|
if not API_KEY_LIST: |
|
|
logging.warning("API_KEYS is not configured.") |
|
|
return "" |
|
|
key = API_KEY_LIST[key_index] |
|
|
key_index = (key_index + 1) % len(API_KEY_LIST) |
|
|
return key |
|
|
|
|
|
@app.before_request |
|
|
def check_api_key(): |
|
|
key = request.headers.get("Authorization") |
|
|
if key != "Bearer " + AUTH_KEY: |
|
|
return jsonify({"success": False, "message": "Unauthorized: Invalid API key"}), 403 |
|
|
|
|
|
@app.route("/v1/models", methods=['GET']) |
|
|
def getModels(): |
|
|
api_key = getAPI_KEY() |
|
|
if not api_key: |
|
|
return jsonify({"success": False, "message": "API Key not available"}), 500 |
|
|
|
|
|
headers = { |
|
|
"Authorization": "Bearer " + api_key, |
|
|
"Content-Type": "application/json" |
|
|
} |
|
|
try: |
|
|
response = requests.get(API_BASE_URL + "/models", headers=headers, timeout=30) |
|
|
response.raise_for_status() |
|
|
response_headers = {'Content-Type': response.headers.get('content-type', 'application/json')} |
|
|
|
|
|
return (response.content, response.status_code, response_headers) |
|
|
except requests.exceptions.RequestException as e: |
|
|
logging.error("Get models error. %s", e) |
|
|
return jsonify({"success": False, "message": f"Failed to fetch models: {e}"}), 500 |
|
|
except Exception as e: |
|
|
logging.error("An unexpected error occurred in getModels: %s", e) |
|
|
return jsonify({"success": False, "message": str(e)}), 500 |
|
|
|
|
|
@app.route("/v1/chat/completions",methods=['POST']) |
|
|
def chat(): |
|
|
headers = { |
|
|
"Authorization":"Bearer "+getAPI_KEY(), |
|
|
"Content-Type":"application/json" |
|
|
} |
|
|
data = request.get_json() |
|
|
stream_flag = data.get('stream', True) |
|
|
|
|
|
def generate(): |
|
|
try: |
|
|
with requests.post(API_BASE_URL+"/chat/completions", headers=headers, json=data, stream=stream_flag) as response: |
|
|
response.raise_for_status() |
|
|
for chunk in response.iter_content(chunk_size=1024): |
|
|
yield chunk |
|
|
except requests.exceptions.RequestException as e: |
|
|
logging.error("Request to upstream API failed: %s", e) |
|
|
|
|
|
|
|
|
yield b'{"error": "Upstream API request failed"}' |
|
|
except Exception as e: |
|
|
logging.error("Unexpected error during streaming: %s", e) |
|
|
yield b'{"error": "Internal server error during streaming"}' |
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
if not stream_flag: |
|
|
|
|
|
response = requests.post(API_BASE_URL+"/chat/completions", headers=headers, json=data, stream=False) |
|
|
response.raise_for_status() |
|
|
return Response(response.content, |
|
|
status=response.status_code, |
|
|
content_type=response.headers.get('content-type')) |
|
|
else: |
|
|
|
|
|
|
|
|
|
|
|
initial_response = requests.post(API_BASE_URL+"/chat/completions", headers=headers, json=data, stream=True) |
|
|
initial_response.raise_for_status() |
|
|
|
|
|
return Response(generate_from_response(initial_response), |
|
|
status=initial_response.status_code, |
|
|
content_type=initial_response.headers.get('content-type')) |
|
|
|
|
|
except requests.exceptions.RequestException as e: |
|
|
logging.error("Initial upstream API request failed: %s", e) |
|
|
return jsonify({"success": False, "message": f"Upstream API request failed: {e}"}), 500 |
|
|
except Exception as e: |
|
|
logging.error("Error setting up chat completion: %s", e) |
|
|
return jsonify({"success": False, "message": str(e)}), 500 |
|
|
|
|
|
def generate_from_response(upstream_response): |
|
|
|
|
|
for chunk in upstream_response.iter_content(chunk_size=1024): |
|
|
yield chunk |
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
print("Starting Flask app...") |
|
|
|
|
|
app.run(host='0.0.0.0', port=7860, debug=True) |