botserver/src/main.rs

238 lines
7.1 KiB
Rust
Raw Normal View History

#![allow(dead_code)]
2025-10-06 19:12:13 -03:00
use actix_cors::Cors;
use actix_web::middleware::Logger;
2025-10-06 20:06:43 -03:00
use actix_web::{web, App, HttpServer};
2025-10-11 12:29:03 -03:00
use dotenvy::dotenv;
2025-10-06 19:12:13 -03:00
use log::info;
2025-10-11 20:02:14 -03:00
use std::sync::{Arc, Mutex};
2025-10-06 19:12:13 -03:00
2025-10-06 10:30:17 -03:00
mod auth;
mod automation;
mod basic;
mod bot;
mod channels;
mod config;
mod context;
2025-10-07 10:53:09 -03:00
#[cfg(feature = "email")]
2025-10-06 10:30:17 -03:00
mod email;
mod file;
mod llm;
2025-10-06 20:06:43 -03:00
mod llm_legacy;
2025-10-06 10:30:17 -03:00
mod org;
mod session;
mod shared;
mod tools;
mod whatsapp;
2025-10-06 20:06:43 -03:00
use crate::bot::{
create_session, get_session_history, get_sessions, index, set_mode_handler, static_files,
voice_start, voice_stop, websocket_handler, whatsapp_webhook, whatsapp_webhook_verify,
};
use crate::channels::{VoiceAdapter, WebChannelAdapter};
use crate::config::AppConfig;
2025-10-07 10:53:09 -03:00
#[cfg(feature = "email")]
use crate::email::{
get_emails, get_latest_email_from, list_emails, save_click, save_draft, send_email,
};
2025-10-11 20:02:14 -03:00
use crate::file::upload_file;
use crate::llm_legacy::llm_local::{
chat_completions_local, embeddings_local, ensure_llama_servers_running,
};
2025-10-11 20:02:14 -03:00
use crate::shared::state::AppState;
2025-10-06 20:06:43 -03:00
use crate::whatsapp::WhatsAppAdapter;
2025-10-06 10:30:17 -03:00
2025-10-06 19:12:13 -03:00
#[actix_web::main]
2025-10-06 10:30:17 -03:00
async fn main() -> std::io::Result<()> {
dotenv().ok();
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
2025-10-06 19:12:13 -03:00
info!("Starting General Bots 6.0...");
2025-10-06 10:30:17 -03:00
2025-10-11 20:02:14 -03:00
let cfg = AppConfig::from_env();
let config = std::sync::Arc::new(cfg.clone());
2025-10-06 20:49:38 -03:00
2025-10-11 20:02:14 -03:00
let db_pool = match diesel::Connection::establish(&cfg.database_url()) {
2025-10-11 12:29:03 -03:00
Ok(conn) => {
2025-10-06 20:06:43 -03:00
info!("Connected to main database");
2025-10-11 12:29:03 -03:00
Arc::new(Mutex::new(conn))
2025-10-06 20:06:43 -03:00
}
Err(e) => {
log::error!("Failed to connect to main database: {}", e);
return Err(std::io::Error::new(
std::io::ErrorKind::ConnectionRefused,
format!("Database connection failed: {}", e),
));
}
};
2025-10-06 10:30:17 -03:00
2025-10-11 20:02:14 -03:00
let custom_db_url = format!(
"postgres://{}:{}@{}:{}/{}",
cfg.database_custom.username,
cfg.database_custom.password,
cfg.database_custom.server,
cfg.database_custom.port,
cfg.database_custom.database
);
let db_custom_pool = match diesel::Connection::establish(&custom_db_url) {
Ok(conn) => {
info!("Connected to custom database using constructed URL");
Arc::new(Mutex::new(conn))
}
Err(e2) => {
log::error!("Failed to connect to custom database: {}", e2);
return Err(std::io::Error::new(
std::io::ErrorKind::ConnectionRefused,
format!("Custom Database connection failed: {}", e2),
));
}
};
ensure_llama_servers_running()
.await
.expect("Failed to initialize LLM local server.");
2025-10-06 20:06:43 -03:00
let redis_client = match redis::Client::open("redis://127.0.0.1/") {
Ok(client) => {
info!("Connected to Redis");
Some(Arc::new(client))
}
Err(e) => {
log::warn!("Failed to connect to Redis: {}", e);
None
}
};
2025-10-06 10:30:17 -03:00
2025-10-11 20:02:14 -03:00
let tool_manager = Arc::new(tools::ToolManager::new());
let llm_provider = Arc::new(llm::OpenAIClient::new(
"empty".to_string(),
Some("http://localhost:8081".to_string()),
));
2025-10-06 20:49:38 -03:00
2025-10-06 20:06:43 -03:00
let web_adapter = Arc::new(WebChannelAdapter::new());
let voice_adapter = Arc::new(VoiceAdapter::new(
2025-10-06 19:12:13 -03:00
"https://livekit.example.com".to_string(),
"api_key".to_string(),
"api_secret".to_string(),
2025-10-06 10:30:17 -03:00
));
2025-10-06 20:49:38 -03:00
2025-10-06 20:06:43 -03:00
let whatsapp_adapter = Arc::new(WhatsAppAdapter::new(
2025-10-06 19:12:13 -03:00
"whatsapp_token".to_string(),
"phone_number_id".to_string(),
"verify_token".to_string(),
));
2025-10-06 20:49:38 -03:00
2025-10-06 20:06:43 -03:00
let tool_api = Arc::new(tools::ToolApi::new());
2025-10-06 10:30:17 -03:00
2025-10-11 20:02:14 -03:00
let base_app_state = AppState {
2025-10-11 12:29:03 -03:00
s3_client: None,
2025-10-11 20:02:14 -03:00
config: Some(cfg.clone()),
conn: db_pool.clone(),
custom_conn: db_custom_pool.clone(),
2025-10-11 12:29:03 -03:00
redis_client: redis_client.clone(),
2025-10-11 20:02:14 -03:00
orchestrator: Arc::new(bot::BotOrchestrator::new(
session::SessionManager::new(
diesel::Connection::establish(&cfg.database_url()).unwrap(),
redis_client.clone(),
),
(*tool_manager).clone(),
llm_provider.clone(),
auth::AuthService::new(
diesel::Connection::establish(&cfg.database_url()).unwrap(),
redis_client.clone(),
),
2025-10-11 20:41:52 -03:00
)),
2025-10-06 10:30:17 -03:00
web_adapter,
voice_adapter,
whatsapp_adapter,
2025-10-06 19:12:13 -03:00
tool_api,
};
2025-10-06 10:30:17 -03:00
2025-10-06 20:49:38 -03:00
info!(
"Starting server on {}:{}",
config.server.host, config.server.port
);
2025-10-06 10:30:17 -03:00
2025-10-11 20:02:14 -03:00
let closure_config = config.clone();
2025-10-06 10:30:17 -03:00
HttpServer::new(move || {
2025-10-11 20:02:14 -03:00
let cfg = closure_config.clone();
let auth_service = auth::AuthService::new(
diesel::Connection::establish(&cfg.database_url()).unwrap(),
redis_client.clone(),
);
let session_manager = session::SessionManager::new(
diesel::Connection::establish(&cfg.database_url()).unwrap(),
redis_client.clone(),
);
let orchestrator = Arc::new(bot::BotOrchestrator::new(
session_manager,
(*tool_manager).clone(),
llm_provider.clone(),
auth_service,
));
let app_state = AppState {
s3_client: base_app_state.s3_client.clone(),
config: base_app_state.config.clone(),
conn: base_app_state.conn.clone(),
custom_conn: base_app_state.custom_conn.clone(),
redis_client: base_app_state.redis_client.clone(),
orchestrator,
web_adapter: base_app_state.web_adapter.clone(),
voice_adapter: base_app_state.voice_adapter.clone(),
whatsapp_adapter: base_app_state.whatsapp_adapter.clone(),
tool_api: base_app_state.tool_api.clone(),
};
2025-10-06 19:12:13 -03:00
let cors = Cors::default()
.allow_any_origin()
.allow_any_method()
.allow_any_header()
.max_age(3600);
2025-10-11 20:02:14 -03:00
let app_state_clone = app_state.clone();
2025-10-11 12:29:03 -03:00
let mut app = App::new()
2025-10-06 19:12:13 -03:00
.wrap(cors)
.wrap(Logger::default())
.wrap(Logger::new("HTTP REQUEST: %a %{User-Agent}i"))
2025-10-11 20:02:14 -03:00
.app_data(web::Data::new(app_state_clone));
app = app
.service(upload_file)
2025-10-06 20:06:43 -03:00
.service(index)
.service(static_files)
.service(websocket_handler)
.service(whatsapp_webhook_verify)
.service(whatsapp_webhook)
.service(voice_start)
.service(voice_stop)
.service(create_session)
.service(get_sessions)
.service(get_session_history)
2025-10-11 20:02:14 -03:00
.service(set_mode_handler)
.service(chat_completions_local)
.service(embeddings_local);
2025-10-07 10:53:09 -03:00
#[cfg(feature = "email")]
{
app = app
.service(get_latest_email_from)
.service(get_emails)
.service(list_emails)
.service(send_email)
2025-10-11 20:02:14 -03:00
.service(save_draft)
.service(save_click);
2025-10-07 10:53:09 -03:00
}
app
2025-10-06 10:30:17 -03:00
})
2025-10-06 20:06:43 -03:00
.bind((config.server.host.clone(), config.server.port))?
2025-10-06 10:30:17 -03:00
.run()
.await
}