"tests/test_models/test_detectors/test_voxelnet.py" did not exist on "db44cc50cb678dde52eab6307627c63623964465"
main.py 15.2 KB
Newer Older
1
from fastapi import FastAPI, Request, HTTPException, Depends
Timothy J. Baek's avatar
Timothy J. Baek committed
2
from fastapi.middleware.cors import CORSMiddleware
3
from fastapi.responses import StreamingResponse, FileResponse
Timothy J. Baek's avatar
Timothy J. Baek committed
4
5

import requests
Timothy J. Baek's avatar
Timothy J. Baek committed
6
7
import aiohttp
import asyncio
Timothy J. Baek's avatar
Timothy J. Baek committed
8
import json
9
import logging
Timothy J. Baek's avatar
Timothy J. Baek committed
10

Timothy J. Baek's avatar
Timothy J. Baek committed
11
from pydantic import BaseModel
12
from starlette.background import BackgroundTask
Timothy J. Baek's avatar
Timothy J. Baek committed
13

14
from apps.webui.models.models import Models
Timothy J. Baek's avatar
Timothy J. Baek committed
15
from constants import ERROR_MESSAGES
Timothy J. Baek's avatar
Timothy J. Baek committed
16
17
18
19
from utils.utils import (
    get_verified_user,
    get_admin_user,
)
20
from utils.misc import apply_model_params_to_body, apply_model_system_prompt_to_body
21

22
from config import (
23
    SRC_LOG_LEVELS,
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
24
    ENABLE_OPENAI_API,
25
    AIOHTTP_CLIENT_TIMEOUT,
26
27
28
    OPENAI_API_BASE_URLS,
    OPENAI_API_KEYS,
    CACHE_DIR,
Timothy J. Baek's avatar
Timothy J. Baek committed
29
    ENABLE_MODEL_FILTER,
30
    MODEL_FILTER_LIST,
31
    AppConfig,
32
)
33
from typing import List, Optional, Literal, overload
Timothy J. Baek's avatar
Timothy J. Baek committed
34

Timothy J. Baek's avatar
Timothy J. Baek committed
35
36
37

import hashlib
from pathlib import Path
Timothy J. Baek's avatar
Timothy J. Baek committed
38

39
40
41
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["OPENAI"])

Timothy J. Baek's avatar
Timothy J. Baek committed
42
43
44
45
46
47
48
49
50
app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Timothy J. Baek's avatar
Timothy J. Baek committed
51

52
53
app.state.config = AppConfig()

Timothy J. Baek's avatar
Timothy J. Baek committed
54
55
app.state.config.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER
app.state.config.MODEL_FILTER_LIST = MODEL_FILTER_LIST
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
56
57

app.state.config.ENABLE_OPENAI_API = ENABLE_OPENAI_API
58
59
app.state.config.OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS
app.state.config.OPENAI_API_KEYS = OPENAI_API_KEYS
Timothy J. Baek's avatar
Timothy J. Baek committed
60
61
62

app.state.MODELS = {}

Timothy J. Baek's avatar
Timothy J. Baek committed
63

Timothy J. Baek's avatar
Timothy J. Baek committed
64
65
66
67
@app.middleware("http")
async def check_url(request: Request, call_next):
    if len(app.state.MODELS) == 0:
        await get_all_models()
Timothy J. Baek's avatar
Timothy J. Baek committed
68

Timothy J. Baek's avatar
Timothy J. Baek committed
69
70
    response = await call_next(request)
    return response
Timothy J. Baek's avatar
Timothy J. Baek committed
71
72


Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
@app.get("/config")
async def get_config(user=Depends(get_admin_user)):
    return {"ENABLE_OPENAI_API": app.state.config.ENABLE_OPENAI_API}


class OpenAIConfigForm(BaseModel):
    enable_openai_api: Optional[bool] = None


@app.post("/config/update")
async def update_config(form_data: OpenAIConfigForm, user=Depends(get_admin_user)):
    app.state.config.ENABLE_OPENAI_API = form_data.enable_openai_api
    return {"ENABLE_OPENAI_API": app.state.config.ENABLE_OPENAI_API}


Timothy J. Baek's avatar
Timothy J. Baek committed
88
89
class UrlsUpdateForm(BaseModel):
    urls: List[str]
Timothy J. Baek's avatar
Timothy J. Baek committed
90
91


Timothy J. Baek's avatar
Timothy J. Baek committed
92
93
class KeysUpdateForm(BaseModel):
    keys: List[str]
Timothy J. Baek's avatar
Timothy J. Baek committed
94
95


Timothy J. Baek's avatar
Timothy J. Baek committed
96
97
@app.get("/urls")
async def get_openai_urls(user=Depends(get_admin_user)):
98
    return {"OPENAI_API_BASE_URLS": app.state.config.OPENAI_API_BASE_URLS}
99

Timothy J. Baek's avatar
Timothy J. Baek committed
100

Timothy J. Baek's avatar
Timothy J. Baek committed
101
102
@app.post("/urls/update")
async def update_openai_urls(form_data: UrlsUpdateForm, user=Depends(get_admin_user)):
103
    await get_all_models()
104
105
    app.state.config.OPENAI_API_BASE_URLS = form_data.urls
    return {"OPENAI_API_BASE_URLS": app.state.config.OPENAI_API_BASE_URLS}
Timothy J. Baek's avatar
Timothy J. Baek committed
106
107


Timothy J. Baek's avatar
Timothy J. Baek committed
108
109
@app.get("/keys")
async def get_openai_keys(user=Depends(get_admin_user)):
110
    return {"OPENAI_API_KEYS": app.state.config.OPENAI_API_KEYS}
Timothy J. Baek's avatar
Timothy J. Baek committed
111
112
113
114


@app.post("/keys/update")
async def update_openai_key(form_data: KeysUpdateForm, user=Depends(get_admin_user)):
115
116
    app.state.config.OPENAI_API_KEYS = form_data.keys
    return {"OPENAI_API_KEYS": app.state.config.OPENAI_API_KEYS}
Timothy J. Baek's avatar
Timothy J. Baek committed
117
118


Timothy J. Baek's avatar
Timothy J. Baek committed
119
@app.post("/audio/speech")
120
async def speech(request: Request, user=Depends(get_verified_user)):
Timothy J. Baek's avatar
Timothy J. Baek committed
121
122
    idx = None
    try:
123
        idx = app.state.config.OPENAI_API_BASE_URLS.index("https://api.openai.com/v1")
Timothy J. Baek's avatar
Timothy J. Baek committed
124
125
126
127
128
129
130
131
132
133
134
135
136
        body = await request.body()
        name = hashlib.sha256(body).hexdigest()

        SPEECH_CACHE_DIR = Path(CACHE_DIR).joinpath("./audio/speech/")
        SPEECH_CACHE_DIR.mkdir(parents=True, exist_ok=True)
        file_path = SPEECH_CACHE_DIR.joinpath(f"{name}.mp3")
        file_body_path = SPEECH_CACHE_DIR.joinpath(f"{name}.json")

        # Check if the file already exists in the cache
        if file_path.is_file():
            return FileResponse(file_path)

        headers = {}
137
        headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEYS[idx]}"
Timothy J. Baek's avatar
Timothy J. Baek committed
138
        headers["Content-Type"] = "application/json"
139
140
141
        if "openrouter.ai" in app.state.config.OPENAI_API_BASE_URLS[idx]:
            headers["HTTP-Referer"] = "https://openwebui.com/"
            headers["X-Title"] = "Open WebUI"
Timothy J. Baek's avatar
Timothy J. Baek committed
142
        r = None
Timothy J. Baek's avatar
Timothy J. Baek committed
143
144
        try:
            r = requests.post(
145
                url=f"{app.state.config.OPENAI_API_BASE_URLS[idx]}/audio/speech",
Timothy J. Baek's avatar
Timothy J. Baek committed
146
147
148
149
                data=body,
                headers=headers,
                stream=True,
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
150

Timothy J. Baek's avatar
Timothy J. Baek committed
151
            r.raise_for_status()
Timothy J. Baek's avatar
Timothy J. Baek committed
152

Timothy J. Baek's avatar
Timothy J. Baek committed
153
154
155
156
            # Save the streaming content to a file
            with open(file_path, "wb") as f:
                for chunk in r.iter_content(chunk_size=8192):
                    f.write(chunk)
Timothy J. Baek's avatar
Timothy J. Baek committed
157

Timothy J. Baek's avatar
Timothy J. Baek committed
158
159
            with open(file_body_path, "w") as f:
                json.dump(json.loads(body.decode("utf-8")), f)
Timothy J. Baek's avatar
Timothy J. Baek committed
160

Timothy J. Baek's avatar
Timothy J. Baek committed
161
162
            # Return the saved file
            return FileResponse(file_path)
Timothy J. Baek's avatar
Timothy J. Baek committed
163

Timothy J. Baek's avatar
Timothy J. Baek committed
164
        except Exception as e:
165
            log.exception(e)
Timothy J. Baek's avatar
Timothy J. Baek committed
166
167
168
169
170
171
            error_detail = "Open WebUI: Server Connection Error"
            if r is not None:
                try:
                    res = r.json()
                    if "error" in res:
                        error_detail = f"External: {res['error']}"
172
                except Exception:
Timothy J. Baek's avatar
Timothy J. Baek committed
173
174
                    error_detail = f"External: {e}"

Timothy J. Baek's avatar
Timothy J. Baek committed
175
176
177
            raise HTTPException(
                status_code=r.status_code if r else 500, detail=error_detail
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
178
179
180

    except ValueError:
        raise HTTPException(status_code=401, detail=ERROR_MESSAGES.OPENAI_NOT_FOUND)
Timothy J. Baek's avatar
Timothy J. Baek committed
181
182


Timothy J. Baek's avatar
Timothy J. Baek committed
183
async def fetch_url(url, key):
Timothy J. Baek's avatar
Timothy J. Baek committed
184
    timeout = aiohttp.ClientTimeout(total=5)
Timothy J. Baek's avatar
Timothy J. Baek committed
185
    try:
186
        headers = {"Authorization": f"Bearer {key}"}
187
        async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session:
188
189
            async with session.get(url, headers=headers) as response:
                return await response.json()
Timothy J. Baek's avatar
Timothy J. Baek committed
190
191
    except Exception as e:
        # Handle connection error here
192
        log.error(f"Connection error: {e}")
Timothy J. Baek's avatar
Timothy J. Baek committed
193
194
195
        return None


196
197
198
199
200
201
202
203
204
205
async def cleanup_response(
    response: Optional[aiohttp.ClientResponse],
    session: Optional[aiohttp.ClientSession],
):
    if response:
        response.close()
    if session:
        await session.close()


Timothy J. Baek's avatar
Timothy J. Baek committed
206
def merge_models_lists(model_lists):
207
    log.debug(f"merge_models_lists {model_lists}")
Timothy J. Baek's avatar
Timothy J. Baek committed
208
209
210
    merged_list = []

    for idx, models in enumerate(model_lists):
Timothy J. Baek's avatar
Timothy J. Baek committed
211
212
213
        if models is not None and "error" not in models:
            merged_list.extend(
                [
214
215
                    {
                        **model,
216
                        "name": model.get("name", model["id"]),
217
218
219
220
                        "owned_by": "openai",
                        "openai": model,
                        "urlIdx": idx,
                    }
Timothy J. Baek's avatar
Timothy J. Baek committed
221
                    for model in models
222
                    if "api.openai.com"
223
                    not in app.state.config.OPENAI_API_BASE_URLS[idx]
Timothy J. Baek's avatar
Timothy J. Baek committed
224
225
226
                    or "gpt" in model["id"]
                ]
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
227

Timothy J. Baek's avatar
Timothy J. Baek committed
228
    return merged_list
Timothy J. Baek's avatar
Timothy J. Baek committed
229
230


231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
def is_openai_api_disabled():
    api_keys = app.state.config.OPENAI_API_KEYS
    no_keys = len(api_keys) == 1 and api_keys[0] == ""
    return no_keys or not app.state.config.ENABLE_OPENAI_API


async def get_all_models_raw() -> list:
    if is_openai_api_disabled():
        return []

    # Check if API KEYS length is same than API URLS length
    num_urls = len(app.state.config.OPENAI_API_BASE_URLS)
    num_keys = len(app.state.config.OPENAI_API_KEYS)

    if num_keys != num_urls:
        # if there are more keys than urls, remove the extra keys
        if num_keys > num_urls:
            new_keys = app.state.config.OPENAI_API_KEYS[:num_urls]
            app.state.config.OPENAI_API_KEYS = new_keys
        # if there are more urls than keys, add empty keys
        else:
            app.state.config.OPENAI_API_KEYS += [""] * (num_urls - num_keys)

    tasks = [
        fetch_url(f"{url}/models", app.state.config.OPENAI_API_KEYS[idx])
        for idx, url in enumerate(app.state.config.OPENAI_API_BASE_URLS)
    ]

    responses = await asyncio.gather(*tasks)
    log.debug(f"get_all_models:responses() {responses}")

    return responses


265
266
267
268
269
270
271
272
273
@overload
async def get_all_models(raw: Literal[True]) -> list: ...


@overload
async def get_all_models(raw: Literal[False] = False) -> dict[str, list]: ...


async def get_all_models(raw=False) -> dict[str, list] | list:
274
    log.info("get_all_models()")
275
    if is_openai_api_disabled():
276
        return [] if raw else {"data": []}
277

278
    responses = await get_all_models_raw()
279
280
    if raw:
        return responses
281

282
283
284
285
286
287
    def extract_data(response):
        if response and "data" in response:
            return response["data"]
        if isinstance(response, list):
            return response
        return None
Timothy J. Baek's avatar
Timothy J. Baek committed
288

289
290
291
292
    models = {"data": merge_models_lists(map(extract_data, responses))}

    log.debug(f"models: {models}")
    app.state.MODELS = {model["id"]: model for model in models["data"]}
Timothy J. Baek's avatar
Timothy J. Baek committed
293

294
295
296
    return models


Timothy J. Baek's avatar
Timothy J. Baek committed
297
298
@app.get("/models")
@app.get("/models/{url_idx}")
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
299
async def get_models(url_idx: Optional[int] = None, user=Depends(get_verified_user)):
300
    if url_idx is None:
Timothy J. Baek's avatar
Timothy J. Baek committed
301
        models = await get_all_models()
Timothy J. Baek's avatar
Timothy J. Baek committed
302
        if app.state.config.ENABLE_MODEL_FILTER:
Timothy J. Baek's avatar
Timothy J. Baek committed
303
            if user.role == "user":
304
305
                models["data"] = list(
                    filter(
Timothy J. Baek's avatar
Timothy J. Baek committed
306
                        lambda model: model["id"] in app.state.config.MODEL_FILTER_LIST,
307
308
                        models["data"],
                    )
Timothy J. Baek's avatar
Timothy J. Baek committed
309
310
311
                )
                return models
        return models
Timothy J. Baek's avatar
Timothy J. Baek committed
312
    else:
313
        url = app.state.config.OPENAI_API_BASE_URLS[url_idx]
314
315
316
317
318
        key = app.state.config.OPENAI_API_KEYS[url_idx]

        headers = {}
        headers["Authorization"] = f"Bearer {key}"
        headers["Content-Type"] = "application/json"
Timothy J. Baek's avatar
Timothy J. Baek committed
319
320
321

        r = None

Timothy J. Baek's avatar
Timothy J. Baek committed
322
        try:
323
            r = requests.request(method="GET", url=f"{url}/models", headers=headers)
Timothy J. Baek's avatar
Timothy J. Baek committed
324
325
326
327
328
329
330
331
332
333
            r.raise_for_status()

            response_data = r.json()
            if "api.openai.com" in url:
                response_data["data"] = list(
                    filter(lambda model: "gpt" in model["id"], response_data["data"])
                )

            return response_data
        except Exception as e:
334
            log.exception(e)
Timothy J. Baek's avatar
Timothy J. Baek committed
335
336
337
338
339
340
            error_detail = "Open WebUI: Server Connection Error"
            if r is not None:
                try:
                    res = r.json()
                    if "error" in res:
                        error_detail = f"External: {res['error']}"
341
                except Exception:
Timothy J. Baek's avatar
Timothy J. Baek committed
342
343
344
345
346
347
                    error_detail = f"External: {e}"

            raise HTTPException(
                status_code=r.status_code if r else 500,
                detail=error_detail,
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
348
349


Timothy J. Baek's avatar
Timothy J. Baek committed
350
351
352
353
354
355
356
@app.post("/chat/completions")
@app.post("/chat/completions/{url_idx}")
async def generate_chat_completion(
    form_data: dict,
    url_idx: Optional[int] = None,
    user=Depends(get_verified_user),
):
Timothy J. Baek's avatar
Timothy J. Baek committed
357
    idx = 0
Timothy J. Baek's avatar
Timothy J. Baek committed
358
    payload = {**form_data}
Timothy J. Baek's avatar
Timothy J. Baek committed
359
360
361

    if "metadata" in payload:
        payload.pop("metadata")
Timothy J. Baek's avatar
Timothy J. Baek committed
362

Timothy J. Baek's avatar
Timothy J. Baek committed
363
364
    model_id = form_data.get("model")
    model_info = Models.get_model_by_id(model_id)
Timothy J. Baek's avatar
Timothy J. Baek committed
365

Timothy J. Baek's avatar
Timothy J. Baek committed
366
367
368
    if model_info:
        if model_info.base_model_id:
            payload["model"] = model_info.base_model_id
Timothy J. Baek's avatar
Timothy J. Baek committed
369

370
371
372
        params = model_info.params.model_dump()
        payload = apply_model_params_to_body(params, payload)
        payload = apply_model_system_prompt_to_body(params, payload, user)
Timothy J. Baek's avatar
Timothy J. Baek committed
373

Timothy J. Baek's avatar
Timothy J. Baek committed
374
375
    model = app.state.MODELS[payload.get("model")]
    idx = model["urlIdx"]
Timothy J. Baek's avatar
Timothy J. Baek committed
376

Timothy J. Baek's avatar
Timothy J. Baek committed
377
    if "pipeline" in model and model.get("pipeline"):
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
378
379
380
381
382
383
        payload["user"] = {
            "name": user.name,
            "id": user.id,
            "email": user.email,
            "role": user.role,
        }
Timothy J. Baek's avatar
Timothy J. Baek committed
384

Timothy J. Baek's avatar
Timothy J. Baek committed
385
386
    # Convert the modified body back to JSON
    payload = json.dumps(payload)
Timothy J. Baek's avatar
Timothy J. Baek committed
387

388
    log.debug(payload)
Timothy J. Baek's avatar
Timothy J. Baek committed
389

Timothy J. Baek's avatar
Timothy J. Baek committed
390
391
    url = app.state.config.OPENAI_API_BASE_URLS[idx]
    key = app.state.config.OPENAI_API_KEYS[idx]
Timothy J. Baek's avatar
Timothy J. Baek committed
392

Timothy J. Baek's avatar
Timothy J. Baek committed
393
394
395
    headers = {}
    headers["Authorization"] = f"Bearer {key}"
    headers["Content-Type"] = "application/json"
396
397
398
    if "openrouter.ai" in app.state.config.OPENAI_API_BASE_URLS[idx]:
        headers["HTTP-Referer"] = "https://openwebui.com/"
        headers["X-Title"] = "Open WebUI"
Timothy J. Baek's avatar
Timothy J. Baek committed
399

Timothy J. Baek's avatar
Timothy J. Baek committed
400
401
402
403
404
    r = None
    session = None
    streaming = False

    try:
405
406
407
        session = aiohttp.ClientSession(
            trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT)
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
408
409
410
411
412
413
        r = await session.request(
            method="POST",
            url=f"{url}/chat/completions",
            data=payload,
            headers=headers,
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
414

Timothy J. Baek's avatar
Timothy J. Baek committed
415
        r.raise_for_status()
Timothy J. Baek's avatar
Timothy J. Baek committed
416

Timothy J. Baek's avatar
Timothy J. Baek committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
        # Check if response is SSE
        if "text/event-stream" in r.headers.get("Content-Type", ""):
            streaming = True
            return StreamingResponse(
                r.content,
                status_code=r.status,
                headers=dict(r.headers),
                background=BackgroundTask(
                    cleanup_response, response=r, session=session
                ),
            )
        else:
            response_data = await r.json()
            return response_data
    except Exception as e:
        log.exception(e)
        error_detail = "Open WebUI: Server Connection Error"
        if r is not None:
            try:
                res = await r.json()
                print(res)
                if "error" in res:
                    error_detail = f"External: {res['error']['message'] if 'message' in res['error'] else res['error']}"
440
            except Exception:
Timothy J. Baek's avatar
Timothy J. Baek committed
441
442
443
444
445
446
447
448
449
450
451
452
453
454
                error_detail = f"External: {e}"
        raise HTTPException(status_code=r.status if r else 500, detail=error_detail)
    finally:
        if not streaming and session:
            if r:
                r.close()
            await session.close()


@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
    idx = 0

    body = await request.body()
Timothy J. Baek's avatar
Timothy J. Baek committed
455

456
457
    url = app.state.config.OPENAI_API_BASE_URLS[idx]
    key = app.state.config.OPENAI_API_KEYS[idx]
Timothy J. Baek's avatar
Timothy J. Baek committed
458
459
460

    target_url = f"{url}/{path}"

461
    headers = {}
Timothy J. Baek's avatar
Timothy J. Baek committed
462
    headers["Authorization"] = f"Bearer {key}"
Timothy J. Baek's avatar
Timothy J. Baek committed
463
    headers["Content-Type"] = "application/json"
Timothy J. Baek's avatar
Timothy J. Baek committed
464

Timothy J. Baek's avatar
Timothy J. Baek committed
465
    r = None
466
467
    session = None
    streaming = False
Timothy J. Baek's avatar
Timothy J. Baek committed
468

Timothy J. Baek's avatar
Timothy J. Baek committed
469
    try:
470
        session = aiohttp.ClientSession(trust_env=True)
471
        r = await session.request(
Jun Siang Cheah's avatar
Jun Siang Cheah committed
472
473
            method=request.method,
            url=target_url,
Timothy J. Baek's avatar
Timothy J. Baek committed
474
            data=body,
Jun Siang Cheah's avatar
Jun Siang Cheah committed
475
            headers=headers,
Timothy J. Baek's avatar
Timothy J. Baek committed
476
477
478
479
        )

        r.raise_for_status()

480
481
        # Check if response is SSE
        if "text/event-stream" in r.headers.get("Content-Type", ""):
482
            streaming = True
483
            return StreamingResponse(
484
485
                r.content,
                status_code=r.status,
486
                headers=dict(r.headers),
487
488
489
                background=BackgroundTask(
                    cleanup_response, response=r, session=session
                ),
490
491
            )
        else:
492
            response_data = await r.json()
493
            return response_data
Timothy J. Baek's avatar
Timothy J. Baek committed
494
    except Exception as e:
495
        log.exception(e)
Timothy J. Baek's avatar
Timothy J. Baek committed
496
        error_detail = "Open WebUI: Server Connection Error"
Timothy J. Baek's avatar
Timothy J. Baek committed
497
498
        if r is not None:
            try:
499
                res = await r.json()
Timothy J. Baek's avatar
Timothy J. Baek committed
500
                print(res)
Timothy J. Baek's avatar
Timothy J. Baek committed
501
                if "error" in res:
Timothy J. Baek's avatar
Timothy J. Baek committed
502
                    error_detail = f"External: {res['error']['message'] if 'message' in res['error'] else res['error']}"
503
            except Exception:
Timothy J. Baek's avatar
Timothy J. Baek committed
504
                error_detail = f"External: {e}"
505
506
507
508
509
510
        raise HTTPException(status_code=r.status if r else 500, detail=error_detail)
    finally:
        if not streaming and session:
            if r:
                r.close()
            await session.close()