init commit

This commit is contained in:
sigoden
2024-05-15 08:50:49 +00:00
commit 281bf5623d
7 changed files with 237 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
/tmp
/functions.txt
/functions.json
/.env
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
set -e
# @meta dotenv
# @cmd Call the function
# @arg func![`_choice_func`] The function name
# @arg args~[?`_choice_func_args`] The function args
call() {
"./bin/$argc_func" "${argc_args[@]}"
}
# @cmd Build declarations for specific functions
# @option --output=functions.json <FILE> Specify a file path to save the function declarations
# @option --names-file=functions.txt Specify a file containing function names
# @arg funcs*[`_choice_func`] The function names
build-declarations() {
if [[ "${#argc_funcs[@]}" -gt 0 ]]; then
names=("${argc_funcs[@]}" )
elif [[ -f "$argc_names_file" ]]; then
names=($(cat "$argc_names_file"))
fi
if [[ -z "$names" ]]; then
_die "error: no specific function"
fi
result=()
for name in "${names[@]}"; do
result+=("$(build-func-declaration "$name")")
done
echo "["$(IFS=,; echo "${result[*]}")"]" | jq '.' > "$argc_output"
}
# @cmd
# @arg func![`_choice_func`] The function name
build-func-declaration() {
argc --argc-export bin/$1 | \
jq -r '
def parse_description(flag_option):
if flag_option.describe == "" then
{}
else
{ "description": flag_option.describe }
end;
def parse_enum(flag_option):
if flag_option.choice.type == "Values" then
{ "enum": flag_option.choice.data }
else
{}
end;
def parse_property(flag_option):
[
{ condition: (flag_option.flag == true), result: { type: "boolean" } },
{ condition: (flag_option.multiple_occurs == true), result: { type: "array", items: { type: "string" } } },
{ condition: (flag_option.notations[0] == "INT"), result: { type: "integer" } },
{ condition: (flag_option.notations[0] == "NUM"), result: { type: "number" } },
{ condition: true, result: { type: "string" } } ]
| map(select(.condition) | .result) | first
| (. + parse_description(flag_option))
| (. + parse_enum(flag_option))
;
def parse_parameter(flag_options):
{
type: "object",
properties: (reduce flag_options[] as $item ({}; . + { ($item.id | sub("-"; "_"; "g")): parse_property($item) })),
required: [flag_options[] | select(.required == true) | .id],
};
{
name: (.name | sub("-"; "_"; "g")),
description: .describe,
parameters: parse_parameter([.flag_options[] | select(.id != "help" and .id != "version")])
}'
}
_choice_func() {
ls -1 bin
}
_choice_func_args() {
args=( "${argc__positionals[@]}" )
argc --argc-compgen generic "bin/${args[0]}" "${args[@]}"
}
_die() {
echo "$*"
exit 1
}
# See more details at https://github.com/sigoden/argc
eval "$(argc --argc-eval "$0" "$@")"
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) sigoden
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+81
View File
@@ -0,0 +1,81 @@
# LLM Functions: Extend LLM with functions written in Bash.
This project allows you to enhance large language models (LLMs) with custom functions written in Bash. Imagine your LLM being able to execute system commands, access web APIs, or perform other complex tasks all triggered by simple, natural language prompts.
## Prerequisites
Make sure you have the following tools installed:
- [argc](https://github.com/sigoden/argc): A bash command-line framewrok and command runner
- [jq](https://github.com/jqlang/jq): A JSON processor
- [curl](https://curl.se): A command-line tool for transferring data with URLs
## Getting Started with AIChat
**1. Clone the repository:**
```sh
git clone https://github.com/sigoden/llm-functions
```
**2. Build function declarations:**
Before using the functions, you need to generate a `./functions.json` file that describes the available functions for the LLM.
```sh
argc build-declarations <function_names>...
```
Replace `<function_names>...` with the actual names of your functions. Go to the [./bin](https://github.com/sigoden/llm-functions/tree/main/bin) directory for valid function names.
> 💡 You can also create a `./functions.txt` file with each function name on a new line, Once done, simply run `argc build-declarations` without specifying the function names to automatically use the ones listed in.
**3. Configure your aichat application:**
Symlink this repo directory to aichat **functions_dir**:
```sh
ln -s "$(pwd)" "$(aichat --info | grep functions_dir | awk '{print $2}')"
```
Then, add the following settings to your AIChat configuration file:
```yaml
function_calling: true
```
AIChat will automatically load `functions.json` and execute functions located in the `./bin` directory based on your prompts.
**4. Start using your functions:**
Now you can interact with your LLM using natural language prompts that trigger your defined functions. For example:
```
$ aichat -r "%function%" What's the weather in London?
Call Function: get_current_weather --location=London
London: ☀️ 🌡️+18°C 🌬↑4.7m/s
```
## Writing Your Own Functions
Create a new Bash script in the `./bin` directory with the name of your function (e.g., `get-current-weather`). Use the following structure within the script:
```sh
# @describe Get the current weather in a given location.
# @env TOMORROW_API_KEY! The tomorrow.io api key
# @option --location! The city and state, e.g. San Francisco, CA
main() {
curl "https://wttr.in/$(echo "$argc_location" | sed 's/ /+/g')?format=4&M"
}
eval "$(argc --argc-eval "$0" "$@")"
```
After creating your function, don't forget to rebuild the function declarations (step 2) to include it in your LLM's capabilities.
## License
The project is under the MIT License, Refer to the [LICENSE](https://github.com/sigoden/llm-functions/blob/main/LICENSE) file for detailed information.
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -e
# @describe Use this function to search DuckDuckGo for a query.
# @meta require-tools ddgr
# @option --query! The query to search for.
# @option --max-results=5 The number of returned results.
main() {
ddgr --num $argc_max_results --json "$argc_query" | \
jq -r '.[] | "**[\(.title)](\(.url))**\n\(.abstract)\n"'
}
eval "$(argc --argc-eval "$0" "$@")"
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
# @describe Executes a shell command and returns the output.
# @option --shell-command~ "Shell command to execute, such as `ls -la`"
main() {
eval $argc_shell_command
}
eval "$(argc --argc-eval "$0" "$@")"
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
# @describe Get the current weather in a given location.
# @option --location! The city and state, e.g. San Francisco, CA
main() {
curl "https://wttr.in/$(echo "$argc_location" | sed 's/ /+/g')?format=4&M"
}
eval "$(argc --argc-eval "$0" "$@")"