87 lines
3 KiB
Rust
87 lines
3 KiB
Rust
|
|
//! AI service binary - HTTP wrapper for AI capabilities including RAG, MCP tool
|
||
|
|
//! invocation, and knowledge graphs
|
||
|
|
|
||
|
|
use std::net::SocketAddr;
|
||
|
|
use std::sync::Arc;
|
||
|
|
|
||
|
|
use ai_service::{handlers, AiService, DEFAULT_PORT};
|
||
|
|
use axum::Router;
|
||
|
|
use clap::Parser;
|
||
|
|
|
||
|
|
#[derive(Parser, Debug)]
|
||
|
|
#[command(name = "ai-service")]
|
||
|
|
#[command(about = "HTTP service for AI capabilities including RAG, MCP tool invocation, DAG operations, and knowledge graphs", long_about = None)]
|
||
|
|
struct Args {
|
||
|
|
/// Configuration file path (highest priority)
|
||
|
|
#[arg(short = 'c', long, env = "AI_SERVICE_CONFIG")]
|
||
|
|
config: Option<std::path::PathBuf>,
|
||
|
|
|
||
|
|
/// Configuration directory (searches for ai-service.ncl|toml|json)
|
||
|
|
#[arg(long, env = "PROVISIONING_CONFIG_DIR")]
|
||
|
|
config_dir: Option<std::path::PathBuf>,
|
||
|
|
|
||
|
|
/// Deployment mode (solo, multiuser, cicd, enterprise)
|
||
|
|
#[arg(short = 'm', long, env = "AI_SERVICE_MODE")]
|
||
|
|
mode: Option<String>,
|
||
|
|
|
||
|
|
/// Service bind address
|
||
|
|
#[arg(short = 'H', long, default_value = "127.0.0.1")]
|
||
|
|
host: String,
|
||
|
|
|
||
|
|
/// Service bind port
|
||
|
|
#[arg(short = 'p', long, default_value_t = DEFAULT_PORT)]
|
||
|
|
port: u16,
|
||
|
|
|
||
|
|
/// Print all #[onto_api] registered routes as JSON and exit.
|
||
|
|
/// Pipe to api-catalog-ai-service.json: `just export-api-catalog`
|
||
|
|
#[arg(long)]
|
||
|
|
dump_api_catalog: bool,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::main]
|
||
|
|
async fn main() -> anyhow::Result<()> {
|
||
|
|
// Parse CLI arguments FIRST (so --help works before any other processing)
|
||
|
|
let args = Args::parse();
|
||
|
|
|
||
|
|
if args.dump_api_catalog {
|
||
|
|
println!("{}", ontoref_ontology::api::dump_catalog_json());
|
||
|
|
return Ok(());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize centralized observability (logging, metrics, health checks)
|
||
|
|
let _guard = observability::init_from_env("ai-service", env!("CARGO_PKG_VERSION"))?;
|
||
|
|
|
||
|
|
// Check if ai-service is enabled in deployment-mode.ncl
|
||
|
|
if let Ok(deployment) = platform_config::load_deployment_mode() {
|
||
|
|
if let Ok(enabled) = deployment.is_service_enabled("ai_service") {
|
||
|
|
if !enabled {
|
||
|
|
tracing::warn!("⚠ AI Service is DISABLED in deployment-mode.ncl");
|
||
|
|
std::process::exit(1);
|
||
|
|
}
|
||
|
|
tracing::info!("✓ AI Service is ENABLED in deployment-mode.ncl");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Try to load ai-service.ncl
|
||
|
|
if let Ok(config) = platform_config::load_service_config_from_ncl("ai-service") {
|
||
|
|
tracing::info!("✓ Loaded ai-service configuration from NCL");
|
||
|
|
tracing::debug!("Config: {:?}", config);
|
||
|
|
}
|
||
|
|
let addr: SocketAddr = format!("{}:{}", args.host, args.port).parse()?;
|
||
|
|
|
||
|
|
// Create service
|
||
|
|
let service = Arc::new(AiService::new(addr));
|
||
|
|
tracing::info!("Starting AI service on {}", addr);
|
||
|
|
|
||
|
|
// Create router
|
||
|
|
let app = Router::new()
|
||
|
|
.merge(handlers::create_routes(service))
|
||
|
|
.fallback(|| async { (axum::http::StatusCode::NOT_FOUND, "Not found") });
|
||
|
|
|
||
|
|
// Start server
|
||
|
|
let listener = tokio::net::TcpListener::bind(&addr).await?;
|
||
|
|
axum::serve(listener, app).await?;
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|