Skip to content

Commit 88b1997

Browse files
authored
Merge pull request voquill#449 from NeoHuncho/dev/apple-speech-framework
2 parents 1138c4a + 42498d0 commit 88b1997

19 files changed

Lines changed: 647 additions & 28 deletions

File tree

‎apps/desktop/src-tauri/Info.plist‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<dict>
55
<key>NSMicrophoneUsageDescription</key>
66
<string>Voquill records your microphone so you can transcribe and insert speech anywhere.</string>
7+
<key>NSSpeechRecognitionUsageDescription</key>
8+
<string>Voquill uses Apple's Speech framework to transcribe your recordings on this Mac.</string>
79
<key>NSAccessibilityUsageDescription</key>
810
<string>Voquill requests accessibility permission so it can monitor your hotkeys across the system.</string>
911
</dict>

‎apps/desktop/src-tauri/examples/gen_bindings.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ fn main() {
3131
remote_sender_pair_with_receiver,
3232
start_recording,
3333
stop_recording,
34+
apple_speech_transcribe,
3435
store_transcription_audio,
3536
storage_upload_data,
3637
storage_get_download_url,

‎apps/desktop/src-tauri/macos/Voquill.entitlements‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@
1010
<true/>
1111
<key>com.apple.security.personal-information.accessibility</key>
1212
<true/>
13+
<key>com.apple.security.personal-information.speech-recognition</key>
14+
<true/>
1315
</dict>
1416
</plist>

‎apps/desktop/src-tauri/src/app.rs‎

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,24 @@ pub fn build() -> tauri::Builder<tauri::Wry> {
8080
)
8181
.on_window_event(|window, event| {
8282
match event {
83-
WindowEvent::CloseRequested { api, .. } => {
84-
if window.label() == "main" {
85-
api.prevent_close();
86-
let _ = window
87-
.app_handle()
88-
.save_window_state(StateFlags::SIZE | StateFlags::POSITION);
89-
let _ = window.hide();
90-
// On Windows, force the WebView to stay active after hiding the window
91-
// so that background JS (global hotkey detection via keys_held events)
92-
// continues running while the app is minimized to the system tray.
93-
#[cfg(target_os = "windows")]
94-
{
95-
crate::platform::window::keep_webview_active(
96-
window.app_handle(),
97-
"main",
98-
);
99-
crate::platform::window::set_webview_keepalive(true);
100-
}
101-
#[cfg(target_os = "macos")]
102-
{
103-
if let Err(err) = crate::platform::macos::dock::hide_dock_icon() {
104-
log::error!("Failed to hide dock icon: {err}");
105-
}
83+
WindowEvent::CloseRequested { api, .. } if window.label() == "main" => {
84+
api.prevent_close();
85+
let _ = window
86+
.app_handle()
87+
.save_window_state(StateFlags::SIZE | StateFlags::POSITION);
88+
let _ = window.hide();
89+
// On Windows, force the WebView to stay active after hiding the window
90+
// so that background JS (global hotkey detection via keys_held events)
91+
// continues running while the app is minimized to the system tray.
92+
#[cfg(target_os = "windows")]
93+
{
94+
crate::platform::window::keep_webview_active(window.app_handle(), "main");
95+
crate::platform::window::set_webview_keepalive(true);
96+
}
97+
#[cfg(target_os = "macos")]
98+
{
99+
if let Err(err) = crate::platform::macos::dock::hide_dock_icon() {
100+
log::error!("Failed to hide dock icon: {err}");
106101
}
107102
}
108103
}
@@ -247,6 +242,7 @@ pub fn build() -> tauri::Builder<tauri::Wry> {
247242
crate::commands::remote_sender_pair_with_receiver,
248243
crate::commands::start_recording,
249244
crate::commands::stop_recording,
245+
crate::commands::apple_speech_transcribe,
250246
crate::commands::store_transcription_audio,
251247
crate::commands::storage_upload_data,
252248
crate::commands::storage_get_download_url,

‎apps/desktop/src-tauri/src/commands.rs‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,25 @@ pub struct StopRecordingResponse {
2727
pub sample_rate: u32,
2828
}
2929

30+
#[derive(serde::Deserialize, specta::Type)]
31+
#[serde(rename_all = "camelCase")]
32+
pub struct AppleSpeechTranscribeArgs {
33+
pub samples: Vec<f32>,
34+
pub sample_rate: u32,
35+
#[serde(default)]
36+
pub language: Option<String>,
37+
#[serde(default)]
38+
pub contextual_strings: Vec<String>,
39+
}
40+
41+
#[derive(serde::Serialize, specta::Type)]
42+
#[serde(rename_all = "camelCase")]
43+
pub struct AppleSpeechTranscribeResponse {
44+
pub text: String,
45+
pub model: String,
46+
pub inference_device: String,
47+
}
48+
3049
#[derive(serde::Serialize, specta::Type)]
3150
#[serde(rename_all = "camelCase")]
3251
pub struct StartRecordingResponse {
@@ -1392,6 +1411,35 @@ pub async fn stop_recording(
13921411
.map_err(|err| err.to_string())?
13931412
}
13941413

1414+
#[tauri::command]
1415+
#[specta::specta]
1416+
pub async fn apple_speech_transcribe(
1417+
args: AppleSpeechTranscribeArgs,
1418+
) -> Result<AppleSpeechTranscribeResponse, String> {
1419+
#[cfg(target_os = "macos")]
1420+
{
1421+
let text = crate::platform::macos::speech::transcribe_audio(
1422+
args.samples,
1423+
args.sample_rate,
1424+
args.language,
1425+
args.contextual_strings,
1426+
)
1427+
.await?;
1428+
1429+
Ok(AppleSpeechTranscribeResponse {
1430+
text,
1431+
model: "Apple Speech".to_string(),
1432+
inference_device: "macOS Speech (On-Device)".to_string(),
1433+
})
1434+
}
1435+
1436+
#[cfg(not(target_os = "macos"))]
1437+
{
1438+
let _ = args;
1439+
Err("Apple Speech transcription is only available on macOS.".to_string())
1440+
}
1441+
}
1442+
13951443
#[tauri::command]
13961444
#[specta::specta]
13971445
pub async fn store_transcription_audio(

‎apps/desktop/src-tauri/src/platform/macos/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod monitor;
99
pub mod overlay;
1010
pub mod permissions;
1111
pub mod position;
12+
pub mod speech;
1213
pub mod volume;
1314
pub mod window;
1415

0 commit comments

Comments
 (0)