Tutorial
From one question and its exit code to a saved question and a stream of messages.
1. Install it
curl -fsSL https://thinkthen.dev/install.sh | shbrew install botassembly/thinkthen/thinkthenThe install page covers the key and every language and database.
2. Ask one question
Name the question, pipe the message in, and pass the question as an argument. decide prints a bare true, false, or null, and it sets the exit code to match.
question="Does the customer ask for a refund?"
cat <<'EOF' |
I renewed once this morning, but my card shows two charges.
Please refund the duplicate.
EOF
thinkthen decide "$question"true
The exit code is the answer. A script branches on it the way it branches on test.
3. Set a band
--threshold is your bar on the probability. One number is a cut, and the default is 0.5. Two numbers make a band: under the low bar is no, at or over the high bar is yes, and anything between is not sure.
question="Does the customer ask for a refund?"
printf '%s\n' "I want to send this back." |
thinkthen decide "$question" \
--threshold 0.2:0.8null
The threshold never changes the probability. It changes what you call a yes.
4. Branch on the answer
A script reads the exit code and hands a person the calls it should not make alone.
question="Does the customer ask for a refund?"
printf '%s\n' "I want to send this back." |
thinkthen decide "$question" \
--quiet \
--threshold 0.2:0.8
refund_code=$?
case $refund_code in
0) echo "refund it" ;;
1) echo "answer it as usual" ;;
3) echo "send it to a person" ;;
esac
test "$refund_code" -eq 3send it to a person
5. Save the question to a file
A question file holds one question: the words, what a yes and a no mean, and the threshold.
{
"decide": "Does the customer ask for a refund?",
"true": "The customer asks for money back.",
"false": "Anything else, such as a cancellation or thanks.",
"threshold": "0.2:0.8"
}Write @refund.json in place of the question words.
cat <<'EOF' |
I would like to return this and get my money back.
EOF
thinkthen decide @refund.jsontrue
printf '%s\n' "I want to send this back." |
thinkthen decide @refund.jsonnull
6. Judge a stream
--lines tells decide to judge each line as its own message. Each answer then prints as one JSON line with its input beside it. The input shows which answer belongs to which message. jq . spreads each line out to read.
question="Does the customer ask for a refund?"
cat <<'EOF' |
Please refund my order. It arrived broken.
Thanks for the quick help yesterday!
I want to send this back.
EOF
thinkthen decide "$question" \
--batch 1 \
--lines \
--threshold 0.2:0.8 |
jq .{
"input": "Please refund my order. It arrived broken.",
"value": true
}
{
"input": "Thanks for the quick help yesterday!",
"value": false
}
{
"input": "I want to send this back.",
"value": null
}filter reads one record per line with no flag. It keeps the records where the answer is yes, byte for byte and in order.
question="Is this a complaint?"
cat <<'EOF' |
Arrived a day early. Thank you!
The zipper broke the first time I used it.
Does this come in blue?
The strap snapped on day two.
EOF
thinkthen filter "$question" --batch 1The zipper broke the first time I used it. The strap snapped on day two.
rank sorts the records by how likely the answer is yes.
question="Is this urgent?"
cat <<'EOF' |
Newsletter: our autumn catalog is here. No reply needed.
Our checkout page is down and customers cannot pay
Reminder: your invoice is due in 30 days
Please send the signed quote by 5 pm today
EOF
thinkthen rank "$question" --batch 1Our checkout page is down and customers cannot pay Please send the signed quote by 5 pm today Reminder: your invoice is due in 30 days Newsletter: our autumn catalog is here. No reply needed.
Put them in a pipe and the second question reads only what the first kept. See the leads how-to for filter, rank, and choose in one pipeline.
7. Ask many questions at once
annotate answers a question set for every record. A question set is any mix of decide, choose, score, and tag questions in one file.
{
"version": 1,
"questions": {
"kind": {
"choose": "What kind of message is this?",
"options": [
"billing",
"delivery",
"question"
]
},
"urgency": {
"score": "How urgent is this?",
"levels": [
"Routine.",
"Soon.",
"Immediate."
]
}
}
}question="Does this need a reply?"
cat <<'EOF' |
Please fix the wrong amount on my invoice.
Just saying thanks, no reply needed.
Order never arrived and the party is tonight.
Do you ship to Canada?
EOF
thinkthen filter "$question" --batch 1 |
thinkthen annotate inbox-form.json \
--batch 1 --lines |
jq .{
"input": "Please fix the wrong amount on my invoice.",
"value": {
"kind": "billing",
"urgency": 0.58
}
}
{
"input": "Order never arrived and the party is tonight.",
"value": {
"kind": "delivery",
"urgency": 1.96
}
}
{
"input": "Do you ship to Canada?",
"value": {
"kind": "question",
"urgency": 0.01
}
}filter drops the thank-you note. Each message left comes back with one field per question.
ThinkThen answers. Your code acts.
Next: Beatles Bench · Learn the Bash techniques
On GitHub: github.com/botassembly/thinkthen