API / server.py
Severian's picture
Update server.py
40a4a3c verified
import os
import json
import requests
import logging
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import parse_qs, urlparse
from typing import Dict, Any, Tuple
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Constants
ANTHROPIC_API_URL = os.getenv(
'ANTHROPIC_API_URL',
'https://relay.stagwellmarketingcloud.io/anthropic/v1/messages'
)
API_KEY = os.getenv('ANTHROPIC_API_KEY')
def transform_to_anthropic_request(request_data: Dict[str, Any]) -> Dict[str, Any]:
"""Transform OpenAI-style request to Anthropic format."""
if 'messages' in request_data:
return {
"model": request_data.get('model', 'claude-3-5-sonnet-20240620'),
"max_tokens": request_data.get('max_tokens', 1024),
"messages": request_data['messages']
}
else:
return {
"model": request_data.get('model', 'claude-3-5-sonnet-20240620'),
"max_tokens": request_data.get('max_tokens', 1024),
"messages": [{
"role": "user",
"content": request_data.get('prompt', '')
}]
}
def make_anthropic_request(
request_data: Dict[str, Any]
) -> Tuple[Dict[str, Any], int]:
"""Make request to Anthropic API with proper error handling."""
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json',
}
try:
anthropic_request = transform_to_anthropic_request(request_data)
logger.info(
f"Sending request to Anthropic API: {json.dumps(anthropic_request)}"
)
response = requests.post(
ANTHROPIC_API_URL,
headers=headers,
json=anthropic_request,
timeout=30
)
response.raise_for_status()
return response.json(), 200
except requests.RequestException as e:
error_msg = f"Error communicating with Anthropic API: {str(e)}"
if hasattr(e, 'response') and e.response is not None:
error_msg += f"\nResponse: {e.response.text}"
logger.error(error_msg)
return {"error": error_msg}, e.response.status_code if e.response else 500
except Exception as e:
error_msg = f"Unexpected error: {str(e)}"
logger.error(error_msg)
return {"error": error_msg}, 500
class AnthropicProxyHandler(SimpleHTTPRequestHandler):
def send_json_response(self, data: Dict[str, Any], status: int = 200):
"""Helper method to send JSON responses."""
self.send_response(status)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps(data).encode('utf-8'))
def do_GET(self):
"""Handle GET requests."""
if self.path == "/v1":
self.send_json_response({"status": True})
elif self.path == "/v1/models":
self.send_json_response({
"data": [{
"id": "claude-3-5-sonnet-20240620",
"object": "model",
"created": 1706745202,
"owned_by": "anthropic"
}]
})
else:
super().do_GET()
def do_POST(self):
"""Handle POST requests."""
content_length = int(self.headers.get('Content-Length', 0))
request_body = self.rfile.read(content_length)
request_data = json.loads(request_body)
if self.path == "/v1/completions":
logger.info(f"Received completion request: {json.dumps(request_data)}")
response, status_code = make_anthropic_request(request_data)
if status_code != 200:
self.send_json_response(response, status_code)
return
completion_response = {
"id": "cmpl-" + response.get('id', 'default'),
"object": "text_completion",
"created": response.get('created', 0),
"choices": [{
"text": response['content'][0]['text'],
"index": 0,
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": -1,
"completion_tokens": -1,
"total_tokens": -1
}
}
self.send_json_response(completion_response)
elif self.path == "/v1/chat/completions":
logger.info(
f"Received chat completion request: {json.dumps(request_data)}"
)
response, status_code = make_anthropic_request(request_data)
if status_code != 200:
self.send_json_response(response, status_code)
return
chat_response = {
"id": "chatcmpl-" + response.get('id', 'default'),
"object": "chat.completion",
"created": response.get('created', 0),
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": response['content'][0]['text']
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": -1,
"completion_tokens": -1,
"total_tokens": -1
}
}
self.send_json_response(chat_response)
else:
self.send_json_response(
{"error": "Invalid endpoint"},
status=404
)
def run_server(port: int = 7860):
"""Start the server on the specified port."""
server = ThreadingHTTPServer(("", port), AnthropicProxyHandler)
logger.info(f"Starting server on port {port}")
server.serve_forever()
if __name__ == "__main__":
run_server()