aurum_core/providers/
mod.rs1pub mod local;
4pub mod openrouter;
5
6use crate::audio::AudioInput;
7use crate::error::Result;
8use async_trait::async_trait;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum BackendKind {
15 Asr,
17 LlmAssisted,
19}
20
21#[derive(Debug, Clone)]
23pub struct TranscriptionOptions {
24 pub model: String,
26 pub language: String,
28 pub timestamps: bool,
30 pub cancel: Option<crate::cancel::CancelFlag>,
32}
33
34impl Default for TranscriptionOptions {
35 fn default() -> Self {
36 Self {
37 model: crate::config::DEFAULT_LOCAL_MODEL.to_string(),
38 language: crate::config::DEFAULT_LANGUAGE.to_string(),
39 timestamps: false,
40 cancel: None,
41 }
42 }
43}
44
45impl TranscriptionOptions {
46 pub fn with_cancel(mut self, flag: crate::cancel::CancelFlag) -> Self {
47 self.cancel = Some(flag);
48 self
49 }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
54pub struct Segment {
55 pub start: f64,
57 pub end: f64,
59 pub text: String,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct TranscriptionResult {
65 pub text: String,
66 pub segments: Vec<Segment>,
67 pub language: Option<String>,
68 pub model: String,
69 pub provider: String,
70 pub duration_secs: f64,
71 #[serde(default = "default_backend_kind")]
73 pub backend_kind: BackendKind,
74 #[serde(default = "default_true")]
76 pub timestamps_reliable: bool,
77 #[serde(default)]
79 pub cleanup_style: crate::cleanup::CleanupStyle,
80 #[serde(default, skip_serializing_if = "Option::is_none")]
82 pub cleanup_provider: Option<crate::cleanup::CleanupProviderKind>,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub original_text: Option<String>,
86}
87
88fn default_backend_kind() -> BackendKind {
89 BackendKind::Asr
90}
91fn default_true() -> bool {
92 true
93}
94
95impl TranscriptionResult {
96 pub fn local(
97 text: String,
98 segments: Vec<Segment>,
99 language: Option<String>,
100 model: String,
101 duration_secs: f64,
102 ) -> Self {
103 Self {
104 text,
105 segments,
106 language,
107 model,
108 provider: "local".into(),
109 duration_secs,
110 backend_kind: BackendKind::Asr,
111 timestamps_reliable: true,
112 cleanup_style: crate::cleanup::CleanupStyle::Raw,
113 cleanup_provider: None,
114 original_text: None,
115 }
116 }
117
118 pub fn openrouter(
119 text: String,
120 segments: Vec<Segment>,
121 language: Option<String>,
122 model: String,
123 duration_secs: f64,
124 _timestamps_requested: bool,
125 ) -> Self {
126 Self {
127 text,
128 segments,
129 language,
130 model,
131 provider: "openrouter".into(),
132 duration_secs,
133 backend_kind: BackendKind::LlmAssisted,
134 timestamps_reliable: false,
136 cleanup_style: crate::cleanup::CleanupStyle::Raw,
137 cleanup_provider: None,
138 original_text: None,
139 }
140 }
141}
142
143#[async_trait]
145pub trait TranscriptionProvider: Send + Sync {
146 fn name(&self) -> &'static str;
148
149 fn backend_kind(&self) -> BackendKind;
151
152 fn timestamps_reliable(&self) -> bool {
154 matches!(self.backend_kind(), BackendKind::Asr)
155 }
156
157 async fn transcribe(
159 &self,
160 input: &AudioInput,
161 options: &TranscriptionOptions,
162 ) -> Result<TranscriptionResult>;
163}
164
165pub use local::LocalWhisperProvider;
166pub use openrouter::OpenRouterProvider;