feat: expose tauri app commands

This commit is contained in:
Evandro committed 2026-06-10 20:58:44 -03:00
1 parent 54e8b42330
commit bfa96248aa
3 files changed
+236 -1

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
use std::sync::Mutex;
use serde::{Deserialize, Serialize};
use crate::audio::{RecordingSession, RecordingStatus};
use crate::models::{model_statuses, ModelWithStatus};
use crate::settings::AppSettings;
#[derive(Debug)]
pub struct ManagedAppState {
pub settings: Mutex<AppSettings>,
pub recording: Mutex<RecordingSession>,
pub transcript: Mutex<TranscriptDraft>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct TranscriptDraft {
pub text: String,
pub last_message: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct AppSnapshot {
pub settings: AppSettings,
pub recording_status: RecordingStatus,
pub transcript: TranscriptDraft,
pub models: Vec<ModelWithStatus>,
}
impl Default for ManagedAppState {
fn default() -> Self {
Self {
settings: Mutex::new(AppSettings::default()),
recording: Mutex::new(RecordingSession::default()),
transcript: Mutex::new(TranscriptDraft::default()),
}
}
}
impl ManagedAppState {
pub fn snapshot(&self) -> Result<AppSnapshot, String> {
let settings = self
.settings
.lock()
.map_err(|_| "falha ao acessar configurações".to_string())?
.clone();
let recording_status = self
.recording
.lock()
.map_err(|_| "falha ao acessar estado de gravação".to_string())?
.status
.clone();
let transcript = self
.transcript
.lock()
.map_err(|_| "falha ao acessar transcrição".to_string())?
.clone();
Ok(AppSnapshot {
settings,
recording_status,
transcript,
models: model_statuses(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_snapshot_starts_idle() {
let state = ManagedAppState::default();
let snapshot = state.snapshot().expect("snapshot should work");
assert_eq!(snapshot.recording_status, RecordingStatus::Idle);
assert!(snapshot.transcript.text.is_empty());
assert_eq!(snapshot.models.len(), 1);
}
}
+17 -1
View File
@@ -1,13 +1,29 @@
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub mod app_state;
pub mod audio;
pub mod error;
pub mod injection;
pub mod models;
pub mod settings;
pub mod transcription;
pub mod ui_commands;
use app_state::ManagedAppState;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.manage(ManagedAppState::default())
.invoke_handler(tauri::generate_handler![
ui_commands::get_app_snapshot,
ui_commands::start_recording,
ui_commands::stop_recording_and_transcribe,
ui_commands::copy_ready_text,
ui_commands::request_insert_text,
ui_commands::list_models,
ui_commands::get_settings,
ui_commands::save_settings
])
.run(tauri::generate_context!())
.expect("erro ao executar o aplicativo Tauri");
}
+136
View File
@@ -0,0 +1,136 @@
use std::path::PathBuf;
use tauri::State;
use crate::app_state::{AppSnapshot, ManagedAppState};
use crate::injection::{FallbackInjector, InsertMethod, InsertRequest, InsertResult, TextInjector};
use crate::models::{model_statuses, ModelWithStatus};
use crate::settings::AppSettings;
use crate::transcription::crispasr::{CrispAsrConfig, CrispAsrTranscriber};
use crate::transcription::{Transcriber, TranscriptionInput, TranscriptionOptions};
#[tauri::command]
pub(crate) fn get_app_snapshot(state: State<'_, ManagedAppState>) -> Result<AppSnapshot, String> {
state.snapshot()
}
#[tauri::command]
pub(crate) fn start_recording(state: State<'_, ManagedAppState>) -> Result<AppSnapshot, String> {
state
.recording
.lock()
.map_err(|_| "falha ao acessar estado de gravação".to_string())?
.start()
.map_err(String::from)?;
state.snapshot()
}
#[tauri::command]
pub(crate) fn stop_recording_and_transcribe(
state: State<'_, ManagedAppState>,
) -> Result<AppSnapshot, String> {
let sequence = state
.recording
.lock()
.map_err(|_| "falha ao acessar estado de gravação".to_string())?
.stop()
.map_err(String::from)?;
let settings = state
.settings
.lock()
.map_err(|_| "falha ao acessar configurações".to_string())?
.clone();
let transcriber = CrispAsrTranscriber::new(CrispAsrConfig {
sidecar_name: None,
model_path: None,
});
let result = transcriber.transcribe(TranscriptionInput {
audio_path: PathBuf::from(format!("recording-{sequence}.wav")),
options: TranscriptionOptions {
model_id: settings.transcription.model_id,
language: settings.transcription.language,
timestamps: false,
},
});
let mut transcript = state
.transcript
.lock()
.map_err(|_| "falha ao acessar transcrição".to_string())?;
match result {
Ok(result) => {
transcript.text = result.text;
transcript.last_message = Some("Transcrição concluída.".to_string());
}
Err(error) => {
transcript.text = "".to_string();
transcript.last_message = Some(error.to_string());
}
}
drop(transcript);
state.snapshot()
}
#[tauri::command]
pub(crate) fn copy_ready_text(state: State<'_, ManagedAppState>) -> Result<String, String> {
let transcript = state
.transcript
.lock()
.map_err(|_| "falha ao acessar transcrição".to_string())?;
Ok(transcript.text.clone())
}
#[tauri::command]
pub(crate) fn request_insert_text(
text: String,
state: State<'_, ManagedAppState>,
) -> Result<InsertResult, String> {
let injector = FallbackInjector;
let result = injector.insert_text(InsertRequest {
text,
target: None,
method: InsertMethod::ClipboardPaste,
});
state
.transcript
.lock()
.map_err(|_| "falha ao acessar transcrição".to_string())?
.last_message = Some(result.message.clone());
Ok(result)
}
#[tauri::command]
pub(crate) fn list_models() -> Vec<ModelWithStatus> {
model_statuses()
}
#[tauri::command]
pub(crate) fn get_settings(state: State<'_, ManagedAppState>) -> Result<AppSettings, String> {
state
.settings
.lock()
.map_err(|_| "falha ao acessar configurações".to_string())
.map(|settings| settings.clone())
}
#[tauri::command]
pub(crate) fn save_settings(
settings: AppSettings,
state: State<'_, ManagedAppState>,
) -> Result<AppSettings, String> {
*state
.settings
.lock()
.map_err(|_| "falha ao acessar configurações".to_string())? = settings.clone();
Ok(settings)
}