fix: load DeepSeek config from browser runtime
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::Deserialize;
|
||||
use thiserror::Error;
|
||||
|
||||
const DEFAULT_DEEPSEEK_BASE_URL: &str = "https://api.deepseek.com";
|
||||
@@ -12,20 +15,65 @@ pub struct DeepSeekSettings {
|
||||
|
||||
impl DeepSeekSettings {
|
||||
pub fn from_env() -> Result<Self, ConfigError> {
|
||||
let api_key = std::env::var("DEEPSEEK_API_KEY")
|
||||
.map_err(|_| ConfigError::MissingEnv("DEEPSEEK_API_KEY"))?;
|
||||
Self::maybe_from_env()?.ok_or(ConfigError::MissingEnv("DEEPSEEK_API_KEY"))
|
||||
}
|
||||
|
||||
pub fn load(config_path: Option<&Path>) -> Result<Option<Self>, ConfigError> {
|
||||
if let Some(path) = config_path {
|
||||
if path.exists() {
|
||||
return Self::from_config_path(path).map(Some);
|
||||
}
|
||||
}
|
||||
|
||||
Self::maybe_from_env()
|
||||
}
|
||||
|
||||
fn maybe_from_env() -> Result<Option<Self>, ConfigError> {
|
||||
let api_key = match std::env::var("DEEPSEEK_API_KEY") {
|
||||
Ok(value) => value,
|
||||
Err(std::env::VarError::NotPresent) => return Ok(None),
|
||||
Err(std::env::VarError::NotUnicode(_)) => {
|
||||
return Err(ConfigError::InvalidEnv("DEEPSEEK_API_KEY"))
|
||||
}
|
||||
};
|
||||
let base_url = std::env::var("DEEPSEEK_BASE_URL")
|
||||
.unwrap_or_else(|_| DEFAULT_DEEPSEEK_BASE_URL.to_string());
|
||||
let model =
|
||||
std::env::var("DEEPSEEK_MODEL").unwrap_or_else(|_| DEFAULT_DEEPSEEK_MODEL.to_string());
|
||||
|
||||
if api_key.trim().is_empty() {
|
||||
Ok(Some(Self::new(api_key, base_url, model)?))
|
||||
}
|
||||
|
||||
fn from_config_path(path: &Path) -> Result<Self, ConfigError> {
|
||||
let raw = std::fs::read_to_string(path)
|
||||
.map_err(|err| ConfigError::ConfigRead(path.to_path_buf(), err.to_string()))?;
|
||||
let config: RawDeepSeekSettings = serde_json::from_str(&raw)
|
||||
.map_err(|err| ConfigError::ConfigParse(path.to_path_buf(), err.to_string()))?;
|
||||
|
||||
Self::new(config.api_key, config.base_url, config.model)
|
||||
.map_err(|err| err.with_path(path))
|
||||
}
|
||||
|
||||
fn new(api_key: String, base_url: String, model: String) -> Result<Self, ConfigError> {
|
||||
let api_key = api_key.trim().to_string();
|
||||
let base_url = if base_url.trim().is_empty() {
|
||||
DEFAULT_DEEPSEEK_BASE_URL.to_string()
|
||||
} else {
|
||||
base_url.trim().to_string()
|
||||
};
|
||||
let model = if model.trim().is_empty() {
|
||||
DEFAULT_DEEPSEEK_MODEL.to_string()
|
||||
} else {
|
||||
model.trim().to_string()
|
||||
};
|
||||
|
||||
if api_key.is_empty() {
|
||||
return Err(ConfigError::EmptyValue("DEEPSEEK_API_KEY"));
|
||||
}
|
||||
if base_url.trim().is_empty() {
|
||||
if base_url.is_empty() {
|
||||
return Err(ConfigError::EmptyValue("DEEPSEEK_BASE_URL"));
|
||||
}
|
||||
if model.trim().is_empty() {
|
||||
if model.is_empty() {
|
||||
return Err(ConfigError::EmptyValue("DEEPSEEK_MODEL"));
|
||||
}
|
||||
|
||||
@@ -37,10 +85,37 @@ impl DeepSeekSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct RawDeepSeekSettings {
|
||||
#[serde(rename = "apiKey", default)]
|
||||
api_key: String,
|
||||
#[serde(rename = "baseUrl", default)]
|
||||
base_url: String,
|
||||
#[serde(default)]
|
||||
model: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Clone, PartialEq, Eq)]
|
||||
pub enum ConfigError {
|
||||
#[error("missing environment variable: {0}")]
|
||||
MissingEnv(&'static str),
|
||||
#[error("environment variable must not be empty: {0}")]
|
||||
EmptyValue(&'static str),
|
||||
#[error("invalid non-utf8 environment variable: {0}")]
|
||||
InvalidEnv(&'static str),
|
||||
#[error("failed to read DeepSeek config file {0}: {1}")]
|
||||
ConfigRead(PathBuf, String),
|
||||
#[error("invalid DeepSeek config JSON in {0}: {1}")]
|
||||
ConfigParse(PathBuf, String),
|
||||
#[error("DeepSeek config value must not be empty: {0} ({1})")]
|
||||
ConfigValueEmpty(&'static str, PathBuf),
|
||||
}
|
||||
|
||||
impl ConfigError {
|
||||
fn with_path(self, path: &Path) -> Self {
|
||||
match self {
|
||||
Self::EmptyValue(field) => Self::ConfigValueEmpty(field, path.to_path_buf()),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user