1use std::ffi::CStr;
9use std::os::raw::c_char;
10
11use transcribe_cpp_sys as sys;
12
13use crate::types::TimestampKind;
14
15#[derive(Debug, Clone, Default, PartialEq)]
17#[cfg_attr(
18 feature = "serde",
19 derive(serde::Serialize, serde::Deserialize),
20 serde(default)
21)]
22pub struct Transcript {
23 pub text: String,
25 pub raw_text: String,
29 pub language: Option<String>,
32 pub timestamp_kind: TimestampKind,
34 pub segments: Vec<Segment>,
37 pub speaker_segments: Vec<SpeakerSegment>,
39 pub words: Vec<Word>,
41 pub tokens: Vec<Token>,
43 pub timings: Timings,
45}
46
47#[derive(Debug, Clone, Default, PartialEq)]
49#[cfg_attr(
50 feature = "serde",
51 derive(serde::Serialize, serde::Deserialize),
52 serde(default)
53)]
54pub struct Segment {
55 pub t0_ms: i64,
56 pub t1_ms: i64,
57 pub first_word: i32,
58 pub n_words: i32,
59 pub first_token: i32,
60 pub n_tokens: i32,
61 pub text: String,
62 pub speaker_id: i32,
64}
65
66#[derive(Debug, Clone, Default, PartialEq)]
69#[cfg_attr(
70 feature = "serde",
71 derive(serde::Serialize, serde::Deserialize),
72 serde(default)
73)]
74pub struct SpeakerSegment {
75 pub t0_ms: i64,
76 pub t1_ms: i64,
77 pub speaker_id: i32,
78 #[cfg_attr(
79 feature = "serde",
80 serde(default = "nan", deserialize_with = "nan_from_null")
81 )]
82 pub p: f32,
83}
84
85#[derive(Debug, Clone, Default, PartialEq)]
87#[cfg_attr(
88 feature = "serde",
89 derive(serde::Serialize, serde::Deserialize),
90 serde(default)
91)]
92pub struct Word {
93 pub t0_ms: i64,
94 pub t1_ms: i64,
95 pub seg_index: i32,
96 pub first_token: i32,
97 pub n_tokens: i32,
98 pub text: String,
99}
100
101#[derive(Debug, Clone, Default, PartialEq)]
104#[cfg_attr(
105 feature = "serde",
106 derive(serde::Serialize, serde::Deserialize),
107 serde(default)
108)]
109pub struct Token {
110 pub id: i32,
111 #[cfg_attr(
112 feature = "serde",
113 serde(default = "nan", deserialize_with = "nan_from_null")
114 )]
115 pub p: f32,
116 pub t0_ms: i64,
117 pub t1_ms: i64,
118 pub seg_index: i32,
119 pub word_index: i32,
120 pub text: String,
121}
122
123#[derive(Debug, Clone, Copy, Default, PartialEq)]
125#[cfg_attr(
126 feature = "serde",
127 derive(serde::Serialize, serde::Deserialize),
128 serde(default)
129)]
130pub struct Timings {
131 pub load_ms: f32,
132 pub mel_ms: f32,
133 pub encode_ms: f32,
134 pub decode_ms: f32,
135}
136
137#[cfg(feature = "serde")]
139fn nan() -> f32 {
140 f32::NAN
141}
142
143#[cfg(feature = "serde")]
146fn nan_from_null<'de, D: serde::Deserializer<'de>>(d: D) -> Result<f32, D::Error> {
147 use serde::Deserialize;
148 if d.is_human_readable() {
149 Ok(Option::<f32>::deserialize(d)?.unwrap_or(f32::NAN))
150 } else {
151 f32::deserialize(d)
152 }
153}
154
155pub(crate) fn owned_str(ptr: *const c_char) -> String {
157 if ptr.is_null() {
158 return String::new();
159 }
160 unsafe { CStr::from_ptr(ptr) }
161 .to_string_lossy()
162 .into_owned()
163}
164
165pub(crate) fn owned_opt_str(ptr: *const c_char) -> Option<String> {
167 if ptr.is_null() {
168 return None;
169 }
170 let s = unsafe { CStr::from_ptr(ptr) }
171 .to_string_lossy()
172 .into_owned();
173 if s.is_empty() {
174 None
175 } else {
176 Some(s)
177 }
178}
179
180impl Segment {
181 pub(crate) fn from_raw(raw: &sys::transcribe_segment) -> Self {
182 Segment {
183 t0_ms: raw.t0_ms,
184 t1_ms: raw.t1_ms,
185 first_word: raw.first_word,
186 n_words: raw.n_words,
187 first_token: raw.first_token,
188 n_tokens: raw.n_tokens,
189 text: owned_str(raw.text),
190 speaker_id: raw.speaker_id,
191 }
192 }
193}
194
195impl SpeakerSegment {
196 pub(crate) fn from_raw(raw: &sys::transcribe_speaker_segment) -> Self {
197 SpeakerSegment {
198 t0_ms: raw.t0_ms,
199 t1_ms: raw.t1_ms,
200 speaker_id: raw.speaker_id,
201 p: raw.p,
202 }
203 }
204}
205
206impl Word {
207 pub(crate) fn from_raw(raw: &sys::transcribe_word) -> Self {
208 Word {
209 t0_ms: raw.t0_ms,
210 t1_ms: raw.t1_ms,
211 seg_index: raw.seg_index,
212 first_token: raw.first_token,
213 n_tokens: raw.n_tokens,
214 text: owned_str(raw.text),
215 }
216 }
217}
218
219impl Token {
220 pub(crate) fn from_raw(raw: &sys::transcribe_token) -> Self {
221 Token {
222 id: raw.id,
223 p: raw.p,
224 t0_ms: raw.t0_ms,
225 t1_ms: raw.t1_ms,
226 seg_index: raw.seg_index,
227 word_index: raw.word_index,
228 text: owned_str(raw.text),
229 }
230 }
231}
232
233impl Timings {
234 pub(crate) fn from_raw(raw: &sys::transcribe_timings) -> Self {
235 Timings {
236 load_ms: raw.load_ms,
237 mel_ms: raw.mel_ms,
238 encode_ms: raw.encode_ms,
239 decode_ms: raw.decode_ms,
240 }
241 }
242}