git-aicommit-message 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- git_aicommit_message-0.1.0/PKG-INFO +82 -0
- git_aicommit_message-0.1.0/README.md +72 -0
- git_aicommit_message-0.1.0/git_aicommit_message.egg-info/PKG-INFO +82 -0
- git_aicommit_message-0.1.0/git_aicommit_message.egg-info/SOURCES.txt +14 -0
- git_aicommit_message-0.1.0/git_aicommit_message.egg-info/dependency_links.txt +1 -0
- git_aicommit_message-0.1.0/git_aicommit_message.egg-info/entry_points.txt +2 -0
- git_aicommit_message-0.1.0/git_aicommit_message.egg-info/requires.txt +1 -0
- git_aicommit_message-0.1.0/git_aicommit_message.egg-info/top_level.txt +1 -0
- git_aicommit_message-0.1.0/pyproject.toml +24 -0
- git_aicommit_message-0.1.0/setup.cfg +4 -0
- git_aicommit_message-0.1.0/src/__init__.py +0 -0
- git_aicommit_message-0.1.0/src/editor.py +40 -0
- git_aicommit_message-0.1.0/src/git.py +44 -0
- git_aicommit_message-0.1.0/src/heuristic.py +27 -0
- git_aicommit_message-0.1.0/src/main.py +64 -0
- git_aicommit_message-0.1.0/src/ollama.py +81 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: git-aicommit-message
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AI-powered git commit message generator using Ollama
|
|
5
|
+
Author: TRAORE Timothée Rachid
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: requests>=2.28.0
|
|
10
|
+
|
|
11
|
+
# git-ai-commit
|
|
12
|
+
|
|
13
|
+
> Generate smart commit messages using AI — powered by Ollama (local, private).
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- Python 3.8+
|
|
18
|
+
- Ollama installed and running
|
|
19
|
+
|
|
20
|
+
## Install everything in one command
|
|
21
|
+
```bash
|
|
22
|
+
curl -fsSL https://raw.githubusercontent.com/rachid-traore/git-ai-commit/main/install.sh | sh
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This script will automatically install Ollama, pull the `mistral` model, and install `git-ai-commit`.
|
|
26
|
+
|
|
27
|
+
## Manual installation
|
|
28
|
+
|
|
29
|
+
**1. Install Ollama**
|
|
30
|
+
|
|
31
|
+
| OS | Command |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Mac | `brew install ollama` |
|
|
34
|
+
| Linux | `curl -fsSL https://ollama.com/install.sh \| sh` |
|
|
35
|
+
| Windows | [ollama.com/download](https://ollama.com/download) |
|
|
36
|
+
|
|
37
|
+
**2. Start Ollama and pull the model**
|
|
38
|
+
```bash
|
|
39
|
+
ollama serve &
|
|
40
|
+
ollama pull mistral
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**3. Install git-ai-commit**
|
|
44
|
+
```bash
|
|
45
|
+
pip install git-ai-commit
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
```bash
|
|
50
|
+
# Stage your changes
|
|
51
|
+
git add .
|
|
52
|
+
|
|
53
|
+
# Generate and commit
|
|
54
|
+
git ai-commit
|
|
55
|
+
|
|
56
|
+
# Open message in $EDITOR before committing
|
|
57
|
+
git ai-commit --edit
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Example output
|
|
61
|
+
```
|
|
62
|
+
🤖 Analyse du diff en cours...
|
|
63
|
+
→ feat: add user authentication via JWT
|
|
64
|
+
|
|
65
|
+
[Y] Valider [e] Éditer [n] Annuler :
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## How it works
|
|
69
|
+
|
|
70
|
+
1. Reads your staged diff (`git diff --cached`)
|
|
71
|
+
2. Detects commit type instantly via heuristics (`feat`, `fix`, `chore`...)
|
|
72
|
+
3. Sends diff to local Ollama (`mistral` model)
|
|
73
|
+
4. Proposes a [Conventional Commits](https://www.conventionalcommits.org) message
|
|
74
|
+
5. You validate, edit, or cancel
|
|
75
|
+
|
|
76
|
+
## Privacy
|
|
77
|
+
|
|
78
|
+
Your code never leaves your machine. Ollama runs 100% locally.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# git-ai-commit
|
|
2
|
+
|
|
3
|
+
> Generate smart commit messages using AI — powered by Ollama (local, private).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Python 3.8+
|
|
8
|
+
- Ollama installed and running
|
|
9
|
+
|
|
10
|
+
## Install everything in one command
|
|
11
|
+
```bash
|
|
12
|
+
curl -fsSL https://raw.githubusercontent.com/rachid-traore/git-ai-commit/main/install.sh | sh
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This script will automatically install Ollama, pull the `mistral` model, and install `git-ai-commit`.
|
|
16
|
+
|
|
17
|
+
## Manual installation
|
|
18
|
+
|
|
19
|
+
**1. Install Ollama**
|
|
20
|
+
|
|
21
|
+
| OS | Command |
|
|
22
|
+
|---|---|
|
|
23
|
+
| Mac | `brew install ollama` |
|
|
24
|
+
| Linux | `curl -fsSL https://ollama.com/install.sh \| sh` |
|
|
25
|
+
| Windows | [ollama.com/download](https://ollama.com/download) |
|
|
26
|
+
|
|
27
|
+
**2. Start Ollama and pull the model**
|
|
28
|
+
```bash
|
|
29
|
+
ollama serve &
|
|
30
|
+
ollama pull mistral
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**3. Install git-ai-commit**
|
|
34
|
+
```bash
|
|
35
|
+
pip install git-ai-commit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
```bash
|
|
40
|
+
# Stage your changes
|
|
41
|
+
git add .
|
|
42
|
+
|
|
43
|
+
# Generate and commit
|
|
44
|
+
git ai-commit
|
|
45
|
+
|
|
46
|
+
# Open message in $EDITOR before committing
|
|
47
|
+
git ai-commit --edit
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Example output
|
|
51
|
+
```
|
|
52
|
+
🤖 Analyse du diff en cours...
|
|
53
|
+
→ feat: add user authentication via JWT
|
|
54
|
+
|
|
55
|
+
[Y] Valider [e] Éditer [n] Annuler :
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## How it works
|
|
59
|
+
|
|
60
|
+
1. Reads your staged diff (`git diff --cached`)
|
|
61
|
+
2. Detects commit type instantly via heuristics (`feat`, `fix`, `chore`...)
|
|
62
|
+
3. Sends diff to local Ollama (`mistral` model)
|
|
63
|
+
4. Proposes a [Conventional Commits](https://www.conventionalcommits.org) message
|
|
64
|
+
5. You validate, edit, or cancel
|
|
65
|
+
|
|
66
|
+
## Privacy
|
|
67
|
+
|
|
68
|
+
Your code never leaves your machine. Ollama runs 100% locally.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
MIT
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: git-aicommit-message
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AI-powered git commit message generator using Ollama
|
|
5
|
+
Author: TRAORE Timothée Rachid
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: requests>=2.28.0
|
|
10
|
+
|
|
11
|
+
# git-ai-commit
|
|
12
|
+
|
|
13
|
+
> Generate smart commit messages using AI — powered by Ollama (local, private).
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- Python 3.8+
|
|
18
|
+
- Ollama installed and running
|
|
19
|
+
|
|
20
|
+
## Install everything in one command
|
|
21
|
+
```bash
|
|
22
|
+
curl -fsSL https://raw.githubusercontent.com/rachid-traore/git-ai-commit/main/install.sh | sh
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This script will automatically install Ollama, pull the `mistral` model, and install `git-ai-commit`.
|
|
26
|
+
|
|
27
|
+
## Manual installation
|
|
28
|
+
|
|
29
|
+
**1. Install Ollama**
|
|
30
|
+
|
|
31
|
+
| OS | Command |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Mac | `brew install ollama` |
|
|
34
|
+
| Linux | `curl -fsSL https://ollama.com/install.sh \| sh` |
|
|
35
|
+
| Windows | [ollama.com/download](https://ollama.com/download) |
|
|
36
|
+
|
|
37
|
+
**2. Start Ollama and pull the model**
|
|
38
|
+
```bash
|
|
39
|
+
ollama serve &
|
|
40
|
+
ollama pull mistral
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**3. Install git-ai-commit**
|
|
44
|
+
```bash
|
|
45
|
+
pip install git-ai-commit
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
```bash
|
|
50
|
+
# Stage your changes
|
|
51
|
+
git add .
|
|
52
|
+
|
|
53
|
+
# Generate and commit
|
|
54
|
+
git ai-commit
|
|
55
|
+
|
|
56
|
+
# Open message in $EDITOR before committing
|
|
57
|
+
git ai-commit --edit
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Example output
|
|
61
|
+
```
|
|
62
|
+
🤖 Analyse du diff en cours...
|
|
63
|
+
→ feat: add user authentication via JWT
|
|
64
|
+
|
|
65
|
+
[Y] Valider [e] Éditer [n] Annuler :
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## How it works
|
|
69
|
+
|
|
70
|
+
1. Reads your staged diff (`git diff --cached`)
|
|
71
|
+
2. Detects commit type instantly via heuristics (`feat`, `fix`, `chore`...)
|
|
72
|
+
3. Sends diff to local Ollama (`mistral` model)
|
|
73
|
+
4. Proposes a [Conventional Commits](https://www.conventionalcommits.org) message
|
|
74
|
+
5. You validate, edit, or cancel
|
|
75
|
+
|
|
76
|
+
## Privacy
|
|
77
|
+
|
|
78
|
+
Your code never leaves your machine. Ollama runs 100% locally.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
git_aicommit_message.egg-info/PKG-INFO
|
|
4
|
+
git_aicommit_message.egg-info/SOURCES.txt
|
|
5
|
+
git_aicommit_message.egg-info/dependency_links.txt
|
|
6
|
+
git_aicommit_message.egg-info/entry_points.txt
|
|
7
|
+
git_aicommit_message.egg-info/requires.txt
|
|
8
|
+
git_aicommit_message.egg-info/top_level.txt
|
|
9
|
+
src/__init__.py
|
|
10
|
+
src/editor.py
|
|
11
|
+
src/git.py
|
|
12
|
+
src/heuristic.py
|
|
13
|
+
src/main.py
|
|
14
|
+
src/ollama.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.28.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
src
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "git-aicommit-message"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "AI-powered git commit message generator using Ollama"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "TRAORE Timothée Rachid"}
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"requests>=2.28.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
git-aicommit-message = "src.main:main"
|
|
21
|
+
|
|
22
|
+
[tool.setuptools.packages.find]
|
|
23
|
+
where = ["."]
|
|
24
|
+
include = ["src*"]
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import tempfile
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
def open_in_editor(message: str) -> str:
|
|
7
|
+
"""
|
|
8
|
+
Ouvre le message dans $EDITOR pour que l'utilisateur puisse le modifier.
|
|
9
|
+
Retourne le message modifié.
|
|
10
|
+
"""
|
|
11
|
+
editor = os.environ.get("EDITOR", _default_editor())
|
|
12
|
+
# Écrit le message dans un fichier temporaire
|
|
13
|
+
with tempfile.NamedTemporaryFile(
|
|
14
|
+
mode="w", suffix=".txt", delete=False, prefix="git_ai_commit_"
|
|
15
|
+
) as f:
|
|
16
|
+
f.write(message)
|
|
17
|
+
f.write("\n\n# Modifie le message ci-dessus puis sauvegarde et ferme l'éditeur.")
|
|
18
|
+
f.write("\n# Les lignes commençant par # sont ignorées.")
|
|
19
|
+
tmp_path = f.name
|
|
20
|
+
try:
|
|
21
|
+
subprocess.call([editor, tmp_path])
|
|
22
|
+
with open(tmp_path, "r") as f:
|
|
23
|
+
lines = f.readlines()
|
|
24
|
+
# Ignore les commentaires et lignes vides
|
|
25
|
+
edited = "".join(
|
|
26
|
+
line for line in lines
|
|
27
|
+
if not line.startswith("#")
|
|
28
|
+
).strip()
|
|
29
|
+
if not edited:
|
|
30
|
+
print("❌ Message vide, commit annulé.")
|
|
31
|
+
sys.exit(0)
|
|
32
|
+
return edited
|
|
33
|
+
finally:
|
|
34
|
+
os.unlink(tmp_path)
|
|
35
|
+
|
|
36
|
+
def _default_editor():
|
|
37
|
+
"""Retourne un éditeur par défaut selon l'OS."""
|
|
38
|
+
if os.name == "nt": # Windows
|
|
39
|
+
return "notepad"
|
|
40
|
+
return "nano" # Mac / Linux
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
def check_git_repo():
|
|
5
|
+
"""Vérifie qu'on est bien dans un repo git."""
|
|
6
|
+
result = subprocess.run(
|
|
7
|
+
["git", "rev-parse", "--is-inside-work-tree"],
|
|
8
|
+
capture_output=True, text=True
|
|
9
|
+
)
|
|
10
|
+
if result.returncode != 0:
|
|
11
|
+
print("❌ Tu n'es pas dans un repo git.")
|
|
12
|
+
sys.exit(1)
|
|
13
|
+
|
|
14
|
+
def get_staged_diff():
|
|
15
|
+
"""Récupère le diff des fichiers stagés."""
|
|
16
|
+
result = subprocess.run(
|
|
17
|
+
["git", "diff", "--cached"],
|
|
18
|
+
capture_output=True, text=True
|
|
19
|
+
)
|
|
20
|
+
diff = result.stdout.strip()
|
|
21
|
+
if not diff:
|
|
22
|
+
print("❌ Aucun fichier stagé. Fais d'abord un `git add`.")
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
return diff
|
|
25
|
+
|
|
26
|
+
def get_staged_files():
|
|
27
|
+
"""Retourne la liste des fichiers stagés."""
|
|
28
|
+
result = subprocess.run(
|
|
29
|
+
["git", "diff", "--cached", "--name-only"],
|
|
30
|
+
capture_output=True, text=True
|
|
31
|
+
)
|
|
32
|
+
return result.stdout.strip().splitlines()
|
|
33
|
+
|
|
34
|
+
def do_commit(message):
|
|
35
|
+
"""Exécute le commit avec le message donné."""
|
|
36
|
+
result = subprocess.run(
|
|
37
|
+
["git", "commit", "-m", message],
|
|
38
|
+
capture_output=True, text=True
|
|
39
|
+
)
|
|
40
|
+
if result.returncode == 0:
|
|
41
|
+
print(f"✅ Commit effectué :\n {message}")
|
|
42
|
+
else:
|
|
43
|
+
print(f"❌ Erreur lors du commit :\n{result.stderr}")
|
|
44
|
+
sys.exit(1)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
# Règles : si un fichier matche → on suggère ce type
|
|
5
|
+
RULES = [
|
|
6
|
+
(["test_", "_test.", ".spec.", ".test."], "test"),
|
|
7
|
+
(["package.json", "requirements.txt", "pyproject.toml",
|
|
8
|
+
"Makefile", "Dockerfile", ".github/", ".gitignore",
|
|
9
|
+
"setup.cfg", "setup.py"], "chore"),
|
|
10
|
+
(["README", ".md", "docs/", "CHANGELOG"], "docs"),
|
|
11
|
+
(["fix", "bug", "hotfix", "patch"], "fix"),
|
|
12
|
+
(["refactor", "clean", "rename", "move"], "refactor"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
def detect_type(staged_files: List[str]) -> str:
|
|
16
|
+
"""
|
|
17
|
+
Analyse les noms de fichiers stagés et devine le type Conventional Commit.
|
|
18
|
+
Retourne 'feat' par défaut si rien ne matche.
|
|
19
|
+
"""
|
|
20
|
+
for file in staged_files:
|
|
21
|
+
filename = os.path.basename(file).lower()
|
|
22
|
+
filepath = file.lower()
|
|
23
|
+
for patterns, commit_type in RULES:
|
|
24
|
+
for pattern in patterns:
|
|
25
|
+
if pattern.lower() in filename or pattern.lower() in filepath:
|
|
26
|
+
return commit_type
|
|
27
|
+
return "feat" # fallback par défaut
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import argparse
|
|
3
|
+
from src.git import check_git_repo, get_staged_diff, get_staged_files, do_commit
|
|
4
|
+
from src.heuristic import detect_type
|
|
5
|
+
from src.ollama import generate_message
|
|
6
|
+
from src.editor import open_in_editor
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
parser = argparse.ArgumentParser(
|
|
10
|
+
description="🤖 Génère un message de commit via Ollama"
|
|
11
|
+
)
|
|
12
|
+
parser.add_argument(
|
|
13
|
+
"--edit", "-e",
|
|
14
|
+
action="store_true",
|
|
15
|
+
help="Ouvre le message dans $EDITOR avant de committer"
|
|
16
|
+
)
|
|
17
|
+
args = parser.parse_args()
|
|
18
|
+
|
|
19
|
+
# 1. Vérifications de base
|
|
20
|
+
check_git_repo()
|
|
21
|
+
|
|
22
|
+
# 2. Récupère les infos git
|
|
23
|
+
diff = get_staged_diff()
|
|
24
|
+
staged_files = get_staged_files()
|
|
25
|
+
|
|
26
|
+
# 3. Heuristique immédiate (pendant qu'Ollama réfléchit)
|
|
27
|
+
fallback_type = detect_type(staged_files)
|
|
28
|
+
|
|
29
|
+
# 4. Génère le message via Ollama
|
|
30
|
+
print("🤖 Analyse du diff en cours...")
|
|
31
|
+
message = generate_message(diff, fallback_type)
|
|
32
|
+
|
|
33
|
+
# 5. Si Ollama a échoué → on construit un message minimal avec l'heuristique
|
|
34
|
+
if not message:
|
|
35
|
+
staged_names = ", ".join(staged_files[:3])
|
|
36
|
+
message = f"{fallback_type}: update {staged_names}"
|
|
37
|
+
print(f" Message de fallback : {message}")
|
|
38
|
+
|
|
39
|
+
# 6. Mode --edit : ouvre dans $EDITOR
|
|
40
|
+
if args.edit:
|
|
41
|
+
message = open_in_editor(message)
|
|
42
|
+
|
|
43
|
+
# 7. Affiche la proposition
|
|
44
|
+
print(f"\n→ {message}\n")
|
|
45
|
+
|
|
46
|
+
# 8. Demande confirmation
|
|
47
|
+
try:
|
|
48
|
+
choice = input("[Y] Valider [e] Éditer [n] Annuler : ").strip().lower()
|
|
49
|
+
except KeyboardInterrupt:
|
|
50
|
+
print("\n❌ Annulé.")
|
|
51
|
+
sys.exit(0)
|
|
52
|
+
|
|
53
|
+
if choice in ("", "y"):
|
|
54
|
+
do_commit(message)
|
|
55
|
+
elif choice == "e":
|
|
56
|
+
message = open_in_editor(message)
|
|
57
|
+
print(f"\n→ {message}\n")
|
|
58
|
+
confirm = input("Valider ce message ? [Y/n] : ").strip().lower()
|
|
59
|
+
if confirm in ("", "y"):
|
|
60
|
+
do_commit(message)
|
|
61
|
+
else:
|
|
62
|
+
print("❌ Commit annulé.")
|
|
63
|
+
else:
|
|
64
|
+
print("❌ Commit annulé.")
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
OLLAMA_URL = "http://localhost:11434/api/generate"
|
|
5
|
+
MODEL = "mistral"
|
|
6
|
+
MAX_DIFF_CHARS = 4000 # ~1000 tokens, suffisant pour un diff normal
|
|
7
|
+
|
|
8
|
+
PROMPT_TEMPLATE = """You are a git commit message assistant.
|
|
9
|
+
Analyze the following git diff and write a commit message.
|
|
10
|
+
|
|
11
|
+
Rules:
|
|
12
|
+
- Use Conventional Commits format: type: short description
|
|
13
|
+
- Types allowed: feat, fix, chore, docs, refactor, test, style
|
|
14
|
+
- Title only, NO body, NO bullet points
|
|
15
|
+
- Maximum 72 characters total
|
|
16
|
+
- Always write in English
|
|
17
|
+
- Be specific and concise
|
|
18
|
+
|
|
19
|
+
Git diff:
|
|
20
|
+
{diff}
|
|
21
|
+
|
|
22
|
+
Respond with ONLY the commit message, nothing else."""
|
|
23
|
+
|
|
24
|
+
def check_ollama():
|
|
25
|
+
"""Vérifie qu'Ollama est accessible."""
|
|
26
|
+
try:
|
|
27
|
+
response = requests.get("http://localhost:11434", timeout=3)
|
|
28
|
+
return True
|
|
29
|
+
except requests.exceptions.ConnectionError:
|
|
30
|
+
print("❌ Ollama n'est pas détecté sur cette machine.")
|
|
31
|
+
print("")
|
|
32
|
+
print(" Installe-le :")
|
|
33
|
+
print(" → Mac : brew install ollama")
|
|
34
|
+
print(" → Linux : curl -fsSL https://ollama.com/install.sh | sh")
|
|
35
|
+
print(" → Win : https://ollama.com/download")
|
|
36
|
+
print("")
|
|
37
|
+
print(" Puis lance :")
|
|
38
|
+
print(" → ollama serve (démarre le serveur)")
|
|
39
|
+
print(" → ollama pull mistral (télécharge le modèle)")
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
|
|
42
|
+
def truncate_diff(diff: str) -> str:
|
|
43
|
+
"""Tronque le diff si trop long, en gardant le début."""
|
|
44
|
+
if len(diff) <= MAX_DIFF_CHARS:
|
|
45
|
+
return diff
|
|
46
|
+
truncated = diff[:MAX_DIFF_CHARS]
|
|
47
|
+
return truncated + "\n\n[... diff tronqué pour respecter la fenêtre de contexte ...]"
|
|
48
|
+
|
|
49
|
+
def generate_message(diff: str, fallback_type: str) -> str:
|
|
50
|
+
"""Envoie le diff à Ollama et retourne le message généré."""
|
|
51
|
+
check_ollama()
|
|
52
|
+
diff = truncate_diff(diff)
|
|
53
|
+
prompt = PROMPT_TEMPLATE.format(diff=diff)
|
|
54
|
+
try:
|
|
55
|
+
response = requests.post(
|
|
56
|
+
OLLAMA_URL,
|
|
57
|
+
json={"model": MODEL, "prompt": prompt, "stream": False},
|
|
58
|
+
timeout=30
|
|
59
|
+
)
|
|
60
|
+
response.raise_for_status()
|
|
61
|
+
message = response.json().get("response", "").strip()
|
|
62
|
+
# Nettoyage : enlève les guillemets si l'IA en met
|
|
63
|
+
message = message.strip('"').strip("'")
|
|
64
|
+
# Vérifie que le message a un type Conventional Commit
|
|
65
|
+
# Sinon on préfixe avec le fallback heuristique
|
|
66
|
+
known_types = ["feat", "fix", "chore", "docs", "refactor", "test", "style"]
|
|
67
|
+
has_type = any(message.startswith(f"{t}:") or
|
|
68
|
+
message.startswith(f"{t}(") for t in known_types)
|
|
69
|
+
if not has_type:
|
|
70
|
+
message = f"{fallback_type}: {message}"
|
|
71
|
+
# Tronque si > 72 caractères
|
|
72
|
+
if len(message) > 72:
|
|
73
|
+
message = message[:72]
|
|
74
|
+
return message
|
|
75
|
+
except requests.exceptions.Timeout:
|
|
76
|
+
print("⚠️ Ollama a mis trop de temps à répondre.")
|
|
77
|
+
print(f" Utilisation de l'heuristique : type détecté = '{fallback_type}'")
|
|
78
|
+
return None
|
|
79
|
+
except Exception as e:
|
|
80
|
+
print(f"❌ Erreur Ollama : {e}")
|
|
81
|
+
return None
|