This commit is contained in:
Timothy Jaeryang Baek 2025-01-12 12:53:55 -08:00
parent 58edd82696
commit 8f499475fd
6 changed files with 99 additions and 33 deletions

View File

@ -11,7 +11,7 @@ const config: ForgeConfig = {
packagerConfig: {
asar: true,
icon: 'public/assets/icon.png',
extraResource: ['public/assets', 'resources/python.tar.gz']
extraResource: ['public/assets', 'resources']
},
rebuildConfig: {},
makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})],

View File

@ -12,7 +12,7 @@
"lint": "eslint --ext .ts,.tsx .",
"format": "prettier --plugin-search-dir --write \"**/*.{js,ts,svelte,css,md,html,json}\"",
"create:conda-lock": "cd resources && rimraf conda-lock.yml && conda-lock -f environment.yml && cd -",
"create:python-tar": "rimraf ./resources/python.tar.gz && conda-lock install --prefix ./resources/python ./resources/conda-lock.yml && conda pack -p ./resources/python -o ./resources/python.tar.gz"
"create:python-tar": "rimraf ./resources/python.tar.gz && conda-lock install --prefix ./resources/python ./resources/conda-lock.yml && conda pack -p ./resources/python -o ./resources/python.tar.gz && rimraf ./resources/python"
},
"devDependencies": {
"@electron-forge/cli": "^7.6.0",

View File

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { installStatus, serverStatus } from './lib/stores';
import { installStatus, serverStatus, serverStartedAt } from './lib/stores';
import Main from './lib/components/Main.svelte';
@ -28,6 +28,9 @@
console.log('Server status:', event.data.data);
serverStatus.set(event.data.data);
if ($serverStatus) {
serverStartedAt.set(Date.now());
}
break;
default:

View File

@ -2,13 +2,15 @@
import { onMount } from 'svelte';
import { fly } from 'svelte/transition';
import { installStatus, serverStatus } from '../stores';
import { installStatus, serverStatus, serverStartedAt } from '../stores';
import Spinner from './common/Spinner.svelte';
import ArrowRightCircle from './icons/ArrowRightCircle.svelte';
import backgroundImage from '../assets/images/green.jpg';
let currentTime = Date.now();
let installing = false;
const continueHandler = async () => {
if (window?.electronAPI) {
@ -16,6 +18,16 @@
installing = true;
}
};
onMount(() => {
const interval = setInterval(() => {
currentTime = Date.now();
}, 1000); // Update every second
return () => {
clearInterval(interval); // Cleanup interval on destroy
};
});
</script>
{#if $installStatus === null}
@ -107,10 +119,22 @@
{:else if $installStatus === true}
<div class="flex-1 w-full flex justify-center relative">
<div class="m-auto">
<div class="flex flex-col gap-3">
<div class="flex flex-col gap-3 text-center">
<Spinner className="size-5" />
<div class=" font-secondary">Launching Open WebUI...</div>
{#if $serverStartedAt}
{#if currentTime - $serverStartedAt > 10000}
<div
class=" font-default text-xs"
in:fly={{ duration: 500, y: 10 }}
>
If it's your first time, it might take a few minutes to
start.
</div>
{/if}
{/if}
</div>
</div>
</div>

View File

@ -2,3 +2,5 @@ import { writable } from 'svelte/store';
export const installStatus = writable(null);
export const serverStatus = writable(null);
export const serverStartedAt = writable(null);

View File

@ -192,8 +192,13 @@ export function createAdHocSignCommand(envPath: string): string {
return `cd ${envPath} && codesign -s - -o 0x2 -f ${signList.join(' ')} && cd -`;
}
export async function installOpenWebUI(installationPath: string, version?: string) {
export async function installOpenWebUI(
installationPath: string,
version?: string
): Promise<boolean> {
console.log(installationPath);
// Build the appropriate unpack command based on the platform
let unpackCommand =
process.platform === 'win32'
? `${installationPath}\\Scripts\\activate.bat && pip install open-webui${version ? `==${version}` : ' -U'}`
@ -204,32 +209,47 @@ export async function installOpenWebUI(installationPath: string, version?: strin
// unpackCommand = `${createAdHocSignCommand(installationPath)}\n${unpackCommand}`;
// }
const commandProcess = exec(unpackCommand, {
shell: process.platform === 'win32' ? 'cmd.exe' : '/bin/bash'
});
// Wrap the logic in a Promise to properly handle async execution and return a boolean
return new Promise((resolve, reject) => {
const commandProcess = exec(unpackCommand, {
shell: process.platform === 'win32' ? 'cmd.exe' : '/bin/bash'
});
const onLog = (data) => {
console.log(data);
logEmitter.emit('log', data);
};
// Function to handle logging output
const onLog = (data: any) => {
console.log(data);
logEmitter.emit('log', data);
};
commandProcess.stdout?.on('data', onLog);
commandProcess.stderr?.on('data', onLog);
// Listen to stdout and stderr for logging
commandProcess.stdout?.on('data', onLog);
commandProcess.stderr?.on('data', onLog);
commandProcess.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
logEmitter.emit('log', `Child exited with code ${code}`);
// Handle the exit event
commandProcess.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
logEmitter.emit('log', `Child exited with code ${code}`);
if (code !== 0) {
log.error(`Failed to install open-webui: ${code}`);
logEmitter.emit('log', `Failed to install open-webui: ${code}`);
} else {
logEmitter.emit('log', 'open-webui installed successfully');
}
if (code !== 0) {
log.error(`Failed to install open-webui: ${code}`);
logEmitter.emit('log', `Failed to install open-webui: ${code}`);
resolve(false); // Resolve the Promise with `false` if the command fails
} else {
logEmitter.emit('log', 'open-webui installed successfully');
resolve(true); // Resolve the Promise with `true` if the command succeeds
}
});
// Handle errors during execution
commandProcess.on('error', (error) => {
log.error(`Error occurred while installing open-webui: ${error.message}`);
logEmitter.emit('log', `Error occurred while installing open-webui: ${error.message}`);
reject(error); // Reject the Promise if an unexpected error occurs
});
});
}
export async function installBundledPython(installationPath?: string) {
export async function installBundledPython(installationPath?: string): Promise<boolean> {
installationPath = installationPath || getBundledPythonInstallationPath();
const pythonTarPath = getBundledPythonTarPath();
@ -241,7 +261,7 @@ export async function installBundledPython(installationPath?: string) {
if (!fs.existsSync(pythonTarPath)) {
log.error('Python tarball not found');
logEmitter.emit('log', 'Python tarball not found'); // Emit log
return;
return false;
}
try {
@ -253,6 +273,7 @@ export async function installBundledPython(installationPath?: string) {
} catch (error) {
log.error(error);
logEmitter.emit('log', error); // Emit log
return false; // Return false to indicate failure
}
// Get the path to the installed Python binary
@ -261,7 +282,7 @@ export async function installBundledPython(installationPath?: string) {
if (!fs.existsSync(bundledPythonPath)) {
log.error('Python binary not found in install path');
logEmitter.emit('log', 'Python binary not found in install path'); // Emit log
return;
return false; // Return false to indicate failure
}
try {
@ -271,12 +292,17 @@ export async function installBundledPython(installationPath?: string) {
});
console.log('Installed Python Version:', pythonVersion.trim());
logEmitter.emit('log', `Installed Python Version: ${pythonVersion.trim()}`); // Emit log
return true; // Return true to indicate success
} catch (error) {
log.error('Failed to execute Python binary', error);
return false; // Return false to indicate failure
}
}
export async function installPackage(installationPath?: string) {
export async function installPackage(installationPath?: string): Promise<boolean> {
// Resolve the installation path or use the default bundled Python installation path
installationPath = installationPath || getBundledPythonInstallationPath();
// if (!isBundledPythonInstalled()) {
@ -288,24 +314,35 @@ export async function installPackage(installationPath?: string) {
// }
// }
console.log('Installing python...');
// Log the status for installation steps
console.log('Installing Python...');
try {
await installBundledPython(installationPath);
// Install the bundled Python
const res = await installBundledPython(installationPath);
if (!res) {
throw new Error('Failed to install bundled Python');
}
} catch (error) {
log.error('Failed to install bundled Python', error);
throw new Error('Failed to install bundled Python');
}
console.log('Installing open-webui...');
try {
await installOpenWebUI(installationPath);
// Install the Open-WebUI package
const success = await installOpenWebUI(installationPath);
if (!success) {
// Handle a scenario where `installOpenWebUI` returns `false`
log.error('Failed to install open-webui');
throw new Error('Failed to install open-webui');
}
} catch (error) {
// Log and throw an error if the Open-WebUI installation fails
log.error('Failed to install open-webui', error);
throw new Error('Failed to install open-webui');
}
// Return true if all installations are successful
return true;
}