mirror of
https://github.com/TECHNOFAB11/pay-respects.git
synced 2026-02-02 15:45:11 +01:00
refactor: split request-ai into module
This commit is contained in:
parent
fedee1dc8d
commit
c9b9f66f89
13 changed files with 151 additions and 106 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -471,17 +471,25 @@ name = "pay-respects"
|
||||||
version = "0.5.15"
|
version = "0.5.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"colored",
|
"colored",
|
||||||
"curl",
|
|
||||||
"inquire",
|
"inquire",
|
||||||
"pay-respects-parser",
|
"pay-respects-parser",
|
||||||
"pay-respects-utils",
|
"pay-respects-utils",
|
||||||
"regex-lite",
|
"regex-lite",
|
||||||
"rust-i18n",
|
"rust-i18n",
|
||||||
|
"sys-locale",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pay-respects-fallback-request-ai"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"colored",
|
||||||
|
"curl",
|
||||||
|
"rust-i18n",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sys-locale",
|
"sys-locale",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"toml 0.8.19",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ members = [
|
||||||
"pay-respects-utils",
|
"pay-respects-utils",
|
||||||
# optional modules
|
# optional modules
|
||||||
"pay-respects-module-runtime-rules",
|
"pay-respects-module-runtime-rules",
|
||||||
# "pay-respects-module-request-ai",
|
"pay-respects-fallback-request-ai",
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
||||||
21
pay-respects-fallback-request-ai/Cargo.toml
Normal file
21
pay-respects-fallback-request-ai/Cargo.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "pay-respects-fallback-request-ai"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
colored = "2"
|
||||||
|
sys-locale = "0.3"
|
||||||
|
rust-i18n = "3"
|
||||||
|
serde_json = { version = "1.0" }
|
||||||
|
serde = { version = "1.0", features = ["derive"]}
|
||||||
|
textwrap = { version = "0.16", features = ["terminal_size"] }
|
||||||
|
|
||||||
|
|
||||||
|
curl = { version = "0.4", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# linking to libcurl dynamically requires openssl when compiling and
|
||||||
|
# complicates cross compilation
|
||||||
|
libcurl = ["dep:curl"]
|
||||||
|
|
||||||
14
pay-respects-fallback-request-ai/i18n/i18n.toml
Normal file
14
pay-respects-fallback-request-ai/i18n/i18n.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
_version = 2
|
||||||
|
|
||||||
|
[ai-suggestion]
|
||||||
|
en = "Suggestion from AI"
|
||||||
|
es = "Sugerencia de la IA"
|
||||||
|
de = "Vorschlag von KI"
|
||||||
|
fr = "Suggestion de l'IA"
|
||||||
|
it = "Proposta dall'IA"
|
||||||
|
pt = "Sugestão da IA"
|
||||||
|
ru = "Предложение от ИИ"
|
||||||
|
ja = "AIからの提案"
|
||||||
|
ko = "AI 제안"
|
||||||
|
zh = "AI 建议"
|
||||||
|
|
||||||
36
pay-respects-fallback-request-ai/src/main.rs
Normal file
36
pay-respects-fallback-request-ai/src/main.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
use crate::requests::ai_suggestion;
|
||||||
|
use colored::Colorize;
|
||||||
|
use textwrap::{fill, termwidth};
|
||||||
|
mod requests;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rust_i18n;
|
||||||
|
i18n!("i18n", fallback = "en", minify_key = true);
|
||||||
|
|
||||||
|
fn main() -> Result<(), std::io::Error> {
|
||||||
|
let command = std::env::var("_PR_LAST_COMMAND").expect("_PR_LAST_COMMAND not set");
|
||||||
|
let error = std::env::var("_PR_ERROR_MSG").expect("_PR_ERROR_MSG not set");
|
||||||
|
colored::control::set_override(true);
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
eprintln!("last_command: {}", command);
|
||||||
|
eprintln!("error_msg: {}", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip for commands with no arguments,
|
||||||
|
// very likely to be an error showing the usage
|
||||||
|
if command.split_whitespace().count() == 1 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let suggest = ai_suggestion(&command, &error);
|
||||||
|
if let Some(suggest) = suggest {
|
||||||
|
let warn = format!("{}:", t!("ai-suggestion")).bold().blue();
|
||||||
|
let note = fill(&suggest.note, termwidth());
|
||||||
|
|
||||||
|
eprintln!("{}\n{}", warn, note);
|
||||||
|
let command = suggest.command;
|
||||||
|
print!("{}<_PR_BR>", command);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use sys_locale::get_locale;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
@ -71,7 +72,16 @@ pub fn ai_suggestion(last_command: &str, error_msg: &str) -> Option<AISuggest> {
|
||||||
Err(_) => "llama3-8b-8192".to_string(),
|
Err(_) => "llama3-8b-8192".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_locale = std::env::var("_PR_AI_LOCALE").unwrap_or("en-US".to_string());
|
let user_locale = {
|
||||||
|
let locale = std::env::var("_PR_AI_LOCALE")
|
||||||
|
.unwrap_or_else(|_| get_locale().unwrap_or("en".to_string()));
|
||||||
|
if locale.len() < 2 {
|
||||||
|
"en-US".to_string()
|
||||||
|
} else {
|
||||||
|
locale
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let set_locale = if !user_locale.starts_with("en") {
|
let set_locale = if !user_locale.starts_with("en") {
|
||||||
format!(". Use language for locale {}", user_locale)
|
format!(". Use language for locale {}", user_locale)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -19,21 +19,7 @@ sys-locale = "0.3"
|
||||||
rust-i18n = "3"
|
rust-i18n = "3"
|
||||||
regex-lite = "0.1"
|
regex-lite = "0.1"
|
||||||
|
|
||||||
toml = { version = "0.8", optional = true }
|
|
||||||
serde_json = { version = "1.0", optional = true }
|
|
||||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
|
||||||
curl = { version = "0.4", optional = true }
|
|
||||||
textwrap = { version = "0.16", features = ["terminal_size"], optional = true }
|
|
||||||
|
|
||||||
inquire = "0.7.5"
|
inquire = "0.7.5"
|
||||||
|
|
||||||
pay-respects-parser = { version = "0.3.2", path = "../pay-respects-parser" }
|
pay-respects-parser = { version = "0.3.2", path = "../pay-respects-parser" }
|
||||||
pay-respects-utils = {version = "0.1.0", path = "../pay-respects-utils"}
|
pay-respects-utils = {version = "0.1.0", path = "../pay-respects-utils"}
|
||||||
|
|
||||||
[features]
|
|
||||||
runtime-rules = ["dep:serde", "dep:toml"]
|
|
||||||
request-ai = ["dep:serde", "dep:serde_json", "dep:textwrap"]
|
|
||||||
|
|
||||||
# linking to libcurl dynamically requires openssl when compiling and
|
|
||||||
# complicates cross compilation
|
|
||||||
libcurl = ["dep:curl"]
|
|
||||||
|
|
|
||||||
|
|
@ -142,18 +142,6 @@ ja = "不足しているコマンドのパッケージが見つかりました"
|
||||||
ko = "누락된 명령에 대한 패키지가 발견되었습니다"
|
ko = "누락된 명령에 대한 패키지가 발견되었습니다"
|
||||||
zh = "找到缺失命令的包"
|
zh = "找到缺失命令的包"
|
||||||
|
|
||||||
[ai-suggestion]
|
|
||||||
en = "Suggestion from AI"
|
|
||||||
es = "Sugerencia de la IA"
|
|
||||||
de = "Vorschlag von KI"
|
|
||||||
fr = "Suggestion de l'IA"
|
|
||||||
it = "Proposta dall'IA"
|
|
||||||
pt = "Sugestão da IA"
|
|
||||||
ru = "Предложение от ИИ"
|
|
||||||
ja = "AIからの提案"
|
|
||||||
ko = "AI 제안"
|
|
||||||
zh = "AI 建议"
|
|
||||||
|
|
||||||
[confirm]
|
[confirm]
|
||||||
en = "Execute suggestion?"
|
en = "Execute suggestion?"
|
||||||
es = "¿Ejecutar sugerencia?"
|
es = "¿Ejecutar sugerencia?"
|
||||||
|
|
@ -87,17 +87,4 @@ fn print_version() {
|
||||||
"version: {}",
|
"version: {}",
|
||||||
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
|
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
|
||||||
);
|
);
|
||||||
println!("compile features:");
|
|
||||||
#[cfg(feature = "runtime-rules")]
|
|
||||||
{
|
|
||||||
println!(" - runtime-rules");
|
|
||||||
}
|
|
||||||
#[cfg(feature = "request-ai")]
|
|
||||||
{
|
|
||||||
println!(" - request-ai");
|
|
||||||
}
|
|
||||||
#[cfg(feature = "libcurl")]
|
|
||||||
{
|
|
||||||
println!(" - libcurl");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,6 @@ mod style;
|
||||||
mod suggestions;
|
mod suggestions;
|
||||||
mod system;
|
mod system;
|
||||||
|
|
||||||
#[cfg(feature = "request-ai")]
|
|
||||||
mod requests;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rust_i18n;
|
extern crate rust_i18n;
|
||||||
i18n!("i18n", fallback = "en", minify_key = true);
|
i18n!("i18n", fallback = "en", minify_key = true);
|
||||||
|
|
@ -67,7 +64,7 @@ fn init() -> Result<shell::Data, args::Status> {
|
||||||
let locale = {
|
let locale = {
|
||||||
let sys_locale = get_locale().unwrap_or("en-US".to_string());
|
let sys_locale = get_locale().unwrap_or("en-US".to_string());
|
||||||
if sys_locale.len() < 2 {
|
if sys_locale.len() < 2 {
|
||||||
"en_US".to_string()
|
"en-US".to_string()
|
||||||
} else {
|
} else {
|
||||||
sys_locale
|
sys_locale
|
||||||
}
|
}
|
||||||
|
|
@ -85,12 +82,5 @@ fn init() -> Result<shell::Data, args::Status> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "request-ai")]
|
|
||||||
{
|
|
||||||
if std::env::var("_PR_AI_LOCALE").is_err() {
|
|
||||||
std::env::set_var("_PR_AI_LOCALE", &locale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(shell::Data::init())
|
Ok(shell::Data::init())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,16 @@ use crate::shell::Data;
|
||||||
use pay_respects_parser::parse_rules;
|
use pay_respects_parser::parse_rules;
|
||||||
use pay_respects_utils::evals::*;
|
use pay_respects_utils::evals::*;
|
||||||
|
|
||||||
pub fn match_pattern(executable: &str, data: &mut Data) {
|
pub fn match_pattern(executable: &str, data: &Data) -> Option<Vec<String>> {
|
||||||
let error_msg = &data.error;
|
let error_msg = &data.error;
|
||||||
let shell = &data.shell;
|
let shell = &data.shell;
|
||||||
let last_command = &data.command;
|
let last_command = &data.command;
|
||||||
let executables = &data.executables;
|
let executables = &data.executables;
|
||||||
let candidates = &mut data.candidates;
|
let mut candidates = vec![];
|
||||||
parse_rules!("rules");
|
parse_rules!("rules");
|
||||||
|
if candidates.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(candidates)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,21 +156,6 @@ impl Data {
|
||||||
self.suggest = Some(suggest.to_string());
|
self.suggest = Some(suggest.to_string());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_candidate(&mut self, candidate: &str) {
|
|
||||||
let candidate = candidate.trim();
|
|
||||||
if candidate != self.command {
|
|
||||||
self.candidates.push(candidate.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn add_candidates(&mut self, candidates: &Vec<String>) {
|
|
||||||
for candidate in candidates {
|
|
||||||
let candidate = candidate.trim();
|
|
||||||
if candidate != self.command {
|
|
||||||
self.candidates.push(candidate.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn elevate(data: &mut Data, command: &mut String) {
|
pub fn elevate(data: &mut Data, command: &mut String) {
|
||||||
|
|
@ -182,6 +167,19 @@ pub fn elevate(data: &mut Data, command: &mut String) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_candidates_no_dup(
|
||||||
|
command: &str,
|
||||||
|
candidates: &mut Vec<String>,
|
||||||
|
new_candidates: &Vec<String>,
|
||||||
|
) {
|
||||||
|
for candidate in new_candidates {
|
||||||
|
let candidate = candidate.trim();
|
||||||
|
if candidate != command && !candidates.contains(&candidate.to_string()) {
|
||||||
|
candidates.push(candidate.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_error(shell: &str, command: &str) -> String {
|
pub fn get_error(shell: &str, command: &str) -> String {
|
||||||
let error_msg = std::env::var("_PR_ERROR_MSG");
|
let error_msg = std::env::var("_PR_ERROR_MSG");
|
||||||
let error = if let Ok(error_msg) = error_msg {
|
let error = if let Ok(error_msg) = error_msg {
|
||||||
|
|
@ -255,6 +253,10 @@ pub fn module_output(data: &Data, module: &str) -> Option<Vec<String>> {
|
||||||
.output()
|
.output()
|
||||||
.expect("failed to execute process");
|
.expect("failed to execute process");
|
||||||
|
|
||||||
|
if !output.stderr.is_empty() {
|
||||||
|
eprintln!("{}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
if output.stdout.is_empty() {
|
if output.stdout.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,55 +6,53 @@ use colored::Colorize;
|
||||||
use inquire::*;
|
use inquire::*;
|
||||||
|
|
||||||
use crate::rules::match_pattern;
|
use crate::rules::match_pattern;
|
||||||
use crate::shell::{module_output, shell_evaluated_commands, Data};
|
use crate::shell::{add_candidates_no_dup, module_output, shell_evaluated_commands, Data};
|
||||||
use crate::style::highlight_difference;
|
use crate::style::highlight_difference;
|
||||||
|
|
||||||
pub fn suggest_candidates(data: &mut Data) {
|
pub fn suggest_candidates(data: &mut Data) {
|
||||||
let executable = &data.split[0].to_string();
|
let executable = &data.split[0];
|
||||||
let privilege = &data.privilege.clone();
|
let command = &data.command;
|
||||||
|
let privilege = &data.privilege;
|
||||||
|
let mut suggest_candidates = vec![];
|
||||||
|
|
||||||
|
let modules = &data.modules;
|
||||||
|
let fallbacks = &data.fallbacks;
|
||||||
|
|
||||||
if privilege.is_none() {
|
if privilege.is_none() {
|
||||||
match_pattern("_PR_privilege", data);
|
if let Some(candidates) = match_pattern("_PR_privilege", data) {
|
||||||
|
add_candidates_no_dup(command, &mut suggest_candidates, &candidates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(candidates) = match_pattern(executable, data) {
|
||||||
|
add_candidates_no_dup(command, &mut suggest_candidates, &candidates);
|
||||||
|
}
|
||||||
|
if let Some(candidates) = match_pattern("_PR_general", data) {
|
||||||
|
add_candidates_no_dup(command, &mut suggest_candidates, &candidates);
|
||||||
}
|
}
|
||||||
match_pattern(executable, data);
|
|
||||||
match_pattern("_PR_general", data);
|
|
||||||
|
|
||||||
let modules = &data.modules.clone();
|
|
||||||
eprintln!("modules: {modules:?}");
|
eprintln!("modules: {modules:?}");
|
||||||
|
eprintln!("fallbacks: {fallbacks:?}");
|
||||||
|
|
||||||
for module in modules {
|
for module in modules {
|
||||||
let candidates = module_output(data, module);
|
let new_candidates = module_output(data, module);
|
||||||
eprintln!("runtime: {candidates:?}");
|
|
||||||
if candidates.is_some() {
|
if let Some(candidates) = new_candidates {
|
||||||
data.add_candidates(&candidates.unwrap());
|
add_candidates_no_dup(command, &mut suggest_candidates, &candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "request-ai")]
|
if !suggest_candidates.is_empty() {
|
||||||
{
|
data.candidates = suggest_candidates;
|
||||||
if !data.candidates.is_empty() {
|
return;
|
||||||
|
}
|
||||||
|
for fallback in fallbacks {
|
||||||
|
let candidates = module_output(data, fallback);
|
||||||
|
eprintln!("fallback: {candidates:?}");
|
||||||
|
if candidates.is_some() {
|
||||||
|
add_candidates_no_dup(command, &mut suggest_candidates, &candidates.unwrap());
|
||||||
|
data.candidates = suggest_candidates;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
use crate::requests::ai_suggestion;
|
|
||||||
use textwrap::{fill, termwidth};
|
|
||||||
let command = &data.command;
|
|
||||||
let split_command = &data.split;
|
|
||||||
let error = &data.error.clone();
|
|
||||||
|
|
||||||
// skip for commands with no arguments,
|
|
||||||
// very likely to be an error showing the usage
|
|
||||||
if privilege.is_some() && split_command.len() > 2
|
|
||||||
|| privilege.is_none() && split_command.len() > 1
|
|
||||||
{
|
|
||||||
let suggest = ai_suggestion(command, error);
|
|
||||||
if let Some(suggest) = suggest {
|
|
||||||
let warn = format!("{}:", t!("ai-suggestion")).bold().blue();
|
|
||||||
let note = fill(&suggest.note, termwidth());
|
|
||||||
|
|
||||||
eprintln!("{}\n{}\n", warn, note);
|
|
||||||
let command = suggest.command;
|
|
||||||
data.add_candidate(&command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue