feat: expose tauri app commands
This commit is contained in:
1 parent
54e8b42330
commit
bfa96248aa
3 files changed
+236
-1
No files matched your search
@@ -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
@@ -1,13 +1,29 @@
|
|||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
pub mod app_state;
|
||||||
pub mod audio;
|
pub mod audio;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod injection;
|
pub mod injection;
|
||||||
pub mod models;
|
pub mod models;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod transcription;
|
pub mod transcription;
|
||||||
|
pub mod ui_commands;
|
||||||
|
|
||||||
|
use app_state::ManagedAppState;
|
||||||
|
|
||||||
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_opener::init())
|
.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!())
|
.run(tauri::generate_context!())
|
||||||
.expect("erro ao executar o aplicativo Tauri");
|
.expect("erro ao executar o aplicativo Tauri");
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
Reference in new issue
Block a user