-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
192 lines (147 loc) · 7.02 KB
/
app.py
File metadata and controls
192 lines (147 loc) · 7.02 KB
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
from typing import Dict, Optional
import requests
from fastapi import FastAPI, Request, HTTPException, UploadFile, File, Form
from fastapi.responses import StreamingResponse, JSONResponse
from auth import can_request
from models import get_model_data
app = FastAPI()
async def handle_request(request: Request, api_path: str):
token = request.headers.get('Authorization').split("Bearer ")[1] if 'Authorization' in request.headers else None
body = await request.json()
model = body.get('model')
stream = body.get('stream', False)
stream_options = body.get('stream_options', {})
# Retrieve model data including the target model name
model_data = get_model_data(model, api_path)
if not model_data:
raise HTTPException(status_code=404, detail="Model not supported for this API")
if not can_request(model, token):
raise HTTPException(status_code=403, detail="Unauthorized")
# Replace the model name in the request body with the target model name
body['model'] = model_data['target_model_name']
target_url = model_data['target_base_url'] + '/' + api_path
# Forward the request to the target URL
response = requests.post(target_url, json=body, headers={"Authorization": f"Bearer {token}"},
stream=stream)
return response, stream, stream_options
async def handle_file_upload(request: Request, api_path: str, file: UploadFile, data: Dict[str, Optional[str]]):
token = request.headers.get('Authorization').split("Bearer ")[1] if 'Authorization' in request.headers else None
model = data['model']
if not can_request(model, token):
raise HTTPException(status_code=403, detail="Unauthorized")
model_data = get_model_data(model, api_path)
if not model_data:
raise HTTPException(status_code=404, detail="Model not supported for this API")
# Update model name to target model name for backend compatibility
data['model'] = model_data['target_model_name']
# Read file contents
file_content = await file.read()
# Prepare the form data to be sent, converting all non-file data to strings
form_data = {key: (None, str(value)) for key, value in data.items() if value is not None}
form_data['file'] = (file.filename, file_content, file.content_type)
target_url = model_data['target_base_url'] + '/' + api_path
response = requests.post(target_url, files=form_data, headers={"Authorization": f"Bearer {token}"})
return response
def process_response(response, response_format):
if response.status_code == 200:
if response_format == 'json':
return response.json()
else:
return StreamingResponse(response.iter_content(), media_type=response.headers.get('Content-Type'))
else:
return JSONResponse(status_code=response.status_code, content={"message": "Failed to process request"})
# Define endpoints using the helper function for all required APIs
@app.post("/v1/chat/completions")
async def chat_completions(request: Request):
response, stream, stream_options = await handle_request(request, "v1/chat/completions")
if stream:
return StreamingResponse(response.iter_content(**stream_options))
else:
return response.json()
@app.post("/v1/completions")
async def completions(request: Request):
response, stream, stream_options = await handle_request(request, "v1/completions")
return response.json()
@app.post("/v1/embeddings")
async def embeddings(request: Request):
response, stream, _ = await handle_request(request, "v1/embeddings")
return response.json()
# Additional endpoints for audio, images, models, and moderation will follow the same pattern
# Define additional routes for audio services
@app.post("/v1/audio/speech")
async def audio_speech(request: Request):
# Using the helper function to handle request forwarding and response handling
response, stream, stream_options = await handle_request(request, "v1/audio/speech")
# Check response status and content type before parsing
if response.status_code == 200:
# As it's an audio file content, it will likely not be JSON but a binary stream
content_type = response.headers.get('Content-Type', '')
# Streaming the audio content directly if it's a binary type (assuming mp3 or similar)
if 'audio/' in content_type:
return StreamingResponse(response.iter_content(**stream_options), media_type=content_type)
else:
return JSONResponse(status_code=415, content={"message": "Unsupported Media Type"})
else:
# Log error or return a JSON message in case of failure
return JSONResponse(status_code=response.status_code, content={"message": "Failed to generate audio"})
@app.post("/v1/audio/transcriptions")
async def audio_transcription(
request: Request,
file: UploadFile = File(...),
model: str = Form(...),
language: Optional[str] = Form(None),
prompt: Optional[str] = Form(None),
response_format: Optional[str] = Form('json'),
temperature: Optional[float] = Form(0),
timestamp_granularities: Optional[list] = Form(None)
):
data = {
'model': model,
'language': language,
'prompt': prompt,
'response_format': response_format,
'temperature': temperature,
'timestamp_granularities': ','.join(timestamp_granularities) if timestamp_granularities else None
}
response = await handle_file_upload(request, "v1/audio/transcriptions", file, data)
return process_response(response, response_format)
@app.post("/v1/audio/translations")
async def audio_translation(
request: Request,
file: UploadFile = File(...),
model: str = Form(...),
prompt: Optional[str] = Form(None),
response_format: Optional[str] = Form('json'),
temperature: Optional[float] = Form(0)
):
data = {
'model': model,
'prompt': prompt,
'response_format': response_format,
'temperature': temperature
}
response = await handle_file_upload(request, "v1/audio/translations", file, data)
return process_response(response, response_format)
# Define routes for image services
@app.post("/v1/images/generations")
async def images_generations(request: Request):
response, stream, _ = await handle_request(request, "v1/images/generations")
return response.json()
@app.post("/v1/images/edits")
async def images_edits(request: Request):
response, stream, _ = await handle_request(request, "v1/images/edits")
return response.json()
@app.post("/v1/images/variations")
async def images_variations(request: Request):
response, stream, _ = await handle_request(request, "v1/images/variations")
return response.json()
# Route for model details
@app.get("/v1/models")
async def models_details(request: Request):
response, stream, _ = await handle_request(request, "v1/models")
return response.json()
# Route for content moderation
@app.post("/v1/moderations")
async def moderations(request: Request):
response, stream, _ = await handle_request(request, "v1/moderations")
return response.json()