Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use chrono::{DateTime, Utc};
use rusqlite::{params, Connection};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tauri::{AppHandle, Emitter, Manager};
use tauri::{AppHandle, Manager};
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command};
use std::process::Stdio;
use uuid::Uuid;

// ---------- Data Models ------------------------------------------------------------
Expand Down Expand Up @@ -537,6 +539,34 @@ fn delete_document(
Ok(())
}

#[tauri::command]
async fn run_fine_tune(config: String, app: AppHandle) -> Result<(), String> {
let script_path = app
.path_resolver()
.resolve_resource("../backend/fine_tune.py")
.ok_or("Script not found")?;

let mut child = Command::new("python3")
.arg(script_path)
.arg(config)
.stdout(Stdio::piped())
.spawn()
.map_err(|e| e.to_string())?;

if let Some(stdout) = child.stdout.take() {
let app_handle = app.clone();
tauri::async_runtime::spawn(async move {
let mut reader = BufReader::new(stdout).lines();
while let Ok(Some(line)) = reader.next_line().await {
let _ = app_handle.emit("fine_tune_log", line);
}
});
}

child.wait().await.map_err(|e| e.to_string())?;
Ok(())
}

// ---------- Main Application ---------------------------------------------------

fn main() {
Expand Down Expand Up @@ -564,6 +594,7 @@ fn main() {
chat_with_documents,
get_chat_history,
delete_document,
run_fine_tune,
])
.run(tauri::generate_context!())
.expect("Error running RAG application");
Expand Down
36 changes: 36 additions & 0 deletions src/App.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import RagPanel from './components/RagPanel.svelte';
import FineTunePanel from './components/FineTunePanel.svelte';
import PlaygroundPanel from './components/PlaygroundPanel.svelte';
import { writable } from 'svelte/store';
import { darkMode } from './lib/theme';

type Panel = 'rag' | 'fine-tune' | 'playground';
const panel = writable<Panel>('rag');
</script>

<div class="min-h-screen bg-gray-50 dark:bg-gray-900 text-gray-800 dark:text-gray-100">
<header class="p-4 flex justify-between items-center border-b border-gray-200 dark:border-gray-700">
<h1 class="text-xl font-bold">RAG App</h1>
<div class="flex items-center gap-4">
<nav class="flex gap-4">
<button class="hover:underline" on:click={() => panel.set('rag')}>RAG</button>
<button class="hover:underline" on:click={() => panel.set('fine-tune')}>Fine-tune</button>
<button class="hover:underline" on:click={() => panel.set('playground')}>Playground</button>
</nav>
<label class="flex items-center gap-1 text-sm cursor-pointer">
<input type="checkbox" bind:checked={$darkMode} class="form-checkbox" />
Dark
</label>
</div>
</header>
<main class="p-4">
{#if $panel === 'rag'}
<RagPanel />
{:else if $panel === 'fine-tune'}
<FineTunePanel />
{:else if $panel === 'playground'}
<PlaygroundPanel />
{/if}
</main>
</div>
46 changes: 46 additions & 0 deletions src/components/FineTunePanel.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script lang="ts">
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { onDestroy } from 'svelte';

let datasetPath = '';
let modelName = '';
let logs: string[] = [];
let running = false;
let unlisten: (() => void) | undefined;

async function startFineTune() {
running = true;
logs = [];
unlisten = await listen<string>('fine_tune_log', (event) => {
logs = [...logs, event.payload];
});

try {
await invoke('run_fine_tune', { config: JSON.stringify({ datasetPath, modelName }) });
} catch (e) {
logs = [...logs, `Error: ${e}`];
}
running = false;
if (unlisten) unlisten();
}

function handleFileChange(event: Event) {
const target = event.target as HTMLInputElement;
datasetPath = (target.files?.[0] as any)?.path ?? '';
}

onDestroy(() => {
if (unlisten) unlisten();
});
</script>

<div class="space-y-4">
<h2 class="text-lg font-semibold">Fine-tune Model</h2>
<div class="flex flex-col gap-2 max-w-sm">
<input type="file" on:change={handleFileChange} class="border p-2 rounded" />
<input type="text" placeholder="Model name" bind:value={modelName} class="border p-2 rounded" />
<button class="bg-blue-600 text-white px-4 py-2 rounded" on:click={startFineTune} disabled={running}>Start</button>
</div>
<pre class="bg-gray-100 dark:bg-gray-800 p-2 rounded h-40 overflow-auto">{logs.join('\n')}</pre>
</div>
48 changes: 48 additions & 0 deletions src/components/PlaygroundPanel.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts">
import { invoke } from '@tauri-apps/api/core';

type Mode = 'base' | 'fine' | 'rag';
let message = '';
let mode: Mode = 'base';
let response = '';
let retrieved = '';
let loading = false;

async function send() {
if (!message.trim()) return;
loading = true;
try {
const res = await invoke<any>('chat_with_documents', { query: message });
response = res.message.content;
retrieved = res.sources.map((s: any) => s.relevant_chunks.join('\n')).join('\n');
} catch (e) {
response = 'Error';
}
loading = false;
}
</script>

<div class="space-y-4 max-w-xl">
<h2 class="text-lg font-semibold">Playground</h2>
<div class="flex gap-2">
<select bind:value={mode} class="border p-2 rounded">
<option value="base">Model base</option>
<option value="fine">Model po fine-tuningu</option>
<option value="rag">Model + RAG</option>
</select>
<input class="flex-1 border p-2 rounded" placeholder="Ask something" bind:value={message} />
<button on:click={send} class="bg-blue-600 text-white px-4 py-2 rounded" disabled={loading}>Send</button>
</div>
{#if response}
<div class="bg-gray-100 dark:bg-gray-800 p-3 rounded">
<h3 class="font-semibold mb-1">Response</h3>
<p>{response}</p>
</div>
{/if}
{#if mode === 'rag' && retrieved}
<div class="bg-gray-50 dark:bg-gray-700 p-3 rounded">
<h3 class="font-semibold mb-1">Retrieved context</h3>
<pre class="whitespace-pre-wrap">{retrieved}</pre>
</div>
{/if}
</div>
File renamed without changes.
12 changes: 12 additions & 0 deletions src/lib/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { writable } from 'svelte/store';

export const darkMode = writable(false);

if (typeof window !== 'undefined') {
const stored = localStorage.getItem('darkMode');
darkMode.set(stored === 'true');
darkMode.subscribe((val) => {
localStorage.setItem('darkMode', val ? 'true' : 'false');
document.documentElement.classList.toggle('dark', val);
});
}
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import App from './routes/+page.svelte';
import App from './App.svelte';
import './app.css';

const app = new App({
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
darkMode: 'class',
content: ['./index.html', './src/**/*.{js,ts,svelte}'],
theme: {
extend: {},
Expand Down
Loading