forked from open-webui/open-webui
		
	main #3
					 5 changed files with 93 additions and 53 deletions
				
			
		|  | @ -271,7 +271,7 @@ export const generateChatCompletion = async (token: string = '', body: object) = | ||||||
| 	return [res, controller]; | 	return [res, controller]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const cancelChatCompletion = async (token: string = '', requestId: string) => { | export const cancelOllamaRequest = async (token: string = '', requestId: string) => { | ||||||
| 	let error = null; | 	let error = null; | ||||||
| 
 | 
 | ||||||
| 	const res = await fetch(`${OLLAMA_API_BASE_URL}/cancel/${requestId}`, { | 	const res = await fetch(`${OLLAMA_API_BASE_URL}/cancel/${requestId}`, { | ||||||
|  |  | ||||||
|  | @ -7,7 +7,8 @@ | ||||||
| 		deleteModel, | 		deleteModel, | ||||||
| 		getOllamaUrls, | 		getOllamaUrls, | ||||||
| 		getOllamaVersion, | 		getOllamaVersion, | ||||||
| 		pullModel | 		pullModel, | ||||||
|  | 		cancelOllamaRequest | ||||||
| 	} from '$lib/apis/ollama'; | 	} from '$lib/apis/ollama'; | ||||||
| 	import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; | 	import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; | ||||||
| 	import { WEBUI_NAME, models, user } from '$lib/stores'; | 	import { WEBUI_NAME, models, user } from '$lib/stores'; | ||||||
|  | @ -364,12 +365,24 @@ | ||||||
| 					for (const line of lines) { | 					for (const line of lines) { | ||||||
| 						if (line !== '') { | 						if (line !== '') { | ||||||
| 							let data = JSON.parse(line); | 							let data = JSON.parse(line); | ||||||
|  | 							console.log(data); | ||||||
| 							if (data.error) { | 							if (data.error) { | ||||||
| 								throw data.error; | 								throw data.error; | ||||||
| 							} | 							} | ||||||
| 							if (data.detail) { | 							if (data.detail) { | ||||||
| 								throw data.detail; | 								throw data.detail; | ||||||
| 							} | 							} | ||||||
|  | 
 | ||||||
|  | 							if (data.id) { | ||||||
|  | 								modelDownloadStatus[opts.modelName] = { | ||||||
|  | 									...modelDownloadStatus[opts.modelName], | ||||||
|  | 									requestId: data.id, | ||||||
|  | 									reader, | ||||||
|  | 									done: false | ||||||
|  | 								}; | ||||||
|  | 								console.log(data); | ||||||
|  | 							} | ||||||
|  | 
 | ||||||
| 							if (data.status) { | 							if (data.status) { | ||||||
| 								if (data.digest) { | 								if (data.digest) { | ||||||
| 									let downloadProgress = 0; | 									let downloadProgress = 0; | ||||||
|  | @ -379,12 +392,17 @@ | ||||||
| 										downloadProgress = 100; | 										downloadProgress = 100; | ||||||
| 									} | 									} | ||||||
| 									modelDownloadStatus[opts.modelName] = { | 									modelDownloadStatus[opts.modelName] = { | ||||||
| 										reader, | 										...modelDownloadStatus[opts.modelName], | ||||||
| 										pullProgress: downloadProgress, | 										pullProgress: downloadProgress, | ||||||
| 										digest: data.digest | 										digest: data.digest | ||||||
| 									}; | 									}; | ||||||
| 								} else { | 								} else { | ||||||
| 									toast.success(data.status); | 									toast.success(data.status); | ||||||
|  | 
 | ||||||
|  | 									modelDownloadStatus[opts.modelName] = { | ||||||
|  | 										...modelDownloadStatus[opts.modelName], | ||||||
|  | 										done: data.status === 'success' | ||||||
|  | 									}; | ||||||
| 								} | 								} | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
|  | @ -397,7 +415,14 @@ | ||||||
| 					opts.callback({ success: false, error, modelName: opts.modelName }); | 					opts.callback({ success: false, error, modelName: opts.modelName }); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			opts.callback({ success: true, modelName: opts.modelName }); | 
 | ||||||
|  | 			console.log(modelDownloadStatus[opts.modelName]); | ||||||
|  | 
 | ||||||
|  | 			if (modelDownloadStatus[opts.modelName].done) { | ||||||
|  | 				opts.callback({ success: true, modelName: opts.modelName }); | ||||||
|  | 			} else { | ||||||
|  | 				opts.callback({ success: false, error: 'Download canceled', modelName: opts.modelName }); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | @ -467,10 +492,13 @@ | ||||||
| 		ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false); | 		ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false); | ||||||
| 		liteLLMModelInfo = await getLiteLLMModelInfo(localStorage.token); | 		liteLLMModelInfo = await getLiteLLMModelInfo(localStorage.token); | ||||||
| 	}); | 	}); | ||||||
| 	const deleteModelPull = async (model: string) => { | 
 | ||||||
| 		const { reader } = modelDownloadStatus[model]; | 	const cancelModelPullHandler = async (model: string) => { | ||||||
|  | 		const { reader, requestId } = modelDownloadStatus[model]; | ||||||
| 		if (reader) { | 		if (reader) { | ||||||
| 			await reader.cancel(); | 			await reader.cancel(); | ||||||
|  | 
 | ||||||
|  | 			await cancelOllamaRequest(localStorage.token, requestId); | ||||||
| 			delete modelDownloadStatus[model]; | 			delete modelDownloadStatus[model]; | ||||||
| 			await deleteModel(localStorage.token, model); | 			await deleteModel(localStorage.token, model); | ||||||
| 			toast.success(`${model} download has been canceled`); | 			toast.success(`${model} download has been canceled`); | ||||||
|  | @ -606,46 +634,58 @@ | ||||||
| 
 | 
 | ||||||
| 						{#if Object.keys(modelDownloadStatus).length > 0} | 						{#if Object.keys(modelDownloadStatus).length > 0} | ||||||
| 							{#each Object.keys(modelDownloadStatus) as model} | 							{#each Object.keys(modelDownloadStatus) as model} | ||||||
| 								<div class="flex flex-col"> | 								{#if 'pullProgress' in modelDownloadStatus[model]} | ||||||
| 									<div class="font-medium mb-1">{model}</div> | 									<div class="flex flex-col"> | ||||||
| 									<div class=""> | 										<div class="font-medium mb-1">{model}</div> | ||||||
| 										<div class="flex flex-row space-x-4 pr-2"> | 										<div class=""> | ||||||
| 											<div | 											<div class="flex flex-row justify-between space-x-4 pr-2"> | ||||||
| 												class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full" | 												<div class=" flex-1"> | ||||||
| 												style="width: {Math.max(15, modelDownloadStatus[model].pullProgress ?? 0)}%" | 													<div | ||||||
| 											> | 														class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full" | ||||||
| 												{modelDownloadStatus[model].pullProgress ?? 0}% | 														style="width: {Math.max( | ||||||
|  | 															15, | ||||||
|  | 															modelDownloadStatus[model].pullProgress ?? 0 | ||||||
|  | 														)}%" | ||||||
|  | 													> | ||||||
|  | 														{modelDownloadStatus[model].pullProgress ?? 0}% | ||||||
|  | 													</div> | ||||||
|  | 												</div> | ||||||
|  | 
 | ||||||
|  | 												<Tooltip content="Cancel"> | ||||||
|  | 													<button | ||||||
|  | 														class="text-gray-800 dark:text-gray-100" | ||||||
|  | 														on:click={() => { | ||||||
|  | 															cancelModelPullHandler(model); | ||||||
|  | 														}} | ||||||
|  | 													> | ||||||
|  | 														<svg | ||||||
|  | 															class="w-4 h-4 text-gray-800 dark:text-white" | ||||||
|  | 															aria-hidden="true" | ||||||
|  | 															xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 															width="24" | ||||||
|  | 															height="24" | ||||||
|  | 															fill="currentColor" | ||||||
|  | 															viewBox="0 0 24 24" | ||||||
|  | 														> | ||||||
|  | 															<path | ||||||
|  | 																stroke="currentColor" | ||||||
|  | 																stroke-linecap="round" | ||||||
|  | 																stroke-linejoin="round" | ||||||
|  | 																stroke-width="2" | ||||||
|  | 																d="M6 18 17.94 6M18 18 6.06 6" | ||||||
|  | 															/> | ||||||
|  | 														</svg> | ||||||
|  | 													</button> | ||||||
|  | 												</Tooltip> | ||||||
| 											</div> | 											</div> | ||||||
| 											<button | 											{#if 'digest' in modelDownloadStatus[model]} | ||||||
| 												class="text-gray-800 dark:text-gray-100" | 												<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;"> | ||||||
| 												on:click={() => { | 													{modelDownloadStatus[model].digest} | ||||||
| 													deleteModelPull(model); | 												</div> | ||||||
| 												}} | 											{/if} | ||||||
| 											> |  | ||||||
| 												<svg |  | ||||||
| 													class="w-4 h-4 text-gray-800 dark:text-white" |  | ||||||
| 													aria-hidden="true" |  | ||||||
| 													xmlns="http://www.w3.org/2000/svg" |  | ||||||
| 													width="24" |  | ||||||
| 													height="24" |  | ||||||
| 													fill="currentColor" |  | ||||||
| 													viewBox="0 0 24 24" |  | ||||||
| 												> |  | ||||||
| 													<path |  | ||||||
| 														stroke="currentColor" |  | ||||||
| 														stroke-linecap="round" |  | ||||||
| 														stroke-linejoin="round" |  | ||||||
| 														stroke-width="2" |  | ||||||
| 														d="M6 18 17.94 6M18 18 6.06 6" |  | ||||||
| 													/> |  | ||||||
| 												</svg> |  | ||||||
| 											</button> |  | ||||||
| 										</div> |  | ||||||
| 										<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;"> |  | ||||||
| 											{modelDownloadStatus[model].digest} |  | ||||||
| 										</div> | 										</div> | ||||||
| 									</div> | 									</div> | ||||||
| 								</div> | 								{/if} | ||||||
| 							{/each} | 							{/each} | ||||||
| 						{/if} | 						{/if} | ||||||
| 					</div> | 					</div> | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| 	} from '$lib/stores'; | 	} from '$lib/stores'; | ||||||
| 	import { copyToClipboard, splitStream } from '$lib/utils'; | 	import { copyToClipboard, splitStream } from '$lib/utils'; | ||||||
| 
 | 
 | ||||||
| 	import { generateChatCompletion, cancelChatCompletion, generateTitle } from '$lib/apis/ollama'; | 	import { generateChatCompletion, cancelOllamaRequest, generateTitle } from '$lib/apis/ollama'; | ||||||
| 	import { | 	import { | ||||||
| 		addTagById, | 		addTagById, | ||||||
| 		createNewChat, | 		createNewChat, | ||||||
|  | @ -104,7 +104,7 @@ | ||||||
| 
 | 
 | ||||||
| 	const initNewChat = async () => { | 	const initNewChat = async () => { | ||||||
| 		if (currentRequestId !== null) { | 		if (currentRequestId !== null) { | ||||||
| 			await cancelChatCompletion(localStorage.token, currentRequestId); | 			await cancelOllamaRequest(localStorage.token, currentRequestId); | ||||||
| 			currentRequestId = null; | 			currentRequestId = null; | ||||||
| 		} | 		} | ||||||
| 		window.history.replaceState(history.state, '', `/`); | 		window.history.replaceState(history.state, '', `/`); | ||||||
|  | @ -372,7 +372,7 @@ | ||||||
| 
 | 
 | ||||||
| 					if (stopResponseFlag) { | 					if (stopResponseFlag) { | ||||||
| 						controller.abort('User: Stop Response'); | 						controller.abort('User: Stop Response'); | ||||||
| 						await cancelChatCompletion(localStorage.token, currentRequestId); | 						await cancelOllamaRequest(localStorage.token, currentRequestId); | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					currentRequestId = null; | 					currentRequestId = null; | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| 	} from '$lib/stores'; | 	} from '$lib/stores'; | ||||||
| 	import { copyToClipboard, splitStream, convertMessagesToHistory } from '$lib/utils'; | 	import { copyToClipboard, splitStream, convertMessagesToHistory } from '$lib/utils'; | ||||||
| 
 | 
 | ||||||
| 	import { generateChatCompletion, generateTitle, cancelChatCompletion } from '$lib/apis/ollama'; | 	import { generateChatCompletion, generateTitle, cancelOllamaRequest } from '$lib/apis/ollama'; | ||||||
| 	import { | 	import { | ||||||
| 		addTagById, | 		addTagById, | ||||||
| 		createNewChat, | 		createNewChat, | ||||||
|  | @ -382,7 +382,7 @@ | ||||||
| 
 | 
 | ||||||
| 					if (stopResponseFlag) { | 					if (stopResponseFlag) { | ||||||
| 						controller.abort('User: Stop Response'); | 						controller.abort('User: Stop Response'); | ||||||
| 						await cancelChatCompletion(localStorage.token, currentRequestId); | 						await cancelOllamaRequest(localStorage.token, currentRequestId); | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					currentRequestId = null; | 					currentRequestId = null; | ||||||
|  | @ -843,7 +843,7 @@ | ||||||
| 			shareEnabled={messages.length > 0} | 			shareEnabled={messages.length > 0} | ||||||
| 			initNewChat={async () => { | 			initNewChat={async () => { | ||||||
| 				if (currentRequestId !== null) { | 				if (currentRequestId !== null) { | ||||||
| 					await cancelChatCompletion(localStorage.token, currentRequestId); | 					await cancelOllamaRequest(localStorage.token, currentRequestId); | ||||||
| 					currentRequestId = null; | 					currentRequestId = null; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ | ||||||
| 	} from '$lib/constants'; | 	} from '$lib/constants'; | ||||||
| 	import { WEBUI_NAME, config, user, models, settings } from '$lib/stores'; | 	import { WEBUI_NAME, config, user, models, settings } from '$lib/stores'; | ||||||
| 
 | 
 | ||||||
| 	import { cancelChatCompletion, generateChatCompletion } from '$lib/apis/ollama'; | 	import { cancelOllamaRequest, generateChatCompletion } from '$lib/apis/ollama'; | ||||||
| 	import { generateOpenAIChatCompletion } from '$lib/apis/openai'; | 	import { generateOpenAIChatCompletion } from '$lib/apis/openai'; | ||||||
| 
 | 
 | ||||||
| 	import { splitStream } from '$lib/utils'; | 	import { splitStream } from '$lib/utils'; | ||||||
|  | @ -52,7 +52,7 @@ | ||||||
| 
 | 
 | ||||||
| 	// const cancelHandler = async () => { | 	// const cancelHandler = async () => { | ||||||
| 	// 	if (currentRequestId) { | 	// 	if (currentRequestId) { | ||||||
| 	// 		const res = await cancelChatCompletion(localStorage.token, currentRequestId); | 	// 		const res = await cancelOllamaRequest(localStorage.token, currentRequestId); | ||||||
| 	// 		currentRequestId = null; | 	// 		currentRequestId = null; | ||||||
| 	// 		loading = false; | 	// 		loading = false; | ||||||
| 	// 	} | 	// 	} | ||||||
|  | @ -95,7 +95,7 @@ | ||||||
| 				const { value, done } = await reader.read(); | 				const { value, done } = await reader.read(); | ||||||
| 				if (done || stopResponseFlag) { | 				if (done || stopResponseFlag) { | ||||||
| 					if (stopResponseFlag) { | 					if (stopResponseFlag) { | ||||||
| 						await cancelChatCompletion(localStorage.token, currentRequestId); | 						await cancelOllamaRequest(localStorage.token, currentRequestId); | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					currentRequestId = null; | 					currentRequestId = null; | ||||||
|  | @ -181,7 +181,7 @@ | ||||||
| 				const { value, done } = await reader.read(); | 				const { value, done } = await reader.read(); | ||||||
| 				if (done || stopResponseFlag) { | 				if (done || stopResponseFlag) { | ||||||
| 					if (stopResponseFlag) { | 					if (stopResponseFlag) { | ||||||
| 						await cancelChatCompletion(localStorage.token, currentRequestId); | 						await cancelOllamaRequest(localStorage.token, currentRequestId); | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					currentRequestId = null; | 					currentRequestId = null; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue