lc/cli/
proxy.rs

1//! Proxy server commands
2
3use anyhow::Result;
4use colored::*;
5
6/// Handle proxy-related commands
7pub async fn handle(
8    port: Option<u16>,
9    host: Option<String>,
10    provider: Option<String>,
11    model: Option<String>,
12    api_key: Option<String>,
13    generate_key: bool,
14) -> Result<()> {
15    // Defaults
16    let port_val = port.unwrap_or(8080);
17    let host_str = host.unwrap_or_else(|| "127.0.0.1".to_string());
18
19    // Handle API key generation
20    let final_api_key = if generate_key {
21        let generated_key = crate::services::proxy::generate_api_key();
22        println!(
23            "{} Generated API key: {}",
24            "🔑".green(),
25            generated_key.bold()
26        );
27        Some(generated_key)
28    } else {
29        api_key
30    };
31
32    // Validate provider if specified
33    if let Some(ref provider_name) = provider {
34        let config = crate::config::Config::load()?;
35        if !config.has_provider(provider_name) {
36            anyhow::bail!(
37                "Provider '{}' not found. Add it first with 'lc providers add'",
38                provider_name
39            );
40        }
41    }
42
43    // Validate model if specified (could be alias or provider:model format)
44    if let Some(ref model_name) = model {
45        let config = crate::config::Config::load()?;
46
47        // Check if it's an alias
48        if let Some(_alias_target) = config.get_alias(model_name) {
49            // Valid alias
50        } else if model_name.contains(':') {
51            // Check provider:model format
52            let parts: Vec<&str> = model_name.splitn(2, ':').collect();
53            if parts.len() == 2 {
54                let provider_name = parts[0];
55                if !config.has_provider(provider_name) {
56                    anyhow::bail!(
57                        "Provider '{}' not found in model specification '{}'",
58                        provider_name,
59                        model_name
60                    );
61                }
62            }
63        } else {
64            // Assume it's a model name for the default or specified provider
65            // This will be validated when requests come in
66        }
67    }
68
69    // Show configuration summary
70    println!("\n{}", "Proxy Server Configuration:".bold().blue());
71    println!("  {} {}:{}", "Address:".bold(), host_str, port_val);
72
73    if let Some(ref provider_filter) = provider {
74        println!(
75            "  {} {}",
76            "Provider Filter:".bold(),
77            provider_filter.green()
78        );
79    } else {
80        println!(
81            "  {} {}",
82            "Provider Filter:".bold(),
83            "All providers".dimmed()
84        );
85    }
86
87    if let Some(ref model_filter) = model {
88        println!("  {} {}", "Model Filter:".bold(), model_filter.green());
89    } else {
90        println!("  {} {}", "Model Filter:".bold(), "All models".dimmed());
91    }
92
93    if final_api_key.is_some() {
94        println!("  {} {}", "Authentication:".bold(), "Enabled".green());
95    } else {
96        println!("  {} {}", "Authentication:".bold(), "Disabled".yellow());
97    }
98
99    println!("\n{}", "Available endpoints:".bold().blue());
100    println!("  {} http://{}:{}/models", "•".blue(), host_str, port_val);
101    println!("  {} http://{}:{}/v1/models", "•".blue(), host_str, port_val);
102    println!("  {} http://{}:{}/chat/completions", "•".blue(), host_str, port_val);
103    println!(
104        "  {} http://{}:{}/v1/chat/completions",
105        "•".blue(),
106        host_str,
107        port_val
108    );
109
110    println!("\n{} Press Ctrl+C to stop the server\n", "💡".yellow());
111
112    // Start the proxy server
113    crate::services::proxy::start_proxy_server(
114        host_str,
115        port_val,
116        provider,
117        model,
118        final_api_key,
119    )
120    .await?;
121
122    Ok(())
123}