forked from open-webui/open-webui
		
	feat: openai compatible api support
This commit is contained in:
		
							parent
							
								
									5e4dc98f44
								
							
						
					
					
						commit
						17c66fde0f
					
				
					 9 changed files with 260 additions and 85 deletions
				
			
		|  | @ -1,4 +1,176 @@ | |||
| export const getOpenAIModels = async ( | ||||
| import { OPENAI_API_BASE_URL } from '$lib/constants'; | ||||
| 
 | ||||
| export const getOpenAIUrl = async (token: string = '') => { | ||||
| 	let error = null; | ||||
| 
 | ||||
| 	const res = await fetch(`${OPENAI_API_BASE_URL}/url`, { | ||||
| 		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.log(err); | ||||
| 			if ('detail' in err) { | ||||
| 				error = err.detail; | ||||
| 			} else { | ||||
| 				error = 'Server connection failed'; | ||||
| 			} | ||||
| 			return null; | ||||
| 		}); | ||||
| 
 | ||||
| 	if (error) { | ||||
| 		throw error; | ||||
| 	} | ||||
| 
 | ||||
| 	return res.OPENAI_API_BASE_URL; | ||||
| }; | ||||
| 
 | ||||
| export const updateOpenAIUrl = async (token: string = '', url: string) => { | ||||
| 	let error = null; | ||||
| 
 | ||||
| 	const res = await fetch(`${OPENAI_API_BASE_URL}/url/update`, { | ||||
| 		method: 'POST', | ||||
| 		headers: { | ||||
| 			Accept: 'application/json', | ||||
| 			'Content-Type': 'application/json', | ||||
| 			...(token && { authorization: `Bearer ${token}` }) | ||||
| 		}, | ||||
| 		body: JSON.stringify({ | ||||
| 			url: url | ||||
| 		}) | ||||
| 	}) | ||||
| 		.then(async (res) => { | ||||
| 			if (!res.ok) throw await res.json(); | ||||
| 			return res.json(); | ||||
| 		}) | ||||
| 		.catch((err) => { | ||||
| 			console.log(err); | ||||
| 			if ('detail' in err) { | ||||
| 				error = err.detail; | ||||
| 			} else { | ||||
| 				error = 'Server connection failed'; | ||||
| 			} | ||||
| 			return null; | ||||
| 		}); | ||||
| 
 | ||||
| 	if (error) { | ||||
| 		throw error; | ||||
| 	} | ||||
| 
 | ||||
| 	return res.OPENAI_API_BASE_URL; | ||||
| }; | ||||
| 
 | ||||
| export const getOpenAIKey = async (token: string = '') => { | ||||
| 	let error = null; | ||||
| 
 | ||||
| 	const res = await fetch(`${OPENAI_API_BASE_URL}/key`, { | ||||
| 		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.log(err); | ||||
| 			if ('detail' in err) { | ||||
| 				error = err.detail; | ||||
| 			} else { | ||||
| 				error = 'Server connection failed'; | ||||
| 			} | ||||
| 			return null; | ||||
| 		}); | ||||
| 
 | ||||
| 	if (error) { | ||||
| 		throw error; | ||||
| 	} | ||||
| 
 | ||||
| 	return res.OPENAI_API_KEY; | ||||
| }; | ||||
| 
 | ||||
| export const updateOpenAIKey = async (token: string = '', key: string) => { | ||||
| 	let error = null; | ||||
| 
 | ||||
| 	const res = await fetch(`${OPENAI_API_BASE_URL}/key/update`, { | ||||
| 		method: 'POST', | ||||
| 		headers: { | ||||
| 			Accept: 'application/json', | ||||
| 			'Content-Type': 'application/json', | ||||
| 			...(token && { authorization: `Bearer ${token}` }) | ||||
| 		}, | ||||
| 		body: JSON.stringify({ | ||||
| 			key: key | ||||
| 		}) | ||||
| 	}) | ||||
| 		.then(async (res) => { | ||||
| 			if (!res.ok) throw await res.json(); | ||||
| 			return res.json(); | ||||
| 		}) | ||||
| 		.catch((err) => { | ||||
| 			console.log(err); | ||||
| 			if ('detail' in err) { | ||||
| 				error = err.detail; | ||||
| 			} else { | ||||
| 				error = 'Server connection failed'; | ||||
| 			} | ||||
| 			return null; | ||||
| 		}); | ||||
| 
 | ||||
| 	if (error) { | ||||
| 		throw error; | ||||
| 	} | ||||
| 
 | ||||
| 	return res.OPENAI_API_KEY; | ||||
| }; | ||||
| 
 | ||||
| export const getOpenAIModels = async (token: string = '') => { | ||||
| 	let error = null; | ||||
| 
 | ||||
| 	const res = await fetch(`${OPENAI_API_BASE_URL}/models`, { | ||||
| 		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.log(err); | ||||
| 			error = `OpenAI: ${err?.error?.message ?? 'Network Problem'}`; | ||||
| 			return []; | ||||
| 		}); | ||||
| 
 | ||||
| 	if (error) { | ||||
| 		throw error; | ||||
| 	} | ||||
| 
 | ||||
| 	const models = Array.isArray(res) ? res : res?.data ?? null; | ||||
| 
 | ||||
| 	return models | ||||
| 		? models | ||||
| 				.map((model) => ({ name: model.id, external: true })) | ||||
| 				.sort((a, b) => { | ||||
| 					return a.name.localeCompare(b.name); | ||||
| 				}) | ||||
| 		: models; | ||||
| }; | ||||
| 
 | ||||
| export const getOpenAIModelsDirect = async ( | ||||
| 	base_url: string = 'https://api.openai.com/v1', | ||||
| 	api_key: string = '' | ||||
| ) => { | ||||
|  |  | |||
|  | @ -24,6 +24,13 @@ | |||
| 	import { updateUserPassword } from '$lib/apis/auths'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import Page from '../../../routes/(app)/+page.svelte'; | ||||
| 	import { | ||||
| 		getOpenAIKey, | ||||
| 		getOpenAIModels, | ||||
| 		getOpenAIUrl, | ||||
| 		updateOpenAIKey, | ||||
| 		updateOpenAIUrl | ||||
| 	} from '$lib/apis/openai'; | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 
 | ||||
|  | @ -153,6 +160,13 @@ | |||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	const updateOpenAIHandler = async () => { | ||||
| 		OPENAI_API_BASE_URL = await updateOpenAIUrl(localStorage.token, OPENAI_API_BASE_URL); | ||||
| 		OPENAI_API_KEY = await updateOpenAIKey(localStorage.token, OPENAI_API_KEY); | ||||
| 
 | ||||
| 		await models.set(await getModels()); | ||||
| 	}; | ||||
| 
 | ||||
| 	const toggleTheme = async () => { | ||||
| 		if (theme === 'dark') { | ||||
| 			theme = 'light'; | ||||
|  | @ -484,7 +498,7 @@ | |||
| 	}; | ||||
| 
 | ||||
| 	const getModels = async (type = 'all') => { | ||||
| 		let models = []; | ||||
| 		const models = []; | ||||
| 		models.push( | ||||
| 			...(await getOllamaModels(localStorage.token).catch((error) => { | ||||
| 				toast.error(error); | ||||
|  | @ -493,43 +507,13 @@ | |||
| 		); | ||||
| 
 | ||||
| 		// If OpenAI API Key exists | ||||
| 		if (type === 'all' && $settings.OPENAI_API_KEY) { | ||||
| 			const OPENAI_API_BASE_URL = $settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1'; | ||||
| 		if (type === 'all' && OPENAI_API_KEY) { | ||||
| 			const openAIModels = await getOpenAIModels(localStorage.token).catch((error) => { | ||||
| 				console.log(error); | ||||
| 				return null; | ||||
| 			}); | ||||
| 
 | ||||
| 			// Validate OPENAI_API_KEY | ||||
| 			const openaiModelRes = await fetch(`${OPENAI_API_BASE_URL}/models`, { | ||||
| 				method: 'GET', | ||||
| 				headers: { | ||||
| 					'Content-Type': 'application/json', | ||||
| 					Authorization: `Bearer ${$settings.OPENAI_API_KEY}` | ||||
| 				} | ||||
| 			}) | ||||
| 				.then(async (res) => { | ||||
| 					if (!res.ok) throw await res.json(); | ||||
| 					return res.json(); | ||||
| 				}) | ||||
| 				.catch((error) => { | ||||
| 					console.log(error); | ||||
| 					toast.error(`OpenAI: ${error?.error?.message ?? 'Network Problem'}`); | ||||
| 					return null; | ||||
| 				}); | ||||
| 
 | ||||
| 			const openAIModels = Array.isArray(openaiModelRes) | ||||
| 				? openaiModelRes | ||||
| 				: openaiModelRes?.data ?? null; | ||||
| 
 | ||||
| 			models.push( | ||||
| 				...(openAIModels | ||||
| 					? [ | ||||
| 							{ name: 'hr' }, | ||||
| 							...openAIModels | ||||
| 								.map((model) => ({ name: model.id, external: true })) | ||||
| 								.filter((model) => | ||||
| 									OPENAI_API_BASE_URL.includes('openai') ? model.name.includes('gpt') : true | ||||
| 								) | ||||
| 					  ] | ||||
| 					: []) | ||||
| 			); | ||||
| 			models.push(...(openAIModels ? [{ name: 'hr' }, ...openAIModels] : [])); | ||||
| 		} | ||||
| 
 | ||||
| 		return models; | ||||
|  | @ -564,6 +548,8 @@ | |||
| 		console.log('settings', $user.role === 'admin'); | ||||
| 		if ($user.role === 'admin') { | ||||
| 			API_BASE_URL = await getOllamaAPIUrl(localStorage.token); | ||||
| 			OPENAI_API_BASE_URL = await getOpenAIUrl(localStorage.token); | ||||
| 			OPENAI_API_KEY = await getOpenAIKey(localStorage.token); | ||||
| 		} | ||||
| 
 | ||||
| 		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}'); | ||||
|  | @ -584,9 +570,6 @@ | |||
| 		options = { ...options, ...settings.options }; | ||||
| 		options.stop = (settings?.options?.stop ?? []).join(','); | ||||
| 
 | ||||
| 		OPENAI_API_KEY = settings.OPENAI_API_KEY ?? ''; | ||||
| 		OPENAI_API_BASE_URL = settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1'; | ||||
| 
 | ||||
| 		titleAutoGenerate = settings.titleAutoGenerate ?? true; | ||||
| 		speechAutoSend = settings.speechAutoSend ?? false; | ||||
| 		responseAutoCopy = settings.responseAutoCopy ?? false; | ||||
|  | @ -1415,10 +1398,12 @@ | |||
| 					<form | ||||
| 						class="flex flex-col h-full justify-between space-y-3 text-sm" | ||||
| 						on:submit|preventDefault={() => { | ||||
| 							saveSettings({ | ||||
| 								OPENAI_API_KEY: OPENAI_API_KEY !== '' ? OPENAI_API_KEY : undefined, | ||||
| 								OPENAI_API_BASE_URL: OPENAI_API_BASE_URL !== '' ? OPENAI_API_BASE_URL : undefined | ||||
| 							}); | ||||
| 							updateOpenAIHandler(); | ||||
| 
 | ||||
| 							// saveSettings({ | ||||
| 							// 	OPENAI_API_KEY: OPENAI_API_KEY !== '' ? OPENAI_API_KEY : undefined, | ||||
| 							// 	OPENAI_API_BASE_URL: OPENAI_API_BASE_URL !== '' ? OPENAI_API_BASE_URL : undefined | ||||
| 							// }); | ||||
| 							show = false; | ||||
| 						}} | ||||
| 					> | ||||
|  |  | |||
|  | @ -1,11 +1,10 @@ | |||
| import { dev } from '$app/environment'; | ||||
| 
 | ||||
| export const OLLAMA_API_BASE_URL = dev | ||||
| 	? `http://${location.hostname}:8080/ollama/api` | ||||
| 	: '/ollama/api'; | ||||
| 
 | ||||
| export const WEBUI_BASE_URL = dev ? `http://${location.hostname}:8080` : ``; | ||||
| 
 | ||||
| export const WEBUI_API_BASE_URL = `${WEBUI_BASE_URL}/api/v1`; | ||||
| export const OLLAMA_API_BASE_URL = `${WEBUI_BASE_URL}/ollama/api`; | ||||
| export const OPENAI_API_BASE_URL = `${WEBUI_BASE_URL}/openai/api`; | ||||
| 
 | ||||
| export const WEB_UI_VERSION = 'v1.0.0-alpha-static'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,19 +37,17 @@ | |||
| 				return []; | ||||
| 			})) | ||||
| 		); | ||||
| 		// If OpenAI API Key exists | ||||
| 		if ($settings.OPENAI_API_KEY) { | ||||
| 			const openAIModels = await getOpenAIModels( | ||||
| 				$settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1', | ||||
| 				$settings.OPENAI_API_KEY | ||||
| 			).catch((error) => { | ||||
| 				console.log(error); | ||||
| 				toast.error(error); | ||||
| 				return null; | ||||
| 			}); | ||||
| 
 | ||||
| 			models.push(...(openAIModels ? [{ name: 'hr' }, ...openAIModels] : [])); | ||||
| 		} | ||||
| 		// $settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1', | ||||
| 		// 		$settings.OPENAI_API_KEY | ||||
| 
 | ||||
| 		const openAIModels = await getOpenAIModels(localStorage.token).catch((error) => { | ||||
| 			console.log(error); | ||||
| 			return null; | ||||
| 		}); | ||||
| 
 | ||||
| 		models.push(...(openAIModels ? [{ name: 'hr' }, ...openAIModels] : [])); | ||||
| 
 | ||||
| 		return models; | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy J. Baek
						Timothy J. Baek