pranav8tripathi@gmail.com commited on
Commit
a4feaf2
Β·
1 Parent(s): 02d2955

added GEMINI

Browse files
Files changed (3) hide show
  1. README.md +10 -3
  2. app/code_reviewer.py +37 -26
  3. app/main.py +2 -1
README.md CHANGED
@@ -9,7 +9,7 @@ pinned: false
9
 
10
  # PRism AI Code Reviewer
11
 
12
- Automated AI-powered code review bot for GitHub Pull Requests using DeepSeek AI.
13
 
14
  ## Setup Instructions
15
 
@@ -18,7 +18,7 @@ Automated AI-powered code review bot for GitHub Pull Requests using DeepSeek AI.
18
  Go to your Space Settings β†’ Variables and secrets, and add:
19
 
20
  - `GITHUB_TOKEN` - Your GitHub personal access token with `repo` scope
21
- - `DEEPSEEK_API_KEY` - Your DeepSeek API key
22
  - `GITHUB_WEBHOOK_SECRET` - Random secret string (generate with `openssl rand -hex 32`)
23
 
24
  ### 2. Configure GitHub Webhook
@@ -40,9 +40,16 @@ Open a Pull Request in your repo and watch PRism automatically review it!
40
 
41
  1. PR opened/updated β†’ GitHub sends webhook
42
  2. PRism fetches the code changes (diff)
43
- 3. DeepSeek AI analyzes the code
44
  4. PRism posts review comments back to the PR
45
 
 
 
 
 
 
 
 
46
  ## Local Development
47
 
48
  ```bash
 
9
 
10
  # PRism AI Code Reviewer
11
 
12
+ Automated AI-powered code review bot for GitHub Pull Requests using Google Gemini AI.
13
 
14
  ## Setup Instructions
15
 
 
18
  Go to your Space Settings β†’ Variables and secrets, and add:
19
 
20
  - `GITHUB_TOKEN` - Your GitHub personal access token with `repo` scope
21
+ - `GEMINI_API_KEY` - Your Google Gemini API key (get from https://aistudio.google.com/apikey)
22
  - `GITHUB_WEBHOOK_SECRET` - Random secret string (generate with `openssl rand -hex 32`)
23
 
24
  ### 2. Configure GitHub Webhook
 
40
 
41
  1. PR opened/updated β†’ GitHub sends webhook
42
  2. PRism fetches the code changes (diff)
43
+ 3. Google Gemini AI analyzes the code
44
  4. PRism posts review comments back to the PR
45
 
46
+ ## Features
47
+
48
+ - πŸš€ **Fast**: Uses Gemini 2.0 Flash for quick responses
49
+ - πŸ’¬ **Real-time**: Comments appear as each file is analyzed
50
+ - 🎯 **Accurate**: Line-specific feedback with severity levels
51
+ - πŸ”’ **Secure**: Webhook signature verification
52
+
53
  ## Local Development
54
 
55
  ```bash
app/code_reviewer.py CHANGED
@@ -5,52 +5,62 @@ import logging
5
 
6
  logger = logging.getLogger(__name__)
7
 
8
- DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
9
- DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
10
 
11
  async def analyze_code(file_name: str, patch: str) -> list:
12
  """
13
- Analyze a single file diff using DeepSeek AI model.
14
  Returns a list of structured comments.
15
  """
16
- logger.info(f"πŸ€– Sending to DeepSeek AI: {file_name} ({len(patch)} chars)")
17
 
18
- prompt = f"""
19
- You are a senior code reviewer.
20
- Review the following diff from `{file_name}` and provide detailed, line-specific feedback.
21
 
22
- Respond in JSON list format like:
23
- [
24
- {{
25
- "line": 42,
26
- "severity": "medium",
27
- "comment": "Consider handling null values before using user.name"
28
- }}
29
- ]
30
 
31
- Code Diff:
32
- {patch}
33
- """
 
 
34
 
35
  headers = {
36
- "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
37
  "Content-Type": "application/json"
38
  }
39
 
40
  payload = {
41
- "model": "deepseek-chat",
42
- "messages": [{"role": "user", "content": prompt}]
 
 
 
 
 
 
 
 
 
43
  }
44
 
45
  try:
46
  async with httpx.AsyncClient(timeout=60.0) as client:
47
- logger.info("⏳ Waiting for DeepSeek response...")
48
- response = await client.post(DEEPSEEK_API_URL, headers=headers, json=payload)
49
  response.raise_for_status()
50
  data = response.json()
51
- logger.info("βœ… DeepSeek response received")
52
 
53
- text_output = data["choices"][0]["message"]["content"].strip()
 
54
  logger.info(f"πŸ“„ Response length: {len(text_output)} chars")
55
 
56
  # Defensive: handle non-JSON outputs
@@ -66,7 +76,8 @@ async def analyze_code(file_name: str, patch: str) -> list:
66
  return parsed
