rcmdnk's blog
Last update

20250127_api_200_200

コマンドラインからさっとAIのAPIを使うためのシェルスクリプトを なるべく外部依存を減らして作って通常のUnix環境なら即使えるようなものとして作ってみました。

スクリプト

jqとか使えばJSONのパースとか簡単で複雑なことも確実にできるのですが、 そういうの使わずにやってみます。

ない可能性があるものとしてはcurlsedくらいかな、と思いますが、 sedに関してはGNU版でもmacOSなどに入ってるBSD版でも動くようにしているので 1、 ネットワークさえ繋がっていれば殆どの場合で使えるはずです。

こんな感じ。

重要なのは

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function encode {
  local str="$*"
  str=${str//\\/\\\\}
  str=${str//\"/\\\"}
  str=${str//$'\t'/\\t}
  str=${str//$'\n'/\\n}
  str=${str//$'\r'/}
  echo "$str"
}

function extract {
  local key="$1"
  shift
  local json="$*"
  printf "$(echo "$json"|sed -n 's/.*"'$key'":[[:space:]]*"\([^"\\]*\(\\.[^"\\]*\)*\)".*/\1/p')"
}

追記: 2025/02/15

Windowsで作業する際に改行コードがCRLFが混じってdiffに入るとエラーになることがあるので それを削除するために$'\r'を削除する部分を追加。

追記ここまで

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
content=$(encode "$content")

input_json='{"model": "'$MODEL'", "messages": [{"role": "user", "content": "'"$content"'"}]}'

json=$(curl -s "$ENDPOINT" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $key" \
  -d "$input_json")
echo "$json" > log

output=$(extract content "$json")
if [ -z "$output" ];then
  echo "Failed to get a response from the API (ENDPOINT=$ENDPOINT, MODEL=$MODEL)." 1>&2
  echo "" 1>&2
  extract message "$json" >&2
  exit 1
fi
echo "$output"

の部分。

encodeで入力をエスケープして改行も\nに変換してJSONとして扱えるようにします。

出力はextract$keyに対応する値を取り出します。

model, message[0].role, message[0].contentをJSONにしてcurlを使ってAPIに送ります。

ChatGPTなどのAPIは.../chat/completionsというエンドポイントを叩くと、 返してくるJSON形式のデータの中にchoices[0].message.contentに出力があるのでcontentを取り出します。 最後にprintfでエスケープされてる文字なども直して出力します。

ここでは一回問いかけをするだけのデータを送ってるので返ってくるchoicesは1つなのでシンプルに最初に見つかったものだけを取り出していますが、 複数になるとこのようにやるのはけっこう大変にはなってしまいます。

失敗した際にはmessageにエラーメッセージが入っているのでそれを取り出して表示します。

あとの部分はモデルやエンドポイント、またAPIキーなどを設定して実行するだけです。

https://api.openai.com/v1/chat/completionsと同じ使い方のできるAPIであれば別のAPIでも使えるようになっています。 DeepSeekやローカルLLMのollamaなども基本的にOpenAIと互換性をもたせるような形を作ってくれているので このスクリプトで使うことができます。

使い方

スクリプトは Simple Chat API call script のページからRAWのURLを取得して、

1
$ curl -s -O https://gist.githubusercontent.com/rcmdnk/0c1132b8ac95382c66d988932bd32bc3/raw/40c2092404150649bfb55be8dca8c9a37d1b2d18/chat.sh

`

とするかZIPでダウンロードして展開して使ってください。

コピペでやろうとするとエスケープした部分とかが変わってしまう可能性があるので注意。

使い方としては引数として質問を与えるか、パイプでつなげて標準入力として与えることができます。 両方与えた場合は標準入力のあとに引数で与えた入力を改行した後につなげます。

オプションは

  • -m [MODEL]: モデル指定。デフォルトはgpt-4o
  • -e [ENDPOINT]: エンドポイント指定。デフォルトはhttps://api.openai.com/v1/chat/completions
  • -k [KEY_NAME]: APIキーを入れた環境変数名の指定。デフォルトはOPENAI_API_KEY
  • -v: 詳細モード。入力に使ったJSONデータと出力のJSONデータそのものも表示する。
  • -h: ヘルプ表示。

MODEL, ENDPOINT, KEY_NAME~/.config/chat/configでも変更できます。

例えば

~/.config/chat/config
1
2
3
MODEL=deepseek-chat
ENDPOINT=https://api.deepseek.ai/v1/chat/completions
KEY_NAME=DEEPSEEK_API_KEY

とかすればDeepSeekのAPIを使うようになります。

OpenAIとDeepSeekに関しては、ENDPOINTを指定しなくても gpt*, chatgpt*, o1-*の場合はOpenAIのAPIを、 deepseek*の場合はDeepSeekのAPIを使うようにしています。

これら以外でENDPOINTを指定しないとローカル、 http://localhost:11434/v1/chat/completionsを使うようにしています。 これはollamaのデフォルトのエンドポイントです。

必要に応じて

  • -M: max_completion_tokens
  • -t: temperature

などのオプションを追加してもいいかもしれませんが、 この辺おオプションはdeepseekだとまだmax_tokensしかなかったり OpenAIだとtemperatureしかなかったりするので デフォルトでは入れずに指定されたらjsonに追加するようにする、的な感じが良いかと思います。

モデルを変えてみる

というわけで、実際に使ってみると

1
2
3
4
5
6
$ ./chat.sh who are you
I am OpenAI's language model, designed to assist with a wide range of queries by providing information, answering questions, and engaging in conversation. How can I help you today?
$ ./ask.sh -m deepseek-chat who are you
I am DeepSeek-V3, an artificial intelligence assistant created by DeepSeek. I'm at your service and would be delighted to assist you with any inquiries or tasks you may have.
$ ./chat.sh -m llama3.2 who are you
I'm an artificial intelligence model known as Llama. Llama stands for "Large Language Model Meta AI."

こんな感じでモデルの変更もしながら簡単に使えます。 まあ、各モデルが嘘をつくこともあるので、 この返信で正しいという確実な保証はできませんが2

ちょっと長めの質問、返信を試す

長めの質問をする場合はファイルに書いておいて中身を標準入力で渡すのが楽です。

question.txt
1
2
3
4
pythonでtodo listを作るプロジェクトを作ってください。

1. プロジェクトのディレクトリ構造を決める。
2. 各ディレクトリ内に適当なファイルを作る。

こんな質問をしてみます。

1
$ < question.txt ./chat.sh

結果

~15秒位。

1
$ < question.txt ./chat.sh -m deepseek-chat

結果

~45秒位。

1
$ < question.txt ./chat.sh -m llama3.2

結果

~20秒位(グラボはRTX 2070 Super)。

結構古いグラボであれですが、一応ollama使ってllima3.2でやってみてもこんな感じでできました。 deepseek-chat (deepseek-v3)は結構時間がかかりましたが一番複雑な構造になっています。

まあ、こういった使い方するのであれば普通にウェブでやったほうがその後のやり取りも出来るので 無理にシェルスクリプトでやる必要はありませんが。

Gitのcommitメッセージを生成する

の記事でChatGPTを使ってGitのcommitメッセージを生成するスクリプトを作りましたが、 この中では chatgpt-prompt-wrapper というPythonスクリプトを使ってAPIを叩いていました。

これが入ってないと動かないので、これをcurlでやる上の方法に変更しました。

git-gpt-commit/bin/git-gpt-commit のスクリプトをダウンロードしてPATHの通ったところに置いて使ってください。

もしくはHomebrewでインストールすることもできます。

1
$ brew install rcmdnk/rcmdnkpac/git-gpt-commit

これで、git gpt-commitというGitのサブコマンドが使えるようになります。

長いので、

1
2
[alias]
  c = gpt-commit

とかのエイリアスを設定して使ってます。

これで、commitの代わりにcを使えばgit dif --cachedの出力を使ってcommitメッセージを生成してくれて、 作られたメッセージがデフォルトで記入された状態でcommitメッセージを編集するためにエディタが起動します。

gpt-commitでMODEL等を変更したい場合は~/.config/git_gpt_commit/configに書くことで変更できます。

Sponsored Links
Sponsored Links

« INNOCN 40インチウルトラワイドモニターWR40 PROを購入 ObsidianをWindows/macOS/iOSでGit (GitHub)、Remotely Save (Dropbox)を使って同期、管理する »

}