DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

How does AI transform chaos engineering from an experiment into a critical capability? Learn how to effectively operationalize the chaos.

Data quality isn't just a technical issue: It impacts an organization's compliance, operational efficiency, and customer satisfaction.

Are you a front-end or full-stack developer frustrated by front-end distractions? Learn to move forward with tooling and clear boundaries.

Developer Experience: Demand to support engineering teams has risen, and there is a shift from traditional DevOps to workflow improvements.

Related

  • Simplifying Multi-LLM Integration With KubeMQ
  • Comparing SDLC With and Without AI/ML Integration
  • Seamless CI/CD Integration: Playwright and GitHub Actions
  • Integrated Gradients: AI Explainability for Regulated Industries

Trending

  • How to Use Testcontainers With ScyllaDB
  • Enterprise-Grade Distributed JMeter Load Testing on Kubernetes: A Scalable, CI/CD-Driven DevOps Approach
  • Kung Fu Commands: Shifu Teaches Po the Command Pattern with Java Functional Interfaces
  • Designing AI Multi-Agent Systems in Java
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Code Reviews: Building an AI-Powered GitHub Integration

Code Reviews: Building an AI-Powered GitHub Integration

An AI-powered code review assistant that integrates GitHub, a Flask app, and the qwen2.5-coder model on Ollama to automate code reviews.

By 
Vamshidhar Parupally user avatar
Vamshidhar Parupally
·
May. 22, 25 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
4.4K Views

Join the DZone community and get the full member experience.

Join For Free

One common issue with growing teams with an extensive codebase is maintaining the code quality. It requires tremendous effort to maintain the code base, and manual code reviews often create a bottleneck during the development process. 

One standard practice is to get the pull request (PR) reviewed by a senior engineer before merging it into the code base. But developers often get overloaded with reviews as they continue to deliver their regular tasks and might overlook some of the minute details that end up in production. I personally had an experience where a simple missing null check created a cascading error during migration, ultimately leading to corrupted data in production. Human beings tend to make such mistakes, and it is a very common issue.

In this article, I would like to share how I implemented an AI-powered code review assistant, which pulls the data from GitHub, uses the locally hosted qwen2.5-coder model on Ollama to review the code, and publishes the comments back to GitHub.

You might wonder, “Don’t we have GitHub Copilot?” Yes, we do, but it might not work efficiently with proprietary code, such as code specific to ServiceNow, Salesforce, etc. To address this issue, this project included a manual review system to correct the feedback from the model, which is then used to fine-tune the model.

Problem: Code Review Bottlenecks

Being part of a development team, you will face these issues:

  • Delay in reviews: As senior developers manage code reviews along with their tasks, there is a significant delay in reviews.
  • Inconsistent standards: Different reviewers focus on different aspects, leading to unpredictable feedback.
  • Context switching: Developers lose productivity when switching between coding and reviewing.
  • Learning curve: Junior developers need detailed guidance but don’t always get comprehensive feedback.

All these issues encouraged me to build a solution to provide a consistent one-pass review, while giving human beings the ability to make a final decision.

Solution: GitHub + Ollama Integration

To start with an MVP, I have built a web application based on Flask that acts as a bridge between GitHub and locally hosted LLM models.

Let’s dive into how it works and how you can implement it in your environment. 

+-------------------+      +-------------------+      +--------------------+

|                   |      |                   |      |                    |

|   GitHub          +----->+  Flask App        +----->+  Ollama API        |

|   Enterprise      |      |   (Reviews Server)|      |(Local qwen2.5 Model)|

|                   |      |                   |      |                    |

+-------------------+      +------+-----+------+      +--------------------+

                                  |     ^

                                  |     |

                          +-------v-----+-------+     +--------------------+

                          |                     |     |                    |

                          |  Comments Database  +---->+   Monaco Editor UI |

                          |  (JSON/SQL)         |     |  Web Interface     |

                          |                     |     |                    |

                          +---------------------+     +--------------------+


Here are some core components in the application:

  1. GitHub integration: Fetches PR files and their diffs through GitHub’s API.
  2. Flask application: Processes code for AI consumption and manages the review workflow.
  3. Ollama integration: Sends code to locally-hosted model (qwen2.5-coder) and processes the LLM’s feedback.
  4. Monaco editor UI: Provides a rich interface for reviewing code and suggestions.
  5. Comments database: Stores and tracks review comments (used a simple JSON in this project).

AI-powered GitHub code review integration


Implementation Details

Setting Up Ollama Locally

To set up Ollama locally, visit ollama.com, download Ollama based on your operating system, and follow the onscreen instructions to install it. Once you are done with the installation, you can choose the model based on your use case from the list of models available on Ollama. 

In this case, I have selected qwen2.5-coder. Use the command below to interact with the model in the command line.

Shell
 
ollama run qwen2.5-coder


Setting Up Flask

If you already do not have Flask installed, install it using pip install Flask. Once you’ve successfully set up Flask, you can begin building the application by adding routes, templates, and integrating with external services or databases. 

