//! Application configuration.
use serde::{Deserialize, Serialize};
/// Application configuration.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
/// ML server address
pub ml_server_address: String,
/// Selected TTS model
pub tts_model: String,
/// Selected voice/character
pub voice: String,
/// Selected skill/personality
pub skill: String,
/// Enable emotion detection
pub emotion_detection: bool,
/// Waveform color scheme
pub color_scheme: ColorScheme,
/// Glow intensity (0.0 - 2.0)
pub glow_intensity: f32,
/// Audio input device name (None = default)
pub input_device: Option<String>,
/// Audio output device name (None = default)
pub output_device: Option<String>,
/// Push-to-talk key
pub ptt_key: String,
/// Window position X
pub window_x: Option<f32>,
/// Window position Y
pub window_y: Option<f32>,
/// Window width
pub window_width: Option<f32>,
/// Window height
pub window_height: Option<f32>,
/// Sidebar visible
pub sidebar_visible: bool,
/// Color index
pub color_index: usize,
}
impl Default for AppConfig {
fn default() -> Self {
Self {
ml_server_address: "127.0.0.1:9876".to_string(),
tts_model: "pocket".to_string(),
voice: "assistant".to_string(),
skill: "assistant-default".to_string(),
emotion_detection: true,
color_scheme: ColorScheme::default(),
glow_intensity: 1.5,
input_device: None,
output_device: None,
ptt_key: "Space".to_string(),
window_x: None,
window_y: None,
window_width: None,
window_height: None,
sidebar_visible: true,
color_index: 0,
}
}
}
/// Color scheme selection.
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub enum ColorScheme {
#[default]
LapisLazuli,
MaceWindu,
Emerald,
BurntOrange,
SithRed,
Custom {
r: u8,
g: u8,
b: u8,
},
}
impl AppConfig {
/// Get config file path.
fn config_path() -> std::path::PathBuf {
dirs::config_dir()
.unwrap_or_else(|| std::path::PathBuf::from("."))
.join("LocalVoiceMode")
.join("config.json")
}
/// Load config from file.
pub fn load() -> Self {
let path = Self::config_path();
if path.exists() {
if let Ok(content) = std::fs::read_to_string(&path) {
if let Ok(config) = serde_json::from_str(&content) {
return config;
}
}
}
Self::default()
}
/// Save config to file.
pub fn save(&self) -> anyhow::Result<()> {
let path = Self::config_path();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let content = serde_json::to_string_pretty(self)?;
std::fs::write(path, content)?;
Ok(())
}
}