diff --git a/app/src-tauri/src/google_meet/ingest.rs b/app/src-tauri/src/google_meet/ingest.rs new file mode 100644 index 0000000000..0b110eee81 --- /dev/null +++ b/app/src-tauri/src/google_meet/ingest.rs @@ -0,0 +1,14 @@ +use std::sync::Arc; +use tokio::sync::Mutex; +use tauri::{AppHandle, Runtime}; +use crate::google_meet::types::{MeetingId, IngestOutcome}; +use crate::google_meet::transcript_store::MeetingTranscriptStore; + +pub async fn flush_meeting( + _app: &AppHandle, + _account_id: &str, + _meeting_id: MeetingId, + _store: &Arc>, +) -> IngestOutcome { + IngestOutcome::Pending +} diff --git a/app/src-tauri/src/google_meet/mod.rs b/app/src-tauri/src/google_meet/mod.rs new file mode 100644 index 0000000000..f2d9c7b631 --- /dev/null +++ b/app/src-tauri/src/google_meet/mod.rs @@ -0,0 +1,33 @@ +pub mod ingest; +pub mod transcript_store; +pub mod types; + +use std::sync::Arc; +use tauri::{AppHandle, Manager, Runtime}; +use tokio::sync::Mutex; + +pub use transcript_store::MeetingTranscriptStore; +pub use types::{CaptionLine, IngestOutcome, MeetingId}; + +pub async fn record_caption_batch( + app: &AppHandle, + meeting_id: MeetingId, + batch: Vec, +) { + if let Some(store) = app.try_state::>>() { + let mut store = store.lock().await; + store.record_caption_batch(meeting_id, batch); + } +} + +pub async fn flush_meeting( + app: &AppHandle, + account_id: &str, + meeting_id: MeetingId, +) -> IngestOutcome { + if let Some(store) = app.try_state::>>() { + ingest::flush_meeting(app, account_id, meeting_id, &store).await + } else { + IngestOutcome::Retry("MeetingTranscriptStore not found in app state".to_string()) + } +} diff --git a/app/src-tauri/src/google_meet/transcript_store.rs b/app/src-tauri/src/google_meet/transcript_store.rs new file mode 100644 index 0000000000..504bfdda0f --- /dev/null +++ b/app/src-tauri/src/google_meet/transcript_store.rs @@ -0,0 +1,23 @@ +use std::collections::HashMap; +use crate::google_meet::types::{MeetingId, MeetingTranscript, CaptionLine}; + +#[derive(Default)] +pub struct MeetingTranscriptStore { + transcripts: HashMap, +} + +impl MeetingTranscriptStore { + pub fn record_caption_batch(&mut self, _meeting_id: MeetingId, _batch: Vec) { + } + + pub fn record_transcript(&mut self, _transcript: MeetingTranscript) { + } + + pub fn get_transcript(&self, _meeting_id: &MeetingId) -> Option<&MeetingTranscript> { + None + } + + pub fn remove_transcript(&mut self, _meeting_id: &MeetingId) -> Option { + None + } +} diff --git a/app/src-tauri/src/google_meet/types.rs b/app/src-tauri/src/google_meet/types.rs new file mode 100644 index 0000000000..2d7d2634af --- /dev/null +++ b/app/src-tauri/src/google_meet/types.rs @@ -0,0 +1,26 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct CaptionLine { + pub speaker: String, + pub text: String, + pub ts: i64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct MeetingId(pub String); + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MeetingTranscript { + pub id: MeetingId, + pub started_at: i64, + pub lines: Vec, + pub ended_at: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum IngestOutcome { + Persisted, + Pending, + Retry(String), +} diff --git a/app/src-tauri/src/lib.rs b/app/src-tauri/src/lib.rs index 8a3df7096d..f9ba657890 100644 --- a/app/src-tauri/src/lib.rs +++ b/app/src-tauri/src/lib.rs @@ -9,6 +9,7 @@ mod core_process; mod core_rpc; mod discord_scanner; mod gmessages_scanner; +mod google_meet; mod imessage_scanner; #[cfg(target_os = "macos")] mod mascot_native_window; @@ -1381,6 +1382,9 @@ pub fn run() { let builder = builder.manage(discord_scanner::ScannerRegistry::new()); let builder = builder.manage(telegram_scanner::ScannerRegistry::new()); let builder = builder.manage(screen_capture::ScreenShareState::new()); + let builder = builder.manage(std::sync::Arc::new(tokio::sync::Mutex::new( + google_meet::MeetingTranscriptStore::default(), + ))); builder .setup(move |app| { #[cfg(any(windows, target_os = "linux"))]