/
humanscript
executable file
·79 lines (69 loc) · 2.99 KB
/
humanscript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env bash
# Setup filesystem
DATA_DIR="${HOME}/.humanscript"
CONFIG_FILE="${DATA_DIR}/config"
CACHE_DIR="${DATA_DIR}/cache"
mkdir -p "${CACHE_DIR}"
touch "${CONFIG_FILE}"
# Load settings
source "${CONFIG_FILE}"
# Defaults
HUMANSCRIPT_API_KEY="${HUMANSCRIPT_API_KEY:-"sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}"
HUMANSCRIPT_MODEL="${HUMANSCRIPT_MODEL:-"gpt-4"}"
HUMANSCRIPT_API="${HUMANSCRIPT_API:-"https://api.openai.com/v1"}"
HUMANSCRIPT_EXECUTE="${HUMANSCRIPT_EXECUTE:-"true"}"
HUMANSCRIPT_REGENERATE="${HUMANSCRIPT_REGENERATE:-"false"}"
# Read the script passed to the interpeter
humanscript_path="${1}"
[[ "${humanscript_path}" = "" ]] && echo "Must pass a humanscript" && exit 1
humanscript=$(cat "${humanscript_path}")
# Execute from cache if we have a hit
script_name=$(basename $humanscript_path)
script_hash=$(echo $humanscript | openssl dgst -sha256 | sed 's/^.*= //')
script_cache_path="${CACHE_DIR}/${script_name}-${script_hash}"
[[ "${HUMANSCRIPT_REGENERATE}" = "true" ]] && rm "${script_cache_path}" 2> /dev/null
if [[ -f "${script_cache_path}" ]]
then
[[ "${HUMANSCRIPT_EXECUTE}" = "true" ]] && exec bash "${script_cache_path}" ${@:2}
cat "${script_cache_path}"
exit
fi
# System prompt
system_prompt="
You are humanscript, a human readable script interpreter, here are your rules:
You read an input script consisting of human readable commands and convert it to a bash output script.
You always start the output script with the exact shebang \"#!/usr/bin/env bash\".
You take care to provide portable code that runs well on both macos and linux systems.
Lines in the input script starting with a '#' are comments.
You NEVER respond with markdown, only respond in pure bash.
You NEVER explain anything about the script."
# User prompt
user_prompt="
### Input script:
$(cat "${humanscript_path}")
### Output script:"
# Format JSON payload
function json_string() {
echo "${1}" | jq --raw-input --raw-output --slurp @json
}
data=$(echo '{
"model": "'$HUMANSCRIPT_MODEL'",
"messages": [
{"role": "system", "content": '$(json_string "${system_prompt}")'},
{"role": "user", "content": '$(json_string "${user_prompt}")'}
],
"temperature": 0.7,
"max_tokens": 1000,
"stream": true
}' | jq)
# Send request and stream chunked responses back
curl --silent --show-error "${HUMANSCRIPT_API}/chat/completions" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${HUMANSCRIPT_API_KEY}" \
--data "${data}" | \
sed 's/^data: //' | # Strip chunk header
sed '/^\[DONE\]/d' | # Strip end chunk
tee >(jq --join-output --unbuffered '.error // ""' >&2 || cat) | # Log API errors to stderr (without breaking the pipe)
jq --join-output --unbuffered '.choices[0].delta.content // ""' 2> /dev/null | # Grab content from JSON chunk
tee "${script_cache_path}" | # Cache result
([[ "${HUMANSCRIPT_EXECUTE}" = "true" ]] && exec bash -s ${@:2} || cat) # Pipe to bash (or stdout if HUMANSCRIPT_EXECUTE=false)