CodeCommunity commited on
Commit
a5ac098
·
verified ·
1 Parent(s): 7ac49fd

Create convention_service.py

Browse files
Files changed (1) hide show
  1. app/services/convention_service.py +108 -0
app/services/convention_service.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import re
3
+ import json
4
+ from typing import Dict, Any, Optional
5
+ import httpx
6
+ from app.core.model_loader import llm_engine
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class ConventionService:
11
+ def __init__(self):
12
+ self.cache: Dict[str, Dict[str, Any]] = {}
13
+
14
+ async def get_conventions(self, owner: str, repo: str) -> Dict[str, Any]:
15
+ key = f"{owner}/{repo}"
16
+ if key in self.cache:
17
+ return self.cache[key]
18
+
19
+ # 1. Fetch recent commits from GitHub
20
+ commits = await self._fetch_recent_commits(owner, repo, limit=40)
21
+ if not commits:
22
+ return self._default_conventions()
23
+
24
+ commit_text = "\n".join([c.get("message", "")[:200] for c in commits[:30]])
25
+
26
+ # 2. Ask the LLM to infer conventions
27
+ prompt = f"""Analyze these recent commit messages and return ONLY a valid JSON object with these keys:
28
+ - "commit_style": either "conventional_commits" or "plain"
29
+ - "branch_naming_pattern": a short regex or example pattern (e.g. "feat/.*", "feature/*")
30
+ - "merge_policy": "squash", "merge", "rebase" or "unknown"
31
+ - "exampleGoodCommit": one good example from the history
32
+
33
+ Commit history:
34
+ {commit_text}
35
+ """
36
+
37
+ try:
38
+ raw = llm_engine.generate(prompt, max_tokens=250)
39
+ conventions = self._parse_json(raw)
40
+ except Exception as e:
41
+ logger.warning(f"LLM convention inference failed: {e}")
42
+ conventions = self._default_conventions()
43
+
44
+ # Enrich
45
+ if commits:
46
+ conventions["exampleGoodCommit"] = commits[0].get("message", "")[:120]
47
+ conventions.setdefault("commit_style", "plain")
48
+ conventions.setdefault("branch_naming_pattern", "feature/*")
49
+ conventions.setdefault("merge_policy", "unknown")
50
+
51
+ self.cache[key] = conventions
52
+ return conventions
53
+
54
+ async def _fetch_recent_commits(self, owner: str, repo: str, limit: int = 30) -> list:
55
+ url = f"https://api.github.com/repos/{owner}/{repo}/commits"
56
+ params = {"per_page": min(limit, 100)}
57
+ headers = {"Accept": "application/vnd.github.v3+json"}
58
+
59
+ # Optional: add a GitHub token if you have one in env for higher rate limits
60
+ token = None # os.getenv("GITHUB_TOKEN")
61
+ if token:
62
+ headers["Authorization"] = f"token {token}"
63
+
64
+ try:
65
+ async with httpx.AsyncClient(timeout=15.0) as client:
66
+ resp = await client.get(url, params=params, headers=headers)
67
+ if resp.status_code != 200:
68
+ logger.warning(f"GitHub commits API {resp.status_code}")
69
+ return []
70
+ data = resp.json()
71
+ return [
72
+ {
73
+ "message": c.get("commit", {}).get("message", ""),
74
+ "sha": c.get("sha", ""),
75
+ "author": c.get("commit", {}).get("author", {}).get("name", ""),
76
+ }
77
+ for c in data
78
+ ]
79
+ except Exception as e:
80
+ logger.error(f"Failed to fetch commits: {e}")
81
+ return []
82
+
83
+ def _parse_json(self, text: str) -> dict:
84
+ text = text.strip()
85
+ text = re.sub(r"```(?:json)?", "", text, flags=re.IGNORECASE).strip()
86
+ try:
87
+ return json.loads(text)
88
+ except json.JSONDecodeError:
89
+ start = text.find("{")
90
+ end = text.rfind("}")
91
+ if start != -1 and end > start:
92
+ try:
93
+ return json.loads(text[start : end + 1])
94
+ except Exception:
95
+ pass
96
+ return self._default_conventions()
97
+
98
+ def _default_conventions(self) -> dict:
99
+ return {
100
+ "commit_style": "plain",
101
+ "branch_naming_pattern": "feature/*",
102
+ "merge_policy": "unknown",
103
+ "exampleGoodCommit": "Update something",
104
+ }
105
+
106
+
107
+ # Singleton-style instance
108
+ convention_service = ConventionService()