- First run to generate e-mail.
Some checks failed
GBCI / build (push) Has been cancelled

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-08-02 00:49:33 -03:00
parent 50bfad7642
commit c15bd364c1
7 changed files with 64 additions and 19 deletions

View file

@ -5,21 +5,20 @@ FOR EACH item IN items
let website = WEBSITE OF item.company
PRINT website
let page = GET website
let prompt = "Build the same simulator , but for " + item.company + " using just *content about the company* from its website, so it is possible to create a good and useful emulator in the same langue as the content: " + page
let alias = LLM "Return a single word for " + item.company + " like a token, no spaces, no special characters, no numbers, no uppercase letters."
CREATE_SITE alias, "OpenSourceCars", prompt
let to = item.emailcto
let subject = "General Bots"
let body = "Oi, tudo bem? Criamos o simulador " + alias + " especificamente para vocês!" + "\n\n Acesse o site: https://sites.pragmatismo.com.br/" + alias + "\n\n" + "Para acessar o simulador, clique no link acima ou copie e cole no seu navegador." + "\n\n" + "Para iniciar, clique no ícone de Play." + "\n\n" + "Atenciosamente,\nDário Vieira"
let subject = "Simulador " + alias
let body = "Oi, " + FIRST(item.Contact) + "! Tudo bem? Estou empolgado, pois criamos o simulador " + alias + " especificamente para vocês!" + "\n\n Acesse o site: https://sites.pragmatismo.com.br/" + alias + "\n\n" + "Para acessar o simulador, clique no link acima ou copie e cole no seu navegador." + "\n\n" + "Para iniciar, clique no ícone de Play." + "\n\n" + "Atenciosamente,\nDário Vieira\n\n"
CREATE_DRAFT to, subject, body
NEXT item

View file

@ -0,0 +1,21 @@
use rhai::Dynamic;
use rhai::Engine;
pub fn first_keyword(engine: &mut Engine) {
engine
.register_custom_syntax(&["FIRST", "$expr$"], false, {
move |context, inputs| {
let input_string = context.eval_expression_tree(&inputs[0])?;
let input_str = input_string.to_string();
// Extract first word by splitting on whitespace
let first_word = input_str.split_whitespace()
.next()
.unwrap_or("")
.to_string();
Ok(Dynamic::from(first_word))
}
})
.unwrap();
}

View file

@ -77,8 +77,8 @@ async fn perform_search(
// Extract results
let results = extract_search_results(&driver).await?;
driver.quit().await?;
driver.close_window().await?;
if !results.is_empty() {
Ok(results[0].clone())
} else {

View file

@ -1,6 +1,7 @@
pub mod create_draft;
pub mod create_site;
pub mod find;
pub mod first;
pub mod for_next;
pub mod get;
pub mod get_website;

View file

@ -53,11 +53,13 @@ pub async fn execute_set(
table_str, filter_str, updates_str
);
// Parse the filter condition
let (where_clause, filter_params) = utils::parse_filter(filter_str).map_err(|e| e.to_string())?;
// Parse the updates
// Parse the updates first to know how many parameters we'll have
let (set_clause, update_params) = parse_updates(updates_str).map_err(|e| e.to_string())?;
let update_params_count = update_params.len();
// Parse the filter condition with an offset for parameter indices
let (where_clause, filter_params) = utils::parse_filter_with_offset(filter_str, update_params_count)
.map_err(|e| e.to_string())?;
// Combine all parameters (updates first, then filter)
let mut params = update_params;
@ -69,11 +71,13 @@ pub async fn execute_set(
);
println!("Executing query: {}", query);
// Execute the update
let result = sqlx::query(&query)
.bind(&params[0]) // First update value
.bind(&params[1]) // Second update value if exists
.bind(&params[2]) // Filter value
// Execute the update with all parameters
let mut query_builder = sqlx::query(&query);
for param in &params {
query_builder = query_builder.bind(param);
}
let result = query_builder
.execute(pool)
.await
.map_err(|e| {
@ -98,7 +102,7 @@ fn parse_updates(updates_str: &str) -> Result<(String, Vec<String>), Box<dyn Err
let mut params = Vec::new();
// Split multiple updates by comma
for update in updates_str.split(',') {
for (i, update) in updates_str.split(',').enumerate() {
let parts: Vec<&str> = update.split('=').collect();
if parts.len() != 2 {
return Err("Invalid update format. Expected 'KEY=VALUE'".into());
@ -112,7 +116,7 @@ fn parse_updates(updates_str: &str) -> Result<(String, Vec<String>), Box<dyn Err
return Err("Invalid column name in update".into());
}
set_clauses.push(format!("{} = ${}", column, set_clauses.len() + 1));
set_clauses.push(format!("{} = ${}", column, i + 1));
params.push(value.to_string());
}

View file

@ -9,6 +9,7 @@ use crate::services::keywords::llm_keyword::llm_keyword;
use crate::services::keywords::print::print_keyword;
use crate::services::keywords::set::set_keyword;
use crate::services::keywords::wait::wait_keyword;
use crate::services::keywords::first::first_keyword;
use crate::services::state::AppState;
pub struct ScriptService {
@ -26,7 +27,8 @@ impl ScriptService {
create_draft_keyword(state, &mut engine);
create_site_keyword(state, &mut engine);
find_keyword(state, &mut engine);
for_keyword(state, &mut engine);
for_keyword(state, &mut engine);
first_keyword(&mut engine);
llm_keyword(state, &mut engine);
get_website_keyword(state, &mut engine);
get_keyword(state, &mut engine);

View file

@ -238,3 +238,21 @@ pub fn parse_filter(filter_str: &str) -> Result<(String, Vec<String>), Box<dyn E
// Return the parameterized query part and the value separately
Ok((format!("{} = $1", column), vec![value.to_string()]))
}
pub fn parse_filter_with_offset(filter_str: &str, offset: usize) -> Result<(String, Vec<String>), Box<dyn Error>> {
let parts: Vec<&str> = filter_str.split('=').collect();
if parts.len() != 2 {
return Err("Invalid filter format. Expected 'KEY=VALUE'".into());
}
let column = parts[0].trim();
let value = parts[1].trim();
// Validate column name to prevent SQL injection
if !column.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
return Err("Invalid column name in filter".into());
}
// Use the offset + 1 for the parameter number
Ok((format!("{} = ${}", column, offset + 1), vec![value.to_string()]))
}