Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3579fed
init
galekseev Mar 15, 2025
c8dbd78
fixes
galekseev Mar 15, 2025
6d7e73e
fix
galekseev Mar 15, 2025
650d0a2
Update chatgpt_review.py
galekseev Mar 15, 2025
10f0db1
model change
galekseev Mar 15, 2025
df056d9
fix
galekseev Mar 15, 2025
8630378
fix
galekseev Mar 15, 2025
46c09e9
fix
galekseev Mar 15, 2025
9493bf2
Update chatgpt_review.py
galekseev Mar 15, 2025
3253736
ref
galekseev Mar 15, 2025
a0511bd
fix
galekseev Mar 15, 2025
2442cd7
fix
galekseev Mar 15, 2025
ef1dac8
fix
galekseev Mar 15, 2025
7ea404e
Update o1-mini_review.py
galekseev Mar 15, 2025
47c0ab0
Update o1-mini_review.py
galekseev Mar 15, 2025
5b69a25
Update o1-mini_review.py
galekseev Mar 15, 2025
eceab26
prompt fix
galekseev Mar 15, 2025
dfab659
Update o1-mini_review.py
galekseev Mar 15, 2025
aa3502d
bug fix
galekseev Mar 15, 2025
e49d451
refactoring
galekseev Mar 15, 2025
1c7d074
refactoring
galekseev Mar 15, 2025
61c6b5a
fixes
galekseev Mar 15, 2025
2e9f859
fixes
galekseev Mar 15, 2025
b308433
change model
galekseev Mar 15, 2025
7745950
renamings
galekseev Mar 15, 2025
c498fb4
prompt fix
galekseev Mar 15, 2025
e656ab9
Update ai_review.py
galekseev Mar 15, 2025
a52556f
Update ai_review.py
galekseev Mar 15, 2025
17d6da3
Update ai_review.py
galekseev Mar 15, 2025
c3b2d90
Update ai_review.py
galekseev Mar 15, 2025
1ed4745
Update ai_review.py
galekseev Mar 15, 2025
de00676
Update ai_review.py
galekseev Mar 15, 2025
debf7f7
Update ai_review.py
galekseev Mar 15, 2025
33feff1
Update ai_review.py
galekseev Mar 15, 2025
74853c9
Update ai_review.py
galekseev Mar 15, 2025
3ae5444
Update ai_review.py
galekseev Mar 15, 2025
761a9f0
model change
galekseev Mar 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions .github/scripts/ai_review.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import os
import requests
import openai
import logging

# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('pr_review_bot')

# Define model arrays
REGULAR_MODELS = ["gpt-3.5-turbo", "gpt-4o"]
REASONING_MODELS = ["o1-mini", "o1-preview"]

# Extract PR number from github environment
def get_pr_number(github_ref):
parts = github_ref.split("/")
if len(parts) >= 3 and parts[1] == "pull":
pr_number = parts[2]
else:
raise ValueError(f"Unexpected GITHUB_REF format: {github_ref}")
return pr_number

# Fetch PR code diff
def fetch_diff(pr_url, github_token):
headers = {
"Authorization": f"Bearer {github_token}",
"Accept": "application/vnd.github.v3.diff"
}
diff_response = requests.get(pr_url, headers=headers)
if diff_response.status_code != 200:
raise RuntimeError(f"Failed to fetch PR diff: {diff_response.status_code} {diff_response.text}")
return diff_response.text

# Fetch PR description
def fetch_pr_description(pr_url, github_token):
json_headers = {
"Authorization": f"Bearer {github_token}",
"Accept": "application/vnd.github.v3+json"
}
pr_details_response = requests.get(pr_url, headers=json_headers)
pr_data = pr_details_response.json()
pr_title = pr_data.get("title", "(no title)")
pr_body = pr_data.get("body", "(no body)")
return pr_title, pr_body

def generate_review_regular(diff_text, pr_title, pr_body, model_name):
logger.info(f"Generating code review with regular model: {model_name}")
prompt = (
"You are acting as an advanced code review assistant. Below is a diff from a Pull Request. "
"Please analyze these changes in detail and provide a constructive critique. Focus on:\n"
"- Potential bugs and security vulnerabilities\n"
"- Conformance to coding style and best practices\n"
"- Opportunities for performance or maintainability improvements\n"
"\n"
f"Diff:\n{diff_text}"
)

dev_prompt = (
"You are a highly experienced senior software engineer and code reviewer with deep "
"expertise across various programming languages and frameworks "
"(including Solidity, JavaScript/TypeScript, and Rust). "
"Your role is to thoroughly analyze code changes, focusing on correctness, security, "
"maintainability, and adherence to best practices. Provide clear, actionable, and concise "
"feedback with concrete suggestions for improvement where necessary. Avoid unnecessary elaboration, "
"but ensure that critical details are clearly explained."
)

try:
completion = openai.chat.completions.create(
model=model_name,
messages=[
{"role": "developer", "content": dev_prompt},
{"role": "user", "content": prompt}
],
temperature=0.3,
max_completion_tokens=1000
)
except Exception as e:
logger.error(f"Failed to generate review: {e}")
raise RuntimeError(f"Failed to generate review: {e}")

return completion.choices[0].message.content

def generate_review_reasoning(diff_text, pr_title, pr_body, model_name):
logger.info(f"Generating code review with reasoning model: {model_name}")
prompt = (
"Do code review and analyze code changes. "
"Focus on:\n"
"- Potential bugs and security vulnerabilities\n"
"- Conformance to coding style and best practices\n"
"- Opportunities for performance or maintainability improvements\n"
"\n"
"Give summary of what the code changes are doing. "
"Then identify existing issues and provide specific, actionable suggestions "
"how to fix the identified issues if there are any. "
"Be brief, avoid giving general recommendations not related to code fixes. "
"Do not recommend changes outside of the code changes in the diff."
"\n\n"
f"PR Title:\n{pr_title}\n"
f"PR Description:\n{pr_body}\n"
f"Diff:\n{diff_text}"
)

try:
completion = openai.chat.completions.create(
model=model_name,
messages=[
{"role": "user", "content": prompt}
]
)
except Exception as e:
logger.error(f"Failed to generate review: {e}")
raise RuntimeError(f"Failed to generate review: {e}")

return completion.choices[0].message.content

def generate_review(diff_text, pr_title, pr_body, model_name="o1-mini"):
if model_name in REGULAR_MODELS:
return generate_review_regular(diff_text, pr_title, pr_body, model_name)
elif model_name in REASONING_MODELS:
return generate_review_reasoning(diff_text, pr_title, pr_body, model_name)
else:
logger.warning(f"Unknown model type: {model_name}, trying regular review")
return generate_review_regular(diff_text, pr_title, pr_body, model_name)

# Post review as a comment
def post_review_comment(repo, pr_number, review_text, github_token):
logger.info(f"Posting review comment for PR #{pr_number}")
comment_url = f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments"
comment_headers = {"Authorization": f"Bearer {github_token}"}
response = requests.post(comment_url, headers=comment_headers, json={"body": review_text})
if response.status_code != 201:
logger.error(f"Failed to post comment: {response.status_code} {response.text}")
return False
else:
logger.info("Successfully posted review comment")
return True

# Action start
logger.info("Starting PR review workflow")

# Get environment variables
repo = os.environ.get("GITHUB_REPOSITORY")
github_ref = os.environ.get("GITHUB_REF")
github_token = os.environ.get("GITHUB_TOKEN")
openai.api_key = os.environ["OPENAI_API_KEY"]
model_name = os.environ.get("OPENAI_MODEL", "o1-mini")

# Check if required environment variables exist
if not repo or not github_ref or not github_token:
logger.critical("Missing required environment variables")
raise ValueError("Missing required environment variables: GITHUB_REPOSITORY, GITHUB_REF, or GITHUB_TOKEN")

# Get PR ids
pr_number = get_pr_number(github_ref)
logger.info(f"Processing PR #{pr_number} with model {model_name}")
pr_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}"

# Fetch PR details
logger.info("Fetching PR diff")
diff_text = fetch_diff(pr_url, github_token)
logger.info("Fetching PR description")
pr_title, pr_body = fetch_pr_description(pr_url, github_token)

# Generate review with AI
review_text = generate_review(diff_text, pr_title, pr_body, model_name)

# Post the review
post_review_comment(repo, pr_number, review_text, github_token)
logger.info("PR review workflow completed")
26 changes: 26 additions & 0 deletions .github/workflows/ai-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: AI Code Review

permissions:
contents: read
pull-requests: write

on:
pull_request:
types: [opened, reopened, synchronize]

jobs:
code_review:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Install dependencies
run: pip install openai requests

- name: Run AI code review script
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_MODEL: o1-preview
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: python3 .github/scripts/ai_review.py
Loading