Navya-Sree commited on
Commit
bfc9de1
·
verified ·
1 Parent(s): 8ca954f

Create agents/reviewer_agent.py

Browse files
Files changed (1) hide show
  1. agents/reviewer_agent.py +176 -0
agents/reviewer_agent.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import tempfile
3
+ import os
4
+ import openai
5
+ from typing import Dict, Any
6
+ from dotenv import load_dotenv
7
+
8
+ load_dotenv()
9
+
10
+ class ReviewerAgent:
11
+ """
12
+ Agent responsible for reviewing code for quality, style, and potential issues.
13
+ Uses both static analysis (pylint) and LLM-based review.
14
+ """
15
+
16
+ def __init__(self):
17
+ self.api_key = os.getenv("OPENAI_API_KEY")
18
+ openai.api_key = self.api_key
19
+
20
+ def static_analysis(self, code: str) -> Dict[str, Any]:
21
+ """
22
+ Perform static code analysis using pylint.
23
+
24
+ Args:
25
+ code: Python code to analyze
26
+
27
+ Returns:
28
+ Dictionary with pylint results
29
+ """
30
+ try:
31
+ # Create a temporary file with the code
32
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
33
+ f.write(code)
34
+ temp_file_path = f.name
35
+
36
+ # Run pylint on the temporary file
37
+ result = subprocess.run(
38
+ ['pylint', temp_file_path, '--output-format=json'],
39
+ capture_output=True,
40
+ text=True
41
+ )
42
+
43
+ # Clean up temporary file
44
+ os.unlink(temp_file_path)
45
+
46
+ # Parse pylint output
47
+ if result.returncode == 0:
48
+ # Parse JSON output
49
+ import json
50
+ try:
51
+ issues = json.loads(result.stdout)
52
+ return {
53
+ "status": "success",
54
+ "issues": issues,
55
+ "score": self._calculate_pylint_score(issues),
56
+ "summary": f"Found {len(issues)} issues"
57
+ }
58
+ except:
59
+ return {
60
+ "status": "success",
61
+ "issues": [],
62
+ "score": 10.0,
63
+ "summary": "No issues found"
64
+ }
65
+ else:
66
+ return {
67
+ "status": "error",
68
+ "error": result.stderr,
69
+ "issues": []
70
+ }
71
+
72
+ except Exception as e:
73
+ return {
74
+ "status": "error",
75
+ "error": str(e),
76
+ "issues": []
77
+ }
78
+
79
+ def _calculate_pylint_score(self, issues: list) -> float:
80
+ """Calculate a normalized score from pylint issues."""
81
+ if not issues:
82
+ return 10.0
83
+
84
+ # Count issues by type
85
+ error_count = sum(1 for issue in issues if issue.get('type') == 'error')
86
+ warning_count = sum(1 for issue in issues if issue.get('type') == 'warning')
87
+
88
+ # Simple scoring: start from 10 and deduct points
89
+ score = 10.0
90
+ score -= error_count * 0.5
91
+ score -= warning_count * 0.1
92
+
93
+ return max(0, min(10, score))
94
+
95
+ def llm_review(self, code: str) -> Dict[str, Any]:
96
+ """
97
+ Use LLM to review code for logical errors, improvements, and best practices.
98
+
99
+ Args:
100
+ code: Python code to review
101
+
102
+ Returns:
103
+ Dictionary with LLM review results
104
+ """
105
+ try:
106
+ system_message = """You are an expert code reviewer. Analyze the code for:
107
+ 1. Logical errors
108
+ 2. Security issues
109
+ 3. Performance improvements
110
+ 4. Code style and best practices
111
+ 5. Edge cases not handled
112
+
113
+ Provide specific, actionable feedback."""
114
+
115
+ response = openai.ChatCompletion.create(
116
+ model="gpt-3.5-turbo",
117
+ messages=[
118
+ {"role": "system", "content": system_message},
119
+ {"role": "user", "content": f"Review this code:\n\n{code}"}
120
+ ],
121
+ temperature=0.3,
122
+ max_tokens=300
123
+ )
124
+
125
+ review_text = response.choices[0].message.content
126
+
127
+ # Extract key points
128
+ import re
129
+ suggestions = re.findall(r'[-•]\s*(.*?)(?=\n\n|\Z)', review_text, re.DOTALL)
130
+
131
+ return {
132
+ "status": "success",
133
+ "review": review_text,
134
+ "suggestions": suggestions,
135
+ "tokens_used": response.usage.total_tokens
136
+ }
137
+
138
+ except Exception as e:
139
+ return {
140
+ "status": "error",
141
+ "error": str(e),
142
+ "review": ""
143
+ }
144
+
145
+ def comprehensive_review(self, code: str) -> Dict[str, Any]:
146
+ """
147
+ Combine static analysis and LLM review for comprehensive feedback.
148
+
149
+ Args:
150
+ code: Python code to review
151
+
152
+ Returns:
153
+ Complete review results
154
+ """
155
+ static_result = self.static_analysis(code)
156
+ llm_result = self.llm_review(code)
157
+
158
+ return {
159
+ "static_analysis": static_result,
160
+ "llm_review": llm_result,
161
+ "overall_score": self._calculate_overall_score(static_result, llm_result)
162
+ }
163
+
164
+ def _calculate_overall_score(self, static: Dict, llm: Dict) -> float:
165
+ """Calculate an overall code quality score."""
166
+ if static.get("status") != "success":
167
+ return 0.0
168
+
169
+ static_score = static.get("score", 0.0)
170
+
171
+ # LLM review doesn't give numeric score, so we estimate based on suggestions
172
+ llm_suggestions = len(llm.get("suggestions", []))
173
+ llm_score = max(0, 10 - llm_suggestions * 0.5)
174
+
175
+ # Weighted average: 70% static analysis, 30% LLM review
176
+ return static_score * 0.7 + llm_score * 0.3