67
  except Exception as e:
68
  logger.warning(f"⚠️ Failed to parse JSON, returning raw text: {str(e)}")
 
69
  return [{"line": 1, "severity": "info", "comment": text_output}]
70
  except Exception as e:
71
- logger.error(f"❌ DeepSeek API error: {str(e)}")
72
  raise
 
5
 
6
  logger = logging.getLogger(__name__)
7
 
8
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
9
+ GEMINI_API_URL = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={GEMINI_API_KEY}"
10
 
11
  async def analyze_code(file_name: str, patch: str) -> list:
12
  """
13
+ Analyze a single file diff using Google Gemini AI model.
14
  Returns a list of structured comments.
15
  """
16
+ logger.info(f"πŸ€– Sending to Gemini AI: {file_name} ({len(patch)} chars)")
17
 
18
+ prompt = f"""You are a senior code reviewer.
19
+ Review the following diff from `{file_name}` and provide detailed, line-specific feedback.
 
20
 
21
+ Respond ONLY with a JSON array (no markdown, no explanation), like this:
22
+ [
23
+ {{
24
+ "line": 42,
25
+ "severity": "medium",
26
+ "comment": "Consider handling null values before using user.name"
27
+ }}
28
+ ]
29
 
30
+ If no issues found, return an empty array: []
31
+
32
+ Code Diff:
33
+ {patch}
34
+ """
35
 
36
  headers = {
 
37
  "Content-Type": "application/json"
38
  }
39
 
40
  payload = {
41
+ "contents": [
42
+ {
43
+ "parts": [
44
+ {"text": prompt}
45
+ ]
46
+ }
47
+ ],
48
+ "generationConfig": {
49
+ "temperature": 0.3,
50
+ "maxOutputTokens": 2048
51
+ }
52
  }
53
 
54
  try:
55
  async with httpx.AsyncClient(timeout=60.0) as client:
56
+ logger.info("⏳ Waiting for Gemini response...")
57
+ response = await client.post(GEMINI_API_URL, headers=headers, json=payload)
58
  response.raise_for_status()
59
  data = response.json()
60
+ logger.info("βœ… Gemini response received")
61
 
62
+ # Extract text from Gemini response structure
63
+ text_output = data["candidates"][0]["content"]["parts"][0]["text"].strip()
64
  logger.info(f"πŸ“„ Response length: {len(text_output)} chars")
65
 
66
  # Defensive: handle non-JSON outputs
 
76
  return parsed
77
  except Exception as e:
78
  logger.warning(f"⚠️ Failed to parse JSON, returning raw text: {str(e)}")
79
+ logger.warning(f"Raw response: {text_output[:200]}")
80
  return [{"line": 1, "severity": "info", "comment": text_output}]
81
  except Exception as e:
82
+ logger.error(f"❌ Gemini API error: {str(e)}")
83
  raise
app/main.py CHANGED
@@ -23,9 +23,10 @@ async def startup_event():
23
  logger.info("πŸš€ PRism AI Code Reviewer Starting...")
24
  logger.info("=" * 60)
25
  logger.info(f"βœ… GITHUB_TOKEN: {'Set' if os.getenv('GITHUB_TOKEN') else '❌ MISSING'}")
26
- logger.info(f"βœ… DEEPSEEK_API_KEY: {'Set' if os.getenv('DEEPSEEK_API_KEY') else '❌ MISSING'}")
27
  logger.info(f"βœ… GITHUB_WEBHOOK_SECRET: {'Set' if os.getenv('GITHUB_WEBHOOK_SECRET') else '⚠️ Not set (signature verification disabled)'}")
28
  logger.info("=" * 60)
 
29
  logger.info("πŸ“‘ Webhook endpoint: POST /webhook/github")
30
  logger.info("πŸ₯ Health check: GET /")
31
  logger.info("=" * 60)
 
23
  logger.info("πŸš€ PRism AI Code Reviewer Starting...")
24
  logger.info("=" * 60)
25
  logger.info(f"βœ… GITHUB_TOKEN: {'Set' if os.getenv('GITHUB_TOKEN') else '❌ MISSING'}")
26
+ logger.info(f"βœ… GEMINI_API_KEY: {'Set' if os.getenv('GEMINI_API_KEY') else '❌ MISSING'}")
27
  logger.info(f"βœ… GITHUB_WEBHOOK_SECRET: {'Set' if os.getenv('GITHUB_WEBHOOK_SECRET') else '⚠️ Not set (signature verification disabled)'}")
28
  logger.info("=" * 60)
29
+ logger.info("πŸ€– AI Model: Google Gemini 2.0 Flash")
30
  logger.info("πŸ“‘ Webhook endpoint: POST /webhook/github")
31
  logger.info("πŸ₯ Health check: GET /")
32
  logger.info("=" * 60)