Let’s look into the app.py, which is the core of the Flask app, where we define all the api routes, business logic, etc. So, to call the model, Ollama provides an API endpoint ‘http://localhost:11434/api/generate’. Refer to the code below to understand how we pass the information to Ollama.

Python
 
def call_ollama_model(code):
    try:
        response = requests.post(OLLAMA_API_URL, json={
            'model': 'qwen2.5-coder',
            'prompt': f"""
                Please review the following JavaScript code for potential issues, 
                improvements, and suggestions. For each issue, include:
                1. The line number
                2. The issue type (bug, performance, readability, security)
                3. A brief explanation of the problem
                4. A suggested fix
                
                Here's the code you need to review:
                {code}
                
                Format your response as JSON with the following structure:
                {{
                  "comments": [
                    {{
                      "line": 42,
                      "type": "security",
                      "message": "Unvalidated user input used in SQL query",
                      "suggestion": "Use parameterized queries with prepared statements"
                    }}
                  ]
                }}
            """,
            'stream': False
        })
        
        if response.status_code == 200:
            result = response.json()
            return process_ollama_response(result['response'])
        else:
            return f"Error calling Ollama model: {response.status_code}"
            
    except Exception as e:
        return f"Error calling Ollama model: {str(e)}"


Function to Fetch GitHub PR Details

Python
 
def get_pr_files(repo_owner, repo_name, pull_number):
    headers = {"Authorization": f"token {GITHUB_TOKEN}"}
    url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/pulls/{pull_number}/files"
    
    response = requests.get(url, headers=headers)
    
    if response.status_code == 200:
        files = response.json()
        return files
    else:
        return None


Comment Management System

The application stores comments locally and tracks which ones have been synced to GitHub:

Python
 
def save_comments_to_file(comment):
    # Load existing comments
    if os.path.exists(COMMENTS_FILE):
        with open(COMMENTS_FILE, 'r') as file:
            try:
                all_comments = json.load(file)
            except json.JSONDecodeError:
                all_comments = {}
    else:
        all_comments = {}

    # Add or update comment
    pr_key = f"{comment['repo_owner']}/{comment['repo_name']}/pull/{comment['pull_number']}"

    if pr_key not in all_comments:
        all_comments[pr_key] = []

    # Generate a unique ID for the comment
    comment_id = str(uuid.uuid4())
    comment['id'] = comment_id
    comment['synced_to_github'] = False
    comment['created_at'] = datetime.now().isoformat()

    all_comments[pr_key].append(comment)

    # Save back to file
    with open(COMMENTS_FILE, 'w') as file:
        json.dump(all_comments, file, indent=4)

    return comment_id


Submitting Comments to GitHub

Python
 
def submit_comment_to_github(comment_id):

     # Load all comments
     with open(COMMENTS_FILE, 'r') as file:
         all_comments = json.load(file)         

     # Find the comment by ID
     for pr_key, comments in all_comments.items():
         for comment in comments:
            if comment['id'] == comment_id and not comment['synced_to_github']:
                # Extract PR details
                repo_parts = pr_key.split('/')
                repo_owner = repo_parts[0]
                repo_name = repo_parts[1]
                pull_number = repo_parts[3]                

                # Create GitHub comment
                headers = {"Authorization": f"token {GITHUB_TOKEN}"}
                url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/pulls/{pull_number}/comments"               
                payload = {
                    "body": comment['body'],
                    "commit_id": comment['commit_id'],
                    "path": comment['path'],
                    "line": comment['line']

                }
                
                response = requests.post(url, headers=headers, json=payload)
                
                if response.status_code == 201:
                    # Mark as synced
                    comment['synced_to_github'] = True
                    with open(COMMENTS_FILE, 'w') as write_file:
                        json.dump(all_comments, write_file, indent=4)
                    return True

                return False

     return False


User Interface Implementation

The application features a clean interface built around the Monaco editor, making it easy to review code and manage feedback:

HTML
 
<!DOCTYPE html>
<html>
<head>
    <title>AI Code Review Assistant</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/editor/editor.main.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/loader.js"></script>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>AI Code Review Assistant</h1>
            <form id="prForm">
                <input type="text" id="repoOwner" placeholder="Repository Owner">
                <input type="text" id="repoName" placeholder="Repository Name">
                <input type="number" id="pullNumber" placeholder="PR Number">
                <button type="submit">Analyze PR</button>
            </form>
        </div>
        
        <div class="main">
            <div id="editor-container"></div>
            <div id="comments-container">
                <h3>AI Suggestions</h3>
                <div id="ai-comments"></div>
                
                <h3>Add Comment</h3>
                <form id="commentForm">
                    <input type="number" id="lineNumber" placeholder="Line Number">
                    <select id="commentType">
                        <option value="improvement">Improvement</option>
                        <option value="bug">Bug</option>
                        <option value="security">Security</option>
                        <option value="performance">Performance</option>
                    </select>
                    <textarea id="commentText" placeholder="Comment text"></textarea>
                    <button type="submit">Add Comment</button>
                </form>
                
                <button id="submitToGitHub">Submit All Comments to GitHub</button>
                <button id="exportComments">Export Comments for Training</button>
            </div>
        </div>
    </div>
    
    <script>
        // Monaco editor initialization code
        require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs' }});
        require(['vs/editor/editor.main'], function() {
            window.editor = monaco.editor.create(document.getElementById('editor-container'), {
                value: '// Code will appear here',
                language: 'javascript',
                theme: 'vs-dark',
                readOnly: true,
                lineNumbers: 'on',
                glyphMargin: true
            });
        });
        
        // Rest of the UI JavaScript
    </script>
