aria_kit/speaker/
profile.rs1use std::time::SystemTime;
8
9use serde::{Deserialize, Serialize};
10
11use super::label::reads_as_anonymous;
12
13const MAX_NAME_BYTES: usize = 64;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
20#[serde(rename_all = "snake_case")]
21pub enum Role {
22 Owner,
23 Guest,
24}
25
26impl std::fmt::Display for Role {
27 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 formatter.write_str(match self {
29 Self::Owner => "owner",
30 Self::Guest => "guest",
31 })
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
38pub struct SpeakerName(String);
39
40impl SpeakerName {
41 pub fn new(name: impl Into<String>) -> Result<Self, SpeakerNameError> {
42 let name = name.into();
43 if name.is_empty() {
44 return Err(SpeakerNameError::Empty);
45 }
46 if name.len() > MAX_NAME_BYTES {
47 return Err(SpeakerNameError::TooLong {
48 actual_bytes: name.len(),
49 maximum_bytes: MAX_NAME_BYTES,
50 });
51 }
52 if name.trim() != name {
53 return Err(SpeakerNameError::Padded);
54 }
55 if name.starts_with('.')
58 || name
59 .chars()
60 .any(|character| character.is_control() || matches!(character, '/' | '\\' | ':'))
61 {
62 return Err(SpeakerNameError::Unusable);
63 }
64 if reads_as_anonymous(&name) {
65 return Err(SpeakerNameError::Reserved);
66 }
67 Ok(Self(name))
68 }
69
70 pub fn as_str(&self) -> &str {
71 &self.0
72 }
73}
74
75impl std::fmt::Display for SpeakerName {
76 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 formatter.write_str(&self.0)
78 }
79}
80
81#[derive(Debug, Clone, PartialEq)]
83pub struct Profile {
84 pub name: SpeakerName,
85 pub role: Role,
86 pub engine: String,
88 pub enrolled_at: SystemTime,
89 pub vector: Vec<f32>,
91}
92
93#[cfg(any(test, feature = "test-support"))]
96pub fn enrolled_voice(name: &str, role: Role, vector: Vec<f32>) -> Profile {
97 Profile {
98 name: SpeakerName::new(name).expect("a test name is usable"),
99 role,
100 engine: "test".to_owned(),
101 enrolled_at: SystemTime::UNIX_EPOCH,
102 vector,
103 }
104}
105
106#[derive(Debug, thiserror::Error)]
107pub enum SpeakerNameError {
108 #[error("a speaker name cannot be empty")]
109 Empty,
110
111 #[error("a speaker name holds {actual_bytes} bytes; maximum is {maximum_bytes}")]
112 TooLong {
113 actual_bytes: usize,
114 maximum_bytes: usize,
115 },
116
117 #[error("a speaker name cannot start or end with a space")]
118 Padded,
119
120 #[error("a speaker name cannot start with a dot or hold a path separator")]
121 Unusable,
122
123 #[error("a speaker name cannot read like an anonymous speaker, such as \"Speaker 2\"")]
124 Reserved,
125}