Skip to main content

speakers_core/
protocol.rs

1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4
5use crate::model::ModelVariant;
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(tag = "kind", rename_all = "snake_case")]
9pub enum VoiceSelection {
10    Preset { name: String },
11    Profile { name: String },
12}
13
14impl VoiceSelection {
15    pub fn preset(name: impl Into<String>) -> Self {
16        Self::Preset { name: name.into() }
17    }
18
19    pub fn profile(name: impl Into<String>) -> Self {
20        Self::Profile { name: name.into() }
21    }
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(tag = "type", rename_all = "snake_case")]
26pub enum DaemonRequest {
27    Health,
28    Shutdown,
29    Synthesize {
30        text: String,
31        language: String,
32        output: PathBuf,
33        voice: VoiceSelection,
34        #[serde(skip_serializing_if = "Option::is_none")]
35        rate: Option<i32>,
36        #[serde(skip_serializing_if = "Option::is_none")]
37        pitch: Option<i32>,
38    },
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct HealthData {
43    pub pid: u32,
44    pub model: ModelVariant,
45    pub device: String,
46    pub socket: PathBuf,
47    pub uptime_secs: u64,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct SynthesisData {
52    pub output: PathBuf,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(tag = "kind", content = "payload", rename_all = "snake_case")]
57pub enum ResponseData {
58    Ack,
59    Health(HealthData),
60    Synthesis(SynthesisData),
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct DaemonResponse {
65    pub ok: bool,
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub error_code: Option<String>,
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub error_message: Option<String>,
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub error_details: Option<Vec<String>>,
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub data: Option<ResponseData>,
74}
75
76impl DaemonResponse {
77    pub fn ok(data: Option<ResponseData>) -> Self {
78        Self {
79            ok: true,
80            error_code: None,
81            error_message: None,
82            error_details: None,
83            data,
84        }
85    }
86
87    pub fn error(code: impl Into<String>, message: impl Into<String>) -> Self {
88        Self::error_with_details(code, message, Vec::<String>::new())
89    }
90
91    pub fn error_with_details(
92        code: impl Into<String>,
93        message: impl Into<String>,
94        details: Vec<String>,
95    ) -> Self {
96        Self {
97            ok: false,
98            error_code: Some(code.into()),
99            error_message: Some(message.into()),
100            error_details: (!details.is_empty()).then_some(details),
101            data: None,
102        }
103    }
104}