Skip to content

Instantly share code, notes, and snippets.

@antoinejeannot
Last active December 15, 2023 09:53
Show Gist options
  • Save antoinejeannot/efaa44a9de5b10024eac993034ce3a62 to your computer and use it in GitHub Desktop.
Save antoinejeannot/efaa44a9de5b10024eac993034ce3a62 to your computer and use it in GitHub Desktop.
Minimalist & Easy-to-hack LLM-powered git message
#!/bin/bash
###########################################################################
# Automatically generates a git commit message based on `git diff` and a LLM
# Minimalist & Easy-to-hack implementation:
# . It relies on git hooks
# . it requires `jq` (brew install jq) for json management
#
# . Usage: prefix your git commit message by "auto"
# .. git commit -m "auto"
# .. [refact-cleaner 920c1da8]: refactor: remove import of "collections" and "itertools" from cleaner.py
#
# . Setup: replace / adapt your [PROJECT]/.git/hooks/prepare-commit-msg with this file
# .. By default, it targets OpenAI's API and uses the gpt-3.5-turbo model
# .. You need to install `jq` if not already installed: `brew install jq`
#
# . PARAMETERS:
# .. GIT_LLM_API env variable: API following the standard /chat/generations API interface, defaults to OpenAI
# .. GIT_LLM_MODEL env variable: Model name to leverage, defaults to gpt-3.5-turbo
#
# Feel free to hack it ! There is certainly a ton of improvements to be made :)
#
# Author: Antoine Jeannot
# GitHub: https://github.com/antoinejeannot
# License: MIT License
###########################################################################
# Get the current commit message
if [ "$2" = "merge" ] || [ "$2" = "commit" ]; then
exit
fi
commit_msg_file="$1"
commit_msg=$(cat "$commit_msg_file")
if [[ $commit_msg == "auto"* ]]; then
llm_api="${GIT_LLM_API:-https://api.openai.com/v1/chat/completions}"
llm_model="${GIT_LLM_MODEL:-gpt-3.5-turbo}"
# Prepend the prefix to the commit message
# Replace the system and user messages as needed
system_message='You are the best git assistant whose aim is to generate a git commit message.
IT MUST BE written in English, be concise, be lowercase, relevant and straight to the point.
IT MUST FOLLOW conventional commits specifications and the following template:
<type>[optional scope]: <short description>
[optional body]
Where <type> MUST BE ONE OF: fix, feat, build, chore, ci, docs, style, refactor, perf, test
Where <type> MUST NOT BE: add, update, delete etc.
A commit that has a footer BREAKING CHANGE:, or appends a ! after the type, introduces a breaking API change.
DO NOT ADD UNDER ANY CIRCUMSTANCES: explanation about the commit, details such as file, changes, hash or the conventional commits specs.
Here is the git diff:
'
# Correctly capture system message in JSON format
system_message=$(jq -sR . <<< "$system_message")
# Capture git diff output
git_diff=$(git diff --cached $file --unified=0 --minimal)
# Convert git_diff to JSON format
git_diff=$(jq -sR . <<< "$git_diff")
# Create JSON payload
json_data=$(jq -n \
--arg system_message "$system_message" \
--arg git_diff "$git_diff" \
--arg llm_model "$llm_model" \
'{
"model": $llm_model,
"messages": [
{
"role": "system",
"content": $system_message
},
{
"role": "user",
"content": $git_diff
}
]
}'
)
# Make the API call and store the result in $commit_msg
result=$(curl -s "$llm_api" -H "Content-Type: application/json" -H "Authorization: Bearer ${OPENAI_API_KEY}" -d "$json_data")
commit_msg=$(echo "$result" | jq -r '.choices[0].message.content')
total_tokens=$(echo "$result" | jq '.usage.total_tokens')
echo "LLM API - Total tokens used: $total_tokens"
fi
echo -e "$commit_msg" > "$commit_msg_file"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment