#!/usr/bin/python3 import os import sys import requests import subprocess import argparse class OpenAIProvider: def __init__(self): self.api_key = os.getenv("AI_API_KEY") if not self.api_key: raise EnvironmentError("AI_API_KEY not set in environment.") self.endpoint = "https://api.openai.com/v1/chat/completions" self.model = os.getenv("OPENAI_MODEL", "gpt-4o-mini") def improve_text(self, prompt: str, text: str) -> str: headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", } body = { "model": self.model, "messages": [ {"role": "system", "content": prompt}, {"role": "user", "content": text}, ], "temperature": 0.3, } response = requests.post(self.endpoint, json=body, headers=headers, timeout=30) if response.status_code == 200: return response.json()["choices"][0]["message"]["content"].strip() raise Exception( f"OpenAI API call failed: {response.status_code} - {response.text}" ) def get_diff_from_stdin(): """Reads the diff from stdin (useful for piped input).""" return sys.stdin.read() def get_diff_from_git(): """Runs 'git diff HEAD~1' and captures the output.""" return subprocess.check_output( "GIT_PAGER=cat git diff HEAD~1", shell=True, text=True ) def main(): # Step 1: Parse command-line arguments parser = argparse.ArgumentParser(description="Generate and commit a git commit message.") parser.add_argument( "--print", action="store_true", help="Print the commit message without creating the commit" ) args = parser.parse_args() # Step 2: Get the current working directory cwd = os.getcwd() # Step 3: Get the diff diff = None if not sys.stdin.isatty(): print("Reading git diff from stdin...") diff = get_diff_from_stdin() else: print("Getting git diff from HEAD~1...") diff = get_diff_from_git() if not diff: print("No diff found, nothing to commit.") return # Step 4: Prepare the prompt for OpenAI prompt = "Take the diff and give me a good commit message, give me the commit message and nothing else" # Create an instance of OpenAIProvider openai_provider = OpenAIProvider() # Step 5: Get the commit message from OpenAI print("Generating commit message from OpenAI...") commit_message = openai_provider.improve_text(prompt, diff) if not commit_message: print("No commit message generated. Aborting commit.") return # Step 6: Handle --print argument if args.print: print(f"Commit message (not committing): {commit_message}") return # Step 7: Create the commit with the message from OpenAI print(f"Committing with message: {commit_message}") # Run git commit and suppress interactive editor result = subprocess.run( ["git", "commit", "-m", commit_message], check=True, cwd=cwd, stdin=subprocess.DEVNULL, # Prevents editor from being opened stdout=subprocess.PIPE, # Captures stdout to prevent blocking stderr=subprocess.PIPE # Captures stderr to prevent blocking ) # Print the result of the commit print(f"Commit successful! {result.stdout.decode('utf-8')}") if __name__ == "__main__": main()