Skip to content

Commit 64e5fdf

Browse files
committed
Create doc-helper.py
1 parent 90ebeae commit 64e5fdf

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

.github/scripts/doc-helper.py

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import os
2+
from typing import List, Dict, Tuple
3+
from pathlib import Path
4+
import anthropic
5+
from git import Repo
6+
from datetime import datetime, timedelta
7+
8+
class DocHelperAgent:
9+
def __init__(self, api_key: str):
10+
self.client = anthropic.Client(api_key=api_key)
11+
self.repo = Repo('.')
12+
self.changed_files = self._get_changed_files()
13+
self.commit_history = {}
14+
self._analyze_commit_history()
15+
16+
def _analyze_commit_history(self, days: int = 30):
17+
"""Analyze commit history to understand file importance."""
18+
since = datetime.now() - timedelta(days=days)
19+
commits = list(self.repo.iter_commits(since=since))
20+
21+
for commit in commits:
22+
for file in commit.stats.files:
23+
if file.endswith('.py'):
24+
self.commit_history[file] = self.commit_history.get(file, 0) + 1
25+
26+
def _get_file_importance_score(self, file_path: str) -> float:
27+
"""Calculate importance score for a file based on various factors."""
28+
score = 0.0
29+
30+
# Factor 1: Recent commit frequency (0-5 points)
31+
commit_count = self.commit_history.get(file_path, 0)
32+
score += min(commit_count / 2, 5) # Cap at 5 points
33+
34+
# Factor 2: File size and complexity (0-3 points)
35+
with open(file_path, 'r') as f:
36+
content = f.read()
37+
lines = content.split('\n')
38+
score += min(len(lines) / 100, 3) # Larger files score higher, cap at 3
39+
40+
# Factor 3: Import statements (0-2 points)
41+
import_count = sum(1 for line in lines if line.strip().startswith('import') or line.strip().startswith('from'))
42+
score += min(import_count / 5, 2) # More imports suggest more complexity
43+
44+
return score
45+
46+
def analyze_code_importance(self, code: str) -> Dict[str, float]:
47+
"""Have Claude analyze code importance based on various factors."""
48+
prompt = f"""Analyze this Python code and score each function based on these factors:
49+
1. Complexity (0-5): Number of operations, loops, conditions
50+
2. Impact (0-5): How much other code depends on this function
51+
3. Clarity Need (0-5): How much documentation would help understanding
52+
53+
Return scores in this format:
54+
FUNCTION: name
55+
COMPLEXITY: score
56+
IMPACT: score
57+
CLARITY: score
58+
59+
Code to analyze:
60+
61+
{code}"""
62+
63+
message = self.client.messages.create(
64+
model="claude-3-sonnet-20240229",
65+
max_tokens=1000,
66+
temperature=0.2,
67+
messages=[{"role": "user", "content": prompt}]
68+
)
69+
70+
scores = {}
71+
current_func = None
72+
current_scores = {}
73+
74+
for line in message.content.split('\n'):
75+
if line.startswith('FUNCTION:'):
76+
if current_func:
77+
scores[current_func] = sum(current_scores.values()) / 15 # Normalize to 0-1
78+
current_func = line.replace('FUNCTION:', '').strip()
79+
current_scores = {}
80+
elif line.startswith(('COMPLEXITY:', 'IMPACT:', 'CLARITY:')):
81+
key, value = line.split(':')
82+
current_scores[key.lower()] = float(value.strip())
83+
84+
if current_func:
85+
scores[current_func] = sum(current_scores.values()) / 15
86+
87+
return scores
88+
89+
def make_documentation_decisions(self, file_path: str, code: str) -> List[Dict]:
90+
"""Decide which functions need documentation and in what order."""
91+
# Get file-level importance
92+
file_importance = self._get_file_importance_score(file_path)
93+
94+
# Get function-level importance
95+
function_scores = self.analyze_code_importance(code)
96+
97+
# Combine scores and make decisions
98+
decisions = []
99+
for func_name, func_score in function_scores.items():
100+
combined_score = (file_importance + func_score * 10) / 2
101+
102+
if combined_score >= 3.5: # High priority
103+
priority = "high"
104+
doc_style = "comprehensive"
105+
elif combined_score >= 2: # Medium priority
106+
priority = "medium"
107+
doc_style = "standard"
108+
else: # Low priority
109+
priority = "low"
110+
doc_style = "basic"
111+
112+
decisions.append({
113+
"function": func_name,
114+
"priority": priority,
115+
"doc_style": doc_style,
116+
"score": combined_score
117+
})
118+
119+
# Sort by score
120+
decisions.sort(key=lambda x: x['score'], reverse=True)
121+
return decisions
122+
123+
def analyze_and_update_file(self, file_path: str) -> None:
124+
"""Analyze file and make documentation decisions."""
125+
with open(file_path, 'r') as file:
126+
content = file.read()
127+
128+
# Make decisions about what to document
129+
decisions = self.make_documentation_decisions(file_path, content)
130+
131+
# Only proceed with high and medium priority functions
132+
functions_to_document = [d for d in decisions if d['priority'] in ['high', 'medium']]
133+
134+
if not functions_to_document:
135+
print(f"No high/medium priority documentation needed for {file_path}")
136+
return
137+
138+
# Generate documentation based on decisions
139+
prompt = (
140+
f"""For the following Python code, generate documentation for these functions:
141+
{', '.join(d['function'] for d in functions_to_document)}
142+
143+
For each function, provide:
144+
1. The function name
145+
2. Line number where documentation should be inserted
146+
3. A {' and '.join(f"{d['doc_style']}" for d in functions_to_document)} Google-style docstring
147+
148+
Return in this format:
149+
FUNCTION: function_name
150+
LINE: line_number
151+
DOCSTRING:
152+
'''your docstring here'''
153+
154+
Here's the code:
155+
156+
{content}"""
157+
)
158+
159+
message = self.client.messages.create(
160+
model="claude-3-sonnet-20240229",
161+
max_tokens=2000,
162+
temperature=0.3,
163+
messages=[{"role": "user", "content": prompt}]
164+
)
165+
166+
updates = self._parse_claude_response(message.content)
167+
if updates:
168+
self._apply_updates(file_path, updates)
169+
170+
# ... (rest of the class methods remain the same)

0 commit comments

Comments
 (0)