Skip to content

Instantly share code, notes, and snippets.

@xpepper
Last active April 30, 2024 19:44
Show Gist options
  • Save xpepper/6c194e87183550f54affef78acc8f638 to your computer and use it in GitHub Desktop.
Save xpepper/6c194e87183550f54affef78acc8f638 to your computer and use it in GitHub Desktop.
An AI-driven git commit message generator. It needs a valid OpenAI key set as an env variable`OPENAI_API_KEY`. It works on macOS, needs curl and jq in order to work.
#!/bin/bash
OPENAI_API_KEY="${OPENAI_API_KEY}"
HOST="https://api.openai.com"
MODEL="gpt-3.5-turbo"
# Check if the API key is set
if [ -z "$OPENAI_API_KEY" ]; then
echo "OpenAI API key is not set. Please set the OPENAI_API_KEY environment variable."
exit 1
fi
# Get the diff of staged changes
DIFF=$(git diff --staged)
# Check if there are any staged changes
if [ -z "$DIFF" ]; then
echo "No changes are staged for commit."
exit 1
fi
# Escape special JSON characters in the diff output
# This uses Perl instead of sed for better cross-platform compatibility
ESCAPED_DIFF=$(echo "content: $DIFF" | perl -pe 's/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g; s/\r//g;')
# Prepare the data for the API request
read -r -d '' DATA <<EOF
{
"model": "$MODEL",
"messages": [
{"role": "system", "content": "You are a git message commit generator. You get a set of file changes and you generate a proper git commit message, following the Conventional Commits standard. Don't add any other info if not related to the changes themselves."},
{"role": "user", "content": "$ESCAPED_DIFF"}
],
"max_tokens": 250,
"temperature": 0.3
}
EOF
# Make the API request to OpenAI using the chat completions endpoint
RESPONSE=$(curl -s "$HOST/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d "$DATA")
# Extract the commit message from the response
COMMIT_MESSAGE=$(echo $RESPONSE | jq -r '.choices[0].message.content')
# Output the commit message
echo "Here's a commit message based on the diff:"
echo "$COMMIT_MESSAGE"
@xpepper
Copy link
Author

xpepper commented Apr 29, 2024

A Python version:

import subprocess
import json
import os
import requests

def get_git_diff():
    """Get the staged git diff."""
    return subprocess.run(['git', 'diff', '--staged'], stdout=subprocess.PIPE).stdout.decode('utf-8')

def escape_diff(diff):
    """Escape special JSON characters in the git diff."""
    return diff.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')

def generate_commit_message(diff):
    """Generate a commit message using OpenAI's API."""
    api_key = os.getenv('OPENAI_API_KEY')
    if not api_key:
        print("OpenAI API key is not set. Please set the OPENAI_API_KEY environment variable.")
        return

    if not diff:
        print("No changes are staged for commit.")
        return

    escaped_diff = escape_diff(diff)
    data = {
        "model": "gpt-3.5-turbo",
        "messages": [
            {"role": "system", "content": "You are a git message commit generator. You get a set of file changes and you generate a proper git commit message, following the Conventional Commits standard. Don't add any other info if not related to the changes themselves."},
            {"role": "user", "content": escaped_diff}
        ],
        "max_tokens": 250,
        "temperature": 0.3
    }

    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {api_key}'
    }

    response = requests.post('https://api.openai.com/v1/chat/completions', headers=headers, json=data)
    if response.status_code == 200:
        commit_message = response.json()['choices'][0]['message']['content']
        print("Here's a commit message based on the diff:")
        print(commit_message)
    else:
        print("Failed to generate commit message:", response.text)

if __name__ == '__main__':
    diff = get_git_diff()
    generate_commit_message(diff)

@xpepper
Copy link
Author

xpepper commented Apr 29, 2024

Another Python version using openai lib

import subprocess
import os
from openai import OpenAI

api_key = os.getenv('OPENAI_API_KEY')
if not api_key:
    print("OpenAI API key is not set. Please set the OPENAI_API_KEY environment variable.")
    exit()
model = "gpt-3.5-turbo"
# model = "llama-3-70b-instruct"

client = OpenAI(api_key=api_key, base_url="https://api.openai.com/v1")
# client = OpenAI(api_key=api_key, base_url="https://api.perplexity.ai")

def get_git_diff():
    """Get the staged git diff."""
    return subprocess.run(['git', 'diff', '--staged'], stdout=subprocess.PIPE).stdout.decode('utf-8')

def escape_diff(diff):
    """Escape special JSON characters in the git diff."""
    return diff.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')

def generate_commit_message(diff):
    if not diff:
        print("No changes are staged for commit.")
        return

    escaped_diff = escape_diff(diff)

    try:
        response = client.chat.completions.create(model=model,
        messages=[
            {"role": "system", "content": "You are a git message commit generator. You get a set of file changes and you generate a proper git commit message, following the Conventional Commits standard. Don't add any other info if not related to the changes themselves."},
            {"role": "user", "content": escaped_diff}
        ],
        max_tokens=250,
        temperature=0.3)
        commit_message = response.choices[0].message.content
        print(commit_message)
    except Exception as e:
        print("Failed to generate commit message:", str(e))

if __name__ == '__main__':
    diff = get_git_diff()
    generate_commit_message(diff)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment