Integrate open-webui's frontend

This commit is contained in:
I. A. Naval 2025-06-28 16:00:02 -04:00
parent 3794459323
commit 482eec9d1f
Signed by: potato
GPG Key ID: D22B0F9008C43F2B
2 changed files with 180 additions and 25 deletions

View File

@ -51,7 +51,7 @@ class BackendService {
// Backend not ready yet
}
await new Promise(resolve => setTimeout(resolve, 30000));
await new Promise(resolve => setTimeout(resolve, 10000));
}
throw new Error("Backend failed to start within timeout period");
@ -64,6 +64,17 @@ class BackendService {
return this.baseUrl;
}
getOpenWebUIUrl(): string {
if (!this.baseUrl) {
throw new Error("Backend service not initialized");
}
return this.baseUrl;
}
isRunning(): boolean {
return this.baseUrl !== null;
}
async fetch(path: string, options?: RequestInit): Promise<Response> {
if (!this.baseUrl) {
throw new Error("Backend service not initialized");

View File

@ -7,6 +7,9 @@
let name = $state("");
let greetMsg = $state("");
let backendStatus = $state("Initializing...");
let isBackendRunning = $state(false);
let showWebUI = $state(false);
let webUIUrl = $state("");
async function greet(event: Event) {
event.preventDefault();
@ -14,47 +17,75 @@
greetMsg = await invoke("greet", { name });
}
function toggleWebUI() {
if (backendService.isRunning()) {
showWebUI = !showWebUI;
if (showWebUI) {
webUIUrl = backendService.getOpenWebUIUrl();
}
}
}
onMount(async () => {
try {
backendStatus = "Starting backend...";
await backendService.initialize();
backendStatus = `Backend running at ${backendService.getBaseUrl()}`;
isBackendRunning = true;
} catch (error) {
console.error("Failed to initialize backend:", error);
backendStatus = "Backend failed to start";
isBackendRunning = false;
}
});
</script>
<main class="container">
<h1>Welcome to Tauri + Svelte</h1>
{#if showWebUI}
<div class="webui-container">
<div class="webui-header">
<h2>Open WebUI</h2>
<button class="close-button" onclick={() => (showWebUI = false)}
>✕</button
>
</div>
<iframe src={webUIUrl} title="Open WebUI" class="webui-iframe"></iframe>
</div>
{:else}
<h1>Welcome to Tauri + Svelte</h1>
<div class="backend-status">
<h2>Backend Status</h2>
<p>{backendStatus}</p>
</div>
<div class="backend-status">
<h2>Backend Status</h2>
<p>{backendStatus}</p>
{#if isBackendRunning}
<button class="open-webui-button" onclick={toggleWebUI}>
🌐 Open WebUI
</button>
{/if}
</div>
<h1 class="text-2xl font-bold mb-4">Installed Ollama models</h1>
<ModelsPane />
<h1 class="text-2xl font-bold mb-4">Installed Ollama models</h1>
<ModelsPane />
<div class="row">
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo vite" alt="Vite Logo" />
</a>
<a href="https://tauri.app" target="_blank">
<img src="/tauri.svg" class="logo tauri" alt="Tauri Logo" />
</a>
<a href="https://kit.svelte.dev" target="_blank">
<img src="/svelte.svg" class="logo svelte-kit" alt="SvelteKit Logo" />
</a>
</div>
<p>Click on the Tauri, Vite, and SvelteKit logos to learn more.</p>
<div class="row">
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo vite" alt="Vite Logo" />
</a>
<a href="https://tauri.app" target="_blank">
<img src="/tauri.svg" class="logo tauri" alt="Tauri Logo" />
</a>
<a href="https://kit.svelte.dev" target="_blank">
<img src="/svelte.svg" class="logo svelte-kit" alt="SvelteKit Logo" />
</a>
</div>
<p>Click on the Tauri, Vite, and SvelteKit logos to learn more.</p>
<form class="row" onsubmit={greet}>
<input id="greet-input" placeholder="Enter a name..." bind:value={name} />
<button type="submit">Greet</button>
</form>
<p>{greetMsg}</p>
<form class="row" onsubmit={greet}>
<input id="greet-input" placeholder="Enter a name..." bind:value={name} />
<button type="submit">Greet</button>
</form>
<p>{greetMsg}</p>
{/if}
</main>
<style>
@ -156,6 +187,89 @@
margin-right: 5px;
}
.backend-status {
margin: 2em 0;
padding: 1em;
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.05);
}
.open-webui-button {
margin-top: 1em;
background-color: #24c8db;
border-color: #24c8db;
color: white;
font-weight: 600;
padding: 0.8em 1.5em;
border-radius: 8px;
cursor: pointer;
transition: all 0.25s;
}
.open-webui-button:hover {
background-color: #1ba7c7;
border-color: #1ba7c7;
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(36, 200, 219, 0.3);
}
.open-webui-button:active {
transform: translateY(0);
background-color: #158fa8;
}
.webui-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
z-index: 1000;
display: flex;
flex-direction: column;
}
.webui-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
border-bottom: 1px solid #e0e0e0;
background: #f8f9fa;
}
.webui-header h2 {
margin: 0;
color: #333;
}
.close-button {
background: #ff5757;
color: white;
border: none;
border-radius: 50%;
width: 32px;
height: 32px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: bold;
}
.close-button:hover {
background: #ff4757;
}
.webui-iframe {
flex: 1;
border: none;
width: 100%;
height: 100%;
}
@media (prefers-color-scheme: dark) {
:root {
color: #f6f6f6;
@ -174,5 +288,35 @@
button:active {
background-color: #0f0f0f69;
}
.backend-status {
background-color: rgba(255, 255, 255, 0.05);
}
.open-webui-button {
background-color: #24c8db;
color: #0f0f0f;
}
.open-webui-button:hover {
background-color: #1ba7c7;
}
.open-webui-button:active {
background-color: #158fa8;
}
.webui-container {
background: #2f2f2f;
}
.webui-header {
background: #1f1f1f;
border-bottom-color: #4a4a4a;
}
.webui-header h2 {
color: #f6f6f6;
}
}
</style>