jstoppa commited on
Commit
015df0f
Β·
verified Β·
1 Parent(s): cc9dd62

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +368 -0
app.py ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from langgraph.graph import StateGraph
3
+ from typing import TypedDict, Annotated, List, Dict
4
+ from langgraph.graph.message import add_messages
5
+ from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
6
+ import json
7
+ import requests
8
+ import os
9
+ from dotenv import load_dotenv
10
+ import time
11
+
12
+ # Load environment variables
13
+ load_dotenv()
14
+
15
+ # Define the state structure
16
+ class State(TypedDict):
17
+ messages: Annotated[list[SystemMessage | HumanMessage | AIMessage], add_messages]
18
+ current_step: str
19
+ code: str
20
+ style_analysis: Dict
21
+ security_analysis: Dict
22
+ performance_analysis: Dict
23
+ architecture_analysis: Dict
24
+ final_recommendations: Dict
25
+
26
+ def call_huggingface_api(prompt: str, max_retries=3) -> Dict:
27
+ """Call Hugging Face API with retry logic and proper error handling."""
28
+ api_key = os.getenv("HUGGINGFACE_API_KEY")
29
+ if not api_key:
30
+ raise ValueError("HUGGINGFACE_API_KEY not found in environment variables")
31
+
32
+ # You can change this to any model you prefer
33
+ API_URL = "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1"
34
+ headers = {"Authorization": f"Bearer {api_key}"}
35
+
36
+ for attempt in range(max_retries):
37
+ try:
38
+ response = requests.post(
39
+ API_URL,
40
+ headers=headers,
41
+ json={
42
+ "inputs": prompt,
43
+ "parameters": {
44
+ "max_new_tokens": 1000,
45
+ "temperature": 0.7,
46
+ "top_p": 0.95,
47
+ "return_full_text": False
48
+ }
49
+ }
50
+ )
51
+
52
+ if response.status_code == 200:
53
+ result = response.json()
54
+ if isinstance(result, list) and len(result) > 0:
55
+ # Extract the generated text
56
+ text = result[0].get('generated_text', '')
57
+ # Try to parse as JSON if it contains JSON
58
+ try:
59
+ # Find JSON content between triple backticks if present
60
+ if "```json" in text:
61
+ json_str = text.split("```json")[1].split("```")[0].strip()
62
+ else:
63
+ json_str = text.strip()
64
+ return json.loads(json_str)
65
+ except json.JSONDecodeError:
66
+ return {"error": "Failed to parse JSON from response", "raw_text": text}
67
+
68
+ # If model is loading, wait and retry
69
+ if response.status_code == 503:
70
+ wait_time = 2 ** attempt
71
+ time.sleep(wait_time)
72
+ continue
73
+
74
+ except Exception as e:
75
+ if attempt == max_retries - 1:
76
+ return {"error": f"API call failed: {str(e)}"}
77
+ time.sleep(2 ** attempt)
78
+
79
+ return {"error": "Maximum retries reached"}
80
+
81
+ def analyze_code_style(state: State) -> dict:
82
+ """Analyze code style and best practices."""
83
+ code = state["code"]
84
+ prompt = f"""You are a senior code reviewer focused on code style and best practices. Analyze this code:
85
+
86
+ {code}
87
+
88
+ Focus on:
89
+ 1. Code readability and clarity
90
+ 2. Adherence to common style guides
91
+ 3. Variable/function naming
92
+ 4. Code organization
93
+ 5. Documentation quality
94
+
95
+ Provide your response in JSON format with these exact keys:
96
+ {{
97
+ "issues": ["list of identified style issues"],
98
+ "suggestions": ["list of improvement suggestions"],
99
+ "overall_rating": "1-10 score as a number",
100
+ "primary_concerns": ["list of main style concerns"]
101
+ }}"""
102
+
103
+ analysis = call_huggingface_api(prompt)
104
+ if "error" in analysis:
105
+ analysis = {
106
+ "issues": ["Error analyzing code style"],
107
+ "suggestions": ["Try again later"],
108
+ "overall_rating": 0,
109
+ "primary_concerns": ["Analysis failed"]
110
+ }
111
+
112
+ messages = state["messages"] + [AIMessage(content="Completed code style analysis")]
113
+ return {**state, "messages": messages, "style_analysis": analysis, "current_step": "security"}
114
+
115
+ def analyze_security(state: State) -> dict:
116
+ """Analyze security vulnerabilities."""
117
+ code = state["code"]
118
+ prompt = f"""You are a security expert. Analyze this code for security vulnerabilities:
119
+
120
+ {code}
121
+
122
+ Focus on:
123
+ 1. Input validation
124
+ 2. Authentication/Authorization
125
+ 3. Data exposure
126
+ 4. Common vulnerabilities
127
+ 5. Security best practices
128
+
129
+ Provide your response in JSON format with these exact keys:
130
+ {{
131
+ "vulnerabilities": ["list of potential security issues"],
132
+ "risk_levels": {{"vulnerability": "risk level"}},
133
+ "recommendations": ["list of security improvements"],
134
+ "overall_security_score": "1-10 score as a number"
135
+ }}"""
136
+
137
+ analysis = call_huggingface_api(prompt)
138
+ if "error" in analysis:
139
+ analysis = {
140
+ "vulnerabilities": ["Error analyzing security"],
141
+ "risk_levels": {"Error": "High"},
142
+ "recommendations": ["Try again later"],
143
+ "overall_security_score": 0
144
+ }
145
+
146
+ messages = state["messages"] + [AIMessage(content="Completed security analysis")]
147
+ return {**state, "messages": messages, "security_analysis": analysis, "current_step": "performance"}
148
+
149
+ def analyze_performance(state: State) -> dict:
150
+ """Analyze code performance."""
151
+ code = state["code"]
152
+ prompt = f"""You are a performance optimization expert. Analyze this code for performance issues:
153
+
154
+ {code}
155
+
156
+ Focus on:
157
+ 1. Time complexity
158
+ 2. Space complexity
159
+ 3. Resource usage
160
+ 4. Bottlenecks
161
+ 5. Optimization opportunities
162
+
163
+ Provide your response in JSON format with these exact keys:
164
+ {{
165
+ "bottlenecks": ["list of identified performance bottlenecks"],
166
+ "complexity_analysis": {{
167
+ "time_complexity": "Big O notation",
168
+ "space_complexity": "Big O notation",
169
+ "critical_sections": ["list of critical sections"]
170
+ }},
171
+ "optimization_suggestions": ["list of performance improvements"],
172
+ "performance_score": "1-10 score as a number"
173
+ }}"""
174
+
175
+ analysis = call_huggingface_api(prompt)
176
+ if "error" in analysis:
177
+ analysis = {
178
+ "bottlenecks": ["Error analyzing performance"],
179
+ "complexity_analysis": {
180
+ "time_complexity": "Unknown",
181
+ "space_complexity": "Unknown",
182
+ "critical_sections": []
183
+ },
184
+ "optimization_suggestions": ["Try again later"],
185
+ "performance_score": 0
186
+ }
187
+
188
+ messages = state["messages"] + [AIMessage(content="Completed performance analysis")]
189
+ return {**state, "messages": messages, "performance_analysis": analysis, "current_step": "architecture"}
190
+
191
+ def analyze_architecture(state: State) -> dict:
192
+ """Analyze code architecture patterns."""
193
+ code = state["code"]
194
+ prompt = f"""You are a software architect. Analyze this code's architectural patterns:
195
+
196
+ {code}
197
+
198
+ Focus on:
199
+ 1. Design patterns used
200
+ 2. Code modularity
201
+ 3. Component relationships
202
+ 4. Architectural anti-patterns
203
+ 5. System design principles
204
+
205
+ Provide your response in JSON format with these exact keys:
206
+ {{
207
+ "patterns_identified": ["list of design patterns found"],
208
+ "architectural_issues": ["list of architectural concerns"],
209
+ "improvement_suggestions": ["list of architectural improvements"],
210
+ "architecture_score": "1-10 score as a number"
211
+ }}"""
212
+
213
+ analysis = call_huggingface_api(prompt)
214
+ if "error" in analysis:
215
+ analysis = {
216
+ "patterns_identified": ["Error analyzing architecture"],
217
+ "architectural_issues": ["Analysis failed"],
218
+ "improvement_suggestions": ["Try again later"],
219
+ "architecture_score": 0
220
+ }
221
+
222
+ messages = state["messages"] + [AIMessage(content="Completed architecture analysis")]
223
+ return {**state, "messages": messages, "architecture_analysis": analysis, "current_step": "recommendations"}
224
+
225
+ def generate_final_recommendations(state: State) -> dict:
226
+ """Generate final recommendations based on all analyses."""
227
+ code = state["code"]
228
+ prompt = f"""Analyze all previous results and provide final recommendations for this code:
229
+
230
+ Style Analysis: {json.dumps(state.get('style_analysis', {}))}
231
+ Security Analysis: {json.dumps(state.get('security_analysis', {}))}
232
+ Performance Analysis: {json.dumps(state.get('performance_analysis', {}))}
233
+ Architecture Analysis: {json.dumps(state.get('architecture_analysis', {}))}
234
+
235
+ Provide your response in JSON format with these exact keys:
236
+ {{
237
+ "critical_issues": ["list of most critical issues"],
238
+ "priority_improvements": ["list of high-priority improvements"],
239
+ "quick_wins": ["list of easy-to-implement improvements"],
240
+ "long_term_suggestions": ["list of long-term improvements"],
241
+ "overall_health_score": "1-10 score as a number"
242
+ }}"""
243
+
244
+ recommendations = call_huggingface_api(prompt)
245
+ if "error" in recommendations:
246
+ recommendations = {
247
+ "critical_issues": ["Error generating recommendations"],
248
+ "priority_improvements": ["Try again later"],
249
+ "quick_wins": [],
250
+ "long_term_suggestions": [],
251
+ "overall_health_score": 0
252
+ }
253
+
254
+ messages = state["messages"] + [AIMessage(content="Generated final recommendations")]
255
+ return {**state, "messages": messages, "final_recommendations": recommendations, "current_step": "end"}
256
+
257
+ def format_output(state: State) -> str:
258
+ """Format the analysis results into a readable output."""
259
+ output = """πŸ” Code Analysis Report
260
+
261
+ 🎨 Style & Best Practices
262
+ """
263
+ style = state.get("style_analysis", {})
264
+ output += f"Rating: {style.get('overall_rating', 'N/A')}/10\n"
265
+ output += "Issues:\n" + "\n".join([f"β€’ {issue}" for issue in style.get("issues", [])]) + "\n\n"
266
+
267
+ output += """πŸ”’ Security Analysis
268
+ """
269
+ security = state.get("security_analysis", {})
270
+ output += f"Score: {security.get('overall_security_score', 'N/A')}/10\n"
271
+ vulnerabilities = security.get("vulnerabilities", [])
272
+ risk_levels = security.get("risk_levels", {})
273
+ output += "Vulnerabilities:\n" + "\n".join([f"β€’ {v} ({risk_levels.get(v, 'Unknown')})" for v in vulnerabilities]) + "\n\n"
274
+
275
+ output += """⚑ Performance Analysis
276
+ """
277
+ perf = state.get("performance_analysis", {})
278
+ output += f"Score: {perf.get('performance_score', 'N/A')}/10\n"
279
+ output += "Bottlenecks:\n" + "\n".join([f"β€’ {b}" for b in perf.get("bottlenecks", [])]) + "\n\n"
280
+
281
+ output += """πŸ—οΈ Architecture Analysis
282
+ """
283
+ arch = state.get("architecture_analysis", {})
284
+ output += f"Score: {arch.get('architecture_score', 'N/A')}/10\n"
285
+ output += "Patterns:\n" + "\n".join([f"β€’ {p}" for p in arch.get("patterns_identified", [])]) + "\n\n"
286
+
287
+ output += """πŸ“‹ Final Recommendations
288
+ """
289
+ final = state.get("final_recommendations", {})
290
+ output += f"Overall Health Score: {final.get('overall_health_score', 'N/A')}/10\n\n"
291
+ output += "Critical Issues:\n" + "\n".join([f"β€’ {i}" for i in final.get("critical_issues", [])]) + "\n\n"
292
+ output += "Priority Improvements:\n" + "\n".join([f"β€’ {i}" for i in final.get("priority_improvements", [])])
293
+
294
+ return output
295
+
296
+ # Create and setup graph
297
+ workflow = StateGraph(State)
298
+
299
+ # Add nodes
300
+ workflow.add_node("style", analyze_code_style)
301
+ workflow.add_node("security", analyze_security)
302
+ workflow.add_node("performance", analyze_performance)
303
+ workflow.add_node("architecture", analyze_architecture)
304
+ workflow.add_node("recommendations", generate_final_recommendations)
305
+
306
+ # Add edges
307
+ workflow.add_edge("style", "security")
308
+ workflow.add_edge("security", "performance")
309
+ workflow.add_edge("performance", "architecture")
310
+ workflow.add_edge("architecture", "recommendations")
311
+
312
+ # Set entry and finish points
313
+ workflow.set_entry_point("style")
314
+ workflow.set_finish_point("recommendations")
315
+
316
+ # Compile the workflow
317
+ agent = workflow.compile()
318
+
319
+ def analyze_code(code: str) -> str:
320
+ """Analyze the provided code using multiple perspectives."""
321
+ initial_state = State(
322
+ messages=[SystemMessage(content="Starting code analysis...")],
323
+ current_step="style",
324
+ code=code,
325
+ style_analysis={},
326
+ security_analysis={},
327
+ performance_analysis={},
328
+ architecture_analysis={},
329
+ final_recommendations={}
330
+ )
331
+
332
+ final_state = agent.invoke(initial_state)
333
+ return format_output(final_state)
334
+
335
+ # Create Gradio interface
336
+ iface = gr.Interface(
337
+ fn=analyze_code,
338
+ inputs=gr.Code(
339
+ label="Enter your code for analysis",
340
+ language="python",
341
+ lines=20
342
+ ),
343
+ outputs=gr.Textbox(
344
+ label="Analysis Results",
345
+ lines=25
346
+ ),
347
+ title="πŸ” Code Architecture Critic",
348
+ description="Paste your code to get a comprehensive analysis of style, security, performance, and architecture.",
349
+ examples=[
350
+ ['''def process_data(data):
351
+ result = []
352
+ for i in range(len(data)):
353
+ for j in range(len(data)):
354
+ if data[i] + data[j] == 10:
355
+ result.append((data[i], data[j]))
356
+ return result
357
+
358
+ def save_to_db(user_input):
359
+ query = "INSERT INTO users VALUES ('" + user_input + "')"
360
+ db.execute(query)
361
+
362
+ API_KEY = "sk_test_123456789"''']
363
+ ],
364
+ theme=gr.themes.Soft()
365
+ )
366
+
367
+ if __name__ == "__main__":
368
+ iface.launch()