diff --git a/packages/kbot/cat_gen_1.png b/packages/kbot/cat_gen_1.png new file mode 100644 index 00000000..ff331f83 Binary files /dev/null and b/packages/kbot/cat_gen_1.png differ diff --git a/packages/kbot/cat_gen_2.png b/packages/kbot/cat_gen_2.png new file mode 100644 index 00000000..ffe690da Binary files /dev/null and b/packages/kbot/cat_gen_2.png differ diff --git a/packages/kbot/dist/win-64/tauri-app.exe b/packages/kbot/dist/win-64/tauri-app.exe index e4984d04..223e583d 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/generated_gen_10.png b/packages/kbot/generated_gen_10.png new file mode 100644 index 00000000..c7388101 Binary files /dev/null and b/packages/kbot/generated_gen_10.png differ diff --git a/packages/kbot/gui/tauri-app/package-lock.json b/packages/kbot/gui/tauri-app/package-lock.json index cc7143a3..4fc3e0db 100644 --- a/packages/kbot/gui/tauri-app/package-lock.json +++ b/packages/kbot/gui/tauri-app/package-lock.json @@ -34,7 +34,8 @@ "mime-types": "^2.1.35", "react": "^19.1.0", "react-dom": "^19.1.0", - "react-terminal": "^1.4.5" + "react-terminal": "^1.4.5", + "react-zoom-pan-pinch": "^3.7.0" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.13", @@ -2675,6 +2676,20 @@ "ua-parser-js": "^2.0.0" } }, + "node_modules/react-zoom-pan-pinch": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.7.0.tgz", + "integrity": "sha512-UmReVZ0TxlKzxSbYiAj+LeGRW8s8LraAFTXRAxzMYnNRgGPsxCudwZKVkjvGmjtx7SW/hZamt69NUmGf4xrkXA==", + "license": "MIT", + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, "node_modules/rollup": { "version": "4.50.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", diff --git a/packages/kbot/gui/tauri-app/package.json b/packages/kbot/gui/tauri-app/package.json index 85e11905..8f439cc3 100644 --- a/packages/kbot/gui/tauri-app/package.json +++ b/packages/kbot/gui/tauri-app/package.json @@ -37,7 +37,8 @@ "mime-types": "^2.1.35", "react": "^19.1.0", "react-dom": "^19.1.0", - "react-terminal": "^1.4.5" + "react-terminal": "^1.4.5", + "react-zoom-pan-pinch": "^3.7.0" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.13", diff --git a/packages/kbot/gui/tauri-app/src/App.tsx b/packages/kbot/gui/tauri-app/src/App.tsx index 1bccd262..530e2f7c 100644 --- a/packages/kbot/gui/tauri-app/src/App.tsx +++ b/packages/kbot/gui/tauri-app/src/App.tsx @@ -45,6 +45,8 @@ function App() { const [prompts, setPrompts] = useState([]); const [promptHistory, setPromptHistory] = useState([]); const [historyIndex, setHistoryIndex] = useState(-1); + const [fileHistory, setFileHistory] = useState([]); + const [showFileHistory, setShowFileHistory] = useState(false); const appendStyle = (style: string) => { @@ -97,11 +99,20 @@ function App() { await generateImage(action.prompt, [targetImage]); }; - const addToHistory = (promptText: string) => { + const addToHistory = async (promptText: string) => { if (promptText.trim() && !promptHistory.includes(promptText.trim())) { - setPromptHistory(prev => [...prev, promptText.trim()]); + const newHistory = [...promptHistory, promptText.trim()]; + setPromptHistory(newHistory); setHistoryIndex(-1); // Reset to end of history log.info(`📝 Added to history: "${promptText.substring(0, 50)}..."`); + + // Auto-save to store + try { + await saveStore(prompts, newHistory); + log.info('💾 History saved to store'); + } catch (error) { + log.error('Failed to save history', { error: (error as Error).message }); + } } }; @@ -257,6 +268,8 @@ function App() { setGenerationTimeoutId, setIsGenerating, prompt, + setCurrentIndex, + setPromptHistory, }); const addFiles = async (newPaths: string[]) => { @@ -492,7 +505,7 @@ function App() { if (apiKey) { // Add to history before generating - addToHistory(prompt); + await addToHistory(prompt); // Generate image via backend (always chat mode now) // Only use explicitly selected images. If none are selected, generate from prompt alone. @@ -539,7 +552,7 @@ function App() { const savePrompts = async (promptsToSave: PromptTemplate[]) => { try { - await saveStore(promptsToSave); + await saveStore(promptsToSave, promptHistory); } catch (error) { log.error('Failed to save prompts', { error: (error as Error).message diff --git a/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx b/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx index 3edc3458..6affe6a0 100644 --- a/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx +++ b/packages/kbot/gui/tauri-app/src/components/DebugPanel.tsx @@ -1,232 +1,232 @@ -import React from 'react'; -import { tauriApi } from '../lib/tauriApi'; -import log from '../lib/log'; - -// Safe JSON stringify to prevent circular reference crashes -function safeStringify(obj: any, maxDepth = 3): string { - const seen = new WeakSet(); - - function serialize(value: any, depth: number): any { - if (depth > maxDepth) { - return '[Max depth reached]'; - } - - if (value === null || value === undefined) { - return value; - } - - if (typeof value !== 'object') { - return value; - } - - if (seen.has(value)) { - return '[Circular Reference]'; - } - - seen.add(value); - - if (Array.isArray(value)) { - return value.slice(0, 10).map((item, index) => { - if (index >= 10) return '[Truncated]'; - return serialize(item, depth + 1); - }); - } - - const result: any = {}; - const keys = Object.keys(value).slice(0, 20); // Limit keys - - for (const key of keys) { - try { - result[key] = serialize(value[key], depth + 1); - } catch (e) { - result[key] = '[Serialization Error]'; - } - } - - if (Object.keys(value).length > 20) { - result['[truncated]'] = `${Object.keys(value).length - 20} more keys...`; - } - - return result; - } - - try { - return JSON.stringify(serialize(obj, 0), null, 2); - } catch (e) { - return `[Serialization failed: ${e instanceof Error ? e.message : 'Unknown error'}]`; - } -} - -interface DebugPanelProps { - debugMessages: any[]; - sendIPCMessage: (messageType: string, data: any) => void; - clearDebugMessages: () => void; - ipcInitialized: boolean; - messageToSend: string; - setMessageToSend: (message: string) => void; - sendMessageToImages: () => void; -} - -const DebugPanel: React.FC = ({ - debugMessages, - sendIPCMessage, - clearDebugMessages, - ipcInitialized, - messageToSend, - setMessageToSend, - sendMessageToImages, -}) => { - return ( -
-
-
-

Debug Panel

-
- - - - -
-
- -
- {debugMessages.length === 0 ? ( -
- No debug messages yet. -
- ) : ( -
- {debugMessages.map((msg, index) => ( -
-
-
-
- - {msg.isIPC ? '📨 IPC' : msg.level} - - {msg.timestamp} - {msg.isIPC && msg.data?.id && ( - - {msg.data.id.split('_').pop()} - - )} -
-
{msg.message}
- {msg.data && ( -
- {safeStringify(msg.data)} -
- )} -
-
-
- ))} -
- )} -
- -
-
-

Send Message to images.ts

- - {ipcInitialized ? '🟢 Connected' : '🔴 Disconnected'} - -
-
-