Spaces:
Paused
Paused
| import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; | |
| import { convertOpenApiToToolPayload } from '$lib/utils'; | |
| import { getOpenAIModelsDirect } from './openai'; | |
| import { parse } from 'yaml'; | |
| import { toast } from 'svelte-sonner'; | |
| export const getModels = async ( | |
| token: string = '', | |
| connections: object | null = null, | |
| base: boolean = false | |
| ) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/models${base ? '/base' : ''}`, { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| error = err; | |
| console.error(err); | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| let models = res?.data ?? []; | |
| if (connections && !base) { | |
| let localModels = []; | |
| if (connections) { | |
| const OPENAI_API_BASE_URLS = connections.OPENAI_API_BASE_URLS; | |
| const OPENAI_API_KEYS = connections.OPENAI_API_KEYS; | |
| const OPENAI_API_CONFIGS = connections.OPENAI_API_CONFIGS; | |
| const requests = []; | |
| for (const idx in OPENAI_API_BASE_URLS) { | |
| const url = OPENAI_API_BASE_URLS[idx]; | |
| if (idx.toString() in OPENAI_API_CONFIGS) { | |
| const apiConfig = OPENAI_API_CONFIGS[idx.toString()] ?? {}; | |
| const enable = apiConfig?.enable ?? true; | |
| const modelIds = apiConfig?.model_ids ?? []; | |
| if (enable) { | |
| if (modelIds.length > 0) { | |
| const modelList = { | |
| object: 'list', | |
| data: modelIds.map((modelId) => ({ | |
| id: modelId, | |
| name: modelId, | |
| owned_by: 'openai', | |
| openai: { id: modelId }, | |
| urlIdx: idx | |
| })) | |
| }; | |
| requests.push( | |
| (async () => { | |
| return modelList; | |
| })() | |
| ); | |
| } else { | |
| requests.push( | |
| (async () => { | |
| return await getOpenAIModelsDirect(url, OPENAI_API_KEYS[idx]) | |
| .then((res) => { | |
| return res; | |
| }) | |
| .catch((err) => { | |
| return { | |
| object: 'list', | |
| data: [], | |
| urlIdx: idx | |
| }; | |
| }); | |
| })() | |
| ); | |
| } | |
| } else { | |
| requests.push( | |
| (async () => { | |
| return { | |
| object: 'list', | |
| data: [], | |
| urlIdx: idx | |
| }; | |
| })() | |
| ); | |
| } | |
| } | |
| } | |
| const responses = await Promise.all(requests); | |
| for (const idx in responses) { | |
| const response = responses[idx]; | |
| const apiConfig = OPENAI_API_CONFIGS[idx.toString()] ?? {}; | |
| let models = Array.isArray(response) ? response : (response?.data ?? []); | |
| models = models.map((model) => ({ ...model, openai: { id: model.id }, urlIdx: idx })); | |
| const prefixId = apiConfig.prefix_id; | |
| if (prefixId) { | |
| for (const model of models) { | |
| model.id = `${prefixId}.${model.id}`; | |
| } | |
| } | |
| const tags = apiConfig.tags; | |
| if (tags) { | |
| for (const model of models) { | |
| model.tags = tags; | |
| } | |
| } | |
| localModels = localModels.concat(models); | |
| } | |
| } | |
| models = models.concat( | |
| localModels.map((model) => ({ | |
| ...model, | |
| name: model?.name ?? model?.id, | |
| direct: true | |
| })) | |
| ); | |
| // Remove duplicates | |
| const modelsMap = {}; | |
| for (const model of models) { | |
| modelsMap[model.id] = model; | |
| } | |
| models = Object.values(modelsMap); | |
| } | |
| return models; | |
| }; | |
| type ChatCompletedForm = { | |
| model: string; | |
| messages: string[]; | |
| chat_id: string; | |
| session_id: string; | |
| }; | |
| export const chatCompleted = async (token: string, body: ChatCompletedForm) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/chat/completed`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| }, | |
| body: JSON.stringify(body) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| type ChatActionForm = { | |
| model: string; | |
| messages: string[]; | |
| chat_id: string; | |
| }; | |
| export const chatAction = async (token: string, action_id: string, body: ChatActionForm) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/chat/actions/${action_id}`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| }, | |
| body: JSON.stringify(body) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const stopTask = async (token: string, id: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/tasks/stop/${id}`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getTaskIdsByChatId = async (token: string, chat_id: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/tasks/chat/${chat_id}`, { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getToolServerData = async (token: string, url: string) => { | |
| let error = null; | |
| const res = await fetch(`${url}`, { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| // Check if URL ends with .yaml or .yml to determine format | |
| if (url.toLowerCase().endsWith('.yaml') || url.toLowerCase().endsWith('.yml')) { | |
| if (!res.ok) throw await res.text(); | |
| const text = await res.text(); | |
| return parse(text); | |
| } else { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| } | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| const data = { | |
| openapi: res, | |
| info: res.info, | |
| specs: convertOpenApiToToolPayload(res) | |
| }; | |
| console.log(data); | |
| return data; | |
| }; | |
| export const getToolServersData = async (i18n, servers: object[]) => { | |
| return ( | |
| await Promise.all( | |
| servers | |
| .filter((server) => server?.config?.enable) | |
| .map(async (server) => { | |
| const data = await getToolServerData( | |
| (server?.auth_type ?? 'bearer') === 'bearer' ? server?.key : localStorage.token, | |
| (server?.path ?? '').includes('://') | |
| ? server?.path | |
| : `${server?.url}${(server?.path ?? '').startsWith('/') ? '' : '/'}${server?.path}` | |
| ).catch((err) => { | |
| toast.error( | |
| i18n.t(`Failed to connect to {{URL}} OpenAPI tool server`, { | |
| URL: (server?.path ?? '').includes('://') | |
| ? server?.path | |
| : `${server?.url}${(server?.path ?? '').startsWith('/') ? '' : '/'}${server?.path}` | |
| }) | |
| ); | |
| return null; | |
| }); | |
| if (data) { | |
| const { openapi, info, specs } = data; | |
| return { | |
| url: server?.url, | |
| openapi: openapi, | |
| info: info, | |
| specs: specs | |
| }; | |
| } | |
| }) | |
| ) | |
| ).filter((server) => server); | |
| }; | |
| export const executeToolServer = async ( | |
| token: string, | |
| url: string, | |
| name: string, | |
| params: Record<string, any>, | |
| serverData: { openapi: any; info: any; specs: any } | |
| ) => { | |
| let error = null; | |
| try { | |
| // Find the matching operationId in the OpenAPI spec | |
| const matchingRoute = Object.entries(serverData.openapi.paths).find(([_, methods]) => | |
| Object.entries(methods as any).some(([__, operation]: any) => operation.operationId === name) | |
| ); | |
| if (!matchingRoute) { | |
| throw new Error(`No matching route found for operationId: ${name}`); | |
| } | |
| const [routePath, methods] = matchingRoute; | |
| const methodEntry = Object.entries(methods as any).find( | |
| ([_, operation]: any) => operation.operationId === name | |
| ); | |
| if (!methodEntry) { | |
| throw new Error(`No matching method found for operationId: ${name}`); | |
| } | |
| const [httpMethod, operation]: [string, any] = methodEntry; | |
| // Split parameters by type | |
| const pathParams: Record<string, any> = {}; | |
| const queryParams: Record<string, any> = {}; | |
| let bodyParams: any = {}; | |
| if (operation.parameters) { | |
| operation.parameters.forEach((param: any) => { | |
| const paramName = param.name; | |
| const paramIn = param.in; | |
| if (params.hasOwnProperty(paramName)) { | |
| if (paramIn === 'path') { | |
| pathParams[paramName] = params[paramName]; | |
| } else if (paramIn === 'query') { | |
| queryParams[paramName] = params[paramName]; | |
| } | |
| } | |
| }); | |
| } | |
| let finalUrl = `${url}${routePath}`; | |
| // Replace path parameters (`{param}`) | |
| Object.entries(pathParams).forEach(([key, value]) => { | |
| finalUrl = finalUrl.replace(new RegExp(`{${key}}`, 'g'), encodeURIComponent(value)); | |
| }); | |
| // Append query parameters to URL if any | |
| if (Object.keys(queryParams).length > 0) { | |
| const queryString = new URLSearchParams( | |
| Object.entries(queryParams).map(([k, v]) => [k, String(v)]) | |
| ).toString(); | |
| finalUrl += `?${queryString}`; | |
| } | |
| // Handle requestBody composite | |
| if (operation.requestBody && operation.requestBody.content) { | |
| const contentType = Object.keys(operation.requestBody.content)[0]; | |
| if (params !== undefined) { | |
| bodyParams = params; | |
| } else { | |
| // Optional: Fallback or explicit error if body is expected but not provided | |
| throw new Error(`Request body expected for operation '${name}' but none found.`); | |
| } | |
| } | |
| // Prepare headers and request options | |
| const headers: Record<string, string> = { | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| }; | |
| let requestOptions: RequestInit = { | |
| method: httpMethod.toUpperCase(), | |
| headers | |
| }; | |
| if (['post', 'put', 'patch'].includes(httpMethod.toLowerCase()) && operation.requestBody) { | |
| requestOptions.body = JSON.stringify(bodyParams); | |
| } | |
| const res = await fetch(finalUrl, requestOptions); | |
| if (!res.ok) { | |
| const resText = await res.text(); | |
| throw new Error(`HTTP error! Status: ${res.status}. Message: ${resText}`); | |
| } | |
| return await res.json(); | |
| } catch (err: any) { | |
| error = err.message; | |
| console.error('API Request Error:', error); | |
| return { error }; | |
| } | |
| }; | |
| export const getTaskConfig = async (token: string = '') => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/config`, { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const updateTaskConfig = async (token: string, config: object) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/config/update`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| }, | |
| body: JSON.stringify(config) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const generateTitle = async ( | |
| token: string = '', | |
| model: string, | |
| messages: object[], | |
| chat_id?: string | |
| ) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/title/completions`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| model: model, | |
| messages: messages, | |
| ...(chat_id && { chat_id: chat_id }) | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| try { | |
| // Step 1: Safely extract the response string | |
| const response = res?.choices[0]?.message?.content ?? ''; | |
| // Step 2: Attempt to fix common JSON format issues like single quotes | |
| const sanitizedResponse = response.replace(/['‘’`]/g, '"'); // Convert single quotes to double quotes for valid JSON | |
| // Step 3: Find the relevant JSON block within the response | |
| const jsonStartIndex = sanitizedResponse.indexOf('{'); | |
| const jsonEndIndex = sanitizedResponse.lastIndexOf('}'); | |
| // Step 4: Check if we found a valid JSON block (with both `{` and `}`) | |
| if (jsonStartIndex !== -1 && jsonEndIndex !== -1) { | |
| const jsonResponse = sanitizedResponse.substring(jsonStartIndex, jsonEndIndex + 1); | |
| // Step 5: Parse the JSON block | |
| const parsed = JSON.parse(jsonResponse); | |
| // Step 6: If there's a "tags" key, return the tags array; otherwise, return an empty array | |
| if (parsed && parsed.title) { | |
| return parsed.title; | |
| } else { | |
| return null; | |
| } | |
| } | |
| // If no valid JSON block found, return an empty array | |
| return null; | |
| } catch (e) { | |
| // Catch and safely return empty array on any parsing errors | |
| console.error('Failed to parse response: ', e); | |
| return null; | |
| } | |
| }; | |
| export const generateFollowUps = async ( | |
| token: string = '', | |
| model: string, | |
| messages: string, | |
| chat_id?: string | |
| ) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/follow_ups/completions`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| model: model, | |
| messages: messages, | |
| ...(chat_id && { chat_id: chat_id }) | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| try { | |
| // Step 1: Safely extract the response string | |
| const response = res?.choices[0]?.message?.content ?? ''; | |
| // Step 2: Attempt to fix common JSON format issues like single quotes | |
| const sanitizedResponse = response.replace(/['‘’`]/g, '"'); // Convert single quotes to double quotes for valid JSON | |
| // Step 3: Find the relevant JSON block within the response | |
| const jsonStartIndex = sanitizedResponse.indexOf('{'); | |
| const jsonEndIndex = sanitizedResponse.lastIndexOf('}'); | |
| // Step 4: Check if we found a valid JSON block (with both `{` and `}`) | |
| if (jsonStartIndex !== -1 && jsonEndIndex !== -1) { | |
| const jsonResponse = sanitizedResponse.substring(jsonStartIndex, jsonEndIndex + 1); | |
| // Step 5: Parse the JSON block | |
| const parsed = JSON.parse(jsonResponse); | |
| // Step 6: If there's a "follow_ups" key, return the follow_ups array; otherwise, return an empty array | |
| if (parsed && parsed.follow_ups) { | |
| return Array.isArray(parsed.follow_ups) ? parsed.follow_ups : []; | |
| } else { | |
| return []; | |
| } | |
| } | |
| // If no valid JSON block found, return an empty array | |
| return []; | |
| } catch (e) { | |
| // Catch and safely return empty array on any parsing errors | |
| console.error('Failed to parse response: ', e); | |
| return []; | |
| } | |
| }; | |
| export const generateTags = async ( | |
| token: string = '', | |
| model: string, | |
| messages: string, | |
| chat_id?: string | |
| ) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/tags/completions`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| model: model, | |
| messages: messages, | |
| ...(chat_id && { chat_id: chat_id }) | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| try { | |
| // Step 1: Safely extract the response string | |
| const response = res?.choices[0]?.message?.content ?? ''; | |
| // Step 2: Attempt to fix common JSON format issues like single quotes | |
| const sanitizedResponse = response.replace(/['‘’`]/g, '"'); // Convert single quotes to double quotes for valid JSON | |
| // Step 3: Find the relevant JSON block within the response | |
| const jsonStartIndex = sanitizedResponse.indexOf('{'); | |
| const jsonEndIndex = sanitizedResponse.lastIndexOf('}'); | |
| // Step 4: Check if we found a valid JSON block (with both `{` and `}`) | |
| if (jsonStartIndex !== -1 && jsonEndIndex !== -1) { | |
| const jsonResponse = sanitizedResponse.substring(jsonStartIndex, jsonEndIndex + 1); | |
| // Step 5: Parse the JSON block | |
| const parsed = JSON.parse(jsonResponse); | |
| // Step 6: If there's a "tags" key, return the tags array; otherwise, return an empty array | |
| if (parsed && parsed.tags) { | |
| return Array.isArray(parsed.tags) ? parsed.tags : []; | |
| } else { | |
| return []; | |
| } | |
| } | |
| // If no valid JSON block found, return an empty array | |
| return []; | |
| } catch (e) { | |
| // Catch and safely return empty array on any parsing errors | |
| console.error('Failed to parse response: ', e); | |
| return []; | |
| } | |
| }; | |
| export const generateEmoji = async ( | |
| token: string = '', | |
| model: string, | |
| prompt: string, | |
| chat_id?: string | |
| ) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/emoji/completions`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| model: model, | |
| prompt: prompt, | |
| ...(chat_id && { chat_id: chat_id }) | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| const response = res?.choices[0]?.message?.content.replace(/["']/g, '') ?? null; | |
| if (response) { | |
| if (/\p{Extended_Pictographic}/u.test(response)) { | |
| return response.match(/\p{Extended_Pictographic}/gu)[0]; | |
| } | |
| } | |
| return null; | |
| }; | |
| export const generateQueries = async ( | |
| token: string = '', | |
| model: string, | |
| messages: object[], | |
| prompt: string, | |
| type?: string = 'web_search' | |
| ) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/queries/completions`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| model: model, | |
| messages: messages, | |
| prompt: prompt, | |
| type: type | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| // Step 1: Safely extract the response string | |
| const response = res?.choices[0]?.message?.content ?? ''; | |
| try { | |
| const jsonStartIndex = response.indexOf('{'); | |
| const jsonEndIndex = response.lastIndexOf('}'); | |
| if (jsonStartIndex !== -1 && jsonEndIndex !== -1) { | |
| const jsonResponse = response.substring(jsonStartIndex, jsonEndIndex + 1); | |
| // Step 5: Parse the JSON block | |
| const parsed = JSON.parse(jsonResponse); | |
| // Step 6: If there's a "queries" key, return the queries array; otherwise, return an empty array | |
| if (parsed && parsed.queries) { | |
| return Array.isArray(parsed.queries) ? parsed.queries : []; | |
| } else { | |
| return []; | |
| } | |
| } | |
| // If no valid JSON block found, return response as is | |
| return [response]; | |
| } catch (e) { | |
| // Catch and safely return empty array on any parsing errors | |
| console.error('Failed to parse response: ', e); | |
| return [response]; | |
| } | |
| }; | |
| export const generateAutoCompletion = async ( | |
| token: string = '', | |
| model: string, | |
| prompt: string, | |
| messages?: object[], | |
| type: string = 'search query' | |
| ) => { | |
| const controller = new AbortController(); | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/auto/completions`, { | |
| signal: controller.signal, | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| model: model, | |
| prompt: prompt, | |
| ...(messages && { messages: messages }), | |
| type: type, | |
| stream: false | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| const response = res?.choices[0]?.message?.content ?? ''; | |
| try { | |
| const jsonStartIndex = response.indexOf('{'); | |
| const jsonEndIndex = response.lastIndexOf('}'); | |
| if (jsonStartIndex !== -1 && jsonEndIndex !== -1) { | |
| const jsonResponse = response.substring(jsonStartIndex, jsonEndIndex + 1); | |
| // Step 5: Parse the JSON block | |
| const parsed = JSON.parse(jsonResponse); | |
| // Step 6: If there's a "queries" key, return the queries array; otherwise, return an empty array | |
| if (parsed && parsed.text) { | |
| return parsed.text; | |
| } else { | |
| return ''; | |
| } | |
| } | |
| // If no valid JSON block found, return response as is | |
| return response; | |
| } catch (e) { | |
| // Catch and safely return empty array on any parsing errors | |
| console.error('Failed to parse response: ', e); | |
| return response; | |
| } | |
| }; | |
| export const generateMoACompletion = async ( | |
| token: string = '', | |
| model: string, | |
| prompt: string, | |
| responses: string[] | |
| ) => { | |
| const controller = new AbortController(); | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/tasks/moa/completions`, { | |
| signal: controller.signal, | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| model: model, | |
| prompt: prompt, | |
| responses: responses, | |
| stream: true | |
| }) | |
| }).catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return [res, controller]; | |
| }; | |
| export const getPipelinesList = async (token: string = '') => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/list`, { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| let pipelines = res?.data ?? []; | |
| return pipelines; | |
| }; | |
| export const uploadPipeline = async (token: string, file: File, urlIdx: string) => { | |
| let error = null; | |
| // Create a new FormData object to handle the file upload | |
| const formData = new FormData(); | |
| formData.append('file', file); | |
| formData.append('urlIdx', urlIdx); | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/upload`, { | |
| method: 'POST', | |
| headers: { | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| // 'Content-Type': 'multipart/form-data' is not needed as Fetch API will set it automatically | |
| }, | |
| body: formData | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const downloadPipeline = async (token: string, url: string, urlIdx: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/add`, { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| }, | |
| body: JSON.stringify({ | |
| url: url, | |
| urlIdx: urlIdx | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const deletePipeline = async (token: string, id: string, urlIdx: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/delete`, { | |
| method: 'DELETE', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| }, | |
| body: JSON.stringify({ | |
| id: id, | |
| urlIdx: urlIdx | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getPipelines = async (token: string, urlIdx?: string) => { | |
| let error = null; | |
| const searchParams = new URLSearchParams(); | |
| if (urlIdx !== undefined) { | |
| searchParams.append('urlIdx', urlIdx); | |
| } | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/v1/pipelines/?${searchParams.toString()}`, { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| let pipelines = res?.data ?? []; | |
| return pipelines; | |
| }; | |
| export const getPipelineValves = async (token: string, pipeline_id: string, urlIdx: string) => { | |
| let error = null; | |
| const searchParams = new URLSearchParams(); | |
| if (urlIdx !== undefined) { | |
| searchParams.append('urlIdx', urlIdx); | |
| } | |
| const res = await fetch( | |
| `${WEBUI_BASE_URL}/api/v1/pipelines/${pipeline_id}/valves?${searchParams.toString()}`, | |
| { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| } | |
| ) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getPipelineValvesSpec = async (token: string, pipeline_id: string, urlIdx: string) => { | |
| let error = null; | |
| const searchParams = new URLSearchParams(); | |
| if (urlIdx !== undefined) { | |
| searchParams.append('urlIdx', urlIdx); | |
| } | |
| const res = await fetch( | |
| `${WEBUI_BASE_URL}/api/v1/pipelines/${pipeline_id}/valves/spec?${searchParams.toString()}`, | |
| { | |
| method: 'GET', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| } | |
| } | |
| ) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const updatePipelineValves = async ( | |
| token: string = '', | |
| pipeline_id: string, | |
| valves: object, | |
| urlIdx: string | |
| ) => { | |
| let error = null; | |
| const searchParams = new URLSearchParams(); | |
| if (urlIdx !== undefined) { | |
| searchParams.append('urlIdx', urlIdx); | |
| } | |
| const res = await fetch( | |
| `${WEBUI_BASE_URL}/api/v1/pipelines/${pipeline_id}/valves/update?${searchParams.toString()}`, | |
| { | |
| method: 'POST', | |
| headers: { | |
| Accept: 'application/json', | |
| 'Content-Type': 'application/json', | |
| ...(token && { authorization: `Bearer ${token}` }) | |
| }, | |
| body: JSON.stringify(valves) | |
| } | |
| ) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| if ('detail' in err) { | |
| error = err.detail; | |
| } else { | |
| error = err; | |
| } | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getUsage = async (token: string = '') => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/usage`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| ...(token && { Authorization: `Bearer ${token}` }) | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getBackendConfig = async () => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/config`, { | |
| method: 'GET', | |
| credentials: 'include', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getChangelog = async () => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/changelog`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getVersionUpdates = async (token: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/version/updates`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getModelFilterConfig = async (token: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/config/model/filter`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const updateModelFilterConfig = async ( | |
| token: string, | |
| enabled: boolean, | |
| models: string[] | |
| ) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/config/model/filter`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| enabled: enabled, | |
| models: models | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getWebhookUrl = async (token: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/webhook`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res.url; | |
| }; | |
| export const updateWebhookUrl = async (token: string, url: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/webhook`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| url: url | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res.url; | |
| }; | |
| export const getCommunitySharingEnabledStatus = async (token: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/community_sharing`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const toggleCommunitySharingEnabledStatus = async (token: string) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/community_sharing/toggle`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err.detail; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |
| export const getModelConfig = async (token: string): Promise<GlobalModelConfig> => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/config/models`, { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| } | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res.models; | |
| }; | |
| export interface ModelConfig { | |
| id: string; | |
| name: string; | |
| meta: ModelMeta; | |
| base_model_id?: string; | |
| params: ModelParams; | |
| } | |
| export interface ModelMeta { | |
| description?: string; | |
| capabilities?: object; | |
| profile_image_url?: string; | |
| } | |
| export interface ModelParams {} | |
| export type GlobalModelConfig = ModelConfig[]; | |
| export const updateModelConfig = async (token: string, config: GlobalModelConfig) => { | |
| let error = null; | |
| const res = await fetch(`${WEBUI_BASE_URL}/api/config/models`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| Authorization: `Bearer ${token}` | |
| }, | |
| body: JSON.stringify({ | |
| models: config | |
| }) | |
| }) | |
| .then(async (res) => { | |
| if (!res.ok) throw await res.json(); | |
| return res.json(); | |
| }) | |
| .catch((err) => { | |
| console.error(err); | |
| error = err; | |
| return null; | |
| }); | |
| if (error) { | |
| throw error; | |
| } | |
| return res; | |
| }; | |