ibm_watson/text-to-speech/customisations/models/mod.rs
1use std::borrow::Cow;
2
3use reqwest::{Method, Request, StatusCode, Url, Version};
4use serde::{Deserialize, Serialize};
5
6use crate::tts::TextToSpeech;
7
8use super::{
9 errors::{CreateModelError, DeleteModelError, GetModelError, ListModelError, UpdateModelError},
10 prompts::Prompt,
11 words::Word,
12};
13
14#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
15/// Defines a custom model
16pub struct Model {
17 /// the customisation id (guid) of the custom model. the create a custom model method returns only this field. it does not not return the other fields of this object.
18 #[serde(rename = "customization_id")]
19 pub customisation_id: String,
20 /// the name of the custom model.
21 #[serde(rename = "name")]
22 pub name: String,
23 /// the language identifier of the custom model (for example, en-us).
24 #[serde(rename = "language", skip_serializing_if = "Option::is_none")]
25 pub language: Option<String>,
26 /// the guid of the credentials for the instance of the service that owns the custom model.
27 #[serde(rename = "owner", skip_serializing_if = "Option::is_none")]
28 pub owner: Option<String>,
29 /// the date and time in coordinated universal time (utc) at which the custom model was created. the value is provided in full iso 8601 format (yyyy-mm-ddthh:mm:ss.stzd)
30 #[serde(rename = "created", skip_serializing_if = "Option::is_none")]
31 pub created: Option<String>,
32 /// the date and time in coordinated universal time (utc) at which the custom model was last modified. the created and updated fields are equal when a model is first added but has yet to be updated. the value is provided in full iso 8601 format (yyyy-mm-ddthh:mm:ss.stzd).
33 #[serde(rename = "last_modified", skip_serializing_if = "Option::is_none")]
34 pub last_modified: Option<String>,
35 /// the description of the custom model.
36 #[serde(rename = "description", skip_serializing_if = "Option::is_none")]
37 pub description: Option<String>,
38 /// an array of word objects that lists the words and their translations from the custom model. the words are listed in alphabetical order, with uppercase letters listed before lowercase letters. the array is empty if no words are defined for the custom model. this field is returned only by the get a custom model method.
39 #[serde(rename = "words", skip_serializing_if = "Option::is_none")]
40 pub words: Option<Vec<Word>>,
41 /// an array of prompt objects that provides information about the prompts that are defined for the specified custom model. the array is empty if no prompts are defined for the custom model. this field is returned only by the get a custom model method.
42 #[serde(rename = "prompts", skip_serializing_if = "Option::is_none")]
43 pub prompts: Option<Vec<Prompt>>,
44}
45
46#[non_exhaustive]
47#[derive(Default)]
48/// The language of the new custom model
49pub enum Language {
50 /// Arabic
51 ArMs,
52 /// Czech (Czechia)
53 CsCz,
54 /// German (Germany)
55 DeDe,
56 /// English (Australia)
57 EnAu,
58 /// English (United Kingdom)
59 EnGb,
60 #[default]
61 /// English (United States)
62 EnUs,
63 /// Spanish (Spain)
64 EsEs,
65 /// Spanish (Latin America)
66 EsLa,
67 /// Spanish (United States)
68 EsUs,
69 /// French (Canada)
70 FrCa,
71 /// French (France)
72 FrFr,
73 /// Italian (Italy)
74 ItIt,
75 /// Japanese (Japan)
76 JaJp,
77 /// Koren (South Korea)
78 KoKr,
79 /// Dutch (Belgium)
80 NlBe,
81 /// Dutch (Netherlands)
82 NlNl,
83 /// Portuguese (Brazil)
84 PtBr,
85 /// Swedish (Sweden)
86 SvSe,
87 /// Chinese (PRC)
88 ZhCn,
89}
90
91impl Language {
92 /// The value that the server expects for a particular language
93 pub fn id(&self) -> Cow<'static, str> {
94 match self {
95 Language::ArMs => Cow::from("ar-MS"),
96 Language::CsCz => Cow::from("cs-CZ"),
97 Language::DeDe => Cow::from("de-DE"),
98 Language::EnAu => Cow::from("en-AU"),
99 Language::EnGb => Cow::from("en-GB"),
100 Language::EnUs => Cow::from("en-US"),
101 Language::EsEs => Cow::from("es-ES"),
102 Language::EsLa => Cow::from("es-LA"),
103 Language::EsUs => Cow::from("es-US"),
104 Language::FrCa => Cow::from("fr-CA"),
105 Language::FrFr => Cow::from("fr-FR"),
106 Language::ItIt => Cow::from("it-IT"),
107 Language::JaJp => Cow::from("ja-JP"),
108 Language::KoKr => Cow::from("ko-KR"),
109 Language::NlBe => Cow::from("nl-BE"),
110 Language::NlNl => Cow::from("nl-NL"),
111 Language::PtBr => Cow::from("pt-BR"),
112 Language::SvSe => Cow::from("sv-SE"),
113 Language::ZhCn => Cow::from("zh-CN"),
114 }
115 }
116}
117
118impl TextToSpeech<'_> {
119 /// Creates a new empty custom model. You must specify a name for the new custom model. You can optionally specify the language and a description for the new model. The model is owned by the instance of the service whose credentials are used to create it
120 ///
121 /// # Parameters
122 ///
123 /// * `name` - The name of the new custom model
124 /// * `language` - The language of the new custom model. You create a custom model for a specific language, not for a specific voice. A custom model can be used with any voice for its specified language. If [`None`] is specified, the [`default language`] is used
125 /// * `description` - A description of the new custom model. Specifying a description is recommended
126 ///
127 /// # Example
128 /// ``` no_run
129 /// # use ibm_watson::{
130 /// # auth::IamAuthenticator,
131 /// # tts::{voices::WatsonVoice, TextToSpeech},
132 /// # };
133 /// # async fn foo()-> Result<(), Box<dyn std::error::Error>> {
134 /// # let auth = IamAuthenticator::new("api_key").await?;
135 /// # let tts = TextToSpeech::new(&auth, "service_url");
136 /// let model = tts.create_custom_model("new model", None, Some("example")).await?;
137 /// println!("model: {:#?}", model);
138 /// # Ok(())
139 /// # }
140 /// ```
141 /// [`None`]: std::option::Option::None
142 /// [`default language`]: self::Language::EnUs
143 pub async fn create_custom_model(
144 &self,
145 name: impl AsRef<str>,
146 language: Option<Language>,
147 description: Option<impl AsRef<str>>,
148 ) -> Result<Model, CreateModelError> {
149 let mut url = Url::parse(self.service_url).unwrap();
150 url.set_path("v1/customizations");
151 #[derive(Serialize, Deserialize)]
152 struct FormBody<'a> {
153 name: &'a str,
154 language: &'a str,
155 description: &'a str,
156 }
157 let name = name.as_ref();
158 let language = language.unwrap_or_default().id().to_owned();
159 let description = match description {
160 Some(s) => s.as_ref().to_owned(),
161 None => String::default(),
162 };
163 let form_body = FormBody {
164 name,
165 language: &language,
166 description: &description,
167 };
168 let client = self.get_client();
169 let response = client
170 .post(url)
171 .json(&form_body)
172 .version(if cfg!(feature = "http2") {
173 Version::HTTP_2
174 } else {
175 Version::default()
176 })
177 .send()
178 .await
179 .map_err(|e| CreateModelError::ConnectionError(e.to_string()))?;
180 match response.status() {
181 StatusCode::OK => {
182 let root: Model = response.json().await.unwrap();
183 Ok(root)
184 }
185 StatusCode::BAD_REQUEST => Err(CreateModelError::BadRequest400),
186 StatusCode::INTERNAL_SERVER_ERROR => Err(CreateModelError::InternalServerError500),
187 StatusCode::SERVICE_UNAVAILABLE => Err(CreateModelError::ServiceUnavailable503),
188 _ => {
189 unreachable!()
190 }
191 }
192 }
193
194 /// Lists metadata such as the name and description for all custom models that are owned by an instance of the service. Specify a [`language`] to list the custom models for that language only. To see the words and prompts in addition to the metadata for a specific custom model, use [`get_custom_model()`]. You must use credentials for the instance of the service that owns a model to list information about it.
195 ///
196 /// # Parameters
197 ///
198 /// * `language` - The language for which custom models that are owned by the requesting credentials are to be returned. Pass [`None`] to see all custom models that are owned by the requester
199 ///
200 /// # Example
201 /// ``` no_run
202 /// # use ibm_watson::{
203 /// # auth::IamAuthenticator,
204 /// # tts::{voices::WatsonVoice, TextToSpeech},
205 /// # };
206 /// # async fn foo()-> Result<(), Box<dyn std::error::Error>> {
207 /// # let auth = IamAuthenticator::new("api_key").await?;
208 /// # let tts = TextToSpeech::new(&auth, "service_url");
209 /// let models = tts.list_custom_models(None).await?;
210 /// println!("found: {:#?} models", models.len());
211 /// # Ok(())
212 /// # }
213 /// ```
214 /// [`None`]: std::option::Option::None
215 /// [`language`]: self::Language
216 /// [`get_custom_model()`]: Self::get_custom_model()
217 pub async fn list_custom_models(
218 &self,
219 language: Option<Language>,
220 ) -> Result<Vec<Model>, ListModelError> {
221 let mut url = Url::parse(self.service_url).unwrap();
222 url.set_path("v1/customizations");
223 url.set_query(Some(&language.unwrap_or_default().id()));
224 let mut req = Request::new(Method::GET, url);
225
226 if cfg!(feature = "http2") {
227 *req.version_mut() = Version::HTTP_2;
228 }
229
230 let client = self.get_client();
231 let response = client
232 .execute(req)
233 .await
234 .map_err(|e| ListModelError::ConnectionError(e.to_string()))?;
235 match response.status() {
236 StatusCode::OK => {
237 #[derive(Deserialize, Serialize)]
238 struct Root {
239 customizations: Vec<Model>,
240 }
241 let root: Root = response.json().await.unwrap();
242 Ok(root.customizations)
243 }
244 StatusCode::BAD_REQUEST => Err(ListModelError::BadRequest400),
245 StatusCode::INTERNAL_SERVER_ERROR => Err(ListModelError::InternalServerError500),
246 StatusCode::SERVICE_UNAVAILABLE => Err(ListModelError::ServiceUnavailable503),
247 _ => {
248 unreachable!()
249 }
250 }
251 }
252
253 /// Updates information for the specified custom model. You can update metadata such as the
254 /// name and description of the model. You can also update the words in the model and their
255 /// translations. Adding a new translation for a word that already exists in a custom model
256 /// overwrites the word's existing translation. A custom model can contain no more than 20,000
257 /// entries. You must use credentials for the instance of the service that owns a model to
258 /// update it
259 ///
260 /// # Parameters
261 ///
262 /// * `customisation_id` - The customisation ID (GUID) of the custom model. You must make the request with credentials for the instance of the service that owns the custom model
263 /// * `name` - A new [`name`] for the custom model
264 /// * `description` - A new [`description`] for the custom model
265 /// * `words` - An array of [`Word`] objects that provides the words and their translations that are to be added or updated for the custom model. Pass an empty array to make no additions or updates
266 ///
267 /// # Example
268 /// ``` no_run
269 /// # use ibm_watson::{
270 /// # auth::IamAuthenticator,
271 /// # tts::{voices::WatsonVoice, TextToSpeech},
272 /// # };
273 /// # async fn foo()-> Result<(), Box<dyn std::error::Error>> {
274 /// # let auth = IamAuthenticator::new("api_key").await?;
275 /// # let tts = TextToSpeech::new(&auth, "service_url");
276 /// tts.update_custom_model("cust-id", Some("foo"), None, None).await?;
277 /// # Ok(())
278 /// # }
279 /// ```
280 /// [`name`]: crate::tts::customisations::Model::name
281 /// [`description`]: crate::tts::customisations::Model::description
282 /// [`Word`]: crate::tts::customisations::Word
283 pub async fn update_custom_model(
284 &self,
285 customisation_id: impl AsRef<str>,
286 name: Option<&str>,
287 description: Option<&str>,
288 words: Option<&[Word]>,
289 ) -> Result<(), UpdateModelError> {
290 let mut url = Url::parse(self.service_url).unwrap();
291 url.set_path(&format!("v1/customizations/{}", customisation_id.as_ref()));
292 #[derive(Deserialize, Serialize)]
293 struct Foo<'a> {
294 #[serde(skip_serializing_if = "Option::is_none")]
295 name: Option<&'a str>,
296 #[serde(skip_serializing_if = "Option::is_none")]
297 description: Option<&'a str>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 words: Option<Vec<Word>>,
300 }
301 impl<'a> Foo<'a> {
302 fn new(
303 name: Option<&'a str>,
304 description: Option<&'a str>,
305 words: Option<&'a [Word]>,
306 ) -> Self {
307 Self {
308 name,
309 description,
310 words: words.map(|f| f.to_owned()),
311 }
312 }
313 }
314 let data = Foo::new(name, description, words);
315 let client = self.get_client();
316 let response = client
317 .post(url)
318 .json(&data)
319 .version(if cfg!(feature = "http2") {
320 Version::HTTP_2
321 } else {
322 Version::default()
323 })
324 .send()
325 .await
326 .map_err(|e| UpdateModelError::ConnectionError(e.to_string()))?;
327 match response.status() {
328 StatusCode::OK => Ok(()),
329 StatusCode::BAD_REQUEST => Err(UpdateModelError::BadRequest400),
330 StatusCode::INTERNAL_SERVER_ERROR => Err(UpdateModelError::InternalServerError500),
331 StatusCode::SERVICE_UNAVAILABLE => Err(UpdateModelError::ServiceUnavailable503),
332 StatusCode::UNAUTHORIZED => Err(UpdateModelError::Unauthorised401(
333 customisation_id.as_ref().to_owned(),
334 )),
335 _ => {
336 unreachable!()
337 }
338 }
339 }
340
341 /// Gets all information about a specified custom model. In addition to metadata such as the name and description of the custom model, the output includes the words and their translations that are defined for the model, as well as any prompts that are defined for the model. To see just the metadata for a model, use [`list_custom_models()`].
342 ///
343 /// # Parameters
344 ///
345 /// * `customisation_id` - The customisation ID (GUID) of the custom model. You must make the request with credentials for the instance of the service that owns the custom model
346 ///
347 /// # Example
348 /// ``` no_run
349 /// # use ibm_watson::{
350 /// # auth::IamAuthenticator,
351 /// # tts::{voices::WatsonVoice, TextToSpeech},
352 /// # };
353 /// # async fn foo()-> Result<(), Box<dyn std::error::Error>> {
354 /// # let auth = IamAuthenticator::new("api_key").await?;
355 /// # let tts = TextToSpeech::new(&auth, "service_url");
356 /// let model = tts.get_custom_model("cust-id").await?;
357 /// println!("{:#?}", model);
358 /// # Ok(())
359 /// # }
360 /// ```
361 /// [`language`]: self::Language
362 /// [`list_custom_models()`]: Self::list_custom_models()
363 pub async fn get_custom_model(
364 &self,
365 customisation_id: impl AsRef<str>,
366 ) -> Result<Model, GetModelError> {
367 let mut url = Url::parse(self.service_url).unwrap();
368 url.set_path(&format!("v1/customizations/{}", customisation_id.as_ref()));
369 let mut req = Request::new(Method::GET, url);
370
371 if cfg!(feature = "http2") {
372 *req.version_mut() = Version::HTTP_2;
373 }
374
375 let client = self.get_client();
376 let response = client
377 .execute(req)
378 .await
379 .map_err(|e| GetModelError::ConnectionError(e.to_string()))?;
380 match response.status() {
381 StatusCode::OK => {
382 let root: Model = response.json().await.unwrap();
383 Ok(root)
384 }
385 StatusCode::BAD_REQUEST => Err(GetModelError::BadRequest400(
386 customisation_id.as_ref().to_owned(),
387 )),
388 StatusCode::INTERNAL_SERVER_ERROR => Err(GetModelError::InternalServerError500),
389 StatusCode::SERVICE_UNAVAILABLE => Err(GetModelError::ServiceUnavailable503),
390 StatusCode::NOT_MODIFIED => Err(GetModelError::NotModified304),
391 StatusCode::UNAUTHORIZED => Err(GetModelError::Unauthorised401(
392 customisation_id.as_ref().to_owned(),
393 )),
394 _ => {
395 unreachable!()
396 }
397 }
398 }
399
400 /// Deletes the specified custom model. You must use credentials for the instance of the service that owns a model to delete it.
401 ///
402 /// # Parameters
403 ///
404 /// * `customisation_id` - The customisation ID (GUID) of the custom model. You must make the request with credentials for the instance of the service that owns the custom model
405 ///
406 /// # Example
407 /// ``` no_run
408 /// # use ibm_watson::{
409 /// # auth::IamAuthenticator,
410 /// # tts::{voices::WatsonVoice, TextToSpeech},
411 /// # };
412 /// # async fn foo()-> Result<(), Box<dyn std::error::Error>> {
413 /// # let auth = IamAuthenticator::new("api_key").await?;
414 /// # let tts = TextToSpeech::new(&auth, "service_url");
415 /// if tts.delete_custom_model("cust-id").await.is_ok() {
416 /// println!("model deleted");
417 /// }
418 /// # Ok(())
419 /// # }
420 /// ```
421 /// [`language`]: self::Language
422 /// [`list_custom_models()`]: Self::list_custom_models()
423 pub async fn delete_custom_model(
424 &self,
425 customisation_id: impl AsRef<str>,
426 ) -> Result<(), DeleteModelError> {
427 let mut url = Url::parse(self.service_url).unwrap();
428 url.set_path(&format!("v1/customizations/{}", customisation_id.as_ref()));
429 let mut req = Request::new(Method::DELETE, url);
430
431 if cfg!(feature = "http2") {
432 *req.version_mut() = Version::HTTP_2;
433 }
434
435 let client = self.get_client();
436 let response = client
437 .execute(req)
438 .await
439 .map_err(|e| DeleteModelError::ConnectionError(e.to_string()))?;
440 match response.status() {
441 StatusCode::NO_CONTENT => Ok(()),
442 StatusCode::BAD_REQUEST => Err(DeleteModelError::BadRequest400(
443 customisation_id.as_ref().to_owned(),
444 )),
445 StatusCode::INTERNAL_SERVER_ERROR => Err(DeleteModelError::InternalServerError500),
446 StatusCode::SERVICE_UNAVAILABLE => Err(DeleteModelError::ServiceUnavailable503),
447 StatusCode::UNAUTHORIZED => Err(DeleteModelError::Unauthorised401(
448 customisation_id.as_ref().to_owned(),
449 )),
450 _ => {
451 unreachable!()
452 }
453 }
454 }
455}