CodeCommunity commited on
Commit
984fc65
·
verified ·
1 Parent(s): 11440af

Update app/main.py

Browse files
Files changed (1) hide show
  1. app/main.py +46 -41
app/main.py CHANGED
@@ -3,7 +3,9 @@ import re
3
  import logging
4
  import traceback
5
  import time
 
6
  from typing import List, Optional, Dict
 
7
  from dotenv import load_dotenv
8
 
9
  from fastapi import FastAPI, HTTPException
@@ -13,9 +15,9 @@ import uvicorn
13
  # Load environment variables
14
  load_dotenv()
15
 
 
 
16
  from app.predictor import classifier, guide_generator, reviewer
17
- # Note: AIReviewerService from the first version is typically
18
- # the underlying service for the 'reviewer' object in the second.
19
 
20
  # 1. Setup Logging
21
  logging.basicConfig(level=logging.INFO)
@@ -76,7 +78,6 @@ async def classify_file(request: FileRequest):
76
  try:
77
  result = classifier.predict(request.fileName, request.content)
78
 
79
- # Cache embedding if repoName is provided
80
  if request.repoName:
81
  if request.repoName not in REPO_CACHE:
82
  REPO_CACHE[request.repoName] = {}
@@ -90,7 +91,6 @@ async def classify_file(request: FileRequest):
90
  }
91
  except Exception as e:
92
  logger.error(f"Classify failed: {e}")
93
- traceback.print_exc()
94
  raise HTTPException(status_code=500, detail=str(e))
95
 
96
  @app.post("/review-batch-code")
@@ -101,7 +101,6 @@ async def review_batch_code(request: BatchReviewRequest):
101
  total_files = len(reviews)
102
  total_vulns = sum(len(r.get("vulnerabilities", [])) for r in reviews)
103
 
104
- # Calculate Average Maintainability
105
  m_scores = [r.get("metrics", {}).get("maintainability", 8) for r in reviews]
106
  avg_maint = sum(m_scores) / max(total_files, 1)
107
 
@@ -117,37 +116,55 @@ async def review_batch_code(request: BatchReviewRequest):
117
 
118
  @app.post("/repo-dashboard-stats")
119
  async def get_dashboard_stats(request: BatchReviewRequest):
120
- """Aggregated stats for frontend dashboards including health and API sniffing."""
121
  try:
122
- raw_reviews = reviewer.service.review_batch_code(request.files)
123
-
124
- # 1. Security Count
125
- total_vulns = sum(len(r.get("vulnerabilities", [])) for r in raw_reviews)
126
-
127
- # 2. Performance/Maintainability Ratio
128
- scores = [r.get("metrics", {}).get("maintainability", 8) for r in raw_reviews]
129
- avg_maintainability = (sum(scores) / len(scores)) * 10 if scores else 0
130
-
131
- # 3. API Sniffing (Regex)
132
- found_apis = []
133
- for f in request.files:
134
- if f.content:
135
- matches = re.findall(r'(?:get|post|put|delete|patch)\([\'"]\/(.*?)[\'"]', f.content.lower())
 
 
 
 
 
 
 
 
 
 
 
 
136
  for match in matches:
137
- found_apis.append(f"/{match}")
138
 
139
- # 4. Repo Health Calculation
140
- health_score = max(10, 100 - (total_vulns * 10))
 
 
 
 
141
 
142
  return {
143
  "repo_health": health_score,
144
- "health_label": "Excellent Health" if health_score > 80 else "Needs Review",
145
  "security_issues": total_vulns,
146
- "performance_ratio": f"{int(avg_maintainability)}%",
147
- "exposed_apis": list(set(found_apis))[:10]
 
148
  }
149
  except Exception as e:
150
  logger.error(f"Dashboard stats failed: {e}")
 
151
  raise HTTPException(status_code=500, detail="Failed to aggregate repository stats")
152
 
153
  @app.post("/analyze-file")
@@ -195,8 +212,6 @@ async def semantic_search(request: SearchRequest):
195
  async def chat(request: ChatRequest):
196
  """RAG-based chat using provided file context."""
197
  start_time = time.time()
198
- logger.info(f"Received Chat Request for {request.repoName}")
199
-
200
  try:
201
  from app.core.model_loader import llm_engine
202
 
@@ -208,21 +223,12 @@ async def chat(request: ChatRequest):
208
  prompt = f"""
209
  You are "GitGud AI", an expert software architect.
210
  Repository: "{request.repoName}"
211
-
212
- INSTRUCTIONS:
213
- 1. Use the provided CONTEXT to answer.
214
- 2. If context is missing, state: "I am using general knowledge as I don't have specific snippets for this."
215
- 3. Use markdown for code.
216
-
217
- CONTEXT:
218
- {context_str if has_context else "[(NO CODE SNIPPETS PROVIDED)]"}
219
-
220
- USER QUESTION:
221
- {request.query}
222
  """
223
  response = llm_engine.generate_text(prompt)
224
 
225
- logger.info(f"Chat response generated in {time.time() - start_time:.2f}s")
226
  return {"response": response}
227
  except Exception as e:
228
  traceback.print_exc()
@@ -240,6 +246,5 @@ async def generate_guide(request: GuideRequest):
240
 
241
  # 5. Application Entry Point
242
  if __name__ == "__main__":
243
- # Note: Using 7860 for HF Spaces compatibility, change to 8000 if preferred for local dev
244
  port = int(os.environ.get("PORT", 7860))
245
  uvicorn.run(app, host="0.0.0.0", port=port)
 
3
  import logging
4
  import traceback
5
  import time
6
+ import asyncio
7
  from typing import List, Optional, Dict
8
+ from concurrent.futures import ThreadPoolExecutor
9
  from dotenv import load_dotenv
10
 
11
  from fastapi import FastAPI, HTTPException
 
15
  # Load environment variables
16
  load_dotenv()
17
 
18
+ # Import internal services
19
+ # Note: Ensure these modules exist in your /app directory
20
  from app.predictor import classifier, guide_generator, reviewer
 
 
21
 
22
  # 1. Setup Logging
23
  logging.basicConfig(level=logging.INFO)
 
78
  try:
79
  result = classifier.predict(request.fileName, request.content)
80
 
 
81
  if request.repoName:
82
  if request.repoName not in REPO_CACHE:
83
  REPO_CACHE[request.repoName] = {}
 
91
  }
92
  except Exception as e:
93
  logger.error(f"Classify failed: {e}")
 
94
  raise HTTPException(status_code=500, detail=str(e))
95
 
96
  @app.post("/review-batch-code")
 
101
  total_files = len(reviews)
102
  total_vulns = sum(len(r.get("vulnerabilities", [])) for r in reviews)
103
 
 
104
  m_scores = [r.get("metrics", {}).get("maintainability", 8) for r in reviews]
105
  avg_maint = sum(m_scores) / max(total_files, 1)
106
 
 
116
 
117
  @app.post("/repo-dashboard-stats")
118
  async def get_dashboard_stats(request: BatchReviewRequest):
119
+ """Aggregated stats using parallel processing for speed and review-first logic."""
120
  try:
121
+ # 1. Run the heavy AI review process in a thread pool to prevent blocking
122
+ loop = asyncio.get_event_loop()
123
+ with ThreadPoolExecutor() as executor:
124
+ raw_reviews = await loop.run_in_executor(
125
+ executor, reviewer.service.review_batch_code, request.files
126
+ )
127
+
128
+ # 2. Extract Data from the Review Results
129
+ total_vulns = 0
130
+ maint_scores = []
131
+ found_apis = set()
132
+ api_regex = re.compile(r'(?:get|post|put|delete|patch)\([\'"]\/(.*?)[\'"]', re.IGNORECASE)
133
+
134
+ for i, review in enumerate(raw_reviews):
135
+ # Security Count from Review
136
+ vulns = review.get("vulnerabilities", [])
137
+ total_vulns += len(vulns)
138
+
139
+ # Maintainability Score
140
+ m_score = review.get("metrics", {}).get("maintainability", 8)
141
+ maint_scores.append(m_score)
142
+
143
+ # API Sniffing
144
+ content = request.files[i].content
145
+ if content:
146
+ matches = api_regex.findall(content)
147
  for match in matches:
148
+ found_apis.add(f"/{match}")
149
 
150
+ # 3. Aggregation & Calculations
151
+ num_files = len(maint_scores)
152
+ avg_maint = (sum(maint_scores) / num_files) if num_files > 0 else 0
153
+
154
+ # Health Calculation: Base 100, -12 per vulnerability
155
+ health_score = max(10, 100 - (total_vulns * 12))
156
 
157
  return {
158
  "repo_health": health_score,
159
+ "health_label": "Excellent" if health_score > 85 else "Good" if health_score > 60 else "Critical",
160
  "security_issues": total_vulns,
161
+ "performance_ratio": f"{int(avg_maint * 10)}%",
162
+ "exposed_apis": list(found_apis)[:12],
163
+ "total_files_processed": num_files
164
  }
165
  except Exception as e:
166
  logger.error(f"Dashboard stats failed: {e}")
167
+ traceback.print_exc()
168
  raise HTTPException(status_code=500, detail="Failed to aggregate repository stats")
169
 
170
  @app.post("/analyze-file")
 
212
  async def chat(request: ChatRequest):
213
  """RAG-based chat using provided file context."""
214
  start_time = time.time()
 
 
215
  try:
216
  from app.core.model_loader import llm_engine
217
 
 
223
  prompt = f"""
224
  You are "GitGud AI", an expert software architect.
225
  Repository: "{request.repoName}"
226
+ CONTEXT: {context_str if has_context else "(NO CODE PROVIDED)"}
227
+ USER QUESTION: {request.query}
 
 
 
 
 
 
 
 
 
228
  """
229
  response = llm_engine.generate_text(prompt)
230
 
231
+ logger.info(f"Chat generated in {time.time() - start_time:.2f}s")
232
  return {"response": response}
233
  except Exception as e:
234
  traceback.print_exc()
 
246
 
247
  # 5. Application Entry Point
248
  if __name__ == "__main__":
 
249
  port = int(os.environ.get("PORT", 7860))
250
  uvicorn.run(app, host="0.0.0.0", port=port)