2025-09-17 20:11:56 -03:00
use log ::info ;
2025-07-20 00:03:37 -03:00
use rhai ::Dynamic ;
use rhai ::Engine ;
2025-07-31 00:36:10 -03:00
use std ::error ::Error ;
2025-07-21 12:16:17 -03:00
use std ::fs ;
2025-08-02 00:07:54 -03:00
use std ::io ::Read ;
2025-09-17 20:11:56 -03:00
use std ::path ::PathBuf ;
2025-07-20 00:03:37 -03:00
use crate ::services ::state ::AppState ;
2025-07-31 00:36:10 -03:00
use crate ::services ::utils ;
2025-07-20 00:03:37 -03:00
2025-07-31 00:36:10 -03:00
pub fn create_site_keyword ( state : & AppState , engine : & mut Engine ) {
let state_clone = state . clone ( ) ;
2025-07-20 00:03:37 -03:00
engine
. register_custom_syntax (
2025-09-17 20:11:56 -03:00
& [ " CREATE_SITE " , " $expr$ " , " , " , " $expr$ " , " , " , " $expr$ " ] ,
2025-08-02 00:07:54 -03:00
true ,
2025-07-21 12:16:17 -03:00
move | context , inputs | {
2025-08-02 00:07:54 -03:00
if inputs . len ( ) < 3 {
2025-07-20 00:03:37 -03:00
return Err ( " Not enough arguments for CREATE SITE " . into ( ) ) ;
}
2025-08-02 00:07:54 -03:00
let alias = context . eval_expression_tree ( & inputs [ 0 ] ) ? ;
let template_dir = context . eval_expression_tree ( & inputs [ 1 ] ) ? ;
let prompt = context . eval_expression_tree ( & inputs [ 2 ] ) ? ;
2025-09-17 20:11:56 -03:00
let config = state_clone
. config
. as_ref ( )
. expect ( " Config must be initialized " )
. clone ( ) ;
2025-08-02 00:07:54 -03:00
let fut = create_site ( & config , alias , template_dir , prompt ) ;
2025-07-31 00:36:10 -03:00
let result =
tokio ::task ::block_in_place ( | | tokio ::runtime ::Handle ::current ( ) . block_on ( fut ) )
2025-08-02 00:07:54 -03:00
. map_err ( | e | format! ( " Site creation failed: {} " , e ) ) ? ;
2025-07-20 00:03:37 -03:00
2025-07-31 00:36:10 -03:00
Ok ( Dynamic ::from ( result ) )
2025-07-20 00:03:37 -03:00
} ,
)
. unwrap ( ) ;
2025-07-31 00:36:10 -03:00
}
async fn create_site (
2025-08-02 00:07:54 -03:00
config : & crate ::services ::config ::AppConfig ,
alias : Dynamic ,
template_dir : Dynamic ,
2025-07-31 00:36:10 -03:00
prompt : Dynamic ,
2025-08-02 00:07:54 -03:00
) -> Result < String , Box < dyn Error + Send + Sync > > {
// Convert paths to platform-specific format
let base_path = PathBuf ::from ( & config . site_path ) ;
let template_path = base_path . join ( template_dir . to_string ( ) ) ;
let alias_path = base_path . join ( alias . to_string ( ) ) ;
// Create destination directory
fs ::create_dir_all ( & alias_path ) . map_err ( | e | e . to_string ( ) ) ? ;
2025-07-31 00:36:10 -03:00
2025-08-02 00:07:54 -03:00
// Process all HTML files in template directory
let mut combined_content = String ::new ( ) ;
2025-09-17 20:11:56 -03:00
2025-08-02 00:07:54 -03:00
for entry in fs ::read_dir ( & template_path ) . map_err ( | e | e . to_string ( ) ) ? {
let entry = entry . map_err ( | e | e . to_string ( ) ) ? ;
let path = entry . path ( ) ;
2025-09-17 20:11:56 -03:00
2025-08-02 00:07:54 -03:00
if path . extension ( ) . map_or ( false , | ext | ext = = " html " ) {
let mut file = fs ::File ::open ( & path ) . map_err ( | e | e . to_string ( ) ) ? ;
let mut contents = String ::new ( ) ;
2025-09-17 20:11:56 -03:00
file . read_to_string ( & mut contents )
. map_err ( | e | e . to_string ( ) ) ? ;
2025-08-02 00:07:54 -03:00
combined_content . push_str ( & contents ) ;
combined_content . push_str ( " \n \n --- TEMPLATE SEPARATOR --- \n \n " ) ;
}
}
2025-07-31 00:36:10 -03:00
2025-08-02 00:07:54 -03:00
// Combine template content with prompt
let full_prompt = format! (
" TEMPLATE FILES: \n {} \n \n PROMPT: {} \n \n Generate a new HTML file cloning all previous TEMPLATE (keeping only the local _assets libraries use, no external resources), but turning this into this prompt: " ,
combined_content ,
prompt . to_string ( )
) ;
2025-07-31 00:36:10 -03:00
2025-08-02 00:07:54 -03:00
// Call LLM with the combined prompt
2025-09-17 20:11:56 -03:00
info! ( " Asking LLM to create site. " ) ;
2025-08-02 00:07:54 -03:00
let llm_result = utils ::call_llm ( & full_prompt , & config . ai ) . await ? ;
2025-07-31 00:36:10 -03:00
2025-08-02 00:07:54 -03:00
// Write the generated HTML file
let index_path = alias_path . join ( " index.html " ) ;
2025-07-31 00:36:10 -03:00
fs ::write ( index_path , llm_result ) . map_err ( | e | e . to_string ( ) ) ? ;
2025-09-17 20:11:56 -03:00
info! ( " Site created at: {} " , alias_path . display ( ) ) ;
2025-08-02 00:07:54 -03:00
Ok ( alias_path . to_string_lossy ( ) . into_owned ( ) )
2025-09-17 20:11:56 -03:00
}