mirror of
https://github.com/TECHNOFAB11/pay-respects.git
synced 2025-12-11 22:10:09 +01:00
chore: rearrange directories
This commit is contained in:
parent
d5fb7462e0
commit
4c9aac45a8
46 changed files with 11 additions and 18 deletions
21
module-request-ai/Cargo.toml
Normal file
21
module-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
module-request-ai/i18n/i18n.toml
Normal file
14
module-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
module-request-ai/src/main.rs
Normal file
36
module-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(())
|
||||
}
|
||||
200
module-request-ai/src/requests.rs
Normal file
200
module-request-ai/src/requests.rs
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
use std::collections::HashMap;
|
||||
use sys_locale::get_locale;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Input {
|
||||
role: String,
|
||||
content: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Messages {
|
||||
messages: Vec<Input>,
|
||||
model: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AISuggest {
|
||||
pub command: String,
|
||||
pub note: String,
|
||||
}
|
||||
|
||||
pub fn ai_suggestion(last_command: &str, error_msg: &str) -> Option<AISuggest> {
|
||||
if std::env::var("_PR_AI_DISABLE").is_ok() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let error_msg = if error_msg.len() > 300 {
|
||||
&error_msg[..300]
|
||||
} else {
|
||||
error_msg
|
||||
};
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert("last_command", last_command);
|
||||
map.insert("error_msg", error_msg);
|
||||
|
||||
let api_key = match std::env::var("_PR_AI_API_KEY") {
|
||||
Ok(key) => Some(key),
|
||||
Err(_) => {
|
||||
let env_key = option_env!("_DEF_PR_AI_API_KEY").map(|key| key.to_string());
|
||||
if env_key.is_none() {
|
||||
Some("Y29uZ3JhdHVsYXRpb25zLCB5b3UgZm91bmQgdGhlIHNlY3JldCE=".to_string())
|
||||
} else if env_key.as_ref().unwrap().is_empty() {
|
||||
None
|
||||
} else {
|
||||
env_key
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let api_key = match api_key {
|
||||
Some(key) => {
|
||||
if key.is_empty() {
|
||||
return None;
|
||||
}
|
||||
key
|
||||
}
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let request_url = match std::env::var("_PR_AI_URL") {
|
||||
Ok(url) => url,
|
||||
Err(_) => "https://iff.envs.net/completions.py".to_string(),
|
||||
};
|
||||
let model = match std::env::var("_PR_AI_MODEL") {
|
||||
Ok(model) => model,
|
||||
Err(_) => "llama3-8b-8192".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") {
|
||||
format!(". Use language for locale {}", user_locale)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let ai_prompt = format!(
|
||||
r#"
|
||||
The command `{last_command}` returns the following error message: `{error_msg}`. Provide a command to fix it. Answer in the following JSON format without any extra text:
|
||||
```
|
||||
{{"command":"suggestion","note":"why it may fix the error{set_locale}"}}
|
||||
```
|
||||
"#
|
||||
);
|
||||
|
||||
let res;
|
||||
let messages = Messages {
|
||||
messages: vec![Input {
|
||||
role: "user".to_string(),
|
||||
content: ai_prompt.to_string(),
|
||||
}],
|
||||
model,
|
||||
};
|
||||
|
||||
#[cfg(feature = "libcurl")]
|
||||
{
|
||||
use curl::easy::Easy as Curl;
|
||||
use curl::easy::List;
|
||||
use std::io::Read;
|
||||
|
||||
let str_json = serde_json::to_string(&messages).unwrap();
|
||||
let mut data = str_json.as_bytes();
|
||||
|
||||
let mut dst = Vec::new();
|
||||
let mut handle = Curl::new();
|
||||
|
||||
handle.url(&request_url).unwrap();
|
||||
handle.post(true).unwrap();
|
||||
handle.post_field_size(data.len() as u64).unwrap();
|
||||
|
||||
let mut headers = List::new();
|
||||
headers
|
||||
.append(&format!("Authorization: Bearer {}", api_key))
|
||||
.unwrap();
|
||||
headers.append("Content-Type: application/json").unwrap();
|
||||
handle.http_headers(headers).unwrap();
|
||||
|
||||
{
|
||||
let mut transfer = handle.transfer();
|
||||
|
||||
transfer
|
||||
.read_function(|buf| Ok(data.read(buf).unwrap_or(0)))
|
||||
.unwrap();
|
||||
|
||||
transfer
|
||||
.write_function(|buf| {
|
||||
dst.extend_from_slice(buf);
|
||||
Ok(buf.len())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
transfer.perform().expect("Failed to perform request");
|
||||
}
|
||||
|
||||
res = String::from_utf8(dst).unwrap();
|
||||
}
|
||||
#[cfg(not(feature = "libcurl"))]
|
||||
{
|
||||
let proc = std::process::Command::new("curl")
|
||||
.arg("-X")
|
||||
.arg("POST")
|
||||
.arg("-H")
|
||||
.arg(format!("Authorization: Bearer {}", api_key))
|
||||
.arg("-H")
|
||||
.arg("Content-Type: application/json")
|
||||
.arg("-d")
|
||||
.arg(serde_json::to_string(&messages).unwrap())
|
||||
.arg(request_url)
|
||||
.output();
|
||||
|
||||
let out = match proc {
|
||||
Ok(proc) => proc.stdout,
|
||||
Err(_) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
res = String::from_utf8(out).unwrap();
|
||||
}
|
||||
let json: Value = {
|
||||
let json = serde_json::from_str(&res);
|
||||
if let Ok(json) = json {
|
||||
json
|
||||
} else {
|
||||
eprintln!("Failed to parse JSON response: {}", res);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let content = &json["choices"][0]["message"]["content"];
|
||||
|
||||
let suggestion: AISuggest = {
|
||||
let str = {
|
||||
let str = content.as_str();
|
||||
str?;
|
||||
str.expect("Failed to get content from response")
|
||||
.trim_start_matches("```")
|
||||
.trim_end_matches("```")
|
||||
};
|
||||
let json = serde_json::from_str(str);
|
||||
if json.is_err() {
|
||||
return None;
|
||||
}
|
||||
json.unwrap()
|
||||
};
|
||||
Some(suggestion)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue