Compare commits
No commits in common. "69e19c3b87376189372e8d987879a40228874b56" and "621f54316a5154a29deb61f48f70bc2c95c0850b" have entirely different histories.
69e19c3b87
...
621f54316a
|
@ -401,7 +401,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -994,15 +993,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_spanned"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -1252,40 +1242,6 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml"
|
|
||||||
version = "0.8.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
"serde_spanned",
|
|
||||||
"toml_datetime",
|
|
||||||
"toml_edit",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml_datetime"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml_edit"
|
|
||||||
version = "0.22.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap",
|
|
||||||
"serde",
|
|
||||||
"serde_spanned",
|
|
||||||
"toml_datetime",
|
|
||||||
"winnow",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
|
@ -1654,15 +1610,6 @@ version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winnow"
|
|
||||||
version = "0.6.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
|
@ -15,4 +15,3 @@ reqwest = "0.12.3"
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
serde_json = "1.0.115"
|
serde_json = "1.0.115"
|
||||||
tokio = { version = "1.37.0", features = ["full"] }
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
toml = "0.8.12"
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl Cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_file_name<T: From<String>>() -> T {
|
pub fn get_file_name<T: From<String>>() -> T {
|
||||||
match env::var("HEY_CACHE_FILENAME") {
|
match env::var("HEY_CACHE_PATH") {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => "cache.json".into()
|
Err(_) => "cache.json".into()
|
||||||
}.into()
|
}.into()
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
use std::{env, error::Error, fs, io, path::PathBuf};
|
|
||||||
|
|
||||||
use home::home_dir;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub enum Model {
|
|
||||||
#[serde(rename = "claude-instant-1.2")]
|
|
||||||
Claude12,
|
|
||||||
#[serde(rename = "gpt-3.5-turbo-0125")]
|
|
||||||
GPT35,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Config {
|
|
||||||
pub model: Model,
|
|
||||||
pub tos: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Config {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
model: Model::Claude12,
|
|
||||||
tos: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn get_path<T: From<String>>() -> T {
|
|
||||||
match env::var("HEY_CONFIG_PATH") {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) =>
|
|
||||||
match home_dir() {
|
|
||||||
Some(home) => home.join(".config/hey").as_os_str().as_encoded_bytes().iter().map(|x| char::from(*x)).collect::<String>(),
|
|
||||||
None => panic!("Cannot detect your home directory!")
|
|
||||||
}
|
|
||||||
}.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_file_name<T: From<String>>() -> T {
|
|
||||||
match env::var("HEY_CONFIG_FILENAME") {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => "conf.toml".into()
|
|
||||||
}.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_dir_exists() -> io::Result<()> {
|
|
||||||
let path: PathBuf = Self::get_path();
|
|
||||||
if ! path.is_dir() { fs::create_dir_all(path)? }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save(self: &Self) -> Result<(), Box<dyn Error>> {
|
|
||||||
let path = Self::get_path::<PathBuf>();
|
|
||||||
Self::ensure_dir_exists()?;
|
|
||||||
|
|
||||||
let file_path = path.join(Self::get_file_name::<String>());
|
|
||||||
fs::write(file_path, toml::to_string_pretty(self)?)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load() -> Result<Self, Box<dyn Error>> {
|
|
||||||
let path = Self::get_path::<PathBuf>();
|
|
||||||
|
|
||||||
let file_path = path.join(Self::get_file_name::<String>());
|
|
||||||
if ! file_path.is_file() {
|
|
||||||
Ok(Self::default())
|
|
||||||
} else {
|
|
||||||
Ok(toml::from_str(&fs::read_to_string(file_path)?)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
39
src/main.rs
39
src/main.rs
|
@ -1,20 +1,17 @@
|
||||||
use std::{error::Error, path::PathBuf, process::exit};
|
use std::{error::Error, process::exit};
|
||||||
|
|
||||||
use reqwest::{header::{HeaderMap, HeaderValue}, Client};
|
use reqwest::{header::{HeaderMap, HeaderValue}, Client};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::io::{stdout, IsTerminal};
|
|
||||||
|
|
||||||
use crate::{cache::Cache, config::Config};
|
use crate::cache::Cache;
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
mod config;
|
|
||||||
|
|
||||||
const GREEN: &str = "\x1b[1;32m";
|
const GREEN: &str = "\x1b[1;32m";
|
||||||
const RED: &str = "\x1b[1;31m";
|
const RED: &str = "\x1b[1;31m";
|
||||||
const BLUE: &str = "\x1b[34m";
|
const WARN: &str = "\x1b[1;34m";
|
||||||
const WARN: &str = "\x1b[33m";
|
|
||||||
const RESET: &str = "\x1b[0m";
|
const RESET: &str = "\x1b[0m";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
@ -148,46 +145,22 @@ async fn get_res<'a>(cli: &Client, query: String, vqd: String, cache: &'a mut Ca
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
|
#[clap(trailing_var_arg=true)]
|
||||||
struct Args {
|
struct Args {
|
||||||
#[arg(long, default_value = "false", required = false, help = "If you want to agree to the DuckDuckGo TOS")]
|
|
||||||
pub agree_tos: bool,
|
|
||||||
#[arg()]
|
#[arg()]
|
||||||
pub query: Vec<String>,
|
pub query: Vec<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
femme::start();
|
femme::start();
|
||||||
|
|
||||||
if ! stdout().is_terminal() {
|
println!("{GREEN}Contacting DuckDuckGo chat AI...{RESET}");
|
||||||
eprintln!("{RED}Refusing to run in a non-terminal environment{RESET}");
|
|
||||||
eprintln!("This is done to prevent API scraping.");
|
|
||||||
exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let query = args.query.join(" ");
|
let query = args.query.join(" ");
|
||||||
|
|
||||||
let mut cache = Cache::load().unwrap();
|
let mut cache = Cache::load().unwrap();
|
||||||
let mut config = Config::load().unwrap();
|
|
||||||
|
|
||||||
if args.agree_tos {
|
|
||||||
if ! config.tos {
|
|
||||||
println!("{GREEN}TOS accepted{RESET}");
|
|
||||||
}
|
|
||||||
config.tos = true;
|
|
||||||
config.save().expect("Error saving config");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! config.tos {
|
|
||||||
eprintln!("{RED}You need to agree to duckduckgo AI chat TOS to continue.{RESET}");
|
|
||||||
eprintln!("{RED}Visit it on this URL: {RESET}{BLUE}https://duckduckgo.com/?q=duckduckgo+ai+chat&ia=chat{RESET}");
|
|
||||||
eprintln!("Once you read it, pass --agree-tos parameter to agree.");
|
|
||||||
eprintln!("{WARN}Note: if you want to, modify `tos` parameter in {}{RESET}", Config::get_path::<PathBuf>().join(Config::get_file_name::<String>()).display());
|
|
||||||
exit(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{GREEN}Contacting DuckDuckGo chat AI...{RESET}");
|
|
||||||
|
|
||||||
let cli = Client::new();
|
let cli = Client::new();
|
||||||
simulate_browser_reqs(&cli).await.unwrap();
|
simulate_browser_reqs(&cli).await.unwrap();
|
||||||
|
|
Loading…
Reference in New Issue