Skip to content

Instantly share code, notes, and snippets.

@hizkifw
Last active October 25, 2024 05:40
Show Gist options
  • Save hizkifw/86c941c5a8e289b7429a7e2fa4807571 to your computer and use it in GitHub Desktop.
Save hizkifw/86c941c5a8e289b7429a7e2fa4807571 to your computer and use it in GitHub Desktop.
Invoke LLMs from the command line
#!/usr/bin/env bash
#
# ai.sh - invoke llm from command line
#
# Usage:
# * Run interactively
# ai.sh
#
# * Invoke a single inference from command line
# ai.sh ffmpeg convert all mp4 in this folder to mp3
#
# * Inject text content into the context
# cat document.txt | ai summarize this document
#
# * Inject text content into interactive session
# cat document.txt | ai
#
aish_openai_endpoint='https://openrouter.ai/api/v1'
aish_openai_key='sk-or-v1-xxxxxxxxxxxxxxxx'
aish_openai_model='anthropic/claude-3.5-sonnet'
system='You are an assistant invoked through a command line. Generate a code
snippet to fulfill the task. By default: only output the command, no explanations,
unless otherwise asked by user. If asked to explain, format responses such that
it looks good in the CLI, e.g. hard wrap to 80 characters, and be concise.'
require() {
cmd="$1"
if ! command -v "$cmd" >/dev/null; then
echo "$cmd not installed"
exit 1
fi
}
require curl
require jq
# Attach stdin if it exists
prompt="$@"
interactive=false
extra_content=''
if [[ ! -t 0 ]]; then
stdin=`cat`
extra_content="[stdin after this line]\n$stdin"
nchars=$(wc -c <<< "$stdin")
echo "[*] Loaded $nchars bytes from stdin into context"
fi
messages=$(jq -n \
--arg system "$system" \
--arg extra "$extra_content" \
'[
{ role: "system", content: $system },
(if $extra != "" then
{ role: "user", content: $extra }
else
empty
end)
]'
)
add_message() {
role="$1"
content="$2"
messages=$(jq \
--arg role "$role" \
--arg content "$content" \
'. + [ { role: $role, content: $content } ]' \
<<< "$messages"
)
}
inference() {
# Prompt user if there is no prompt from the arguments
if [[ -z "$prompt" ]]; then
interactive=true
IFS= read -r -p "> " prompt < /dev/tty || {
echo '^D'
exit 0
}
fi
# Update context
add_message user "$prompt"
# Construct request object
req_json=$(jq -n \
--arg model "$aish_openai_model" \
--argjson messages "$messages" \
'{
model: $model,
messages: $messages,
stream: true
}'
)
# Send streaming request
curl -fsSLN "$aish_openai_endpoint/chat/completions" \
-XPOST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $aish_openai_key" \
-d "$req_json" \
| grep --line-buffered -E '^data: ' \
| grep --line-buffered -v '[[DONE]]' \
| stdbuf -oL cut -c 7- \
| jq --unbuffered -j '.choices[0].delta.content' \
| tee >/dev/stderr | read -r response
echo ''
# Update context
add_message assistant "$response"
# Prepare for next loop if any
prompt=''
}
inference
while [ "$interactive" = true ]; do
inference
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment