diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cdea4a..257037e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ ## Unreleased +## 2023-04-16 0.1.7 + - Disable spinners with env `DISABLE_SPINNER` +- Disable spinners with flag `x` +- `prompt` also accepts text from stdin ## 2023-04-05 0.1.6 diff --git a/Cargo.lock b/Cargo.lock index dcafa03..e0279d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,7 +289,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -306,7 +306,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -352,13 +352,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -460,9 +460,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -471,7 +471,7 @@ dependencies = [ [[package]] name = "gpto" -version = "0.1.6" +version = "0.1.7" dependencies = [ "chrono", "chrono-tz", @@ -492,9 +492,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", @@ -581,9 +581,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -704,14 +704,14 @@ checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "is-terminal" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -875,9 +875,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl" -version = "0.10.49" +version = "0.10.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33" +checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" dependencies = [ "bitflags", "cfg-if", @@ -896,7 +896,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -907,9 +907,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.84" +version = "0.9.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa" +checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" dependencies = [ "cc", "libc", @@ -1171,16 +1171,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.7" +version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1256,7 +1256,7 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -1395,9 +1395,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -1443,7 +1443,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index baf77de..6a117ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gpto" -version = "0.1.6" +version = "0.1.7" authors = ["Alan Vardy "] edition = "2021" license = "MIT" diff --git a/PUBLISH_CHECKLIST.md b/PUBLISH_CHECKLIST.md index 88fd57a..9d1bfee 100644 --- a/PUBLISH_CHECKLIST.md +++ b/PUBLISH_CHECKLIST.md @@ -14,23 +14,15 @@ This checklist is just here for me to reduce the friction of publishing new vers Code changes -1. Update dependencies and make sure nothing broke +1. Update dependencies and make sure nothing broke with `./update_test.sh` +2. Change the version in `Cargo.toml` and in this document (do a global find and replace) +3. Update CHANGELOG.md with the version number +4. Update README.md with help text `cargo run -- -h` +5. Add any new examples to README.md +6. Open PR for the version and wait for it to pass +7. Commit and merge PR -```bash -cargo update && \ -./test.sh && \ -./manual_test.sh -``` - -2. Revert the change to the test `gpto.cfg` -3. Change the version in `Cargo.toml` and in this document (do a global find and replace) -4. Update CHANGELOG.md with the version number -5. Update README.md with help text `cargo run -- -h` -6. Add any new examples to README.md -7. Open PR for the version and wait for it to pass -8. Commit and merge PR - -9. Build release +8. Build release ```bash git checkout main @@ -38,33 +30,15 @@ git pull cargo aur ``` -10. [Create a new release](https://github.com/alanvardy/gpto/releases/new) +9. [Create a new release](https://github.com/alanvardy/gpto/releases/new) - Make sure to use the label and title in format `v0.1.6` - Add binary from gpto directory -11. Publish to Cargo +10. Publish to Cargo ```bash cargo publish ``` -12. Make sure we have the latest AUR git history - -```bash -cd ../gpto-bin/ -git pull -cd ../gpto/ -``` - -13. Push to AUR - -```bash -makepkg --printsrcinfo > ../gpto-bin/.SRCINFO -mv PKGBUILD ../gpto-bin/ -rm *.tar.gz -cd ../gpto-bin/ -git add . -git commit -m v0.1.6 -git push aur -``` +11. Push to aur with `./push_aur` diff --git a/README.md b/README.md index 691dbb5..84f5719 100644 --- a/README.md +++ b/README.md @@ -12,31 +12,22 @@ A tiny unofficial OpenAI client Usage: gpto [OPTIONS] Options: - -p, --prompt ... - The prompt(s) to generate completions for + -p, --prompt [...] + The prompt(s) to generate completions for. Also accepts text from stdin + -x, --disable spinner + Disable the spinner and message when querying -c, --conversation [...] Start a conversation with an optional description of the bot's role -s, --suffix ... The suffix that comes after a completion of inserted text. Defaults to an empty string -t, --temperature - What sampling temperature to use. - Higher values means the model will take more risks. - Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. - Defaults to 1.0 + What sampling temperature to use. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. Defaults to 1.0 -n, --number How many completions to generate for each prompt. Defaults to 1 -k, --top_p - An alternative to sampling with temperature, called nucleus sampling, - where the model considers the results of the tokens with top_p probability mass. - So 0.1 means only the tokens comprising the top 10% probability mass are considered. - We generally recommend altering this or temperature but not both. - Defaults to 1.0 + An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We generally recommend altering this or temperature but not both. Defaults to 1.0 -m, --model - - Model to use for completion. Defaults to gpt-3.5-turbo. - This CLI uses the /v1/chat/completions endpoint, - see https://platform.openai.com/docs/models/gpt-3 for models available - + Model to use for completion. Defaults to gpt-3.5-turbo. This CLI uses the /v1/chat/completions endpoint, see https://platform.openai.com/docs/models/gpt-3 for models available -o, --config Absolute path of configuration. Defaults to $XDG_CONFIG_HOME/gpto.cfg -h, --help @@ -95,6 +86,14 @@ Q: What did the fish say when it hit the wall? A: Dam! ``` +Get completions using text from stdin (without displaying the spinner) + +```bash +> echo "what is one plus one" | gpto -xp + +Two +``` + Get a completion with a different model (this example uses the leading code completion model). And yes, the generated code is not idiomatic! Read more about models [here](https://platform.openai.com/docs/models/gpt-3). This CLI app uses the `/v1/chat/completions` endpoint. diff --git a/manual_test.sh b/manual_test.sh index d3b08f0..b3c2ee4 100755 --- a/manual_test.sh +++ b/manual_test.sh @@ -8,6 +8,8 @@ echo "== TESTING -p tell a great joke -t 0 ==" && \ cargo run -- -p tell a great joke -t 0 && \ echo "== TESTING -m gpt-3.5-turbo-0301 ==" && \ cargo run -- -m gpt-3.5-turbo-0301 -p language is elixir create a function that adds two numbers && \ +echo "== TESTING -p with stdin ==" && \ +echo "what is one plus one" | cargo run -- -xp && \ echo "== TESTING -c ==" && \ cargo run -- -c && \ echo "== TESTING -c Roleplay as Shakespeare ==" && \ diff --git a/push_aur.sh b/push_aur.sh new file mode 100755 index 0000000..563398d --- /dev/null +++ b/push_aur.sh @@ -0,0 +1,12 @@ +#!/bin/sh +cd ../gpto-bin/ +git pull +cd ../gpto/ +makepkg --printsrcinfo > ../gpto-bin/.SRCINFO +mv PKGBUILD ../gpto-bin/ +rm *.tar.gz +cd ../gpto-bin/ +git add . +git commit -m "new version" +git push aur +cd ../gpto \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8113d39..f5b3662 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,8 @@ extern crate matches; extern crate clap; +use std::io; + use clap::{Arg, ArgAction, ArgMatches, Command}; use colored::*; @@ -28,7 +30,8 @@ pub const SUFFIX_HELP: &str = pub const CONFIG_HELP: &str = "Absolute path of configuration. Defaults to $XDG_CONFIG_HOME/gpto.cfg"; -pub const PROMPT_HELP: &str = "The prompt(s) to generate completions for"; +pub const PROMPT_HELP: &str = + "The prompt(s) to generate completions for. Also accepts text from stdin"; pub const CONVERSATION_HELP: &str = "Start a conversation with an optional description of the bot's role"; pub const NUMBER_HELP: &str = "How many completions to generate for each prompt. Defaults to 1"; @@ -37,6 +40,7 @@ pub const MODELS_HELP: &str = "Returns a list of models from OpenAI"; pub struct Arguments<'a> { prompt: Option, + disable_spinner: bool, conversation: Option, suffix: Option, number: Option, @@ -52,7 +56,18 @@ fn main() { .author(AUTHOR) .about(ABOUT); let matches = app - .arg(flag_string("prompt", 'p', "Prompt text", PROMPT_HELP)) + .arg(flag_nullable_string( + "prompt", + 'p', + "Prompt text", + PROMPT_HELP, + )) + .arg(flag_arg( + "disable spinner", + 'x', + "disable spinner", + "Disable the spinner and message when querying", + )) .arg(flag_nullable_string( "conversation", 'c', @@ -83,7 +98,8 @@ fn main() { .get_matches(); let arguments = Arguments { - prompt: join_string(matches.clone(), "prompt"), + disable_spinner: has_flag(matches.clone(), "disable spinner"), + prompt: string_or_stdin(matches.clone()), suffix: join_string(matches.clone(), "suffix"), conversation: join_string(matches.clone(), "conversation"), config_path: matches.get_one::("config").map(|s| s.as_str()), @@ -120,6 +136,7 @@ fn dispatch(arguments: Arguments) -> Result { .. } => request::conversation(arguments, config), Arguments { + disable_spinner: _, prompt: None, config_path: _, model: _, @@ -206,3 +223,32 @@ fn join_string(matches: ArgMatches, long: &str) -> Option { .get_many(long) .map(|values| values.cloned().collect::>().join(" ")) } +fn string_or_stdin(matches: ArgMatches) -> Option { + let result = join_string(matches, "prompt"); + match result.clone() { + Some(string) => { + if string.is_empty() { + let mut buffer = String::new(); + io::stdin().read_line(&mut buffer).unwrap(); + Some(buffer) + } else { + result + } + } + None => None, + } +} +fn flag_arg(id: &'static str, short: char, long: &'static str, help: &'static str) -> Arg { + Arg::new(id) + .short(short) + .long(long) + .value_parser(["yes", "no"]) + .num_args(0..1) + .default_value("no") + .default_missing_value("yes") + .required(false) + .help(help) +} +fn has_flag(matches: ArgMatches, id: &'static str) -> bool { + matches.get_one::(id) == Some(&String::from("yes")) +} diff --git a/src/request.rs b/src/request.rs index 5c17faa..bf4d43d 100644 --- a/src/request.rs +++ b/src/request.rs @@ -95,7 +95,12 @@ pub fn conversation(arguments: Arguments, config: Config) -> Result Result Result Result { +fn post_openai( + token: String, + url: String, + body: serde_json::Value, + disable_spinner: bool, +) -> Result { let openai_url: &str = "https://api.openai.com"; let request_url = format!("{openai_url}{url}"); let authorization: &str = &format!("Bearer {token}"); - let spinner = maybe_start_spinner(); + let spinner = maybe_start_spinner(disable_spinner); let response = Client::new() .post(request_url) .header(CONTENT_TYPE, "application/json") @@ -197,15 +212,15 @@ pub fn get_latest_version() -> Result { } } -fn maybe_start_spinner() -> Option { - match env::var("DISABLE_SPINNER") { - Ok(_) => None, - _ => { - let sp = Spinner::new(SPINNER, MESSAGE.into()); - Some(sp) - } +fn maybe_start_spinner(disable_spinner: bool) -> Option { + if env::var("DISABLE_SPINNER").is_ok() || disable_spinner { + None + } else { + let sp = Spinner::new(SPINNER, MESSAGE.into()); + Some(sp) } } + fn maybe_stop_spinner(spinner: Option) { if let Some(mut sp) = spinner { sp.stop(); diff --git a/update_test.sh b/update_test.sh new file mode 100755 index 0000000..af00617 --- /dev/null +++ b/update_test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cargo update && \ +./test.sh && \ +./manual_test.sh