From b7e8c27dfd8cd2b1ffaa7bca3a7f31968b8037f0 Mon Sep 17 00:00:00 2001 From: raghavt3 Date: Thu, 21 Mar 2024 11:49:44 -0500 Subject: [PATCH] NLP added to vayu auto feature --- Cargo.lock | 149 +++++++++++++++++++++- Cargo.toml | 5 +- drawing.svg | 223 +++++++++++++++++++++++++++++++++ src/main.rs | 353 ++++++++-------------------------------------------- 4 files changed, 426 insertions(+), 304 deletions(-) create mode 100644 drawing.svg diff --git a/Cargo.lock b/Cargo.lock index 6136967..a362f02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -242,6 +251,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "date_time_parser" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86cad3e692d9b556cb8b64357f50f3b1b8411f3c8999f0bb94523991b5ded6c" +dependencies = [ + "chrono", + "regex", +] + [[package]] name = "either" version = "1.9.0" @@ -254,6 +273,19 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "event_parser" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e841f083fbbc766c13ceee32aa64908fa95d9cee7ae6eb6d0888d7479659a61" +dependencies = [ + "chrono", + "date_time_parser", + "icalendar 0.10.0", + "iso8601 0.4.2", + "regex", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -261,8 +293,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -304,6 +338,28 @@ dependencies = [ "cc", ] +[[package]] +name = "icalendar" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ef924cc883333ecdc23b8c4a677119ec6a2db9ef7748a2ae74e77c91ef14df" +dependencies = [ + "chrono", + "uuid 0.8.2", +] + +[[package]] +name = "icalendar" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4ffbcf3325ae94554c5259ce0b8907d37133c066cb3d424a2fa96aa1f10088" +dependencies = [ + "chrono", + "iso8601 0.6.1", + "nom", + "uuid 1.8.0", +] + [[package]] name = "indicatif" version = "0.17.7" @@ -332,6 +388,24 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "iso8601" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5b94fbeb759754d87e1daea745bc8efd3037cd16980331fe1d1524c9a79ce96" +dependencies = [ + "nom", +] + +[[package]] +name = "iso8601" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153" +dependencies = [ + "nom", +] + [[package]] name = "itertools" version = "0.12.0" @@ -387,6 +461,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "0.8.10" @@ -399,6 +485,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -537,6 +633,35 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rustversion" version = "1.0.14" @@ -669,14 +794,36 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", + "wasm-bindgen", +] + [[package]] name = "vayu" -version = "0.1.8" +version = "0.1.9" dependencies = [ "chrono", "clap", "colored", "crossterm", + "date_time_parser", + "event_parser", + "icalendar 0.16.0", "indicatif", "rand", "ratatui", diff --git a/Cargo.toml b/Cargo.toml index dd9af51..ed67ce1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vayu" -version = "0.1.8" +version = "0.1.9" edition = "2021" authors = ["Raghav Tirumale raghav.tirumale@gmail.com"] license = "MIT" @@ -19,7 +19,10 @@ chrono = "0.4.31" clap = { version = "4.4.12", features = ["derive"] } colored = "2.1.0" crossterm = "0.27.0" +event_parser = "0.1.1" +icalendar = "0.16.0" indicatif = "0.17.7" +date_time_parser = "0.1.0" rand = "0.8.5" ratatui = "0.25.0" diff --git a/drawing.svg b/drawing.svg new file mode 100644 index 0000000..a6e2058 --- /dev/null +++ b/drawing.svg @@ -0,0 +1,223 @@ + + + + diff --git a/src/main.rs b/src/main.rs index 7317d1e..159bd81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,10 @@ extern crate clap; extern crate colored; extern crate chrono; extern crate indicatif; +extern crate date_time_parser; + +//date parsers. +use date_time_parser::DateParser; //tui use std::io::{self, stdout, BufRead}; @@ -92,7 +96,7 @@ struct Task { #[allow(dead_code)] #[derive(Clone)] -struct Event { +struct Event1 { description: String, start: String, end: String, @@ -144,14 +148,14 @@ fn main() { let mut next_event_id = 0; //reads the event list data into a vector of events. (this is used by event list and for updating the file after adding an event) - let mut events : Vec = Vec::new(); + let mut events : Vec = Vec::new(); if let Ok(lines) = read_lines("events.txt") { // Consumes the iterator, returns an (Optional) String for line in lines { if let Ok(event) = line { let event_vec : Vec<&str> = event.split("%").collect(); let event_id = event_vec[4].to_string().parse::().unwrap(); - let event = Event { + let event = Event1 { description: event_vec[0].to_string(), start: event_vec[1].to_string(), end: event_vec[2].to_string(), @@ -388,296 +392,41 @@ fn add_task(tasks: &mut Vec, next_id: i32, arg1: String) { println!("task added with id {}", next_id) } -fn add_auto(tasks: &mut Vec, next_id: i32, arg1: String) { - //if "end" and "month" are in the arg1 string, add a task for the end of the month - if arg1.contains("end") && arg1.contains("month") { - //get the current date - let mut now = Local::now(); - //while next day is in the same month, add one day - while(now + Duration::days(1)).format("%m").to_string() == now.format("%m").to_string() { - now = now + Duration::days(1); - } - //set the due date to now in the format YYYY-MM-DD - let last_day = now.format("%Y-%m-%d").to_string(); - - //remove end and month from the arg1 string - let mut task_desc = arg1.replace("end", ""); - task_desc = task_desc.replace("month", ""); - //while the task description has a last word of "by", "at", "of" or "on", remove the last word - let mut task_desc_vec : Vec<&str> = task_desc.split(" ").collect(); - //remove all "" entries - task_desc_vec.retain(|&x| x != ""); - let mut last_word: &str = task_desc_vec[task_desc_vec.len()-1]; - let mut desc_temp: String = task_desc.clone(); - //print last_word - while last_word == "by" || last_word == "at" || last_word == "of" || last_word == "on" || last_word == "the" || last_word == "this" { - task_desc_vec.pop(); - desc_temp = task_desc_vec.join(" "); - last_word = task_desc_vec[task_desc_vec.len()-1]; - } - - //print the due date and task description and ask for confirmation - println!("Auto Generated Task with due date: {}. Is it ok (type yes/y)? ", last_day); - stdout().flush().unwrap(); - //get user input - let mut input = String::new(); - io::stdin().read_line(&mut input).expect("error"); - //if the user input is not "y" or "yes", return - if input.to_lowercase().trim() != "y" && input.to_lowercase().trim() != "yes" { - println!("task not added"); - return; - } - else{ - let task = Task { - description: desc_temp, - due: last_day, - done: false, - id: next_id, - }; - tasks.push(task); - println!("task added with id {}", next_id); - } - } - //repeat for end of year - else if arg1.contains("end") && arg1.contains("year") { - //get the current date - let mut now = Local::now(); - //while next day is in the same year, add one day - while(now + Duration::days(1)).format("%Y").to_string() == now.format("%Y").to_string() { - now = now + Duration::days(1); - } - //set the due date to now in the format YYYY-MM-DD - let last_day = now.format("%Y-%m-%d").to_string(); - - //remove end and year from the arg1 string - let mut task_desc = arg1.replace("end", ""); - task_desc = task_desc.replace("year", ""); - //while the task description has a last word of "by", "at", "of" or "on", remove the last word - let mut task_desc_vec : Vec<&str> = task_desc.split(" ").collect(); - task_desc_vec.retain(|&x| x != ""); - let mut last_word: &str = task_desc_vec[task_desc_vec.len()-1]; - let mut desc_temp: String = task_desc.clone(); - //print last_word - while last_word == "by" || last_word == "at" || last_word == "of" || last_word == "on" || last_word == "the" || last_word == "this" { - task_desc_vec.pop(); - desc_temp = task_desc_vec.join(" "); - last_word = task_desc_vec[task_desc_vec.len()-1]; - } - - //print the due date and task description and ask for confirmation - println!("Auto Generated Task with due date: {}. Is it ok (type yes/y)? ", last_day); - stdout().flush().unwrap(); - //get user input - let mut input = String::new(); - io::stdin().read_line(&mut input).expect("error"); - //if the user input is not "y" or "yes", return - if input.to_lowercase().trim() != "y" && input.to_lowercase().trim() != "yes" { - println!("task not added"); - return; - } - else{ - let task = Task { - description: desc_temp, - due: last_day, - done: false, - id: next_id, - }; - tasks.push(task); - println!("task added with id {}", next_id); - } - } - //repeat for end of week - else if arg1.contains("end") && arg1.contains("week") { - //get the current date - let mut now = Local::now(); - //go until day is sunday - while(now + Duration::days(1)).format("%A").to_string() != "Sunday".to_string() { - now = now + Duration::days(1); - } - //set the due date to now in the format YYYY-MM-DD - let last_day = now.format("%Y-%m-%d").to_string(); - - //remove end and week from the arg1 string - let mut task_desc = arg1.replace("end", ""); - task_desc = task_desc.replace("week", ""); - //while the task description has a last word of "by", "at", "of" or "on", remove the last word - let mut task_desc_vec : Vec<&str> = task_desc.split(" ").collect(); - task_desc_vec.retain(|&x| x != ""); - let mut last_word: &str = task_desc_vec[task_desc_vec.len()-1]; - let mut desc_temp: String = task_desc.clone(); - //print last_word - while last_word == "by" || last_word == "at" || last_word == "of" || last_word == "on" || last_word == "the" || last_word == "this" { - task_desc_vec.pop(); - desc_temp = task_desc_vec.join(" "); - last_word = task_desc_vec[task_desc_vec.len()-1]; - } - - //print the due date and task description and ask for confirmation - println!("Auto Generated Task with due date: {}. Is it ok (type yes/y)? ", last_day); - stdout().flush().unwrap(); - //get user input - let mut input = String::new(); - io::stdin().read_line(&mut input).expect("error"); - //if the user input is not "y" or "yes", return - if input.to_lowercase().trim() != "y" && input.to_lowercase().trim() != "yes" { - println!("task not added"); - return; - } - else{ - let task = Task { - description: desc_temp, - due: last_day, - done: false, - id: next_id, - }; - tasks.push(task); - println!("task added with id {}", next_id); - } - } - //check for days of the week shorthands - else if arg1.contains(" mon") || arg1.contains(" tue") || arg1.contains(" wed") || arg1.contains(" thu") || arg1.contains(" fri") || arg1.contains(" sat") || arg1.contains(" sun") { - //get the current date - let mut now = Local::now(); - //if " mon" due date is set to monday - if arg1.contains(" mon") { - while now.format("%A").to_string() != "Monday".to_string() { - now = now + Duration::days(1); - } - } - //if " tue" due date is set to tuesday - if arg1.contains(" tue") { - while now.format("%A").to_string() != "Tuesday".to_string() { - now = now + Duration::days(1); - } - } - //if " wed" due date is set to wednesday - if arg1.contains(" wed") { - while now.format("%A").to_string() != "Wednesday".to_string() { - now = now + Duration::days(1); - } - } - //if " thu" due date is set to thursday - if arg1.contains(" thu") { - while now.format("%A").to_string() != "Thursday".to_string() { - now = now + Duration::days(1); - } - } - //if " fri" due date is set to friday - if arg1.contains(" fri") { - while now.format("%A").to_string() != "Friday".to_string() { - now = now + Duration::days(1); - } - } - //if " sat" due date is set to saturday - if arg1.contains(" sat") { - while now.format("%A").to_string() != "Saturday".to_string() { - now = now + Duration::days(1); - } - } - //if " sun" due date is set to sunday - if arg1.contains(" sun") { - while now.format("%A").to_string() != "Sunday".to_string() { - now = now + Duration::days(1); - } - } - - //set the due date to now in the format YYYY-MM-DD - let last_day = now.format("%Y-%m-%d").to_string(); - let mut task_desc = arg1; - //remove the day of the week from the arg1 string (try removing anything from mon to monday) - let mut remmon: String = "monday".to_string(); - while remmon.len() > 2{ - if task_desc.contains(&remmon){ - task_desc = task_desc.replace(&remmon, ""); - - } - remmon.pop(); - } - let mut remtues: String = "tuesday".to_string(); - while remtues.len() > 2{ - if task_desc.contains(&remtues){ - task_desc = task_desc.replace(&remtues, ""); - - } - remtues.pop(); - } - let mut remwed: String = "wednesday".to_string(); - while remwed.len() > 2{ - if task_desc.contains(&remwed){ - task_desc = task_desc.replace(&remwed, ""); - - } - remwed.pop(); - } - let mut remthurs: String = "thursday".to_string(); - while remthurs.len() > 2{ - if task_desc.contains(&remthurs){ - task_desc = task_desc.replace(&remthurs, ""); - - } - remthurs.pop(); - } - let mut remfri: String = "friday".to_string(); - while remfri.len() > 2{ - if task_desc.contains(&remfri){ - task_desc = task_desc.replace(&remfri, ""); - - } - remfri.pop(); - } - let mut remsat: String = "saturday".to_string(); - while remsat.len() > 2{ - if task_desc.contains(&remsat){ - task_desc = task_desc.replace(&remsat, ""); - +use chrono::format::strftime::StrftimeItems; + +fn add_auto(tasks: &mut Vec, next_id: i32, arg1: String) { + let fetchtask = DateParser::parse(&arg1); + let fmt = StrftimeItems::new("%Y-%m-%d"); + //parse the option + match fetchtask { + //some or none + Some(date) => { + //ask user to confirm + let dt = date.format_with_items(fmt.clone()).to_string(); + println!("auto generated task: {} due on {}", arg1, dt); + println!("confirm? (y/n)"); + let mut confirm = String::new(); + io::stdin().read_line(&mut confirm).expect("error"); + if confirm.trim() == "y" { + let task = Task { + description: arg1, + due: dt, + done: false, + id: next_id, + }; + tasks.push(task); + println!("task added with id {}", next_id); } - remsat.pop(); - } - let mut remsun: String = "sunday".to_string(); - while remsun.len() > 2{ - if task_desc.contains(&remsun){ - task_desc = task_desc.replace(&remsun, ""); - + else { + println!("task not added"); } - remsun.pop(); - } - - + }, + None => { + println!("invalid usage of auto. use --help to see usage"); + } + } - //while the task description has a last word of "by", "at", "of" or "on", remove the last word - - let mut task_desc_vec : Vec<&str> = task_desc.split(" ").collect(); - task_desc_vec.retain(|&x| x != ""); - let mut last_word: &str = task_desc_vec[task_desc_vec.len()-1]; - let mut desc_temp: String = task_desc.clone(); - //print last_word - while last_word == "by" || last_word == "at" || last_word == "of" || last_word == "on" || last_word == "the" || last_word == "this" { - task_desc_vec.pop(); - desc_temp = task_desc_vec.join(" "); - last_word = task_desc_vec[task_desc_vec.len()-1]; - } - //print the due date and task description and ask for confirmation - println!("Auto Generated Task with due date: {}. Is it ok (type yes/y)? ", last_day); - stdout().flush().unwrap(); - //get user input - let mut input = String::new(); - io::stdin().read_line(&mut input).expect("error"); - //if the user input is not "y" or "yes", return - if input.to_lowercase().trim() != "y" && input.to_lowercase().trim() != "yes" { - println!("task not added"); - } - else{ - let task = Task { - description: desc_temp, - due: last_day, - done: false, - id: next_id, - }; - tasks.push(task); - println!("task added with id {}", next_id); - } - } } fn remove_task(tasks: &mut Vec, arg1: String) { @@ -768,7 +517,7 @@ fn read_lines

(filename: P) -> io::Result>> Ok(io::BufReader::new(file).lines()) } -fn add_event(events: &mut Vec, arg1: String, arg2: String, arg3: String, arg4: String, next_id: i32){ +fn add_event(events: &mut Vec, arg1: String, arg2: String, arg3: String, arg4: String, next_id: i32){ //if any arguments are empty, throw error if arg1 == "" || arg2 == "" || arg3 == "" { println!("invalid usage of eadd. use --help to see usage"); @@ -822,7 +571,7 @@ fn add_event(events: &mut Vec, arg1: String, arg2: String, arg3: String, repeat = Local::now().format("%Y-%m-%d").to_string(); } //if all criteria are met, add the event to the event list - let event = Event { + let event = Event1 { description: event_desc, start: start_time, end: end_time, @@ -833,7 +582,7 @@ fn add_event(events: &mut Vec, arg1: String, arg2: String, arg3: String, println!("event added with id {}", next_id); } -fn daily_agenda(events: &mut Vec) { +fn daily_agenda(events: &mut Vec) { //get the current date let now = Local::now(); let today_date = now.format("%Y-%m-%d").to_string(); @@ -842,11 +591,11 @@ fn daily_agenda(events: &mut Vec) { let today_day = "wednesday"; //lowercase the day of the week let today_day = today_day.to_lowercase(); - let mut todays_events : Vec = Vec::new(); + let mut todays_events : Vec = Vec::new(); //get all events that repeat on today's date or today's day of the week for event in events { if event.repeat == today_date || event.repeat.contains(&today_day) { - let eventc = Event { + let eventc = Event1 { description: event.description.clone(), start: event.start.clone(), end: event.end.clone(), @@ -929,14 +678,14 @@ fn daily_agenda(events: &mut Vec) { } -fn list_event_ids(events: &mut Vec) { +fn list_event_ids(events: &mut Vec) { for event in events { println!("{} - {}", event.description, event.id); } } -fn remove_event(events: &mut Vec, arg1: String) { +fn remove_event(events: &mut Vec, arg1: String) { //parse the event id from the arg1 string let event_id = arg1.parse::().unwrap(); //find the event with the given id and remove it from the event list @@ -952,14 +701,14 @@ fn remove_event(events: &mut Vec, arg1: String) { println!("event with id {} not found", event_id); } -fn vayu_ui(tasks: &mut Vec, events: &mut Vec) -> io::Result<()> { +fn vayu_ui(tasks: &mut Vec, events: &mut Vec) -> io::Result<()> { //ratatui ui with task list, calendar, and quote of the day //layout // *vayu* // quote of the day // task list weekly calendar let task_clone : &mut Vec = tasks; - let event_clone : &mut Vec = events; + let event_clone : &mut Vec = events; enable_raw_mode()?; stdout().execute(EnterAlternateScreen)?; let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; @@ -982,7 +731,7 @@ fn vayu_ui(tasks: &mut Vec, events: &mut Vec) -> io::Result<()> { Ok(()) } -fn ui(frame: &mut Frame, tasks: &mut Vec, events: &mut Vec) { +fn ui(frame: &mut Frame, tasks: &mut Vec, events: &mut Vec) { //main window let main_layout = Layout::new( Direction::Vertical, @@ -1025,10 +774,10 @@ fn ui(frame: &mut Frame, tasks: &mut Vec, events: &mut Vec) { day_str.push_str(&cat_day); let day_box = Block::default().title(day_str.clone()); //rendering the calendar - let mut todays_events : Vec = Vec::new(); + let mut todays_events : Vec = Vec::new(); for event in &mut *events { if event.repeat == day_date || event.repeat.contains(&day_day) { - let eventc = Event { + let eventc = Event1 { description: event.description.clone(), start: event.start.clone(), end: event.end.clone(), @@ -1156,7 +905,7 @@ fn ui(frame: &mut Frame, tasks: &mut Vec, events: &mut Vec) { ])); let widths = [Constraint::Length(4), Constraint::Length(10), Constraint::Length(10), Constraint::Length(20), Constraint::Length(20)]; let table = Table::new(rows, widths) - .block(Block::default().title("Event List")) + .block(Block::default().title("Event1 List")) .header(Row::new(vec![" ", " ", " ", " "," "]).bottom_margin(1).style(Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD))) .style(Style::default().fg(Color::White).bg(Color::Black)) .highlight_style(Style::default().add_modifier(Modifier::BOLD))