index.ts 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  1. import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
  2. import { convertOpenApiToToolPayload } from '$lib/utils';
  3. import { getOpenAIModelsDirect } from './openai';
  4. export const getModels = async (
  5. token: string = '',
  6. connections: object | null = null,
  7. base: boolean = false
  8. ) => {
  9. let error = null;
  10. const res = await fetch(`${WEBUI_BASE_URL}/api/models${base ? '/base' : ''}`, {
  11. method: 'GET',
  12. headers: {
  13. Accept: 'application/json',
  14. 'Content-Type': 'application/json',
  15. ...(token && { authorization: `Bearer ${token}` })
  16. }
  17. })
  18. .then(async (res) => {
  19. if (!res.ok) throw await res.json();
  20. return res.json();
  21. })
  22. .catch((err) => {
  23. error = err;
  24. console.log(err);
  25. return null;
  26. });
  27. if (error) {
  28. throw error;
  29. }
  30. let models = res?.data ?? [];
  31. if (connections && !base) {
  32. let localModels = [];
  33. if (connections) {
  34. const OPENAI_API_BASE_URLS = connections.OPENAI_API_BASE_URLS;
  35. const OPENAI_API_KEYS = connections.OPENAI_API_KEYS;
  36. const OPENAI_API_CONFIGS = connections.OPENAI_API_CONFIGS;
  37. const requests = [];
  38. for (const idx in OPENAI_API_BASE_URLS) {
  39. const url = OPENAI_API_BASE_URLS[idx];
  40. if (idx.toString() in OPENAI_API_CONFIGS) {
  41. const apiConfig = OPENAI_API_CONFIGS[idx.toString()] ?? {};
  42. const enable = apiConfig?.enable ?? true;
  43. const modelIds = apiConfig?.model_ids ?? [];
  44. if (enable) {
  45. if (modelIds.length > 0) {
  46. const modelList = {
  47. object: 'list',
  48. data: modelIds.map((modelId) => ({
  49. id: modelId,
  50. name: modelId,
  51. owned_by: 'openai',
  52. openai: { id: modelId },
  53. urlIdx: idx
  54. }))
  55. };
  56. requests.push(
  57. (async () => {
  58. return modelList;
  59. })()
  60. );
  61. } else {
  62. requests.push(
  63. (async () => {
  64. return await getOpenAIModelsDirect(url, OPENAI_API_KEYS[idx])
  65. .then((res) => {
  66. return res;
  67. })
  68. .catch((err) => {
  69. return {
  70. object: 'list',
  71. data: [],
  72. urlIdx: idx
  73. };
  74. });
  75. })()
  76. );
  77. }
  78. } else {
  79. requests.push(
  80. (async () => {
  81. return {
  82. object: 'list',
  83. data: [],
  84. urlIdx: idx
  85. };
  86. })()
  87. );
  88. }
  89. }
  90. }
  91. const responses = await Promise.all(requests);
  92. for (const idx in responses) {
  93. const response = responses[idx];
  94. const apiConfig = OPENAI_API_CONFIGS[idx.toString()] ?? {};
  95. let models = Array.isArray(response) ? response : (response?.data ?? []);
  96. models = models.map((model) => ({ ...model, openai: { id: model.id }, urlIdx: idx }));
  97. const prefixId = apiConfig.prefix_id;
  98. if (prefixId) {
  99. for (const model of models) {
  100. model.id = `${prefixId}.${model.id}`;
  101. }
  102. }
  103. const tags = apiConfig.tags;
  104. if (tags) {
  105. for (const model of models) {
  106. model.tags = tags;
  107. }
  108. }
  109. localModels = localModels.concat(models);
  110. }
  111. }
  112. models = models.concat(
  113. localModels.map((model) => ({
  114. ...model,
  115. name: model?.name ?? model?.id,
  116. direct: true
  117. }))
  118. );
  119. // Remove duplicates
  120. const modelsMap = {};
  121. for (const model of models) {
  122. modelsMap[model.id] = model;
  123. }
  124. models = Object.values(modelsMap);
  125. }
  126. return models;
  127. };
  128. type ChatCompletedForm = {
  129. model: string;
  130. messages: string[];
  131. chat_id: string;
  132. session_id: string;
  133. };
  134. export const chatCompleted = async (token: string, body: ChatCompletedForm) => {
  135. let error = null;
  136. const res = await fetch(`${WEBUI_BASE_URL}/api/chat/completed`, {
  137. method: 'POST',
  138. headers: {
  139. Accept: 'application/json',
  140. 'Content-Type': 'application/json',
  141. ...(token && { authorization: `Bearer ${token}` })
  142. },
  143. body: JSON.stringify(body)
  144. })
  145. .then(async (res) => {
  146. if (!res.ok) throw await res.json();
  147. return res.json();
  148. })
  149. .catch((err) => {
  150. console.log(err);
  151. if ('detail' in err) {
  152. error = err.detail;
  153. } else {
  154. error = err;
  155. }
  156. return null;
  157. });
  158. if (error) {
  159. throw error;
  160. }
  161. return res;
  162. };
  163. type ChatActionForm = {
  164. model: string;
  165. messages: string[];
  166. chat_id: string;
  167. };
  168. export const chatAction = async (token: string, action_id: string, body: ChatActionForm) => {
  169. let error = null;
  170. const res = await fetch(`${WEBUI_BASE_URL}/api/chat/actions/${action_id}`, {
  171. method: 'POST',
  172. headers: {
  173. Accept: 'application/json',
  174. 'Content-Type': 'application/json',
  175. ...(token && { authorization: `Bearer ${token}` })
  176. },
  177. body: JSON.stringify(body)
  178. })
  179. .then(async (res) => {
  180. if (!res.ok) throw await res.json();
  181. return res.json();
  182. })
  183. .catch((err) => {
  184. console.log(err);
  185. if ('detail' in err) {
  186. error = err.detail;
  187. } else {
  188. error = err;
  189. }
  190. return null;
  191. });
  192. if (error) {
  193. throw error;
  194. }
  195. return res;
  196. };
  197. export const stopTask = async (token: string, id: string) => {
  198. let error = null;
  199. const res = await fetch(`${WEBUI_BASE_URL}/api/tasks/stop/${id}`, {
  200. method: 'POST',
  201. headers: {
  202. Accept: 'application/json',
  203. 'Content-Type': 'application/json',
  204. ...(token && { authorization: `Bearer ${token}` })
  205. }
  206. })
  207. .then(async (res) => {
  208. if (!res.ok) throw await res.json();
  209. return res.json();
  210. })
  211. .catch((err) => {
  212. console.log(err);
  213. if ('detail' in err) {
  214. error = err.detail;
  215. } else {
  216. error = err;
  217. }
  218. return null;
  219. });
  220. if (error) {
  221. throw error;
  222. }
  223. return res;
  224. };
  225. export const getToolServerData = async (token: string, url: string) => {
  226. let error = null;
  227. const res = await fetch(`${url}/openapi.json`, {
  228. method: 'GET',
  229. headers: {
  230. Accept: 'application/json',
  231. 'Content-Type': 'application/json',
  232. ...(token && { authorization: `Bearer ${token}` })
  233. }
  234. })
  235. .then(async (res) => {
  236. if (!res.ok) throw await res.json();
  237. return res.json();
  238. })
  239. .catch((err) => {
  240. console.log(err);
  241. if ('detail' in err) {
  242. error = err.detail;
  243. } else {
  244. error = err;
  245. }
  246. return null;
  247. });
  248. if (error) {
  249. throw error;
  250. }
  251. const data = {
  252. openapi: res,
  253. info: res.info,
  254. specs: convertOpenApiToToolPayload(res)
  255. };
  256. console.log(data);
  257. return data;
  258. };
  259. export const getToolServersData = async (servers: object[]) => {
  260. return await Promise.all(
  261. servers
  262. .filter((server) => server?.config?.enable)
  263. .map(async (server) => {
  264. const data = await getToolServerData(server?.key, server?.url).catch((err) => {
  265. console.error(err);
  266. return null;
  267. });
  268. if (data) {
  269. const { openapi, info, specs } = data;
  270. return {
  271. url: server?.url,
  272. openapi: openapi,
  273. info: info,
  274. specs: specs
  275. };
  276. }
  277. })
  278. );
  279. };
  280. export const executeToolServer = async (
  281. token: string,
  282. url: string,
  283. name: string,
  284. params: Record<string, any>,
  285. serverData: { openapi: any; info: any; specs: any }
  286. ) => {
  287. let error = null;
  288. try {
  289. // Find the matching operationId in the OpenAPI spec
  290. const matchingRoute = Object.entries(serverData.openapi.paths).find(([_, methods]) =>
  291. Object.entries(methods as any).some(([__, operation]: any) => operation.operationId === name)
  292. );
  293. if (!matchingRoute) {
  294. throw new Error(`No matching route found for operationId: ${name}`);
  295. }
  296. const [routePath, methods] = matchingRoute;
  297. const methodEntry = Object.entries(methods as any).find(
  298. ([_, operation]: any) => operation.operationId === name
  299. );
  300. if (!methodEntry) {
  301. throw new Error(`No matching method found for operationId: ${name}`);
  302. }
  303. const [httpMethod, operation]: [string, any] = methodEntry;
  304. // Split parameters by type
  305. const pathParams: Record<string, any> = {};
  306. const queryParams: Record<string, any> = {};
  307. let bodyParams: any = {};
  308. if (operation.parameters) {
  309. operation.parameters.forEach((param: any) => {
  310. const paramName = param.name;
  311. const paramIn = param.in;
  312. if (params.hasOwnProperty(paramName)) {
  313. if (paramIn === 'path') {
  314. pathParams[paramName] = params[paramName];
  315. } else if (paramIn === 'query') {
  316. queryParams[paramName] = params[paramName];
  317. }
  318. }
  319. });
  320. }
  321. let finalUrl = `${url}${routePath}`;
  322. // Replace path parameters (`{param}`)
  323. Object.entries(pathParams).forEach(([key, value]) => {
  324. finalUrl = finalUrl.replace(new RegExp(`{${key}}`, 'g'), encodeURIComponent(value));
  325. });
  326. // Append query parameters to URL if any
  327. if (Object.keys(queryParams).length > 0) {
  328. const queryString = new URLSearchParams(
  329. Object.entries(queryParams).map(([k, v]) => [k, String(v)])
  330. ).toString();
  331. finalUrl += `?${queryString}`;
  332. }
  333. // Handle requestBody composite
  334. if (operation.requestBody && operation.requestBody.content) {
  335. const contentType = Object.keys(operation.requestBody.content)[0]; // typically "application/json"
  336. if (params.body !== undefined) {
  337. bodyParams = params.body; // Assume the provided params has a "body" property containing the payload
  338. } else {
  339. // Optional: Fallback or explicit error if body is expected but not provided
  340. throw new Error(`Request body expected for operation '${name}' but none found.`);
  341. }
  342. }
  343. // Prepare headers and request options
  344. const headers: Record<string, string> = {
  345. 'Content-Type': 'application/json',
  346. ...(token && { authorization: `Bearer ${token}` })
  347. };
  348. let requestOptions: RequestInit = {
  349. method: httpMethod.toUpperCase(),
  350. headers
  351. };
  352. if (['post', 'put', 'patch'].includes(httpMethod.toLowerCase()) && operation.requestBody) {
  353. requestOptions.body = JSON.stringify(bodyParams);
  354. }
  355. const res = await fetch(finalUrl, requestOptions);
  356. if (!res.ok) {
  357. const resText = await res.text();
  358. throw new Error(`HTTP error! Status: ${res.status}. Message: ${resText}`);
  359. }
  360. return await res.json();
  361. } catch (err: any) {
  362. error = err.message;
  363. console.error('API Request Error:', error);
  364. return { error };
  365. }
  366. };
  367. export const getTaskConfig = async (token: string = '') => {
  368. let error = null;
  369. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/config`, {
  370. method: 'GET',
  371. headers: {
  372. Accept: 'application/json',
  373. 'Content-Type': 'application/json',
  374. ...(token && { authorization: `Bearer ${token}` })
  375. }
  376. })
  377. .then(async (res) => {
  378. if (!res.ok) throw await res.json();
  379. return res.json();
  380. })
  381. .catch((err) => {
  382. console.log(err);
  383. error = err;
  384. return null;
  385. });
  386. if (error) {
  387. throw error;
  388. }
  389. return res;
  390. };
  391. export const updateTaskConfig = async (token: string, config: object) => {
  392. let error = null;
  393. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/config/update`, {
  394. method: 'POST',
  395. headers: {
  396. Accept: 'application/json',
  397. 'Content-Type': 'application/json',
  398. ...(token && { authorization: `Bearer ${token}` })
  399. },
  400. body: JSON.stringify(config)
  401. })
  402. .then(async (res) => {
  403. if (!res.ok) throw await res.json();
  404. return res.json();
  405. })
  406. .catch((err) => {
  407. console.log(err);
  408. if ('detail' in err) {
  409. error = err.detail;
  410. } else {
  411. error = err;
  412. }
  413. return null;
  414. });
  415. if (error) {
  416. throw error;
  417. }
  418. return res;
  419. };
  420. export const generateTitle = async (
  421. token: string = '',
  422. model: string,
  423. messages: string[],
  424. chat_id?: string
  425. ) => {
  426. let error = null;
  427. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/title/completions`, {
  428. method: 'POST',
  429. headers: {
  430. Accept: 'application/json',
  431. 'Content-Type': 'application/json',
  432. Authorization: `Bearer ${token}`
  433. },
  434. body: JSON.stringify({
  435. model: model,
  436. messages: messages,
  437. ...(chat_id && { chat_id: chat_id })
  438. })
  439. })
  440. .then(async (res) => {
  441. if (!res.ok) throw await res.json();
  442. return res.json();
  443. })
  444. .catch((err) => {
  445. console.log(err);
  446. if ('detail' in err) {
  447. error = err.detail;
  448. }
  449. return null;
  450. });
  451. if (error) {
  452. throw error;
  453. }
  454. return res?.choices[0]?.message?.content.replace(/["']/g, '') ?? 'New Chat';
  455. };
  456. export const generateTags = async (
  457. token: string = '',
  458. model: string,
  459. messages: string,
  460. chat_id?: string
  461. ) => {
  462. let error = null;
  463. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/tags/completions`, {
  464. method: 'POST',
  465. headers: {
  466. Accept: 'application/json',
  467. 'Content-Type': 'application/json',
  468. Authorization: `Bearer ${token}`
  469. },
  470. body: JSON.stringify({
  471. model: model,
  472. messages: messages,
  473. ...(chat_id && { chat_id: chat_id })
  474. })
  475. })
  476. .then(async (res) => {
  477. if (!res.ok) throw await res.json();
  478. return res.json();
  479. })
  480. .catch((err) => {
  481. console.log(err);
  482. if ('detail' in err) {
  483. error = err.detail;
  484. }
  485. return null;
  486. });
  487. if (error) {
  488. throw error;
  489. }
  490. try {
  491. // Step 1: Safely extract the response string
  492. const response = res?.choices[0]?.message?.content ?? '';
  493. // Step 2: Attempt to fix common JSON format issues like single quotes
  494. const sanitizedResponse = response.replace(/['‘’`]/g, '"'); // Convert single quotes to double quotes for valid JSON
  495. // Step 3: Find the relevant JSON block within the response
  496. const jsonStartIndex = sanitizedResponse.indexOf('{');
  497. const jsonEndIndex = sanitizedResponse.lastIndexOf('}');
  498. // Step 4: Check if we found a valid JSON block (with both `{` and `}`)
  499. if (jsonStartIndex !== -1 && jsonEndIndex !== -1) {
  500. const jsonResponse = sanitizedResponse.substring(jsonStartIndex, jsonEndIndex + 1);
  501. // Step 5: Parse the JSON block
  502. const parsed = JSON.parse(jsonResponse);
  503. // Step 6: If there's a "tags" key, return the tags array; otherwise, return an empty array
  504. if (parsed && parsed.tags) {
  505. return Array.isArray(parsed.tags) ? parsed.tags : [];
  506. } else {
  507. return [];
  508. }
  509. }
  510. // If no valid JSON block found, return an empty array
  511. return [];
  512. } catch (e) {
  513. // Catch and safely return empty array on any parsing errors
  514. console.error('Failed to parse response: ', e);
  515. return [];
  516. }
  517. };
  518. export const generateEmoji = async (
  519. token: string = '',
  520. model: string,
  521. prompt: string,
  522. chat_id?: string
  523. ) => {
  524. let error = null;
  525. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/emoji/completions`, {
  526. method: 'POST',
  527. headers: {
  528. Accept: 'application/json',
  529. 'Content-Type': 'application/json',
  530. Authorization: `Bearer ${token}`
  531. },
  532. body: JSON.stringify({
  533. model: model,
  534. prompt: prompt,
  535. ...(chat_id && { chat_id: chat_id })
  536. })
  537. })
  538. .then(async (res) => {
  539. if (!res.ok) throw await res.json();
  540. return res.json();
  541. })
  542. .catch((err) => {
  543. console.log(err);
  544. if ('detail' in err) {
  545. error = err.detail;
  546. }
  547. return null;
  548. });
  549. if (error) {
  550. throw error;
  551. }
  552. const response = res?.choices[0]?.message?.content.replace(/["']/g, '') ?? null;
  553. if (response) {
  554. if (/\p{Extended_Pictographic}/u.test(response)) {
  555. return response.match(/\p{Extended_Pictographic}/gu)[0];
  556. }
  557. }
  558. return null;
  559. };
  560. export const generateQueries = async (
  561. token: string = '',
  562. model: string,
  563. messages: object[],
  564. prompt: string,
  565. type?: string = 'web_search'
  566. ) => {
  567. let error = null;
  568. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/queries/completions`, {
  569. method: 'POST',
  570. headers: {
  571. Accept: 'application/json',
  572. 'Content-Type': 'application/json',
  573. Authorization: `Bearer ${token}`
  574. },
  575. body: JSON.stringify({
  576. model: model,
  577. messages: messages,
  578. prompt: prompt,
  579. type: type
  580. })
  581. })
  582. .then(async (res) => {
  583. if (!res.ok) throw await res.json();
  584. return res.json();
  585. })
  586. .catch((err) => {
  587. console.log(err);
  588. if ('detail' in err) {
  589. error = err.detail;
  590. }
  591. return null;
  592. });
  593. if (error) {
  594. throw error;
  595. }
  596. // Step 1: Safely extract the response string
  597. const response = res?.choices[0]?.message?.content ?? '';
  598. try {
  599. const jsonStartIndex = response.indexOf('{');
  600. const jsonEndIndex = response.lastIndexOf('}');
  601. if (jsonStartIndex !== -1 && jsonEndIndex !== -1) {
  602. const jsonResponse = response.substring(jsonStartIndex, jsonEndIndex + 1);
  603. // Step 5: Parse the JSON block
  604. const parsed = JSON.parse(jsonResponse);
  605. // Step 6: If there's a "queries" key, return the queries array; otherwise, return an empty array
  606. if (parsed && parsed.queries) {
  607. return Array.isArray(parsed.queries) ? parsed.queries : [];
  608. } else {
  609. return [];
  610. }
  611. }
  612. // If no valid JSON block found, return response as is
  613. return [response];
  614. } catch (e) {
  615. // Catch and safely return empty array on any parsing errors
  616. console.error('Failed to parse response: ', e);
  617. return [response];
  618. }
  619. };
  620. export const generateAutoCompletion = async (
  621. token: string = '',
  622. model: string,
  623. prompt: string,
  624. messages?: object[],
  625. type: string = 'search query'
  626. ) => {
  627. const controller = new AbortController();
  628. let error = null;
  629. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/auto/completions`, {
  630. signal: controller.signal,
  631. method: 'POST',
  632. headers: {
  633. Accept: 'application/json',
  634. 'Content-Type': 'application/json',
  635. Authorization: `Bearer ${token}`
  636. },
  637. body: JSON.stringify({
  638. model: model,
  639. prompt: prompt,
  640. ...(messages && { messages: messages }),
  641. type: type,
  642. stream: false
  643. })
  644. })
  645. .then(async (res) => {
  646. if (!res.ok) throw await res.json();
  647. return res.json();
  648. })
  649. .catch((err) => {
  650. console.log(err);
  651. if ('detail' in err) {
  652. error = err.detail;
  653. }
  654. return null;
  655. });
  656. if (error) {
  657. throw error;
  658. }
  659. const response = res?.choices[0]?.message?.content ?? '';
  660. try {
  661. const jsonStartIndex = response.indexOf('{');
  662. const jsonEndIndex = response.lastIndexOf('}');
  663. if (jsonStartIndex !== -1 && jsonEndIndex !== -1) {
  664. const jsonResponse = response.substring(jsonStartIndex, jsonEndIndex + 1);
  665. // Step 5: Parse the JSON block
  666. const parsed = JSON.parse(jsonResponse);
  667. // Step 6: If there's a "queries" key, return the queries array; otherwise, return an empty array
  668. if (parsed && parsed.text) {
  669. return parsed.text;
  670. } else {
  671. return '';
  672. }
  673. }
  674. // If no valid JSON block found, return response as is
  675. return response;
  676. } catch (e) {
  677. // Catch and safely return empty array on any parsing errors
  678. console.error('Failed to parse response: ', e);
  679. return response;
  680. }
  681. };
  682. export const generateMoACompletion = async (
  683. token: string = '',
  684. model: string,
  685. prompt: string,
  686. responses: string[]
  687. ) => {
  688. const controller = new AbortController();
  689. let error = null;
  690. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/moa/completions`, {
  691. signal: controller.signal,
  692. method: 'POST',
  693. headers: {
  694. Accept: 'application/json',
  695. 'Content-Type': 'application/json',
  696. Authorization: `Bearer ${token}`
  697. },
  698. body: JSON.stringify({
  699. model: model,
  700. prompt: prompt,
  701. responses: responses,
  702. stream: true
  703. })
  704. }).catch((err) => {
  705. console.log(err);
  706. error = err;
  707. return null;
  708. });
  709. if (error) {
  710. throw error;
  711. }
  712. return [res, controller];
  713. };
  714. export const getPipelinesList = async (token: string = '') => {
  715. let error = null;
  716. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/list`, {
  717. method: 'GET',
  718. headers: {
  719. Accept: 'application/json',
  720. 'Content-Type': 'application/json',
  721. ...(token && { authorization: `Bearer ${token}` })
  722. }
  723. })
  724. .then(async (res) => {
  725. if (!res.ok) throw await res.json();
  726. return res.json();
  727. })
  728. .catch((err) => {
  729. console.log(err);
  730. error = err;
  731. return null;
  732. });
  733. if (error) {
  734. throw error;
  735. }
  736. let pipelines = res?.data ?? [];
  737. return pipelines;
  738. };
  739. export const uploadPipeline = async (token: string, file: File, urlIdx: string) => {
  740. let error = null;
  741. // Create a new FormData object to handle the file upload
  742. const formData = new FormData();
  743. formData.append('file', file);
  744. formData.append('urlIdx', urlIdx);
  745. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/upload`, {
  746. method: 'POST',
  747. headers: {
  748. ...(token && { authorization: `Bearer ${token}` })
  749. // 'Content-Type': 'multipart/form-data' is not needed as Fetch API will set it automatically
  750. },
  751. body: formData
  752. })
  753. .then(async (res) => {
  754. if (!res.ok) throw await res.json();
  755. return res.json();
  756. })
  757. .catch((err) => {
  758. console.log(err);
  759. if ('detail' in err) {
  760. error = err.detail;
  761. } else {
  762. error = err;
  763. }
  764. return null;
  765. });
  766. if (error) {
  767. throw error;
  768. }
  769. return res;
  770. };
  771. export const downloadPipeline = async (token: string, url: string, urlIdx: string) => {
  772. let error = null;
  773. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/add`, {
  774. method: 'POST',
  775. headers: {
  776. Accept: 'application/json',
  777. 'Content-Type': 'application/json',
  778. ...(token && { authorization: `Bearer ${token}` })
  779. },
  780. body: JSON.stringify({
  781. url: url,
  782. urlIdx: urlIdx
  783. })
  784. })
  785. .then(async (res) => {
  786. if (!res.ok) throw await res.json();
  787. return res.json();
  788. })
  789. .catch((err) => {
  790. console.log(err);
  791. if ('detail' in err) {
  792. error = err.detail;
  793. } else {
  794. error = err;
  795. }
  796. return null;
  797. });
  798. if (error) {
  799. throw error;
  800. }
  801. return res;
  802. };
  803. export const deletePipeline = async (token: string, id: string, urlIdx: string) => {
  804. let error = null;
  805. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/delete`, {
  806. method: 'DELETE',
  807. headers: {
  808. Accept: 'application/json',
  809. 'Content-Type': 'application/json',
  810. ...(token && { authorization: `Bearer ${token}` })
  811. },
  812. body: JSON.stringify({
  813. id: id,
  814. urlIdx: urlIdx
  815. })
  816. })
  817. .then(async (res) => {
  818. if (!res.ok) throw await res.json();
  819. return res.json();
  820. })
  821. .catch((err) => {
  822. console.log(err);
  823. if ('detail' in err) {
  824. error = err.detail;
  825. } else {
  826. error = err;
  827. }
  828. return null;
  829. });
  830. if (error) {
  831. throw error;
  832. }
  833. return res;
  834. };
  835. export const getPipelines = async (token: string, urlIdx?: string) => {
  836. let error = null;
  837. const searchParams = new URLSearchParams();
  838. if (urlIdx !== undefined) {
  839. searchParams.append('urlIdx', urlIdx);
  840. }
  841. const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/?${searchParams.toString()}`, {
  842. method: 'GET',
  843. headers: {
  844. Accept: 'application/json',
  845. 'Content-Type': 'application/json',
  846. ...(token && { authorization: `Bearer ${token}` })
  847. }
  848. })
  849. .then(async (res) => {
  850. if (!res.ok) throw await res.json();
  851. return res.json();
  852. })
  853. .catch((err) => {
  854. console.log(err);
  855. error = err;
  856. return null;
  857. });
  858. if (error) {
  859. throw error;
  860. }
  861. let pipelines = res?.data ?? [];
  862. return pipelines;
  863. };
  864. export const getPipelineValves = async (token: string, pipeline_id: string, urlIdx: string) => {
  865. let error = null;
  866. const searchParams = new URLSearchParams();
  867. if (urlIdx !== undefined) {
  868. searchParams.append('urlIdx', urlIdx);
  869. }
  870. const res = await fetch(
  871. `${WEBUI_BASE_URL}/api/v1/pipelines/${pipeline_id}/valves?${searchParams.toString()}`,
  872. {
  873. method: 'GET',
  874. headers: {
  875. Accept: 'application/json',
  876. 'Content-Type': 'application/json',
  877. ...(token && { authorization: `Bearer ${token}` })
  878. }
  879. }
  880. )
  881. .then(async (res) => {
  882. if (!res.ok) throw await res.json();
  883. return res.json();
  884. })
  885. .catch((err) => {
  886. console.log(err);
  887. error = err;
  888. return null;
  889. });
  890. if (error) {
  891. throw error;
  892. }
  893. return res;
  894. };
  895. export const getPipelineValvesSpec = async (token: string, pipeline_id: string, urlIdx: string) => {
  896. let error = null;
  897. const searchParams = new URLSearchParams();
  898. if (urlIdx !== undefined) {
  899. searchParams.append('urlIdx', urlIdx);
  900. }
  901. const res = await fetch(
  902. `${WEBUI_BASE_URL}/api/v1/pipelines/${pipeline_id}/valves/spec?${searchParams.toString()}`,
  903. {
  904. method: 'GET',
  905. headers: {
  906. Accept: 'application/json',
  907. 'Content-Type': 'application/json',
  908. ...(token && { authorization: `Bearer ${token}` })
  909. }
  910. }
  911. )
  912. .then(async (res) => {
  913. if (!res.ok) throw await res.json();
  914. return res.json();
  915. })
  916. .catch((err) => {
  917. console.log(err);
  918. error = err;
  919. return null;
  920. });
  921. if (error) {
  922. throw error;
  923. }
  924. return res;
  925. };
  926. export const updatePipelineValves = async (
  927. token: string = '',
  928. pipeline_id: string,
  929. valves: object,
  930. urlIdx: string
  931. ) => {
  932. let error = null;
  933. const searchParams = new URLSearchParams();
  934. if (urlIdx !== undefined) {
  935. searchParams.append('urlIdx', urlIdx);
  936. }
  937. const res = await fetch(
  938. `${WEBUI_BASE_URL}/api/v1/pipelines/${pipeline_id}/valves/update?${searchParams.toString()}`,
  939. {
  940. method: 'POST',
  941. headers: {
  942. Accept: 'application/json',
  943. 'Content-Type': 'application/json',
  944. ...(token && { authorization: `Bearer ${token}` })
  945. },
  946. body: JSON.stringify(valves)
  947. }
  948. )
  949. .then(async (res) => {
  950. if (!res.ok) throw await res.json();
  951. return res.json();
  952. })
  953. .catch((err) => {
  954. console.log(err);
  955. if ('detail' in err) {
  956. error = err.detail;
  957. } else {
  958. error = err;
  959. }
  960. return null;
  961. });
  962. if (error) {
  963. throw error;
  964. }
  965. return res;
  966. };
  967. export const getBackendConfig = async () => {
  968. let error = null;
  969. const res = await fetch(`${WEBUI_BASE_URL}/api/config`, {
  970. method: 'GET',
  971. credentials: 'include',
  972. headers: {
  973. 'Content-Type': 'application/json'
  974. }
  975. })
  976. .then(async (res) => {
  977. if (!res.ok) throw await res.json();
  978. return res.json();
  979. })
  980. .catch((err) => {
  981. console.log(err);
  982. error = err;
  983. return null;
  984. });
  985. if (error) {
  986. throw error;
  987. }
  988. return res;
  989. };
  990. export const getChangelog = async () => {
  991. let error = null;
  992. const res = await fetch(`${WEBUI_BASE_URL}/api/changelog`, {
  993. method: 'GET',
  994. headers: {
  995. 'Content-Type': 'application/json'
  996. }
  997. })
  998. .then(async (res) => {
  999. if (!res.ok) throw await res.json();
  1000. return res.json();
  1001. })
  1002. .catch((err) => {
  1003. console.log(err);
  1004. error = err;
  1005. return null;
  1006. });
  1007. if (error) {
  1008. throw error;
  1009. }
  1010. return res;
  1011. };
  1012. export const getVersionUpdates = async (token: string) => {
  1013. let error = null;
  1014. const res = await fetch(`${WEBUI_BASE_URL}/api/version/updates`, {
  1015. method: 'GET',
  1016. headers: {
  1017. 'Content-Type': 'application/json',
  1018. Authorization: `Bearer ${token}`
  1019. }
  1020. })
  1021. .then(async (res) => {
  1022. if (!res.ok) throw await res.json();
  1023. return res.json();
  1024. })
  1025. .catch((err) => {
  1026. console.log(err);
  1027. error = err;
  1028. return null;
  1029. });
  1030. if (error) {
  1031. throw error;
  1032. }
  1033. return res;
  1034. };
  1035. export const getModelFilterConfig = async (token: string) => {
  1036. let error = null;
  1037. const res = await fetch(`${WEBUI_BASE_URL}/api/config/model/filter`, {
  1038. method: 'GET',
  1039. headers: {
  1040. 'Content-Type': 'application/json',
  1041. Authorization: `Bearer ${token}`
  1042. }
  1043. })
  1044. .then(async (res) => {
  1045. if (!res.ok) throw await res.json();
  1046. return res.json();
  1047. })
  1048. .catch((err) => {
  1049. console.log(err);
  1050. error = err;
  1051. return null;
  1052. });
  1053. if (error) {
  1054. throw error;
  1055. }
  1056. return res;
  1057. };
  1058. export const updateModelFilterConfig = async (
  1059. token: string,
  1060. enabled: boolean,
  1061. models: string[]
  1062. ) => {
  1063. let error = null;
  1064. const res = await fetch(`${WEBUI_BASE_URL}/api/config/model/filter`, {
  1065. method: 'POST',
  1066. headers: {
  1067. 'Content-Type': 'application/json',
  1068. Authorization: `Bearer ${token}`
  1069. },
  1070. body: JSON.stringify({
  1071. enabled: enabled,
  1072. models: models
  1073. })
  1074. })
  1075. .then(async (res) => {
  1076. if (!res.ok) throw await res.json();
  1077. return res.json();
  1078. })
  1079. .catch((err) => {
  1080. console.log(err);
  1081. error = err;
  1082. return null;
  1083. });
  1084. if (error) {
  1085. throw error;
  1086. }
  1087. return res;
  1088. };
  1089. export const getWebhookUrl = async (token: string) => {
  1090. let error = null;
  1091. const res = await fetch(`${WEBUI_BASE_URL}/api/webhook`, {
  1092. method: 'GET',
  1093. headers: {
  1094. 'Content-Type': 'application/json',
  1095. Authorization: `Bearer ${token}`
  1096. }
  1097. })
  1098. .then(async (res) => {
  1099. if (!res.ok) throw await res.json();
  1100. return res.json();
  1101. })
  1102. .catch((err) => {
  1103. console.log(err);
  1104. error = err;
  1105. return null;
  1106. });
  1107. if (error) {
  1108. throw error;
  1109. }
  1110. return res.url;
  1111. };
  1112. export const updateWebhookUrl = async (token: string, url: string) => {
  1113. let error = null;
  1114. const res = await fetch(`${WEBUI_BASE_URL}/api/webhook`, {
  1115. method: 'POST',
  1116. headers: {
  1117. 'Content-Type': 'application/json',
  1118. Authorization: `Bearer ${token}`
  1119. },
  1120. body: JSON.stringify({
  1121. url: url
  1122. })
  1123. })
  1124. .then(async (res) => {
  1125. if (!res.ok) throw await res.json();
  1126. return res.json();
  1127. })
  1128. .catch((err) => {
  1129. console.log(err);
  1130. error = err;
  1131. return null;
  1132. });
  1133. if (error) {
  1134. throw error;
  1135. }
  1136. return res.url;
  1137. };
  1138. export const getCommunitySharingEnabledStatus = async (token: string) => {
  1139. let error = null;
  1140. const res = await fetch(`${WEBUI_BASE_URL}/api/community_sharing`, {
  1141. method: 'GET',
  1142. headers: {
  1143. 'Content-Type': 'application/json',
  1144. Authorization: `Bearer ${token}`
  1145. }
  1146. })
  1147. .then(async (res) => {
  1148. if (!res.ok) throw await res.json();
  1149. return res.json();
  1150. })
  1151. .catch((err) => {
  1152. console.log(err);
  1153. error = err;
  1154. return null;
  1155. });
  1156. if (error) {
  1157. throw error;
  1158. }
  1159. return res;
  1160. };
  1161. export const toggleCommunitySharingEnabledStatus = async (token: string) => {
  1162. let error = null;
  1163. const res = await fetch(`${WEBUI_BASE_URL}/api/community_sharing/toggle`, {
  1164. method: 'GET',
  1165. headers: {
  1166. 'Content-Type': 'application/json',
  1167. Authorization: `Bearer ${token}`
  1168. }
  1169. })
  1170. .then(async (res) => {
  1171. if (!res.ok) throw await res.json();
  1172. return res.json();
  1173. })
  1174. .catch((err) => {
  1175. console.log(err);
  1176. error = err.detail;
  1177. return null;
  1178. });
  1179. if (error) {
  1180. throw error;
  1181. }
  1182. return res;
  1183. };
  1184. export const getModelConfig = async (token: string): Promise<GlobalModelConfig> => {
  1185. let error = null;
  1186. const res = await fetch(`${WEBUI_BASE_URL}/api/config/models`, {
  1187. method: 'GET',
  1188. headers: {
  1189. 'Content-Type': 'application/json',
  1190. Authorization: `Bearer ${token}`
  1191. }
  1192. })
  1193. .then(async (res) => {
  1194. if (!res.ok) throw await res.json();
  1195. return res.json();
  1196. })
  1197. .catch((err) => {
  1198. console.log(err);
  1199. error = err;
  1200. return null;
  1201. });
  1202. if (error) {
  1203. throw error;
  1204. }
  1205. return res.models;
  1206. };
  1207. export interface ModelConfig {
  1208. id: string;
  1209. name: string;
  1210. meta: ModelMeta;
  1211. base_model_id?: string;
  1212. params: ModelParams;
  1213. }
  1214. export interface ModelMeta {
  1215. description?: string;
  1216. capabilities?: object;
  1217. profile_image_url?: string;
  1218. }
  1219. export interface ModelParams {}
  1220. export type GlobalModelConfig = ModelConfig[];
  1221. export const updateModelConfig = async (token: string, config: GlobalModelConfig) => {
  1222. let error = null;
  1223. const res = await fetch(`${WEBUI_BASE_URL}/api/config/models`, {
  1224. method: 'POST',
  1225. headers: {
  1226. 'Content-Type': 'application/json',
  1227. Authorization: `Bearer ${token}`
  1228. },
  1229. body: JSON.stringify({
  1230. models: config
  1231. })
  1232. })
  1233. .then(async (res) => {
  1234. if (!res.ok) throw await res.json();
  1235. return res.json();
  1236. })
  1237. .catch((err) => {
  1238. console.log(err);
  1239. error = err;
  1240. return null;
  1241. });
  1242. if (error) {
  1243. throw error;
  1244. }
  1245. return res;
  1246. };