</body>
</html>


Fine-Tuning the AI Model

As discussed in the introduction, to improve the LLM's performance for our specific codebase, we can fine-tune the model using data collected through the review process.

Exporting Training Data

The application includes an endpoint to export comments in a format suitable for fine-tuning:

Python
 
@app.route('/export_comments', methods=['GET'])
def export_comments():
    """Export all comments in a format suitable for model fine-tuning."""
    if os.path.exists(COMMENTS_FILE):
        with open(COMMENTS_FILE, 'r') as file:
            try:
                all_comments = json.load(file)
                
                # Format for fine-tuning
                training_data = []
                
                for pr_key, comments in all_comments.items():
                    for comment in comments:
                        if comment.get('human_approved', False):
                            training_example = {
                                "input": comment.get('code_context', ''),
                                "output": comment.get('body', '')
                            }
                            training_data.append(training_example)
                
                return jsonify({
                    "status": "success",
                    "training_examples": len(training_data),
                    "data": training_data
                })
                
            except json.JSONDecodeError:
                return jsonify({"status": "error", "message": "Invalid comments file"})
    else:
        return jsonify({"status": "error", "message": "No comments file found"})


Fine-Tuning Using Unsloth

Unsloth is an excellent tool for efficiently fine-tuning models. Here's how to use it with your exported data. 

NOTE: In this application I built, I did not have enough data to fine-tune the model, but if you want to try this, please refer to the below. It uses unsloth/llama-3-8b to fine-tune based on the custom data.

Install Unsloth:

Shell
 
pip install unsloth


Then, create a fine-tuning script (taken from the official tutorial):

Python
 
from unsloth import FastLanguageModel
import torch
import pandas as pd
import json
 
# Load the dataset from the exported JSON
with open("exported_comments.json", "r") as f:
    data = json.load(f)
    training_data = data["data"]
 
# Convert to DataFrame
df = pd.DataFrame(training_data)
 
# Initialize the model
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/llama-3-8b",
    max_seq_length=2048,
    dtype=torch.bfloat16,
    load_in_4bit=True,
)
 
# Set up a supervised fine-tuning trainer
trainer = FastLanguageModel.get_peft_trainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=df,
    formatting_func=lambda example: f"Review this code: {example['input']}\n\nReview: {example['output']}",
    peft_config=FastLanguageModel.get_peft_config(r=16, lora_alpha=32, target_modules=["q_proj", "k_proj", "v_proj", "o_proj"]),
    max_seq_length=2048,
    dataset_text_field="formatting_func",
    batch_size=1,
    epochs=3,
    learning_rate=2e-4,
    gradient_accumulation_steps=4,
    warmup_ratio=0.05,
    logging_steps=1,
)
 
# Train the model
trainer.train()
 
# Save the fine-tuned model
model_path = "code-review-model"
trainer.save_model(model_path)
 
# Export for Ollama
FastLanguageModel.export_to_gguf(
    model_path=model_path,
    output_path="code-review-model.gguf",
    quantization_method="q4_k_m"
)


Adding Your Fine-Tuned Model to Ollama

After fine-tuning, create a Modelfile to import your model into Ollama:

Plain Text
 
# code-review-modelfile
FROM ./code-review-model.gguf
PARAMETER temperature 0.1
PARAMETER top_p 0.7
PARAMETER stop "</review>"

SYSTEM """
You are an expert code reviewer specializing in identifying bugs, security issues, performance problems, and code quality improvements. When reviewing code:
1. Focus on substantive issues that impact functionality, security, and performance
2. Provide specific, actionable feedback with line numbers
3. Suggest concrete solutions for each issue identified
4. Format your response consistently for each issue
5. Be concise but thorough
"""


Finally, create the model in Ollama:

Shell
 
ollama create code-reviewer -f code-review-modelfile


Now you can update your application to use your custom fine-tuned model.

Conclusion

AI-powered assistants can help streamline development by automating first-pass reviews while maintaining human oversight for accuracy. Let me know your comments on my project and any suggestions for improving it.

AI GitHub Integration

Opinions expressed by DZone contributors are their own.

Related

  • Simplifying Multi-LLM Integration With KubeMQ
  • Comparing SDLC With and Without AI/ML Integration
  • Seamless CI/CD Integration: Playwright and GitHub Actions
  • Integrated Gradients: AI Explainability for Regulated Industries

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: