tasks.py 21 KB

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