feat: 添加默认配置文件创建功能,确保首次启动时可用
This commit is contained in:
parent
26cbe7aa2d
commit
7d11ab8067
@ -10,8 +10,11 @@ use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
pub providers: HashMap<String, ProviderConfig>,
|
||||
#[serde(default)]
|
||||
pub models: HashMap<String, ModelConfig>,
|
||||
#[serde(default)]
|
||||
pub agents: HashMap<String, AgentConfig>,
|
||||
#[serde(default)]
|
||||
pub time: TimeConfig,
|
||||
@ -886,9 +889,12 @@ impl Config {
|
||||
tracing::info!(path = %fallback.display(), "Config loaded from fallback path");
|
||||
fs::read_to_string(fallback)?
|
||||
} else {
|
||||
return Err(Box::new(ConfigError::ConfigNotFound(
|
||||
path.to_string_lossy().to_string(),
|
||||
)));
|
||||
// Auto-create a minimal config on first startup
|
||||
tracing::info!(
|
||||
path = %path.display(),
|
||||
"Config not found, auto-creating minimal config"
|
||||
);
|
||||
Self::create_default_config(path)?
|
||||
}
|
||||
};
|
||||
let content = resolve_env_placeholders(&content);
|
||||
@ -906,6 +912,46 @@ impl Config {
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Create the default config file with a minimal template on first startup.
|
||||
/// This ensures the gateway can start and the user can configure via web UI.
|
||||
fn create_default_config(path: &Path) -> Result<String, Box<dyn std::error::Error>> {
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
|
||||
let default_config = serde_json::json!({
|
||||
"providers": {
|
||||
"default": {
|
||||
"type": "openai",
|
||||
"base_url": "https://api.openai.com/v1",
|
||||
"api_key": "<YOUR_API_KEY>",
|
||||
"extra_headers": {}
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"default": {
|
||||
"model_id": "gpt-4o",
|
||||
"temperature": 0.7,
|
||||
"context_window_tokens": 128000
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"default": {
|
||||
"provider": "default",
|
||||
"model": "default"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let content = serde_json::to_string_pretty(&default_config)?;
|
||||
fs::write(path, &content)?;
|
||||
tracing::info!(
|
||||
path = %path.display(),
|
||||
"Created default config file — please configure your API key and model"
|
||||
);
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
pub fn get_provider_config(&self, agent_name: &str) -> Result<LLMProviderConfig, ConfigError> {
|
||||
let agent = self
|
||||
.agents
|
||||
|
||||
@ -31,7 +31,7 @@ pub mod ws;
|
||||
use axum::{Router, routing};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::net::TcpSocket;
|
||||
use tokio::sync::Semaphore;
|
||||
use tower_http::services::ServeDir;
|
||||
|
||||
@ -223,8 +223,16 @@ pub async fn run(
|
||||
.with_state(state.clone())
|
||||
};
|
||||
|
||||
let addr = format!("{}:{}", bind_host, bind_port);
|
||||
let listener = TcpListener::bind(&addr).await?;
|
||||
let addr: std::net::SocketAddr = format!("{}:{}", bind_host, bind_port).parse()?;
|
||||
let listener = {
|
||||
let socket = match addr {
|
||||
std::net::SocketAddr::V4(_) => TcpSocket::new_v4()?,
|
||||
std::net::SocketAddr::V6(_) => TcpSocket::new_v6()?,
|
||||
};
|
||||
socket.set_reuseaddr(true)?;
|
||||
socket.bind(addr)?;
|
||||
socket.listen(1024)?
|
||||
};
|
||||
tracing::info!(address = %addr, "Gateway listening");
|
||||
|
||||
// Graceful shutdown / restart signal
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user