main.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. import asyncio
  2. import base64
  3. import json
  4. import logging
  5. import mimetypes
  6. import re
  7. import uuid
  8. from pathlib import Path
  9. from typing import Optional
  10. import requests
  11. from open_webui.apps.images.utils.comfyui import (
  12. ComfyUIGenerateImageForm,
  13. ComfyUIWorkflow,
  14. comfyui_generate_image,
  15. )
  16. from open_webui.config import (
  17. AUTOMATIC1111_API_AUTH,
  18. AUTOMATIC1111_BASE_URL,
  19. AUTOMATIC1111_CFG_SCALE,
  20. AUTOMATIC1111_SAMPLER,
  21. AUTOMATIC1111_SCHEDULER,
  22. CACHE_DIR,
  23. COMFYUI_BASE_URL,
  24. COMFYUI_WORKFLOW,
  25. COMFYUI_WORKFLOW_NODES,
  26. CORS_ALLOW_ORIGIN,
  27. ENABLE_IMAGE_GENERATION,
  28. IMAGE_GENERATION_ENGINE,
  29. IMAGE_GENERATION_MODEL,
  30. IMAGE_SIZE,
  31. IMAGE_STEPS,
  32. IMAGES_OPENAI_API_BASE_URL,
  33. IMAGES_OPENAI_API_KEY,
  34. AppConfig,
  35. )
  36. from open_webui.constants import ERROR_MESSAGES
  37. from open_webui.env import SRC_LOG_LEVELS
  38. from fastapi import Depends, FastAPI, HTTPException, Request
  39. from fastapi.middleware.cors import CORSMiddleware
  40. from pydantic import BaseModel
  41. from open_webui.utils.utils import get_admin_user, get_verified_user
  42. log = logging.getLogger(__name__)
  43. log.setLevel(SRC_LOG_LEVELS["IMAGES"])
  44. IMAGE_CACHE_DIR = Path(CACHE_DIR).joinpath("./image/generations/")
  45. IMAGE_CACHE_DIR.mkdir(parents=True, exist_ok=True)
  46. app = FastAPI()
  47. app.add_middleware(
  48. CORSMiddleware,
  49. allow_origins=CORS_ALLOW_ORIGIN,
  50. allow_credentials=True,
  51. allow_methods=["*"],
  52. allow_headers=["*"],
  53. )
  54. app.state.config = AppConfig()
  55. app.state.config.ENGINE = IMAGE_GENERATION_ENGINE
  56. app.state.config.ENABLED = ENABLE_IMAGE_GENERATION
  57. app.state.config.OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL
  58. app.state.config.OPENAI_API_KEY = IMAGES_OPENAI_API_KEY
  59. app.state.config.MODEL = IMAGE_GENERATION_MODEL
  60. app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL
  61. app.state.config.AUTOMATIC1111_API_AUTH = AUTOMATIC1111_API_AUTH
  62. app.state.config.AUTOMATIC1111_CFG_SCALE = AUTOMATIC1111_CFG_SCALE
  63. app.state.config.AUTOMATIC1111_SAMPLER = AUTOMATIC1111_SAMPLER
  64. app.state.config.AUTOMATIC1111_SCHEDULER = AUTOMATIC1111_SCHEDULER
  65. app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL
  66. app.state.config.COMFYUI_WORKFLOW = COMFYUI_WORKFLOW
  67. app.state.config.COMFYUI_WORKFLOW_NODES = COMFYUI_WORKFLOW_NODES
  68. app.state.config.IMAGE_SIZE = IMAGE_SIZE
  69. app.state.config.IMAGE_STEPS = IMAGE_STEPS
  70. @app.get("/config")
  71. async def get_config(request: Request, user=Depends(get_admin_user)):
  72. return {
  73. "enabled": app.state.config.ENABLED,
  74. "engine": app.state.config.ENGINE,
  75. "openai": {
  76. "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL,
  77. "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY,
  78. },
  79. "automatic1111": {
  80. "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL,
  81. "AUTOMATIC1111_API_AUTH": app.state.config.AUTOMATIC1111_API_AUTH,
  82. "AUTOMATIC1111_CFG_SCALE": app.state.config.AUTOMATIC1111_CFG_SCALE,
  83. "AUTOMATIC1111_SAMPLER": app.state.config.AUTOMATIC1111_SAMPLER,
  84. "AUTOMATIC1111_SCHEDULER": app.state.config.AUTOMATIC1111_SCHEDULER,
  85. },
  86. "comfyui": {
  87. "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL,
  88. "COMFYUI_WORKFLOW": app.state.config.COMFYUI_WORKFLOW,
  89. "COMFYUI_WORKFLOW_NODES": app.state.config.COMFYUI_WORKFLOW_NODES,
  90. },
  91. }
  92. class OpenAIConfigForm(BaseModel):
  93. OPENAI_API_BASE_URL: str
  94. OPENAI_API_KEY: str
  95. class Automatic1111ConfigForm(BaseModel):
  96. AUTOMATIC1111_BASE_URL: str
  97. AUTOMATIC1111_API_AUTH: str
  98. AUTOMATIC1111_CFG_SCALE: Optional[str]
  99. AUTOMATIC1111_SAMPLER: Optional[str]
  100. AUTOMATIC1111_SCHEDULER: Optional[str]
  101. class ComfyUIConfigForm(BaseModel):
  102. COMFYUI_BASE_URL: str
  103. COMFYUI_WORKFLOW: str
  104. COMFYUI_WORKFLOW_NODES: list[dict]
  105. class ConfigForm(BaseModel):
  106. enabled: bool
  107. engine: str
  108. openai: OpenAIConfigForm
  109. automatic1111: Automatic1111ConfigForm
  110. comfyui: ComfyUIConfigForm
  111. @app.post("/config/update")
  112. async def update_config(form_data: ConfigForm, user=Depends(get_admin_user)):
  113. app.state.config.ENGINE = form_data.engine
  114. app.state.config.ENABLED = form_data.enabled
  115. app.state.config.OPENAI_API_BASE_URL = form_data.openai.OPENAI_API_BASE_URL
  116. app.state.config.OPENAI_API_KEY = form_data.openai.OPENAI_API_KEY
  117. app.state.config.AUTOMATIC1111_BASE_URL = (
  118. form_data.automatic1111.AUTOMATIC1111_BASE_URL
  119. )
  120. app.state.config.AUTOMATIC1111_API_AUTH = (
  121. form_data.automatic1111.AUTOMATIC1111_API_AUTH
  122. )
  123. app.state.config.AUTOMATIC1111_CFG_SCALE = (
  124. float(form_data.automatic1111.AUTOMATIC1111_CFG_SCALE)
  125. if form_data.automatic1111.AUTOMATIC1111_CFG_SCALE != ""
  126. else None
  127. )
  128. app.state.config.AUTOMATIC1111_SAMPLER = (
  129. form_data.automatic1111.AUTOMATIC1111_SAMPLER
  130. if form_data.automatic1111.AUTOMATIC1111_SAMPLER != ""
  131. else None
  132. )
  133. app.state.config.AUTOMATIC1111_SCHEDULER = (
  134. form_data.automatic1111.AUTOMATIC1111_SCHEDULER
  135. if form_data.automatic1111.AUTOMATIC1111_SCHEDULER != ""
  136. else None
  137. )
  138. app.state.config.COMFYUI_BASE_URL = form_data.comfyui.COMFYUI_BASE_URL.strip("/")
  139. app.state.config.COMFYUI_WORKFLOW = form_data.comfyui.COMFYUI_WORKFLOW
  140. app.state.config.COMFYUI_WORKFLOW_NODES = form_data.comfyui.COMFYUI_WORKFLOW_NODES
  141. return {
  142. "enabled": app.state.config.ENABLED,
  143. "engine": app.state.config.ENGINE,
  144. "openai": {
  145. "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL,
  146. "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY,
  147. },
  148. "automatic1111": {
  149. "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL,
  150. "AUTOMATIC1111_API_AUTH": app.state.config.AUTOMATIC1111_API_AUTH,
  151. "AUTOMATIC1111_CFG_SCALE": app.state.config.AUTOMATIC1111_CFG_SCALE,
  152. "AUTOMATIC1111_SAMPLER": app.state.config.AUTOMATIC1111_SAMPLER,
  153. "AUTOMATIC1111_SCHEDULER": app.state.config.AUTOMATIC1111_SCHEDULER,
  154. },
  155. "comfyui": {
  156. "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL,
  157. "COMFYUI_WORKFLOW": app.state.config.COMFYUI_WORKFLOW,
  158. "COMFYUI_WORKFLOW_NODES": app.state.config.COMFYUI_WORKFLOW_NODES,
  159. },
  160. }
  161. def get_automatic1111_api_auth():
  162. if app.state.config.AUTOMATIC1111_API_AUTH is None:
  163. return ""
  164. else:
  165. auth1111_byte_string = app.state.config.AUTOMATIC1111_API_AUTH.encode("utf-8")
  166. auth1111_base64_encoded_bytes = base64.b64encode(auth1111_byte_string)
  167. auth1111_base64_encoded_string = auth1111_base64_encoded_bytes.decode("utf-8")
  168. return f"Basic {auth1111_base64_encoded_string}"
  169. @app.get("/config/url/verify")
  170. async def verify_url(user=Depends(get_admin_user)):
  171. if app.state.config.ENGINE == "automatic1111":
  172. try:
  173. r = requests.get(
  174. url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
  175. headers={"authorization": get_automatic1111_api_auth()},
  176. )
  177. r.raise_for_status()
  178. return True
  179. except Exception:
  180. app.state.config.ENABLED = False
  181. raise HTTPException(status_code=400, detail=ERROR_MESSAGES.INVALID_URL)
  182. elif app.state.config.ENGINE == "comfyui":
  183. try:
  184. r = requests.get(url=f"{app.state.config.COMFYUI_BASE_URL}/object_info")
  185. r.raise_for_status()
  186. return True
  187. except Exception:
  188. app.state.config.ENABLED = False
  189. raise HTTPException(status_code=400, detail=ERROR_MESSAGES.INVALID_URL)
  190. else:
  191. return True
  192. def set_image_model(model: str):
  193. log.info(f"Setting image model to {model}")
  194. app.state.config.MODEL = model
  195. if app.state.config.ENGINE in ["", "automatic1111"]:
  196. api_auth = get_automatic1111_api_auth()
  197. r = requests.get(
  198. url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
  199. headers={"authorization": api_auth},
  200. )
  201. options = r.json()
  202. if model != options["sd_model_checkpoint"]:
  203. options["sd_model_checkpoint"] = model
  204. r = requests.post(
  205. url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
  206. json=options,
  207. headers={"authorization": api_auth},
  208. )
  209. return app.state.config.MODEL
  210. def get_image_model():
  211. if app.state.config.ENGINE == "openai":
  212. return app.state.config.MODEL if app.state.config.MODEL else "dall-e-2"
  213. elif app.state.config.ENGINE == "comfyui":
  214. return app.state.config.MODEL if app.state.config.MODEL else ""
  215. elif app.state.config.ENGINE == "automatic1111" or app.state.config.ENGINE == "":
  216. try:
  217. r = requests.get(
  218. url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
  219. headers={"authorization": get_automatic1111_api_auth()},
  220. )
  221. options = r.json()
  222. return options["sd_model_checkpoint"]
  223. except Exception as e:
  224. app.state.config.ENABLED = False
  225. raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
  226. class ImageConfigForm(BaseModel):
  227. MODEL: str
  228. IMAGE_SIZE: str
  229. IMAGE_STEPS: int
  230. @app.get("/image/config")
  231. async def get_image_config(user=Depends(get_admin_user)):
  232. return {
  233. "MODEL": app.state.config.MODEL,
  234. "IMAGE_SIZE": app.state.config.IMAGE_SIZE,
  235. "IMAGE_STEPS": app.state.config.IMAGE_STEPS,
  236. }
  237. @app.post("/image/config/update")
  238. async def update_image_config(form_data: ImageConfigForm, user=Depends(get_admin_user)):
  239. set_image_model(form_data.MODEL)
  240. pattern = r"^\d+x\d+$"
  241. if re.match(pattern, form_data.IMAGE_SIZE):
  242. app.state.config.IMAGE_SIZE = form_data.IMAGE_SIZE
  243. else:
  244. raise HTTPException(
  245. status_code=400,
  246. detail=ERROR_MESSAGES.INCORRECT_FORMAT(" (e.g., 512x512)."),
  247. )
  248. if form_data.IMAGE_STEPS >= 0:
  249. app.state.config.IMAGE_STEPS = form_data.IMAGE_STEPS
  250. else:
  251. raise HTTPException(
  252. status_code=400,
  253. detail=ERROR_MESSAGES.INCORRECT_FORMAT(" (e.g., 50)."),
  254. )
  255. return {
  256. "MODEL": app.state.config.MODEL,
  257. "IMAGE_SIZE": app.state.config.IMAGE_SIZE,
  258. "IMAGE_STEPS": app.state.config.IMAGE_STEPS,
  259. }
  260. @app.get("/models")
  261. def get_models(user=Depends(get_verified_user)):
  262. try:
  263. if app.state.config.ENGINE == "openai":
  264. return [
  265. {"id": "dall-e-2", "name": "DALL·E 2"},
  266. {"id": "dall-e-3", "name": "DALL·E 3"},
  267. ]
  268. elif app.state.config.ENGINE == "comfyui":
  269. # TODO - get models from comfyui
  270. r = requests.get(url=f"{app.state.config.COMFYUI_BASE_URL}/object_info")
  271. info = r.json()
  272. workflow = json.loads(app.state.config.COMFYUI_WORKFLOW)
  273. model_node_id = None
  274. for node in app.state.config.COMFYUI_WORKFLOW_NODES:
  275. if node["type"] == "model":
  276. if node["node_ids"]:
  277. model_node_id = node["node_ids"][0]
  278. break
  279. if model_node_id:
  280. model_list_key = None
  281. print(workflow[model_node_id]["class_type"])
  282. for key in info[workflow[model_node_id]["class_type"]]["input"][
  283. "required"
  284. ]:
  285. if "_name" in key:
  286. model_list_key = key
  287. break
  288. if model_list_key:
  289. return list(
  290. map(
  291. lambda model: {"id": model, "name": model},
  292. info[workflow[model_node_id]["class_type"]]["input"][
  293. "required"
  294. ][model_list_key][0],
  295. )
  296. )
  297. else:
  298. return list(
  299. map(
  300. lambda model: {"id": model, "name": model},
  301. info["CheckpointLoaderSimple"]["input"]["required"][
  302. "ckpt_name"
  303. ][0],
  304. )
  305. )
  306. elif (
  307. app.state.config.ENGINE == "automatic1111" or app.state.config.ENGINE == ""
  308. ):
  309. r = requests.get(
  310. url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/sd-models",
  311. headers={"authorization": get_automatic1111_api_auth()},
  312. )
  313. models = r.json()
  314. return list(
  315. map(
  316. lambda model: {"id": model["title"], "name": model["model_name"]},
  317. models,
  318. )
  319. )
  320. except Exception as e:
  321. app.state.config.ENABLED = False
  322. raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
  323. class GenerateImageForm(BaseModel):
  324. model: Optional[str] = None
  325. prompt: str
  326. size: Optional[str] = None
  327. n: int = 1
  328. negative_prompt: Optional[str] = None
  329. def save_b64_image(b64_str):
  330. try:
  331. image_id = str(uuid.uuid4())
  332. if "," in b64_str:
  333. header, encoded = b64_str.split(",", 1)
  334. mime_type = header.split(";")[0]
  335. img_data = base64.b64decode(encoded)
  336. image_format = mimetypes.guess_extension(mime_type)
  337. image_filename = f"{image_id}{image_format}"
  338. file_path = IMAGE_CACHE_DIR / f"{image_filename}"
  339. with open(file_path, "wb") as f:
  340. f.write(img_data)
  341. return image_filename
  342. else:
  343. image_filename = f"{image_id}.png"
  344. file_path = IMAGE_CACHE_DIR.joinpath(image_filename)
  345. img_data = base64.b64decode(b64_str)
  346. # Write the image data to a file
  347. with open(file_path, "wb") as f:
  348. f.write(img_data)
  349. return image_filename
  350. except Exception as e:
  351. log.exception(f"Error saving image: {e}")
  352. return None
  353. def save_url_image(url):
  354. image_id = str(uuid.uuid4())
  355. try:
  356. r = requests.get(url)
  357. r.raise_for_status()
  358. if r.headers["content-type"].split("/")[0] == "image":
  359. mime_type = r.headers["content-type"]
  360. image_format = mimetypes.guess_extension(mime_type)
  361. if not image_format:
  362. raise ValueError("Could not determine image type from MIME type")
  363. image_filename = f"{image_id}{image_format}"
  364. file_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}")
  365. with open(file_path, "wb") as image_file:
  366. for chunk in r.iter_content(chunk_size=8192):
  367. image_file.write(chunk)
  368. return image_filename
  369. else:
  370. log.error("Url does not point to an image.")
  371. return None
  372. except Exception as e:
  373. log.exception(f"Error saving image: {e}")
  374. return None
  375. @app.post("/generations")
  376. async def image_generations(
  377. form_data: GenerateImageForm,
  378. user=Depends(get_verified_user),
  379. ):
  380. width, height = tuple(map(int, app.state.config.IMAGE_SIZE.split("x")))
  381. r = None
  382. try:
  383. if app.state.config.ENGINE == "openai":
  384. headers = {}
  385. headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEY}"
  386. headers["Content-Type"] = "application/json"
  387. data = {
  388. "model": (
  389. app.state.config.MODEL
  390. if app.state.config.MODEL != ""
  391. else "dall-e-2"
  392. ),
  393. "prompt": form_data.prompt,
  394. "n": form_data.n,
  395. "size": (
  396. form_data.size if form_data.size else app.state.config.IMAGE_SIZE
  397. ),
  398. "response_format": "b64_json",
  399. }
  400. # Use asyncio.to_thread for the requests.post call
  401. r = await asyncio.to_thread(
  402. requests.post,
  403. url=f"{app.state.config.OPENAI_API_BASE_URL}/images/generations",
  404. json=data,
  405. headers=headers,
  406. )
  407. r.raise_for_status()
  408. res = r.json()
  409. images = []
  410. for image in res["data"]:
  411. image_filename = save_b64_image(image["b64_json"])
  412. images.append({"url": f"/cache/image/generations/{image_filename}"})
  413. file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
  414. with open(file_body_path, "w") as f:
  415. json.dump(data, f)
  416. return images
  417. elif app.state.config.ENGINE == "comfyui":
  418. data = {
  419. "prompt": form_data.prompt,
  420. "width": width,
  421. "height": height,
  422. "n": form_data.n,
  423. }
  424. if app.state.config.IMAGE_STEPS is not None:
  425. data["steps"] = app.state.config.IMAGE_STEPS
  426. if form_data.negative_prompt is not None:
  427. data["negative_prompt"] = form_data.negative_prompt
  428. form_data = ComfyUIGenerateImageForm(
  429. **{
  430. "workflow": ComfyUIWorkflow(
  431. **{
  432. "workflow": app.state.config.COMFYUI_WORKFLOW,
  433. "nodes": app.state.config.COMFYUI_WORKFLOW_NODES,
  434. }
  435. ),
  436. **data,
  437. }
  438. )
  439. res = await comfyui_generate_image(
  440. app.state.config.MODEL,
  441. form_data,
  442. user.id,
  443. app.state.config.COMFYUI_BASE_URL,
  444. )
  445. log.debug(f"res: {res}")
  446. images = []
  447. for image in res["data"]:
  448. image_filename = save_url_image(image["url"])
  449. images.append({"url": f"/cache/image/generations/{image_filename}"})
  450. file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
  451. with open(file_body_path, "w") as f:
  452. json.dump(form_data.model_dump(exclude_none=True), f)
  453. log.debug(f"images: {images}")
  454. return images
  455. elif (
  456. app.state.config.ENGINE == "automatic1111" or app.state.config.ENGINE == ""
  457. ):
  458. if form_data.model:
  459. set_image_model(form_data.model)
  460. data = {
  461. "prompt": form_data.prompt,
  462. "batch_size": form_data.n,
  463. "width": width,
  464. "height": height,
  465. }
  466. if app.state.config.IMAGE_STEPS is not None:
  467. data["steps"] = app.state.config.IMAGE_STEPS
  468. if form_data.negative_prompt is not None:
  469. data["negative_prompt"] = form_data.negative_prompt
  470. if app.state.config.AUTOMATIC1111_CFG_SCALE:
  471. data["cfg_scale"] = app.state.config.AUTOMATIC1111_CFG_SCALE
  472. if app.state.config.AUTOMATIC1111_SAMPLER:
  473. data["sampler_name"] = app.state.config.AUTOMATIC1111_SAMPLER
  474. if app.state.config.AUTOMATIC1111_SCHEDULER:
  475. data["scheduler"] = app.state.config.AUTOMATIC1111_SCHEDULER
  476. # Use asyncio.to_thread for the requests.post call
  477. r = await asyncio.to_thread(
  478. requests.post,
  479. url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/txt2img",
  480. json=data,
  481. headers={"authorization": get_automatic1111_api_auth()},
  482. )
  483. res = r.json()
  484. log.debug(f"res: {res}")
  485. images = []
  486. for image in res["images"]:
  487. image_filename = save_b64_image(image)
  488. images.append({"url": f"/cache/image/generations/{image_filename}"})
  489. file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
  490. with open(file_body_path, "w") as f:
  491. json.dump({**data, "info": res["info"]}, f)
  492. return images
  493. except Exception as e:
  494. error = e
  495. if r != None:
  496. data = r.json()
  497. if "error" in data:
  498. error = data["error"]["message"]
  499. raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(error))