diff --git a/vite/package-lock.json b/vite/package-lock.json index d790696..b6ac23d 100644 --- a/vite/package-lock.json +++ b/vite/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@tailwindcss/vite": "^4.1.8", + "@tauri-apps/plugin-fs": "^2.3.0", "@tauri-apps/plugin-http": "^2.4.4", "gsap": "^3.13.0", "react": "^19.1.0", @@ -1595,6 +1596,15 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/plugin-fs": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-fs/-/plugin-fs-2.3.0.tgz", + "integrity": "sha512-G9gEyYVUaaxhdRJBgQTTLmzAe0vtHYxYyN1oTQzU3zwvb8T+tVLcAqCdFMWHq0qGeGbmynI5whvYpcXo5LvZ1w==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.0.0" + } + }, "node_modules/@tauri-apps/plugin-http": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-http/-/plugin-http-2.4.4.tgz", @@ -3886,6 +3896,14 @@ "dev": true, "optional": true }, + "@tauri-apps/plugin-fs": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-fs/-/plugin-fs-2.3.0.tgz", + "integrity": "sha512-G9gEyYVUaaxhdRJBgQTTLmzAe0vtHYxYyN1oTQzU3zwvb8T+tVLcAqCdFMWHq0qGeGbmynI5whvYpcXo5LvZ1w==", + "requires": { + "@tauri-apps/api": "^2.0.0" + } + }, "@tauri-apps/plugin-http": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-http/-/plugin-http-2.4.4.tgz", diff --git a/vite/package.json b/vite/package.json index d328682..0ae3cd4 100644 --- a/vite/package.json +++ b/vite/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@tailwindcss/vite": "^4.1.8", + "@tauri-apps/plugin-fs": "^2.3.0", "@tauri-apps/plugin-http": "^2.4.4", "gsap": "^3.13.0", "react": "^19.1.0", diff --git a/vite/src-tauri/2 b/vite/src-tauri/2 new file mode 100644 index 0000000..1619fe1 --- /dev/null +++ b/vite/src-tauri/2 @@ -0,0 +1,12 @@ + +added 1 package, and audited 148 packages in 3s + +35 packages are looking for funding + run `npm fund` for details + +1 low severity vulnerability + +To address all issues, run: + npm audit fix + +Run `npm audit` for details. diff --git a/vite/src-tauri/Cargo.lock b/vite/src-tauri/Cargo.lock index a98a166..9b75809 100644 --- a/vite/src-tauri/Cargo.lock +++ b/vite/src-tauri/Cargo.lock @@ -101,6 +101,7 @@ dependencies = [ "serde_json", "tauri", "tauri-build", + "tauri-plugin-fs", "tauri-plugin-http", "tauri-plugin-log", "tokio", diff --git a/vite/src-tauri/Cargo.toml b/vite/src-tauri/Cargo.toml index dbefc41..fe1c674 100644 --- a/vite/src-tauri/Cargo.toml +++ b/vite/src-tauri/Cargo.toml @@ -29,3 +29,4 @@ rosc = "0.11.4" tokio = { version = "1.45.1", features = ["net"] } webview2-com = "0.37.0" windows = "0.61.1" +tauri-plugin-fs = "2" diff --git a/vite/src-tauri/capabilities/default.json b/vite/src-tauri/capabilities/default.json index 87ce707..fb1471d 100644 --- a/vite/src-tauri/capabilities/default.json +++ b/vite/src-tauri/capabilities/default.json @@ -11,9 +11,22 @@ "core:app:default", "core:resources:default", "core:webview:default", + { "identifier": "http:default", - "allow": [{ "url": "https://*.openai.com" }] + "allow": [ + { + "url": "https://*.openai.com" + } + ] + }, + "fs:write-files", + "fs:allow-create", + "fs:allow-appdata-write", + "fs:allow-exists", + { + "identifier": "fs:scope", + "allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**/*" }] } ] } \ No newline at end of file diff --git a/vite/src-tauri/src/lib.rs b/vite/src-tauri/src/lib.rs index da39716..eaf72b7 100644 --- a/vite/src-tauri/src/lib.rs +++ b/vite/src-tauri/src/lib.rs @@ -1,24 +1,24 @@ use dotenv::dotenv; -use std::env; use rosc::{encoder, OscMessage, OscPacket, OscType}; +use std::env; use std::{net::SocketAddrV4, str::FromStr}; +use tauri::{AppHandle, Manager}; use tokio::net::UdpSocket; use webview2_com::Microsoft::Web::WebView2::Win32::{ ICoreWebView2Profile4, ICoreWebView2_13, COREWEBVIEW2_PERMISSION_KIND_MICROPHONE, COREWEBVIEW2_PERMISSION_STATE_DEFAULT, }; use windows::core::{Interface, PCWSTR}; -use tauri::{AppHandle, Manager}; #[tauri::command] fn get_env(name: &str) -> String { println!("Getting environment variable: {}", name); - + match env::var(name) { Ok(value) => { // println!("Found environment variable {}: {}", name, value); value - }, + } Err(e) => { println!("Error getting environment variable {}: {}", name, e); String::new() @@ -28,12 +28,11 @@ fn get_env(name: &str) -> String { #[tauri::command] async fn send_osc_message( - key: &str, + key: &str, message: &str, host: &str, - target: &str + target: &str, ) -> Result<(), String> { - // print println!("Sending OSC message: {}", message); @@ -78,11 +77,15 @@ fn reset_permission(origin: &str, app: AppHandle) { #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { - dotenv().ok(); tauri::Builder::default() - .invoke_handler(tauri::generate_handler![get_env, send_osc_message, reset_permission]) + .plugin(tauri_plugin_fs::init()) + .invoke_handler(tauri::generate_handler![ + get_env, + send_osc_message, + reset_permission + ]) .plugin(tauri_plugin_http::init()) .setup(|app| { if cfg!(debug_assertions) { @@ -97,4 +100,3 @@ pub fn run() { .run(tauri::generate_context!()) .expect("error while running tauri application"); } - diff --git a/vite/src-tauri/src/main.rs b/vite/src-tauri/src/main.rs index ad5fe83..69c3a72 100644 --- a/vite/src-tauri/src/main.rs +++ b/vite/src-tauri/src/main.rs @@ -2,5 +2,5 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { - app_lib::run(); + app_lib::run(); } diff --git a/vite/src-tauri/tauri.conf.json b/vite/src-tauri/tauri.conf.json index 153362b..d59ea4b 100644 --- a/vite/src-tauri/tauri.conf.json +++ b/vite/src-tauri/tauri.conf.json @@ -13,8 +13,8 @@ "windows": [ { "title": "theGreatTipsy", - "width": 800, - "height": 600, + "width": 600, + "height": 800, "resizable": true, "fullscreen": false } diff --git a/vite/src/App.jsx b/vite/src/App.jsx index b1d5eb8..dd7430a 100644 --- a/vite/src/App.jsx +++ b/vite/src/App.jsx @@ -6,6 +6,7 @@ import { textToSpeech } from './util/tts'; import { gsap } from "gsap"; import { SplitText } from 'gsap/SplitText'; import { invoke } from '@tauri-apps/api/core'; +import Input from './comps/input'; gsap.registerPlugin(SplitText); @@ -16,6 +17,7 @@ function App() { const [history, setHistory] = useState([]); const [processing, setProcessing] = useState(false); const [showProcessing, setShowProcessing] = useState(false); + const [audioOutput, setAudioOutput] = useState(false); const [prompt, setPrompt] = useState([]); @@ -63,25 +65,33 @@ function App() { ]); // tts - console.log('create speech:', data.output_text); - textToSpeech(data.output_text).then(audioUrl => { - const audio = new Audio(audioUrl); + if(!audioOutput) { - console.log('play audio...', new Date(Date.now()-startTime).toISOString().slice(11, 19)); - - audio.play().catch(error => { - console.error('Audio playback failed:', error); + setProcessing(false); + + }else{ + console.log('create speech:', data.output_text); + textToSpeech(data.output_text).then(audioUrl => { + const audio = new Audio(audioUrl); + + console.log('play audio...', new Date(Date.now()-startTime).toISOString().slice(11, 19)); + + audio.play().catch(error => { + console.error('Audio playback failed:', error); + }); + + setProcessing(false); + + }).catch(error => { + console.error('TTS error:', error); }); - }).catch(error => { - console.error('TTS error:', error); - }); - setProcessing(false); + } }); } - function toggleAudio() { + function toggleAudio(value) { console.log("onclickAudio", listening, browserSupportsSpeechRecognition, isMicrophoneAvailable); if(!browserSupportsSpeechRecognition) { console.warn("Browser does not support speech recognition."); @@ -92,7 +102,7 @@ function App() { return; } - if(!listening){ + if(!listening && value){ SpeechRecognition.startListening({ continuous: true, language: 'zh-TW' }).then(() => { console.log("Speech recognition started."); }).catch(error => { @@ -152,32 +162,42 @@ function App() { - // tts - console.log('create speech:', data.output_text); - textToSpeech(data.output_text).then(audioUrl => { - const audio = new Audio(audioUrl); - - console.log('play audio...', new Date(Date.now()-startTime).toISOString().slice(11, 19)); - setShowProcessing(false); + if(!audioOutput) { + setHistory(prev => [...prev, { role: 'assistant', content: data.output_text, }]); - - audio.play().catch(error => { - console.error('Audio playback failed:', error); - }); - audio.addEventListener('ended',() => { - console.log('Audio playback ended'); + setProcessing(false); + setShowProcessing(false); + }else{ + // tts + console.log('create speech:', data.output_text); + textToSpeech(data.output_text).then(audioUrl => { + const audio = new Audio(audioUrl); + + console.log('play audio...', new Date(Date.now()-startTime).toISOString().slice(11, 19)); + setShowProcessing(false); + setHistory(prev => [...prev, { + role: 'assistant', + content: data.output_text, + }]); + + audio.play().catch(error => { + console.error('Audio playback failed:', error); + }); + + audio.addEventListener('ended',() => { + console.log('Audio playback ended'); + setProcessing(()=>false); + }); + + }).catch(error => { + console.error('TTS error:', error); setProcessing(()=>false); }); - - }).catch(error => { - console.error('TTS error:', error); - setProcessing(()=>false); - }); - + } }); @@ -282,6 +302,7 @@ function App() { return (
+
{prompt?.length==0 ? (
Promp will appear here...
@@ -319,7 +340,20 @@ function App() { refInput.current.value='' resetTranscript(); }}>clear - + + toggleAudio(e.target.checked)} + /> + + + + setAudioOutput(e.target.checked)} /> + +