Last active
July 20, 2023 00:41
-
-
Save u1and0/b4a8647bebbcb8b9b71c6e166726063e to your computer and use it in GitHub Desktop.
Ask ChatGPT from terminal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# ChatGPT client by ShellScript | |
# $ curlgpt "hello world!" | |
# or | |
# $ echo "hello world!" | curlgpt | |
# | |
# MIT License | |
# | |
# Copyright (c) 2023 u1and0 | |
# ローディングスピナーを表示します。 | |
# `$1`には、バックグラウンドで実行されるプロセスのPIDを渡します。 | |
# スピナーのフレームは、`spinstr`変数に保存されます。 | |
# `printf`コマンドを使用して、スピナーの各フレームを表示し、 | |
# `sleep`コマンドを使用して、スピナーの速度を調整します。 | |
# 最後に、`printf`コマンドを使用して、スピナーを消去します。 | |
_spinner() { | |
local pid=$1 | |
local delay=0.02 | |
local spinstr='.' | |
while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do | |
printf " %s " "$spinstr" | |
local spinstr=$spinstr'.' | |
sleep $delay | |
printf "\b\b\b\b\b\b\b" | |
if [ ${#spinstr} -gt 3 ]; then | |
spinstr='.' | |
fi | |
done | |
printf " \b\b\b\b" | |
} | |
# Remove temp file | |
_cleanup() { | |
rm -f "$response_file" | |
} | |
# MAIN | |
# Default values | |
model="gpt-3.5-turbo" | |
temperature=1.0 | |
max_tokens=1000 | |
system_prompt="" | |
USAGE=$(cat <<-END | |
Usage: | |
$ curlgpt "hello world!" | |
or | |
$ echo "hello world!" | curlgpt | |
Options: | |
-m: OpenAI model name (default to gpt-3.5-turbo) | |
-t: temperature value (default to 1.0) | |
-x: max_tokens value (default to 1000) | |
-s: system prompt | |
END | |
) | |
# Options | |
while getopts ":m:t:x:s:h:" option; do | |
case "${option}" in | |
m) model=${OPTARG};; | |
t) temperature=${OPTARG};; | |
x) max_tokens=${OPTARG};; | |
s) system_prompt=${OPTARG};; | |
h) echo "${USAGE}"; exit 0;; | |
\?) echo "Invalid option: -$OPTARG" 1>&2; exit 1;; # 不正なオプション | |
:) echo "${USAGE}" 1>&2; exit 1;; # オプション引数がない | |
esac | |
done | |
shift $(expr $OPTIND - 1) | |
# Get input from stdin or arg | |
if [ -p /dev/stdin ]; then | |
# パイプラインからの入力がある場合 | |
input=$(cat - | xargs | sed -e 's/"/\"/g' | tr -d '[:cntrl:]' 2> /dev/null) | |
elif [ -n "$1" ]; then | |
# 引数がある場合 | |
input="$1" | |
else | |
# 引数がなく、パイプラインからの入力もない場合 | |
printf '%s\n' "${USAGE}" | |
exit 1 | |
fi | |
# curlgpt | |
# curlでchatgptに第一引数の文字列の質問 | |
# jqでcontentのみ表示 | |
response_file="$(mktemp)" | |
messages=$(cat <<-END | |
{ "role":"system", "content": "${system_prompt}" }, | |
{ "role":"user", "content": "${input}" } | |
END | |
) | |
data=$(cat <<-END | |
{ | |
"model": "${model}", | |
"temperature": ${temperature}, | |
"max_tokens": ${max_tokens}, | |
"messages": [${messages}] | |
} | |
END | |
) | |
echo -e "${data}" >&2 | |
curl -s -X POST https://api.openai.com/v1/chat/completions \ | |
-H "Content-Type: application/json" \ | |
-H "Authorization: Bearer ${OPENAI_API_KEY}" \ | |
-d "${data}" -o "$response_file" 2>&1 & | |
curl_pid=$! | |
# curlが終わるまでスピナー表示 | |
_spinner "$curl_pid" >&2 | |
wait "$curl_pid" | |
# curlの終了ステータスによってjqの表示を変える | |
curl_status=$? | |
error_response="$(cat "$response_file" | jq '.error')" | |
if [ "$curl_status" -eq 0 ] && [ "${error_response}" == "null" ]; then | |
s=$( cat "$response_file" | jq -r '.choices[].message.content' ) | |
# print char by char | |
while [ ${#s} -gt 0 ]; do | |
printf '%s' "${s%${s#?}}" | |
s=${s#?} | |
sleep 0.02 | |
done | |
printf '\n' | |
else | |
echo -e "data: ${data}" >&2 | |
cat "$response_file" | jq -r | |
fi | |
trap _cleanup EXIT | |
trap "kill $curl_pid && _cleanup" SIGINT SIGTERM |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment