1use crate::result::Transcript;
10use transcribe_cpp_sys as sys;
11
12pub type Result<T> = std::result::Result<T, Error>;
14
15#[derive(Debug, thiserror::Error)]
21#[non_exhaustive]
22pub enum Error {
23 #[error("invalid argument: {0}")]
25 InvalidArgument(String),
26 #[error("not implemented by this model: {0}")]
28 NotImplemented(String),
29 #[error("model file not found: {0}")]
31 ModelFileNotFound(String),
32 #[error("model load failed: {0}")]
34 ModelLoad(String),
35 #[error("out of memory: {0}")]
37 OutOfMemory(String),
38 #[error("backend error: {0}")]
40 Backend(String),
41 #[error("unsupported request: {0}")]
44 Unsupported(String),
45 #[error("ABI struct-size mismatch: {0}")]
48 BadStructSize(String),
49 #[error("input too long: {0}")]
51 InputTooLong(String),
52 #[error("operation aborted: {message}")]
55 Aborted {
56 message: String,
57 partial: Option<Box<Transcript>>,
59 },
60 #[error("output truncated before end-of-stream: {message}")]
64 OutputTruncated {
65 message: String,
66 partial: Option<Box<Transcript>>,
68 },
69 #[error("output began repeating before end-of-stream: {message}")]
73 OutputRepetition {
74 message: String,
75 partial: Option<Box<Transcript>>,
77 },
78 #[error("native library version mismatch: {0}")]
81 VersionMismatch(String),
82 #[error("string contains an interior NUL byte: {0}")]
84 Nul(#[from] std::ffi::NulError),
85 #[error("model busy: {0}")]
92 Busy(String),
93 #[error("{0}")]
95 Other(String),
96}
97
98impl Error {
99 pub fn raw_status(&self) -> i32 {
102 use sys::transcribe_status as S;
103 let s = match self {
104 Error::InvalidArgument(_) => S::TRANSCRIBE_ERR_INVALID_ARG,
105 Error::NotImplemented(_) => S::TRANSCRIBE_ERR_NOT_IMPLEMENTED,
106 Error::ModelFileNotFound(_) => S::TRANSCRIBE_ERR_FILE_NOT_FOUND,
107 Error::ModelLoad(_) => S::TRANSCRIBE_ERR_GGUF,
108 Error::OutOfMemory(_) => S::TRANSCRIBE_ERR_OOM,
109 Error::Backend(_) => S::TRANSCRIBE_ERR_BACKEND,
110 Error::Unsupported(_) => S::TRANSCRIBE_ERR_UNSUPPORTED_TASK,
111 Error::BadStructSize(_) => S::TRANSCRIBE_ERR_BAD_STRUCT_SIZE,
112 Error::InputTooLong(_) => S::TRANSCRIBE_ERR_INPUT_TOO_LONG,
113 Error::Aborted { .. } => S::TRANSCRIBE_ERR_ABORTED,
114 Error::OutputTruncated { .. } => S::TRANSCRIBE_ERR_OUTPUT_TRUNCATED,
115 Error::OutputRepetition { .. } => S::TRANSCRIBE_ERR_OUTPUT_REPETITION,
116 _ => S::TRANSCRIBE_OK,
117 };
118 s.0 as i32
119 }
120
121 pub fn partial(&self) -> Option<&Transcript> {
125 match self {
126 Error::Aborted { partial, .. }
127 | Error::OutputTruncated { partial, .. }
128 | Error::OutputRepetition { partial, .. } => partial.as_deref(),
129 _ => None,
130 }
131 }
132}
133
134pub(crate) fn status_string(status: i32) -> String {
136 let ptr = unsafe { sys::transcribe_status_string(status) };
138 if ptr.is_null() {
139 return format!("status {status}");
140 }
141 unsafe { std::ffi::CStr::from_ptr(ptr) }
142 .to_string_lossy()
143 .into_owned()
144}
145
146pub(crate) fn error_for_status(status: sys::transcribe_status, context: &str) -> Error {
149 use sys::transcribe_status as S;
150 let code = status.0 as i32;
151 let msg = {
152 let s = status_string(code);
153 if context.is_empty() {
154 format!("{s} (status {code})")
155 } else {
156 format!("{context}: {s} (status {code})")
157 }
158 };
159 match status {
160 S::TRANSCRIBE_ERR_INVALID_ARG | S::TRANSCRIBE_ERR_SAMPLE_RATE => {
161 Error::InvalidArgument(msg)
162 }
163 S::TRANSCRIBE_ERR_NOT_IMPLEMENTED => Error::NotImplemented(msg),
164 S::TRANSCRIBE_ERR_FILE_NOT_FOUND => Error::ModelFileNotFound(msg),
165 S::TRANSCRIBE_ERR_GGUF
166 | S::TRANSCRIBE_ERR_UNSUPPORTED_ARCH
167 | S::TRANSCRIBE_ERR_UNSUPPORTED_VARIANT => Error::ModelLoad(msg),
168 S::TRANSCRIBE_ERR_OOM => Error::OutOfMemory(msg),
169 S::TRANSCRIBE_ERR_BACKEND => Error::Backend(msg),
170 S::TRANSCRIBE_ERR_UNSUPPORTED_LANGUAGE
171 | S::TRANSCRIBE_ERR_UNSUPPORTED_TASK
172 | S::TRANSCRIBE_ERR_UNSUPPORTED_TIMESTAMPS
173 | S::TRANSCRIBE_ERR_UNSUPPORTED_PNC
174 | S::TRANSCRIBE_ERR_UNSUPPORTED_ITN => Error::Unsupported(msg),
175 S::TRANSCRIBE_ERR_BAD_STRUCT_SIZE => Error::BadStructSize(msg),
176 S::TRANSCRIBE_ERR_INPUT_TOO_LONG => Error::InputTooLong(msg),
177 S::TRANSCRIBE_ERR_ABORTED => Error::Aborted {
178 message: msg,
179 partial: None,
180 },
181 S::TRANSCRIBE_ERR_OUTPUT_TRUNCATED => Error::OutputTruncated {
182 message: msg,
183 partial: None,
184 },
185 S::TRANSCRIBE_ERR_OUTPUT_REPETITION => Error::OutputRepetition {
186 message: msg,
187 partial: None,
188 },
189 _ => Error::Other(msg),
190 }
191}
192
193pub(crate) fn check(status: sys::transcribe_status, context: &str) -> Result<()> {
195 if status == sys::transcribe_status::TRANSCRIBE_OK {
196 Ok(())
197 } else {
198 Err(error_for_status(status, context))
199 }
200}