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.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.routers.pipelines import process_pipeline_inlet_filter
  17. from open_webui.utils.task import get_task_model_id
  18. from open_webui.config import (
  19. DEFAULT_QUERY_GENERATION_PROMPT_TEMPLATE,
  20. DEFAULT_AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE,
  21. )
  22. from open_webui.env import SRC_LOG_LEVELS
  23. log = logging.getLogger(__name__)
  24. log.setLevel(SRC_LOG_LEVELS["MODELS"])
  25. router = APIRouter()
  26. ##################################
  27. #
  28. # Task Endpoints
  29. #
  30. ##################################
  31. @router.get("/config")
  32. async def get_task_config(request: Request, user=Depends(get_verified_user)):
  33. return {
  34. "TASK_MODEL": request.app.state.config.TASK_MODEL,
  35. "TASK_MODEL_EXTERNAL": request.app.state.config.TASK_MODEL_EXTERNAL,
  36. "TITLE_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE,
  37. "ENABLE_AUTOCOMPLETE_GENERATION": request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION,
  38. "AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH": request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH,
  39. "TAGS_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE,
  40. "ENABLE_TAGS_GENERATION": request.app.state.config.ENABLE_TAGS_GENERATION,
  41. "ENABLE_SEARCH_QUERY_GENERATION": request.app.state.config.ENABLE_SEARCH_QUERY_GENERATION,
  42. "ENABLE_RETRIEVAL_QUERY_GENERATION": request.app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION,
  43. "QUERY_GENERATION_PROMPT_TEMPLATE": request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE,
  44. "TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE": request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
  45. }
  46. class TaskConfigForm(BaseModel):
  47. TASK_MODEL: Optional[str]
  48. TASK_MODEL_EXTERNAL: Optional[str]
  49. TITLE_GENERATION_PROMPT_TEMPLATE: str
  50. ENABLE_AUTOCOMPLETE_GENERATION: bool
  51. AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH: int
  52. TAGS_GENERATION_PROMPT_TEMPLATE: str
  53. ENABLE_TAGS_GENERATION: bool
  54. ENABLE_SEARCH_QUERY_GENERATION: bool
  55. ENABLE_RETRIEVAL_QUERY_GENERATION: bool
  56. QUERY_GENERATION_PROMPT_TEMPLATE: str
  57. TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE: str
  58. @router.post("/config/update")
  59. async def update_task_config(
  60. request: Request, form_data: TaskConfigForm, user=Depends(get_admin_user)
  61. ):
  62. request.app.state.config.TASK_MODEL = form_data.TASK_MODEL
  63. request.app.state.config.TASK_MODEL_EXTERNAL = form_data.TASK_MODEL_EXTERNAL
  64. request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE = (
  65. form_data.TITLE_GENERATION_PROMPT_TEMPLATE
  66. )
  67. request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION = (
  68. form_data.ENABLE_AUTOCOMPLETE_GENERATION
  69. )
  70. request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH = (
  71. form_data.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH
  72. )
  73. request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE = (
  74. form_data.TAGS_GENERATION_PROMPT_TEMPLATE
  75. )
  76. request.app.state.config.ENABLE_TAGS_GENERATION = form_data.ENABLE_TAGS_GENERATION
  77. request.app.state.config.ENABLE_SEARCH_QUERY_GENERATION = (
  78. form_data.ENABLE_SEARCH_QUERY_GENERATION
  79. )
  80. request.app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION = (
  81. form_data.ENABLE_RETRIEVAL_QUERY_GENERATION
  82. )
  83. request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE = (
  84. form_data.QUERY_GENERATION_PROMPT_TEMPLATE
  85. )
  86. request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = (
  87. form_data.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE
  88. )
  89. return {
  90. "TASK_MODEL": request.app.state.config.TASK_MODEL,
  91. "TASK_MODEL_EXTERNAL": request.app.state.config.TASK_MODEL_EXTERNAL,
  92. "TITLE_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE,
  93. "ENABLE_AUTOCOMPLETE_GENERATION": request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION,
  94. "AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH": request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH,
  95. "TAGS_GENERATION_PROMPT_TEMPLATE": request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE,
  96. "ENABLE_TAGS_GENERATION": request.app.state.config.ENABLE_TAGS_GENERATION,
  97. "ENABLE_SEARCH_QUERY_GENERATION": request.app.state.config.ENABLE_SEARCH_QUERY_GENERATION,
  98. "ENABLE_RETRIEVAL_QUERY_GENERATION": request.app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION,
  99. "QUERY_GENERATION_PROMPT_TEMPLATE": request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE,
  100. "TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE": request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
  101. }
  102. @router.post("/title/completions")
  103. async def generate_title(
  104. request: Request, form_data: dict, user=Depends(get_verified_user)
  105. ):
  106. models = request.app.state.MODELS
  107. model_id = form_data["model"]
  108. if model_id not in models:
  109. raise HTTPException(
  110. status_code=status.HTTP_404_NOT_FOUND,
  111. detail="Model not found",
  112. )
  113. # Check if the user has a custom task model
  114. # If the user has a custom task model, use that model
  115. task_model_id = get_task_model_id(
  116. model_id,
  117. request.app.state.config.TASK_MODEL,
  118. request.app.state.config.TASK_MODEL_EXTERNAL,
  119. models,
  120. )
  121. log.debug(
  122. f"generating chat title using model {task_model_id} for user {user.email} "
  123. )
  124. if request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE != "":
  125. template = request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE
  126. else:
  127. 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.
  128. Examples of titles:
  129. 📉 Stock Market Trends
  130. 🍪 Perfect Chocolate Chip Recipe
  131. Evolution of Music Streaming
  132. Remote Work Productivity Tips
  133. Artificial Intelligence in Healthcare
  134. 🎮 Video Game Development Insights
  135. <chat_history>
  136. {{MESSAGES:END:2}}
  137. </chat_history>"""
  138. content = title_generation_template(
  139. template,
  140. form_data["messages"],
  141. {
  142. "name": user.name,
  143. "location": user.info.get("location") if user.info else None,
  144. },
  145. )
  146. payload = {
  147. "model": task_model_id,
  148. "messages": [{"role": "user", "content": content}],
  149. "stream": False,
  150. **(
  151. {"max_tokens": 50}
  152. if models[task_model_id]["owned_by"] == "ollama"
  153. else {
  154. "max_completion_tokens": 50,
  155. }
  156. ),
  157. "metadata": {
  158. "task": str(TASKS.TITLE_GENERATION),
  159. "task_body": form_data,
  160. "chat_id": form_data.get("chat_id", None),
  161. },
  162. }
  163. # Handle pipeline filters
  164. try:
  165. payload = process_pipeline_inlet_filter(payload, user, models)
  166. except Exception as e:
  167. if len(e.args) > 1:
  168. return JSONResponse(
  169. status_code=e.args[0],
  170. content={"detail": e.args[1]},
  171. )
  172. else:
  173. return JSONResponse(
  174. status_code=status.HTTP_400_BAD_REQUEST,
  175. content={"detail": str(e)},
  176. )
  177. if "chat_id" in payload:
  178. del payload["chat_id"]
  179. return await generate_chat_completions(form_data=payload, user=user)
  180. @router.post("/tags/completions")
  181. async def generate_chat_tags(
  182. request: Request, form_data: dict, user=Depends(get_verified_user)
  183. ):
  184. if not request.app.state.config.ENABLE_TAGS_GENERATION:
  185. return JSONResponse(
  186. status_code=status.HTTP_200_OK,
  187. content={"detail": "Tags generation is disabled"},
  188. )
  189. models = request.app.state.MODELS
  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 = process_pipeline_inlet_filter(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. models = request.app.state.MODELS
  272. model_id = form_data["model"]
  273. if model_id not in models:
  274. raise HTTPException(
  275. status_code=status.HTTP_404_NOT_FOUND,
  276. detail="Model not found",
  277. )
  278. # Check if the user has a custom task model
  279. # If the user has a custom task model, use that model
  280. task_model_id = get_task_model_id(
  281. model_id,
  282. request.app.state.config.TASK_MODEL,
  283. request.app.state.config.TASK_MODEL_EXTERNAL,
  284. models,
  285. )
  286. log.debug(
  287. f"generating {type} queries using model {task_model_id} for user {user.email}"
  288. )
  289. if (request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE).strip() != "":
  290. template = request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE
  291. else:
  292. template = DEFAULT_QUERY_GENERATION_PROMPT_TEMPLATE
  293. content = query_generation_template(
  294. template, form_data["messages"], {"name": user.name}
  295. )
  296. payload = {
  297. "model": task_model_id,
  298. "messages": [{"role": "user", "content": content}],
  299. "stream": False,
  300. "metadata": {
  301. "task": str(TASKS.QUERY_GENERATION),
  302. "task_body": form_data,
  303. "chat_id": form_data.get("chat_id", None),
  304. },
  305. }
  306. # Handle pipeline filters
  307. try:
  308. payload = process_pipeline_inlet_filter(payload, user, models)
  309. except Exception as e:
  310. if len(e.args) > 1:
  311. return JSONResponse(
  312. status_code=e.args[0],
  313. content={"detail": e.args[1]},
  314. )
  315. else:
  316. return JSONResponse(
  317. status_code=status.HTTP_400_BAD_REQUEST,
  318. content={"detail": str(e)},
  319. )
  320. if "chat_id" in payload:
  321. del payload["chat_id"]
  322. return await generate_chat_completions(form_data=payload, user=user)
  323. @router.post("/auto/completions")
  324. async def generate_autocompletion(
  325. request: Request, form_data: dict, user=Depends(get_verified_user)
  326. ):
  327. if not request.app.state.config.ENABLE_AUTOCOMPLETE_GENERATION:
  328. raise HTTPException(
  329. status_code=status.HTTP_400_BAD_REQUEST,
  330. detail=f"Autocompletion generation is disabled",
  331. )
  332. type = form_data.get("type")
  333. prompt = form_data.get("prompt")
  334. messages = form_data.get("messages")
  335. if request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH > 0:
  336. if (
  337. len(prompt)
  338. > request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH
  339. ):
  340. raise HTTPException(
  341. status_code=status.HTTP_400_BAD_REQUEST,
  342. detail=f"Input prompt exceeds maximum length of {request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH}",
  343. )
  344. models = request.app.state.MODELS
  345. model_id = form_data["model"]
  346. if model_id not in models:
  347. raise HTTPException(
  348. status_code=status.HTTP_404_NOT_FOUND,
  349. detail="Model not found",
  350. )
  351. # Check if the user has a custom task model
  352. # If the user has a custom task model, use that model
  353. task_model_id = get_task_model_id(
  354. model_id,
  355. request.app.state.config.TASK_MODEL,
  356. request.app.state.config.TASK_MODEL_EXTERNAL,
  357. models,
  358. )
  359. log.debug(
  360. f"generating autocompletion using model {task_model_id} for user {user.email}"
  361. )
  362. if (request.app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE).strip() != "":
  363. template = request.app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE
  364. else:
  365. template = DEFAULT_AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE
  366. content = autocomplete_generation_template(
  367. template, prompt, messages, type, {"name": user.name}
  368. )
  369. payload = {
  370. "model": task_model_id,
  371. "messages": [{"role": "user", "content": content}],
  372. "stream": False,
  373. "metadata": {
  374. "task": str(TASKS.AUTOCOMPLETE_GENERATION),
  375. "task_body": form_data,
  376. "chat_id": form_data.get("chat_id", None),
  377. },
  378. }
  379. # Handle pipeline filters
  380. try:
  381. payload = process_pipeline_inlet_filter(payload, user, models)
  382. except Exception as e:
  383. if len(e.args) > 1:
  384. return JSONResponse(
  385. status_code=e.args[0],
  386. content={"detail": e.args[1]},
  387. )
  388. else:
  389. return JSONResponse(
  390. status_code=status.HTTP_400_BAD_REQUEST,
  391. content={"detail": str(e)},
  392. )
  393. if "chat_id" in payload:
  394. del payload["chat_id"]
  395. return await generate_chat_completions(form_data=payload, user=user)
  396. @router.post("/emoji/completions")
  397. async def generate_emoji(
  398. request: Request, form_data: dict, user=Depends(get_verified_user)
  399. ):
  400. models = request.app.state.MODELS
  401. model_id = form_data["model"]
  402. if model_id not in models:
  403. raise HTTPException(
  404. status_code=status.HTTP_404_NOT_FOUND,
  405. detail="Model not found",
  406. )
  407. # Check if the user has a custom task model
  408. # If the user has a custom task model, use that model
  409. task_model_id = get_task_model_id(
  410. model_id,
  411. request.app.state.config.TASK_MODEL,
  412. request.app.state.config.TASK_MODEL_EXTERNAL,
  413. models,
  414. )
  415. log.debug(f"generating emoji using model {task_model_id} for user {user.email} ")
  416. template = '''
  417. 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., 😊, 😢, 😡, 😱).
  418. Message: """{{prompt}}"""
  419. '''
  420. content = emoji_generation_template(
  421. template,
  422. form_data["prompt"],
  423. {
  424. "name": user.name,
  425. "location": user.info.get("location") if user.info else None,
  426. },
  427. )
  428. payload = {
  429. "model": task_model_id,
  430. "messages": [{"role": "user", "content": content}],
  431. "stream": False,
  432. **(
  433. {"max_tokens": 4}
  434. if models[task_model_id]["owned_by"] == "ollama"
  435. else {
  436. "max_completion_tokens": 4,
  437. }
  438. ),
  439. "chat_id": form_data.get("chat_id", None),
  440. "metadata": {"task": str(TASKS.EMOJI_GENERATION), "task_body": form_data},
  441. }
  442. # Handle pipeline filters
  443. try:
  444. payload = process_pipeline_inlet_filter(payload, user, models)
  445. except Exception as e:
  446. if len(e.args) > 1:
  447. return JSONResponse(
  448. status_code=e.args[0],
  449. content={"detail": e.args[1]},
  450. )
  451. else:
  452. return JSONResponse(
  453. status_code=status.HTTP_400_BAD_REQUEST,
  454. content={"detail": str(e)},
  455. )
  456. if "chat_id" in payload:
  457. del payload["chat_id"]
  458. return await generate_chat_completions(form_data=payload, user=user)
  459. @router.post("/moa/completions")
  460. async def generate_moa_response(
  461. request: Request, form_data: dict, user=Depends(get_verified_user)
  462. ):
  463. models = request.app.state.MODELS
  464. model_id = form_data["model"]
  465. if model_id not in models:
  466. raise HTTPException(
  467. status_code=status.HTTP_404_NOT_FOUND,
  468. detail="Model not found",
  469. )
  470. # Check if the user has a custom task model
  471. # If the user has a custom task model, use that model
  472. task_model_id = get_task_model_id(
  473. model_id,
  474. request.app.state.config.TASK_MODEL,
  475. request.app.state.config.TASK_MODEL_EXTERNAL,
  476. models,
  477. )
  478. log.debug(f"generating MOA model {task_model_id} for user {user.email} ")
  479. template = """You have been provided with a set of responses from various models to the latest user query: "{{prompt}}"
  480. 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.
  481. Responses from models: {{responses}}"""
  482. content = moa_response_generation_template(
  483. template,
  484. form_data["prompt"],
  485. form_data["responses"],
  486. )
  487. payload = {
  488. "model": task_model_id,
  489. "messages": [{"role": "user", "content": content}],
  490. "stream": form_data.get("stream", False),
  491. "chat_id": form_data.get("chat_id", None),
  492. "metadata": {
  493. "task": str(TASKS.MOA_RESPONSE_GENERATION),
  494. "task_body": form_data,
  495. },
  496. }
  497. try:
  498. payload = process_pipeline_inlet_filter(payload, user, models)
  499. except Exception as e:
  500. if len(e.args) > 1:
  501. return JSONResponse(
  502. status_code=e.args[0],
  503. content={"detail": e.args[1]},
  504. )
  505. else:
  506. return JSONResponse(
  507. status_code=status.HTTP_400_BAD_REQUEST,
  508. content={"detail": str(e)},
  509. )
  510. if "chat_id" in payload:
  511. del payload["chat_id"]
  512. return await generate_chat_completions(form_data=payload, user=user)