tasks.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. from fastapi import APIRouter, Depends, HTTPException, Response, status, Request
  2. from pydantic import BaseModel
  3. from starlette.responses import FileResponse
  4. from typing import Optional
  5. import logging
  6. from open_webui.utils.task import (
  7. title_generation_template,
  8. query_generation_template,
  9. autocomplete_generation_template,
  10. tags_generation_template,
  11. emoji_generation_template,
  12. moa_response_generation_template,
  13. )
  14. from open_webui.utils.auth import get_admin_user, get_verified_user
  15. from open_webui.constants import TASKS
  16. from open_webui.config import (
  17. DEFAULT_QUERY_GENERATION_PROMPT_TEMPLATE,
  18. DEFAULT_AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE,
  19. )
  20. from open_webui.env import SRC_LOG_LEVELS
  21. log = logging.getLogger(__name__)
  22. log.setLevel(SRC_LOG_LEVELS["MODELS"])
  23. router = APIRouter()
  24. ##################################
  25. #
  26. # Task Endpoints
  27. #
  28. ##################################
  29. @router.get("/config")
  30. async def get_task_config(request: Request, user=Depends(get_verified_user)):
  31. return {
  32. "TASK_MODEL": request.app.state.config.TASK_MODEL,
  33. "TASK_MODEL_EXTERNAL": request.app.state.config.TASK_MODEL_EXTERNAL,
  34. "TITLE_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE,
  35. "ENABLE_AUTOCOMPLETE_GENERATION": request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION,
  36. "AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH": request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH,
  37. "TAGS_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE,
  38. "ENABLE_TAGS_GENERATION": request.app.state.config.ENABLE_TAGS_GENERATION,
  39. "ENABLE_SEARCH_QUERY_GENERATION": request.app.state.config.ENABLE_SEARCH_QUERY_GENERATION,
  40. "ENABLE_RETRIEVAL_QUERY_GENERATION": request.app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION,
  41. "QUERY_GENERATION_PROMPT_TEMPLATE": request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE,
  42. "TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE": request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
  43. }
  44. class TaskConfigForm(BaseModel):
  45. TASK_MODEL: Optional[str]
  46. TASK_MODEL_EXTERNAL: Optional[str]
  47. TITLE_GENERATION_PROMPT_TEMPLATE: str
  48. ENABLE_AUTOCOMPLETE_GENERATION: bool
  49. AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH: int
  50. TAGS_GENERATION_PROMPT_TEMPLATE: str
  51. ENABLE_TAGS_GENERATION: bool
  52. ENABLE_SEARCH_QUERY_GENERATION: bool
  53. ENABLE_RETRIEVAL_QUERY_GENERATION: bool
  54. QUERY_GENERATION_PROMPT_TEMPLATE: str
  55. TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE: str
  56. @router.post("/config/update")
  57. async def update_task_config(
  58. request: Request, form_data: TaskConfigForm, user=Depends(get_admin_user)
  59. ):
  60. request.app.state.config.TASK_MODEL = form_data.TASK_MODEL
  61. request.app.state.config.TASK_MODEL_EXTERNAL = form_data.TASK_MODEL_EXTERNAL
  62. request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE = (
  63. form_data.TITLE_GENERATION_PROMPT_TEMPLATE
  64. )
  65. request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION = (
  66. form_data.ENABLE_AUTOCOMPLETE_GENERATION
  67. )
  68. request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH = (
  69. form_data.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH
  70. )
  71. request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE = (
  72. form_data.TAGS_GENERATION_PROMPT_TEMPLATE
  73. )
  74. request.app.state.config.ENABLE_TAGS_GENERATION = form_data.ENABLE_TAGS_GENERATION
  75. request.app.state.config.ENABLE_SEARCH_QUERY_GENERATION = (
  76. form_data.ENABLE_SEARCH_QUERY_GENERATION
  77. )
  78. request.app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION = (
  79. form_data.ENABLE_RETRIEVAL_QUERY_GENERATION
  80. )
  81. request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE = (
  82. form_data.QUERY_GENERATION_PROMPT_TEMPLATE
  83. )
  84. request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = (
  85. form_data.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE
  86. )
  87. return {
  88. "TASK_MODEL": request.app.state.config.TASK_MODEL,
  89. "TASK_MODEL_EXTERNAL": request.app.state.config.TASK_MODEL_EXTERNAL,
  90. "TITLE_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE,
  91. "ENABLE_AUTOCOMPLETE_GENERATION": request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION,
  92. "AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH": request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH,
  93. "TAGS_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE,
  94. "ENABLE_TAGS_GENERATION": request.app.state.config.ENABLE_TAGS_GENERATION,
  95. "ENABLE_SEARCH_QUERY_GENERATION": request.app.state.config.ENABLE_SEARCH_QUERY_GENERATION,
  96. "ENABLE_RETRIEVAL_QUERY_GENERATION": request.app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION,
  97. "QUERY_GENERATION_PROMPT_TEMPLATE": request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE,
  98. "TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE": request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
  99. }
  100. @router.post("/title/completions")
  101. async def generate_title(
  102. request: Request, form_data: dict, user=Depends(get_verified_user)
  103. ):
  104. model_list = await get_all_models()
  105. models = {model["id"]: model for model in model_list}
  106. model_id = form_data["model"]
  107. if model_id not in models:
  108. raise HTTPException(
  109. status_code=status.HTTP_404_NOT_FOUND,
  110. detail="Model not found",
  111. )
  112. # Check if the user has a custom task model
  113. # If the user has a custom task model, use that model
  114. task_model_id = get_task_model_id(
  115. model_id,
  116. request.app.state.config.TASK_MODEL,
  117. request.app.state.config.TASK_MODEL_EXTERNAL,
  118. models,
  119. )
  120. log.debug(
  121. f"generating chat title using model {task_model_id} for user {user.email} "
  122. )
  123. if request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE != "":
  124. template = request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE
  125. else:
  126. template = """Create a concise, 3-5 word title with an emoji as a title for the chat history, in the given language. Suitable Emojis for the summary can be used to enhance understanding but avoid quotation marks or special formatting. RESPOND ONLY WITH THE TITLE TEXT.
  127. Examples of titles:
  128. 📉 Stock Market Trends
  129. 🍪 Perfect Chocolate Chip Recipe
  130. Evolution of Music Streaming
  131. Remote Work Productivity Tips
  132. Artificial Intelligence in Healthcare
  133. 🎮 Video Game Development Insights
  134. <chat_history>
  135. {{MESSAGES:END:2}}
  136. </chat_history>"""
  137. content = title_generation_template(
  138. template,
  139. form_data["messages"],
  140. {
  141. "name": user.name,
  142. "location": user.info.get("location") if user.info else None,
  143. },
  144. )
  145. payload = {
  146. "model": task_model_id,
  147. "messages": [{"role": "user", "content": content}],
  148. "stream": False,
  149. **(
  150. {"max_tokens": 50}
  151. if models[task_model_id]["owned_by"] == "ollama"
  152. else {
  153. "max_completion_tokens": 50,
  154. }
  155. ),
  156. "metadata": {
  157. "task": str(TASKS.TITLE_GENERATION),
  158. "task_body": form_data,
  159. "chat_id": form_data.get("chat_id", None),
  160. },
  161. }
  162. # Handle pipeline filters
  163. try:
  164. payload = filter_pipeline(payload, user, models)
  165. except Exception as e:
  166. if len(e.args) > 1:
  167. return JSONResponse(
  168. status_code=e.args[0],
  169. content={"detail": e.args[1]},
  170. )
  171. else:
  172. return JSONResponse(
  173. status_code=status.HTTP_400_BAD_REQUEST,
  174. content={"detail": str(e)},
  175. )
  176. if "chat_id" in payload:
  177. del payload["chat_id"]
  178. return await generate_chat_completions(form_data=payload, user=user)
  179. @router.post("/tags/completions")
  180. async def generate_chat_tags(
  181. request: Request, form_data: dict, user=Depends(get_verified_user)
  182. ):
  183. if not request.app.state.config.ENABLE_TAGS_GENERATION:
  184. return JSONResponse(
  185. status_code=status.HTTP_200_OK,
  186. content={"detail": "Tags generation is disabled"},
  187. )
  188. model_list = await get_all_models()
  189. models = {model["id"]: model for model in model_list}
  190. model_id = form_data["model"]
  191. if model_id not in models:
  192. raise HTTPException(
  193. status_code=status.HTTP_404_NOT_FOUND,
  194. detail="Model not found",
  195. )
  196. # Check if the user has a custom task model
  197. # If the user has a custom task model, use that model
  198. task_model_id = get_task_model_id(
  199. model_id,
  200. request.app.state.config.TASK_MODEL,
  201. request.app.state.config.TASK_MODEL_EXTERNAL,
  202. models,
  203. )
  204. log.debug(
  205. f"generating chat tags using model {task_model_id} for user {user.email} "
  206. )
  207. if request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE != "":
  208. template = request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE
  209. else:
  210. template = """### Task:
  211. Generate 1-3 broad tags categorizing the main themes of the chat history, along with 1-3 more specific subtopic tags.
  212. ### Guidelines:
  213. - Start with high-level domains (e.g. Science, Technology, Philosophy, Arts, Politics, Business, Health, Sports, Entertainment, Education)
  214. - Consider including relevant subfields/subdomains if they are strongly represented throughout the conversation
  215. - If content is too short (less than 3 messages) or too diverse, use only ["General"]
  216. - Use the chat's primary language; default to English if multilingual
  217. - Prioritize accuracy over specificity
  218. ### Output:
  219. JSON format: { "tags": ["tag1", "tag2", "tag3"] }
  220. ### Chat History:
  221. <chat_history>
  222. {{MESSAGES:END:6}}
  223. </chat_history>"""
  224. content = tags_generation_template(
  225. template, form_data["messages"], {"name": user.name}
  226. )
  227. payload = {
  228. "model": task_model_id,
  229. "messages": [{"role": "user", "content": content}],
  230. "stream": False,
  231. "metadata": {
  232. "task": str(TASKS.TAGS_GENERATION),
  233. "task_body": form_data,
  234. "chat_id": form_data.get("chat_id", None),
  235. },
  236. }
  237. # Handle pipeline filters
  238. try:
  239. payload = filter_pipeline(payload, user, models)
  240. except Exception as e:
  241. if len(e.args) > 1:
  242. return JSONResponse(
  243. status_code=e.args[0],
  244. content={"detail": e.args[1]},
  245. )
  246. else:
  247. return JSONResponse(
  248. status_code=status.HTTP_400_BAD_REQUEST,
  249. content={"detail": str(e)},
  250. )
  251. if "chat_id" in payload:
  252. del payload["chat_id"]
  253. return await generate_chat_completions(form_data=payload, user=user)
  254. @router.post("/queries/completions")
  255. async def generate_queries(
  256. request: Request, form_data: dict, user=Depends(get_verified_user)
  257. ):
  258. type = form_data.get("type")
  259. if type == "web_search":
  260. if not request.app.state.config.ENABLE_SEARCH_QUERY_GENERATION:
  261. raise HTTPException(
  262. status_code=status.HTTP_400_BAD_REQUEST,
  263. detail=f"Search query generation is disabled",
  264. )
  265. elif type == "retrieval":
  266. if not request.app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION:
  267. raise HTTPException(
  268. status_code=status.HTTP_400_BAD_REQUEST,
  269. detail=f"Query generation is disabled",
  270. )
  271. model_list = await get_all_models()
  272. models = {model["id"]: model for model in model_list}
  273. model_id = form_data["model"]
  274. if model_id not in models:
  275. raise HTTPException(
  276. status_code=status.HTTP_404_NOT_FOUND,
  277. detail="Model not found",
  278. )
  279. # Check if the user has a custom task model
  280. # If the user has a custom task model, use that model
  281. task_model_id = get_task_model_id(
  282. model_id,
  283. request.app.state.config.TASK_MODEL,
  284. request.app.state.config.TASK_MODEL_EXTERNAL,
  285. models,
  286. )
  287. log.debug(
  288. f"generating {type} queries using model {task_model_id} for user {user.email}"
  289. )
  290. if (request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE).strip() != "":
  291. template = request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE
  292. else:
  293. template = DEFAULT_QUERY_GENERATION_PROMPT_TEMPLATE
  294. content = query_generation_template(
  295. template, form_data["messages"], {"name": user.name}
  296. )
  297. payload = {
  298. "model": task_model_id,
  299. "messages": [{"role": "user", "content": content}],
  300. "stream": False,
  301. "metadata": {
  302. "task": str(TASKS.QUERY_GENERATION),
  303. "task_body": form_data,
  304. "chat_id": form_data.get("chat_id", None),
  305. },
  306. }
  307. # Handle pipeline filters
  308. try:
  309. payload = filter_pipeline(payload, user, models)
  310. except Exception as e:
  311. if len(e.args) > 1:
  312. return JSONResponse(
  313. status_code=e.args[0],
  314. content={"detail": e.args[1]},
  315. )
  316. else:
  317. return JSONResponse(
  318. status_code=status.HTTP_400_BAD_REQUEST,
  319. content={"detail": str(e)},
  320. )
  321. if "chat_id" in payload:
  322. del payload["chat_id"]
  323. return await generate_chat_completions(form_data=payload, user=user)
  324. @router.post("/auto/completions")
  325. async def generate_autocompletion(
  326. request: Request, form_data: dict, user=Depends(get_verified_user)
  327. ):
  328. if not request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION:
  329. raise HTTPException(
  330. status_code=status.HTTP_400_BAD_REQUEST,
  331. detail=f"Autocompletion generation is disabled",
  332. )
  333. type = form_data.get("type")
  334. prompt = form_data.get("prompt")
  335. messages = form_data.get("messages")
  336. if request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH > 0:
  337. if (
  338. len(prompt)
  339. > request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH
  340. ):
  341. raise HTTPException(
  342. status_code=status.HTTP_400_BAD_REQUEST,
  343. detail=f"Input prompt exceeds maximum length of {request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH}",
  344. )
  345. model_list = await get_all_models()
  346. models = {model["id"]: model for model in model_list}
  347. model_id = form_data["model"]
  348. if model_id not in models:
  349. raise HTTPException(
  350. status_code=status.HTTP_404_NOT_FOUND,
  351. detail="Model not found",
  352. )
  353. # Check if the user has a custom task model
  354. # If the user has a custom task model, use that model
  355. task_model_id = get_task_model_id(
  356. model_id,
  357. request.app.state.config.TASK_MODEL,
  358. request.app.state.config.TASK_MODEL_EXTERNAL,
  359. models,
  360. )
  361. log.debug(
  362. f"generating autocompletion using model {task_model_id} for user {user.email}"
  363. )
  364. if (request.app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE).strip() != "":
  365. template = request.app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE
  366. else:
  367. template = DEFAULT_AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE
  368. content = autocomplete_generation_template(
  369. template, prompt, messages, type, {"name": user.name}
  370. )
  371. payload = {
  372. "model": task_model_id,
  373. "messages": [{"role": "user", "content": content}],
  374. "stream": False,
  375. "metadata": {
  376. "task": str(TASKS.AUTOCOMPLETE_GENERATION),
  377. "task_body": form_data,
  378. "chat_id": form_data.get("chat_id", None),
  379. },
  380. }
  381. # Handle pipeline filters
  382. try:
  383. payload = filter_pipeline(payload, user, models)
  384. except Exception as e:
  385. if len(e.args) > 1:
  386. return JSONResponse(
  387. status_code=e.args[0],
  388. content={"detail": e.args[1]},
  389. )
  390. else:
  391. return JSONResponse(
  392. status_code=status.HTTP_400_BAD_REQUEST,
  393. content={"detail": str(e)},
  394. )
  395. if "chat_id" in payload:
  396. del payload["chat_id"]
  397. return await generate_chat_completions(form_data=payload, user=user)
  398. @router.post("/emoji/completions")
  399. async def generate_emoji(
  400. request: Request, form_data: dict, user=Depends(get_verified_user)
  401. ):
  402. model_list = await get_all_models()
  403. models = {model["id"]: model for model in model_list}
  404. model_id = form_data["model"]
  405. if model_id not in models:
  406. raise HTTPException(
  407. status_code=status.HTTP_404_NOT_FOUND,
  408. detail="Model not found",
  409. )
  410. # Check if the user has a custom task model
  411. # If the user has a custom task model, use that model
  412. task_model_id = get_task_model_id(
  413. model_id,
  414. request.app.state.config.TASK_MODEL,
  415. request.app.state.config.TASK_MODEL_EXTERNAL,
  416. models,
  417. )
  418. log.debug(f"generating emoji using model {task_model_id} for user {user.email} ")
  419. template = '''
  420. Your task is to reflect the speaker's likely facial expression through a fitting emoji. Interpret emotions from the message and reflect their facial expression using fitting, diverse emojis (e.g., 😊, 😢, 😡, 😱).
  421. Message: """{{prompt}}"""
  422. '''
  423. content = emoji_generation_template(
  424. template,
  425. form_data["prompt"],
  426. {
  427. "name": user.name,
  428. "location": user.info.get("location") if user.info else None,
  429. },
  430. )
  431. payload = {
  432. "model": task_model_id,
  433. "messages": [{"role": "user", "content": content}],
  434. "stream": False,
  435. **(
  436. {"max_tokens": 4}
  437. if models[task_model_id]["owned_by"] == "ollama"
  438. else {
  439. "max_completion_tokens": 4,
  440. }
  441. ),
  442. "chat_id": form_data.get("chat_id", None),
  443. "metadata": {"task": str(TASKS.EMOJI_GENERATION), "task_body": form_data},
  444. }
  445. # Handle pipeline filters
  446. try:
  447. payload = filter_pipeline(payload, user, models)
  448. except Exception as e:
  449. if len(e.args) > 1:
  450. return JSONResponse(
  451. status_code=e.args[0],
  452. content={"detail": e.args[1]},
  453. )
  454. else:
  455. return JSONResponse(
  456. status_code=status.HTTP_400_BAD_REQUEST,
  457. content={"detail": str(e)},
  458. )
  459. if "chat_id" in payload:
  460. del payload["chat_id"]
  461. return await generate_chat_completions(form_data=payload, user=user)
  462. @router.post("/moa/completions")
  463. async def generate_moa_response(
  464. request: Request, form_data: dict, user=Depends(get_verified_user)
  465. ):
  466. model_list = await get_all_models()
  467. models = {model["id"]: model for model in model_list}
  468. model_id = form_data["model"]
  469. if model_id not in models:
  470. raise HTTPException(
  471. status_code=status.HTTP_404_NOT_FOUND,
  472. detail="Model not found",
  473. )
  474. # Check if the user has a custom task model
  475. # If the user has a custom task model, use that model
  476. task_model_id = get_task_model_id(
  477. model_id,
  478. request.app.state.config.TASK_MODEL,
  479. request.app.state.config.TASK_MODEL_EXTERNAL,
  480. models,
  481. )
  482. log.debug(f"generating MOA model {task_model_id} for user {user.email} ")
  483. template = """You have been provided with a set of responses from various models to the latest user query: "{{prompt}}"
  484. Your task is to synthesize these responses into a single, high-quality response. It is crucial to critically evaluate the information provided in these responses, recognizing that some of it may be biased or incorrect. Your response should not simply replicate the given answers but should offer a refined, accurate, and comprehensive reply to the instruction. Ensure your response is well-structured, coherent, and adheres to the highest standards of accuracy and reliability.
  485. Responses from models: {{responses}}"""
  486. content = moa_response_generation_template(
  487. template,
  488. form_data["prompt"],
  489. form_data["responses"],
  490. )
  491. payload = {
  492. "model": task_model_id,
  493. "messages": [{"role": "user", "content": content}],
  494. "stream": form_data.get("stream", False),
  495. "chat_id": form_data.get("chat_id", None),
  496. "metadata": {
  497. "task": str(TASKS.MOA_RESPONSE_GENERATION),
  498. "task_body": form_data,
  499. },
  500. }
  501. try:
  502. payload = filter_pipeline(payload, user, models)
  503. except Exception as e:
  504. if len(e.args) > 1:
  505. return JSONResponse(
  506. status_code=e.args[0],
  507. content={"detail": e.args[1]},
  508. )
  509. else:
  510. return JSONResponse(
  511. status_code=status.HTTP_400_BAD_REQUEST,
  512. content={"detail": str(e)},
  513. )
  514. if "chat_id" in payload:
  515. del payload["chat_id"]
  516. return await generate_chat_completions(form_data=payload, user=user)