feat: 添加默认配置文件创建功能,确保首次启动时可用
This commit is contained in:
parent
26cbe7aa2d
commit
7d11ab8067
@ -10,8 +10,11 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
#[serde(default)]
|
||||||
pub providers: HashMap<String, ProviderConfig>,
|
pub providers: HashMap<String, ProviderConfig>,
|
||||||
|
#[serde(default)]
|
||||||
pub models: HashMap<String, ModelConfig>,
|
pub models: HashMap<String, ModelConfig>,
|
||||||
|
#[serde(default)]
|
||||||
pub agents: HashMap<String, AgentConfig>,
|
pub agents: HashMap<String, AgentConfig>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub time: TimeConfig,
|
pub time: TimeConfig,
|
||||||
@ -886,9 +889,12 @@ impl Config {
|
|||||||
tracing::info!(path = %fallback.display(), "Config loaded from fallback path");
|
tracing::info!(path = %fallback.display(), "Config loaded from fallback path");
|
||||||
fs::read_to_string(fallback)?
|
fs::read_to_string(fallback)?
|
||||||
} else {
|
} else {
|
||||||
return Err(Box::new(ConfigError::ConfigNotFound(
|
// Auto-create a minimal config on first startup
|
||||||
path.to_string_lossy().to_string(),
|
tracing::info!(
|
||||||
)));
|
path = %path.display(),
|
||||||
|
"Config not found, auto-creating minimal config"
|
||||||
|
);
|
||||||
|
Self::create_default_config(path)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let content = resolve_env_placeholders(&content);
|
let content = resolve_env_placeholders(&content);
|
||||||
@ -906,6 +912,46 @@ impl Config {
|
|||||||
Ok(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> {
|
pub fn get_provider_config(&self, agent_name: &str) -> Result<LLMProviderConfig, ConfigError> {
|
||||||
let agent = self
|
let agent = self
|
||||||
.agents
|
.agents
|
||||||
|
|||||||
@ -31,7 +31,7 @@ pub mod ws;
|
|||||||
use axum::{Router, routing};
|
use axum::{Router, routing};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpSocket;
|
||||||
use tokio::sync::Semaphore;
|
use tokio::sync::Semaphore;
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
|
|
||||||
@ -223,8 +223,16 @@ pub async fn run(
|
|||||||
.with_state(state.clone())
|
.with_state(state.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
let addr = format!("{}:{}", bind_host, bind_port);
|
let addr: std::net::SocketAddr = format!("{}:{}", bind_host, bind_port).parse()?;
|
||||||
let listener = TcpListener::bind(&addr).await?;
|
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");
|
tracing::info!(address = %addr, "Gateway listening");
|
||||||
|
|
||||||
// Graceful shutdown / restart signal
|
// Graceful shutdown / restart signal
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user