diff --git a/gemini/gemini-query-aarch64-apple-darwin b/gemini/gemini-query-aarch64-apple-darwin new file mode 100755 index 0000000..2985699 Binary files /dev/null and b/gemini/gemini-query-aarch64-apple-darwin differ diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 8b5f00b..7cfc69d 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3888,6 +3888,7 @@ version = "0.1.0" dependencies = [ "anyhow", "base64 0.21.7", + "futures-util", "image", "reqwest 0.11.27", "serde", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1b2d193..705f8c5 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -18,6 +18,7 @@ tauri = { version = "2.0.0", features = [] } tokio = { version = "1.36", features = ["full"] } anyhow = "1.0" thiserror = "1.0" +futures-util = "0.3" tauri-plugin-shell = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" } tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" } tauri-plugin-fs = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" } diff --git a/src-tauri/binaries/gemini-query-aarch64-apple-darwin b/src-tauri/binaries/gemini-query-aarch64-apple-darwin new file mode 100755 index 0000000..2985699 Binary files /dev/null and b/src-tauri/binaries/gemini-query-aarch64-apple-darwin differ diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 8dca92b..8d2c9ac 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -24,7 +24,13 @@ }, { "identifier": "shell:allow-execute", - "description": "Allows executing FFmpeg commands" + "description": "Allows executing FFmpeg commands and sidecars", + "allow": [ + { + "name": "gemini-query", + "sidecar": true + } + ] }, { "identifier": "core:event:allow-emit", diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 589ced2..a361b48 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize}; use std::process::{Command, Stdio}; use std::sync::Mutex; use std::io::BufRead; -use tauri::{Runtime, State, Emitter, Manager}; +use tauri::{Runtime, State, Emitter}; +use tauri_plugin_shell::ShellExt; use tempfile::TempDir; use std::fs; use base64::Engine; @@ -174,30 +175,17 @@ async fn query_gemini( println!("Image Path: {}", path); } - let executable_path = if cfg!(debug_assertions) { - // Development mode - use absolute path - std::path::PathBuf::from("/Users/chaulmark/homemade-scripts/video-subtitle-merger/subtitle-merge/gemini/gemini-query") - } else { - // Production mode - use resource path - app_handle.path().resource_dir() - .map_err(|e| Error::IoError(std::io::Error::new( - std::io::ErrorKind::NotFound, - format!("Resource directory not found: {}", e) - )))? - .join("gemini-query") - }; - - println!("Executable path: {:?}", executable_path); - let mut command = Command::new(executable_path); - command.arg(api_key) - .arg(prompt); + let sidecar = app_handle.shell().sidecar("gemini-query") + .map_err(|e| Error::GeminiError(format!("Failed to get sidecar: {}", e)))?; + + let mut command = sidecar.arg(api_key).arg(prompt); if let Some(path) = image_path { - command.arg(path); + command = command.arg(path); } - println!("\nExecuting command: {:?}", command); - let output = command.output() + println!("\nExecuting sidecar command"); + let output = command.output().await .map_err(|e| Error::GeminiError(format!("Failed to execute Gemini query: {}", e)))?; let response_text = String::from_utf8_lossy(&output.stdout); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 217cb37..8ea3995 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -28,7 +28,13 @@ }, "bundle": { "active": true, - "targets": ["app"], + "targets": ["dmg", "app"], + "macOS": { + "frameworks": [], + "minimumSystemVersion": "10.13", + "signingIdentity": "Developer ID Application: Chris Haulmark (RJHWWWSF6Q)", + "providerShortName": null + }, "icon": [ "icons/32x32.png", "icons/128x128.png", @@ -36,8 +42,8 @@ "icons/icon.icns", "icons/icon.ico" ], - "resources": [ - "../gemini/gemini-query" + "externalBin": [ + "binaries/gemini-query" ] } } diff --git a/src/App.tsx b/src/App.tsx index 84dc04c..dce8659 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,7 +11,7 @@ function App() { const [selectedTask, setSelectedTask] = useState(null); const [error, setError] = useState(null); const [isSettingsOpen, setIsSettingsOpen] = useState(false); - const [apiKey, setApiKey] = useState('AIzaSyAF825tPTh77oL0knsGFEyvsN0iPUO_bXc'); + const [apiKey, setApiKey] = useState(''); const [visualPrompt, setVisualPrompt] = useState(() => { const saved = localStorage.getItem('visualPrompt'); return saved || DEFAULT_VISUAL_PROMPT; @@ -110,6 +110,7 @@ function App() { apiKey={apiKey} visualPrompt={visualPrompt} subtitlePrompt={subtitlePrompt} + onOpenSettings={() => setIsSettingsOpen(true)} /> )} diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 4e5a5c3..8cc2238 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -14,7 +14,7 @@ interface SettingsProps { // Note: We keep subtitle prompt in Settings since it's still used by the merge task -export const DEFAULT_API_KEY = 'AIzaSyAF825tPTh77oL0knsGFEyvsN0iPUO_bXc'; +export const DEFAULT_API_KEY = ''; export const DEFAULT_VISUAL_PROMPT = `Analyze this video frame from timestamp {} and provide a visual description focusing on: 1. The visual setup and environment 2. The people present, their appearance, and positioning @@ -83,10 +83,6 @@ export const Settings: React.FC = ({ setDisplayValue('*'.repeat(apiKey.length)); }; - const resetApiKeyToDefault = () => { - onApiKeyChange(DEFAULT_API_KEY); - }; - const resetVisualPromptToDefault = () => { onVisualPromptChange(DEFAULT_VISUAL_PROMPT); }; @@ -98,6 +94,13 @@ export const Settings: React.FC = ({ const testApiKey = async () => { setTesting(true); setTestResult(null); + + if (!apiKey.trim()) { + setTestResult('Error: API Key is required for testing'); + setTesting(false); + return; + } + try { await invoke('test_gemini_api', { apiKey }); setTestResult('API key is valid'); @@ -145,6 +148,14 @@ export const Settings: React.FC = ({
+ + Get API Key + - - {apiKey !== DEFAULT_API_KEY && ( - - )}
{testResult && ( @@ -174,19 +176,14 @@ export const Settings: React.FC = ({ -
-