diff --git a/packages/kbot/dist/win-64/tauri-app.exe b/packages/kbot/dist/win-64/tauri-app.exe index 8473c4eb..f4749854 100644 Binary files a/packages/kbot/dist/win-64/tauri-app.exe and b/packages/kbot/dist/win-64/tauri-app.exe differ diff --git a/packages/kbot/gui/tauri-app/package.json b/packages/kbot/gui/tauri-app/package.json index d2755ec4..582f842b 100644 --- a/packages/kbot/gui/tauri-app/package.json +++ b/packages/kbot/gui/tauri-app/package.json @@ -7,7 +7,7 @@ "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", - "dist": "npm run tauri build", + "dist": "npm run tauri build -- --debug", "tauri": "tauri" }, "dependencies": { diff --git a/packages/kbot/gui/tauri-app/scripts/build.sh b/packages/kbot/gui/tauri-app/scripts/build.sh index 1a4ce1dd..fa093d37 100644 --- a/packages/kbot/gui/tauri-app/scripts/build.sh +++ b/packages/kbot/gui/tauri-app/scripts/build.sh @@ -1,2 +1,3 @@ npm run dist -cp src-tauri/target/release/tauri-app.exe ../../dist/win-64 \ No newline at end of file +# cp src-tauri/target/release/tauri-app.exe ../../dist/win-64 +cp src-tauri/target/debug/tauri-app.exe ../../dist/win-64 \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/Cargo.lock b/packages/kbot/gui/tauri-app/src-tauri/Cargo.lock index ad02bcba..f95ddb70 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/Cargo.lock +++ b/packages/kbot/gui/tauri-app/src-tauri/Cargo.lock @@ -117,11 +117,11 @@ dependencies = [ [[package]] name = "async-io" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", @@ -130,7 +130,7 @@ dependencies = [ "polling", "rustix", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel", "async-io", @@ -175,9 +175,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -188,7 +188,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -2837,16 +2837,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] diff --git a/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml b/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml index 74ff5e8f..941284df 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml +++ b/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml @@ -18,9 +18,9 @@ crate-type = ["staticlib", "cdylib", "rlib"] tauri-build = { version = "2", features = [] } [dependencies] -tauri = { version = "2", features = ["protocol-asset"] } -tauri-plugin-opener = "2.0.0" -tauri-plugin-dialog = "2.0.0" +tauri = { version = "2", features = ["protocol-asset", "devtools"] } +tauri-plugin-opener = "2.5.0" +tauri-plugin-dialog = "2.4.0" tauri-plugin-fs = "2.0.0" tauri-plugin-http = "2.0.0" serde = { version = "1", features = ["derive"] } diff --git a/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs b/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs index 09595efa..7f0431f9 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs +++ b/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs @@ -65,7 +65,7 @@ fn submit_prompt(prompt: &str, files: Vec, dst: &str, window: tauri::Win #[tauri::command] fn log_error_to_console(error: &str) { - eprintln!("[WebView ERROR forwarded from JS]: {}", error); + eprintln!("[WebView ERROR forwarded]: {}", error); } #[tauri::command] @@ -305,6 +305,12 @@ pub fn run() { generate_image_via_backend ]) .setup(|app| { + #[cfg(debug_assertions)] // only include this code on debug builds + { + let window = app.get_webview_window("main").unwrap(); + window.open_devtools(); + } + let app_handle = app.handle().clone(); // Listen for stdin commands from images.ts diff --git a/packages/kbot/gui/tauri-app/src-tauri/src/main.rs b/packages/kbot/gui/tauri-app/src-tauri/src/main.rs index 4a9b77a6..7f64dee7 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/src/main.rs +++ b/packages/kbot/gui/tauri-app/src-tauri/src/main.rs @@ -4,3 +4,4 @@ fn main() { tauri_app_lib::run() } + diff --git a/packages/kbot/gui/tauri-app/src/App.tsx b/packages/kbot/gui/tauri-app/src/App.tsx index f39e0d0d..272fafea 100644 --- a/packages/kbot/gui/tauri-app/src/App.tsx +++ b/packages/kbot/gui/tauri-app/src/App.tsx @@ -52,6 +52,28 @@ function App() { await tauriApi.addDebugMessage(message, level, data); }; + const addImageFromUrl = async (url: string) => { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch image: ${response.statusText}`); + } + const blob = await response.blob(); + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = () => { + const base64data = reader.result as string; + const newImageFile: ImageFile = { + path: `url_${Date.now()}.jpg`, + src: base64data, + }; + setFiles(prevFiles => [...prevFiles, newImageFile]); + }; + } catch (error) { + console.error('Failed to add image from URL:', error); + } + }; + useTauriListeners({ setPrompt, setDst, @@ -427,6 +449,7 @@ function App() { isGenerating={isGenerating} saveAndClose={saveAndClose} submit={submit} + addImageFromUrl={addImageFromUrl} /> {/* Debug Panel */} diff --git a/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx b/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx index d56fa1f7..1510a683 100644 --- a/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx +++ b/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx @@ -43,7 +43,7 @@ const DebugPanel: React.FC = ({ onClick={() => sendIPCMessage('test-message', { content: 'Hello from GUI', timestamp: Date.now() })} className="glass-button text-sm px-4 py-2 rounded-lg border-blue-400/50 text-blue-600 hover:bg-blue-500/20" > - Send IPC + Send IPC - DEPRECATED +
+ + +
diff --git a/packages/kbot/gui/tauri-app/src/lib/tauriApi.ts b/packages/kbot/gui/tauri-app/src/lib/tauriApi.ts index 9c1f66ee..33ce6977 100644 --- a/packages/kbot/gui/tauri-app/src/lib/tauriApi.ts +++ b/packages/kbot/gui/tauri-app/src/lib/tauriApi.ts @@ -1,131 +1,144 @@ -import { TauriCommand } from '../constants'; - -// Dynamically import Tauri APIs -let invoke: any; -let open: any; -let save: any; -let readFile: any; -let writeFile: any; -let BaseDirectory: any; -let listen: any; -let getCurrentWindow: any; - -let isTauri = false; -const isBrowser = typeof window !== 'undefined'; - -const apiInitializationPromise = (async () => { - if (!isBrowser) return; - - try { - const windowApi = await import('@tauri-apps/api/window'); - getCurrentWindow = windowApi.getCurrentWindow; - isTauri = true; - console.log('✅ Tauri window API loaded'); - - const coreApi = await import('@tauri-apps/api/core'); - invoke = coreApi.invoke; - - const eventApi = await import('@tauri-apps/api/event'); - listen = eventApi.listen; - - const dialogApi = await import('@tauri-apps/plugin-dialog'); - open = dialogApi.open; - save = dialogApi.save; - - const fsApi = await import('@tauri-apps/plugin-fs'); - readFile = fsApi.readFile; - writeFile = fsApi.writeFile; - BaseDirectory = fsApi.BaseDirectory; - } catch (e) { - console.warn('Tauri APIs not available, running in browser mode.'); - isTauri = false; - } -})(); - -export const ensureTauriApi = async () => { - await apiInitializationPromise; -}; - -// Safe invoke function -export const safeInvoke = async (command: TauriCommand, args?: any): Promise => { - await ensureTauriApi(); - if (isTauri && typeof invoke === 'function') { - try { - return await invoke(command, args); - } catch (error) { - console.error(`Invoke failed for command "${command}":`, error); - return null; - } - } else { - console.log(`[Browser Mode] Would invoke: ${command}`, args); - return null; - } -}; - -export { invoke, isTauri }; - -// Typed API wrappers -export const tauriApi = { - ensureTauriApi, - isTauri: () => isTauri, - listen: async (...args: Parameters) => { - await ensureTauriApi(); - return listen ? listen(...args) : () => {}; - }, - fs: { - readFile: async (...args: Parameters) => { - await ensureTauriApi(); - return readFile ? readFile(...args) : new Uint8Array(); - }, - writeFile: async (...args: Parameters) => { - await ensureTauriApi(); - if (writeFile) { - return writeFile(...args); - } - }, - BaseDirectory: () => BaseDirectory, - }, - dialog: { - open: async (...args: Parameters) => { - await ensureTauriApi(); - return open ? open(...args) : null; - }, - save: async (...args: Parameters) => { - await ensureTauriApi(); - return save ? save(...args) : null; - }, - }, - window: { - getCurrent: async () => { - await ensureTauriApi(); - return getCurrentWindow ? getCurrentWindow() : null; - }, - }, - // Add typed wrappers for your app's specific commands - resolvePathRelativeToHome: (absolutePath: string) => - safeInvoke(TauriCommand.RESOLVE_PATH_RELATIVE_TO_HOME, { absolutePath }), - - submitPrompt: (data: { prompt: string; files: string[]; dst: string }) => - safeInvoke(TauriCommand.SUBMIT_PROMPT, data), - - generateImageViaBackend: (data: { prompt: string; files: string[]; dst: string }) => - safeInvoke(TauriCommand.GENERATE_IMAGE_VIA_BACKEND, data), - - requestConfigFromImages: () => - safeInvoke(TauriCommand.REQUEST_CONFIG_FROM_IMAGES), - - addDebugMessage: (message: string, level: string, data?: any) => - safeInvoke(TauriCommand.ADD_DEBUG_MESSAGE, { message, level, data }), - - clearDebugMessages: () => - safeInvoke(TauriCommand.CLEAR_DEBUG_MESSAGES), - - sendMessageToStdout: (message: string) => - safeInvoke(TauriCommand.SEND_MESSAGE_TO_STDOUT, { message }), - - logErrorToConsole: (error: string) => - safeInvoke(TauriCommand.LOG_ERROR_TO_CONSOLE, { error }), - - sendIPCMessage: (messageType: string, data: any) => - safeInvoke(TauriCommand.SEND_IPC_MESSAGE, { messageType, data }), -}; +import { TauriCommand } from '../constants'; + +// Dynamically import Tauri APIs +let invoke: any; +let open: any; +let save: any; +let readFile: any; +let writeFile: any; +let BaseDirectory: any; +let listen: any; +let getCurrentWindow: any; +let fetch: any; + +let isTauri = false; +const isBrowser = typeof window !== 'undefined'; + +const apiInitializationPromise = (async () => { + if (!isBrowser) return; + + try { + const windowApi = await import('@tauri-apps/api/window'); + getCurrentWindow = windowApi.getCurrentWindow; + isTauri = true; + console.log('✅ Tauri window API loaded'); + + const coreApi = await import('@tauri-apps/api/core'); + invoke = coreApi.invoke; + + const eventApi = await import('@tauri-apps/api/event'); + listen = eventApi.listen; + + const dialogApi = await import('@tauri-apps/plugin-dialog'); + open = dialogApi.open; + save = dialogApi.save; + + const fsApi = await import('@tauri-apps/plugin-fs'); + readFile = fsApi.readFile; + writeFile = fsApi.writeFile; + BaseDirectory = fsApi.BaseDirectory; + + const httpApi = await import('@tauri-apps/plugin-http'); + fetch = httpApi.fetch; + } catch (e) { + console.warn('Tauri APIs not available, running in browser mode.'); + isTauri = false; + } + + if (isBrowser && !fetch) { + fetch = window.fetch; + } +})(); + +export const ensureTauriApi = async () => { + await apiInitializationPromise; +}; + +// Safe invoke function +export const safeInvoke = async (command: TauriCommand, args?: any): Promise => { + await ensureTauriApi(); + if (isTauri && typeof invoke === 'function') { + try { + return await invoke(command, args); + } catch (error) { + console.error(`Invoke failed for command "${command}":`, error); + return null; + } + } else { + console.log(`[Browser Mode] Would invoke: ${command}`, args); + return null; + } +}; + +export { invoke, isTauri }; + +// Typed API wrappers +export const tauriApi = { + ensureTauriApi, + isTauri: () => isTauri, + fetch: async (...args: Parameters): Promise => { + await ensureTauriApi(); + const fetchFn = fetch || window.fetch; + return fetchFn(...args); + }, + listen: async (...args: Parameters) => { + await ensureTauriApi(); + return listen ? listen(...args) : () => {}; + }, + fs: { + readFile: async (...args: Parameters) => { + await ensureTauriApi(); + return readFile ? readFile(...args) : new Uint8Array(); + }, + writeFile: async (...args: Parameters) => { + await ensureTauriApi(); + if (writeFile) { + return writeFile(...args); + } + }, + BaseDirectory: () => BaseDirectory, + }, + dialog: { + open: async (...args: Parameters) => { + await ensureTauriApi(); + return open ? open(...args) : null; + }, + save: async (...args: Parameters) => { + await ensureTauriApi(); + return save ? save(...args) : null; + }, + }, + window: { + getCurrent: async () => { + await ensureTauriApi(); + return getCurrentWindow ? getCurrentWindow() : null; + }, + }, + // Add typed wrappers for your app's specific commands + resolvePathRelativeToHome: (absolutePath: string) => + safeInvoke(TauriCommand.RESOLVE_PATH_RELATIVE_TO_HOME, { absolutePath }), + + submitPrompt: (data: { prompt: string; files: string[]; dst: string }) => + safeInvoke(TauriCommand.SUBMIT_PROMPT, data), + + generateImageViaBackend: (data: { prompt: string; files: string[]; dst: string }) => + safeInvoke(TauriCommand.GENERATE_IMAGE_VIA_BACKEND, data), + + requestConfigFromImages: () => + safeInvoke(TauriCommand.REQUEST_CONFIG_FROM_IMAGES), + + addDebugMessage: (message: string, level: string, data?: any) => + safeInvoke(TauriCommand.ADD_DEBUG_MESSAGE, { message, level, data }), + + clearDebugMessages: () => + safeInvoke(TauriCommand.CLEAR_DEBUG_MESSAGES), + + sendMessageToStdout: (message: string) => + safeInvoke(TauriCommand.SEND_MESSAGE_TO_STDOUT, { message }), + + logErrorToConsole: (error: string) => + safeInvoke(TauriCommand.LOG_ERROR_TO_CONSOLE, { error }), + + sendIPCMessage: (messageType: string, data: any) => + safeInvoke(TauriCommand.SEND_IPC_MESSAGE, { messageType, data }), +};