forked from open-webui/open-webui
refac
This commit is contained in:
parent
8f570bc2ee
commit
3853261b40
3 changed files with 134 additions and 114 deletions
|
@ -249,7 +249,8 @@ export const deleteModel = async (token: string, tagName: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const pullModel = async (token: string, tagName: string) => {
|
export const pullModel = async (token: string, tagName: string) => {
|
||||||
try {
|
let error = null;
|
||||||
|
|
||||||
const res = await fetch(`${OLLAMA_API_BASE_URL}/pull`, {
|
const res = await fetch(`${OLLAMA_API_BASE_URL}/pull`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -259,9 +260,31 @@ try {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: tagName
|
name: tagName
|
||||||
})
|
})
|
||||||
})
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
error = err;
|
||||||
|
|
||||||
|
if ('detail' in err) {
|
||||||
|
error = err.detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// export const pullModel = async (token: string, tagName: string) => {
|
||||||
|
// return await fetch(`${OLLAMA_API_BASE_URL}/pull`, {
|
||||||
|
// method: 'POST',
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'text/event-stream',
|
||||||
|
// Authorization: `Bearer ${token}`
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify({
|
||||||
|
// name: tagName
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
|
@ -51,7 +51,11 @@
|
||||||
let notificationEnabled = false;
|
let notificationEnabled = false;
|
||||||
let system = '';
|
let system = '';
|
||||||
const MAX_PARALLEL_DOWNLOADS = 3;
|
const MAX_PARALLEL_DOWNLOADS = 3;
|
||||||
const modelDownloadQueue = queue((task:{modelName: string}, cb) => pullModelHandlerProcessor({modelName: task.modelName, callback: cb}), MAX_PARALLEL_DOWNLOADS);
|
const modelDownloadQueue = queue(
|
||||||
|
(task: { modelName: string }, cb) =>
|
||||||
|
pullModelHandlerProcessor({ modelName: task.modelName, callback: cb }),
|
||||||
|
MAX_PARALLEL_DOWNLOADS
|
||||||
|
);
|
||||||
let modelDownloadStatus: Record<string, any> = {};
|
let modelDownloadStatus: Record<string, any> = {};
|
||||||
|
|
||||||
// Advanced
|
// Advanced
|
||||||
|
@ -250,11 +254,13 @@
|
||||||
saveSettings({ saveChatHistory: saveChatHistory });
|
saveSettings({ saveChatHistory: saveChatHistory });
|
||||||
};
|
};
|
||||||
|
|
||||||
const pullModelHandlerProcessor = async (opts:{modelName:string, callback: Function}) => {
|
const pullModelHandlerProcessor = async (opts: { modelName: string; callback: Function }) => {
|
||||||
|
const res = await pullModel(localStorage.token, opts.modelName).catch((error) => {
|
||||||
|
opts.callback({ success: false, error, modelName: opts.modelName });
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
if (res) {
|
||||||
const res = await pullModel(localStorage.token, opts.modelName);
|
|
||||||
|
|
||||||
const reader = res.body
|
const reader = res.body
|
||||||
.pipeThrough(new TextDecoderStream())
|
.pipeThrough(new TextDecoderStream())
|
||||||
.pipeThrough(splitStream('\n'))
|
.pipeThrough(splitStream('\n'))
|
||||||
|
@ -270,102 +276,70 @@
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (line !== '') {
|
if (line !== '') {
|
||||||
let data = JSON.parse(line);
|
let data = JSON.parse(line);
|
||||||
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.status) {
|
if (data.status) {
|
||||||
if (data.digest) {
|
if (data.digest) {
|
||||||
let downloadProgress = 0;
|
let downloadProgress = 0;
|
||||||
if (data.completed) {
|
if (data.completed) {
|
||||||
downloadProgress = Math.round((data.completed / data.total) * 1000) / 10;
|
downloadProgress = Math.round((data.completed / data.total) * 1000) / 10;
|
||||||
} else {
|
} else {
|
||||||
downloadProgress = 100;
|
downloadProgress = 100;
|
||||||
}
|
}
|
||||||
modelDownloadStatus[opts.modelName] = {pullProgress: downloadProgress, digest: data.digest};
|
modelDownloadStatus[opts.modelName] = {
|
||||||
|
pullProgress: downloadProgress,
|
||||||
|
digest: data.digest
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Failed to read from data stream', error);
|
console.log(error);
|
||||||
throw error;
|
opts.callback({ success: false, error, modelName: opts.modelName });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opts.callback({success: true, modelName: opts.modelName});
|
opts.callback({ success: true, modelName: opts.modelName });
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
opts.callback({success:false, error, modelName: opts.modelName});
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pullModelHandler = async () => {
|
||||||
};
|
if (modelDownloadStatus[modelTag]) {
|
||||||
|
toast.error('Model already in queue for downloading.');
|
||||||
const pullModelHandler = async() => {
|
|
||||||
if(modelDownloadStatus[modelTag]){
|
|
||||||
toast.error("Model already in queue for downloading.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(Object.keys(modelDownloadStatus).length === 3){
|
if (Object.keys(modelDownloadStatus).length === 3) {
|
||||||
toast.error('Maximum of 3 models can be downloading simultaneously. Please try again later');
|
toast.error('Maximum of 3 models can be downloading simultaneously. Please try again later');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
modelTransferring = true;
|
modelTransferring = true;
|
||||||
|
|
||||||
modelDownloadQueue.push({modelName: modelTag},async (data:{modelName: string; success: boolean; error?: Error}) => {
|
modelDownloadQueue.push(
|
||||||
const {modelName} = data;
|
{ modelName: modelTag },
|
||||||
// Remove the downloaded model
|
async (data: { modelName: string; success: boolean; error?: Error }) => {
|
||||||
delete modelDownloadStatus[modelName];
|
const { modelName } = data;
|
||||||
|
// Remove the downloaded model
|
||||||
|
delete modelDownloadStatus[modelName];
|
||||||
|
|
||||||
if(!data.success){
|
console.log(data);
|
||||||
toast.error(`There was some issue in downloading the model ${modelName}`);
|
|
||||||
return;
|
if (!data.success) {
|
||||||
|
toast.error(data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success(`Model ${modelName} was successfully downloaded`);
|
||||||
|
models.set(await getModels());
|
||||||
}
|
}
|
||||||
|
);
|
||||||
toast.success(`Model ${modelName} was successfully downloaded`);
|
|
||||||
models.set(await getModels());
|
|
||||||
});
|
|
||||||
|
|
||||||
modelTag = '';
|
modelTag = '';
|
||||||
modelTransferring = false;
|
modelTransferring = false;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const calculateSHA256 = async (file) => {
|
|
||||||
console.log(file);
|
|
||||||
// Create a FileReader to read the file asynchronously
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
// Define a promise to handle the file reading
|
|
||||||
const readFile = new Promise((resolve, reject) => {
|
|
||||||
reader.onload = () => resolve(reader.result);
|
|
||||||
reader.onerror = reject;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Read the file as an ArrayBuffer
|
|
||||||
reader.readAsArrayBuffer(file);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Wait for the FileReader to finish reading the file
|
|
||||||
const buffer = await readFile;
|
|
||||||
|
|
||||||
// Convert the ArrayBuffer to a Uint8Array
|
|
||||||
const uint8Array = new Uint8Array(buffer);
|
|
||||||
|
|
||||||
// Calculate the SHA-256 hash using Web Crypto API
|
|
||||||
const hashBuffer = await crypto.subtle.digest('SHA-256', uint8Array);
|
|
||||||
|
|
||||||
// Convert the hash to a hexadecimal string
|
|
||||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
||||||
const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
||||||
|
|
||||||
return `sha256:${hashHex}`;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error calculating SHA-256 hash:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const uploadModelHandler = async () => {
|
const uploadModelHandler = async () => {
|
||||||
|
@ -1190,35 +1164,23 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if Object.keys(modelDownloadStatus).length > 0}
|
{#if Object.keys(modelDownloadStatus).length > 0}
|
||||||
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
{#each Object.entries(modelDownloadStatus) as [modelName, payload]}
|
||||||
<thead
|
<div class="flex flex-col">
|
||||||
class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"
|
<div class="font-medium mb-0.5">{modelName}</div>
|
||||||
>
|
<div class="">
|
||||||
<tr>
|
|
||||||
<th scope="col" class="px-6 py-3"> Model Name </th>
|
|
||||||
<th scope="col" class="px-6 py-3"> Download progress </th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{#each Object.entries(modelDownloadStatus) as [modelName, payload]}
|
|
||||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
|
||||||
<td class="px-6 py-4">{modelName}</td>
|
|
||||||
<td class="px-6 py-4">
|
|
||||||
<div
|
<div
|
||||||
class="dark:bg-gray-600 bg-green-600 text-xs font-medium text-blue-100 text-center p-0.5 leading-none rounded-full"
|
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
|
||||||
style="width: {Math.max(15, payload.pullProgress ?? 0)}%"
|
style="width: {Math.max(15, payload.pullProgress ?? 0)}%"
|
||||||
>
|
>
|
||||||
{ payload.pullProgress ?? 0}%
|
{payload.pullProgress ?? 0}%
|
||||||
|
</div>
|
||||||
|
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
|
||||||
|
{payload.digest}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
|
</div>
|
||||||
{payload.digest}
|
{/each}
|
||||||
</div>
|
{/if}
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{/if}
|
|
||||||
<hr class=" dark:border-gray-700" />
|
<hr class=" dark:border-gray-700" />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -127,3 +127,38 @@ export const findWordIndices = (text) => {
|
||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const calculateSHA256 = async (file) => {
|
||||||
|
console.log(file);
|
||||||
|
// Create a FileReader to read the file asynchronously
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
// Define a promise to handle the file reading
|
||||||
|
const readFile = new Promise((resolve, reject) => {
|
||||||
|
reader.onload = () => resolve(reader.result);
|
||||||
|
reader.onerror = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read the file as an ArrayBuffer
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Wait for the FileReader to finish reading the file
|
||||||
|
const buffer = await readFile;
|
||||||
|
|
||||||
|
// Convert the ArrayBuffer to a Uint8Array
|
||||||
|
const uint8Array = new Uint8Array(buffer);
|
||||||
|
|
||||||
|
// Calculate the SHA-256 hash using Web Crypto API
|
||||||
|
const hashBuffer = await crypto.subtle.digest('SHA-256', uint8Array);
|
||||||
|
|
||||||
|
// Convert the hash to a hexadecimal string
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||||
|
const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, '0')).join('');
|
||||||
|
|
||||||
|
return `sha256:${hashHex}`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error calculating SHA-256 hash:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue