2025-10-06 19:12:13 -03:00
|
|
|
use actix_cors::Cors;
|
2025-10-06 20:06:43 -03:00
|
|
|
use actix_web::{web, App, HttpServer};
|
2025-10-06 19:12:13 -03:00
|
|
|
use dotenv::dotenv;
|
|
|
|
|
use log::info;
|
2025-10-06 20:06:43 -03:00
|
|
|
use std::error::Error as StdError;
|
2025-10-06 19:12:13 -03:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
2025-10-06 10:30:17 -03:00
|
|
|
mod auth;
|
|
|
|
|
mod automation;
|
|
|
|
|
mod basic;
|
|
|
|
|
mod bot;
|
|
|
|
|
mod channels;
|
|
|
|
|
mod chart;
|
|
|
|
|
mod config;
|
|
|
|
|
mod context;
|
|
|
|
|
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 web_automation;
|
|
|
|
|
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;
|
|
|
|
|
use crate::email::{send_email, test_email};
|
|
|
|
|
use crate::file::{download_file, list_file, upload_file};
|
|
|
|
|
use crate::llm_legacy::llm::{
|
|
|
|
|
chat_completions_local, embeddings_local, generic_chat_completions, health,
|
|
|
|
|
};
|
|
|
|
|
use crate::shared::state::AppState;
|
|
|
|
|
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();
|
2025-10-06 19:12:13 -03:00
|
|
|
env_logger::init();
|
|
|
|
|
|
2025-10-06 20:06:43 -03:00
|
|
|
info!("Starting BotServer...");
|
2025-10-06 10:30:17 -03:00
|
|
|
|
|
|
|
|
let config = AppConfig::from_env();
|
2025-10-06 20:06:43 -03:00
|
|
|
|
|
|
|
|
let db_pool = match sqlx::postgres::PgPool::connect(&config.database_url()).await {
|
|
|
|
|
Ok(pool) => {
|
|
|
|
|
info!("Connected to main database");
|
|
|
|
|
pool
|
|
|
|
|
}
|
|
|
|
|
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-06 20:06:43 -03:00
|
|
|
let db_custom_pool = match sqlx::postgres::PgPool::connect(&config.database_custom_url()).await {
|
|
|
|
|
Ok(pool) => {
|
|
|
|
|
info!("Connected to custom database");
|
|
|
|
|
pool
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
log::warn!("Failed to connect to custom database: {}", e);
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-10-06 10:30:17 -03:00
|
|
|
|
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-06 20:06:43 -03:00
|
|
|
let minio_client = None;
|
2025-10-06 10:30:17 -03:00
|
|
|
|
2025-10-06 20:06:43 -03:00
|
|
|
let auth_service = auth::AuthService::new(db_pool.clone(), redis_client.clone());
|
|
|
|
|
let session_manager = session::SessionManager::new(db_pool.clone(), redis_client.clone());
|
|
|
|
|
|
2025-10-06 19:12:13 -03:00
|
|
|
let tool_manager = tools::ToolManager::new();
|
2025-10-06 20:06:43 -03:00
|
|
|
let llm_provider = Arc::new(llm::MockLLMProvider::new());
|
|
|
|
|
|
|
|
|
|
let orchestrator = bot::BotOrchestrator::new(
|
|
|
|
|
session_manager,
|
|
|
|
|
tool_manager,
|
|
|
|
|
llm_provider,
|
|
|
|
|
auth_service,
|
|
|
|
|
);
|
2025-10-06 10:30:17 -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: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:06:43 -03:00
|
|
|
|
|
|
|
|
let tool_api = Arc::new(tools::ToolApi::new());
|
2025-10-06 10:30:17 -03:00
|
|
|
|
2025-10-06 20:06:43 -03:00
|
|
|
let browser_pool = match web_automation::BrowserPool::new(2).await {
|
|
|
|
|
Ok(pool) => Arc::new(pool),
|
|
|
|
|
Err(e) => {
|
|
|
|
|
log::warn!("Failed to create browser pool: {}", e);
|
|
|
|
|
Arc::new(web_automation::BrowserPool::new(0).await.unwrap())
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-10-06 19:12:13 -03:00
|
|
|
|
|
|
|
|
let app_state = AppState {
|
2025-10-06 20:06:43 -03:00
|
|
|
minio_client,
|
|
|
|
|
config: Some(config.clone()),
|
|
|
|
|
db: Some(db_pool.clone()),
|
|
|
|
|
db_custom: db_custom_pool,
|
2025-10-06 19:12:13 -03:00
|
|
|
browser_pool,
|
2025-10-06 20:06:43 -03:00
|
|
|
orchestrator: Arc::new(orchestrator),
|
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:06:43 -03:00
|
|
|
info!("Starting server on {}:{}", config.server.host, config.server.port);
|
2025-10-06 10:30:17 -03:00
|
|
|
|
|
|
|
|
HttpServer::new(move || {
|
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-06 10:30:17 -03:00
|
|
|
App::new()
|
2025-10-06 19:12:13 -03:00
|
|
|
.wrap(cors)
|
2025-10-06 20:06:43 -03:00
|
|
|
.app_data(web::Data::new(app_state.clone()))
|
|
|
|
|
.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)
|
|
|
|
|
.service(set_mode_handler)
|
|
|
|
|
.service(send_email)
|
|
|
|
|
.service(test_email)
|
|
|
|
|
.service(upload_file)
|
|
|
|
|
.service(list_file)
|
|
|
|
|
.service(download_file)
|
|
|
|
|
.service(health)
|
|
|
|
|
.service(chat_completions_local)
|
|
|
|
|
.service(embeddings_local)
|
|
|
|
|
.service(generic_chat_completions)
|
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
|
|
|
|
|
}
|