MinaFoundation / PGT_LeaderBot

Tool that will track and rank contributions across the different Mina developer programs
4 stars 5 forks source link
hacktoberfest

LeaderBot

Tool that will track and rank contributions across the different Mina developer programs. Consists of two bot:

  1. Github Tracker Bot
  2. Leaderbot

Getting Started

Prerequisites

Installation & Setup

  1. Clone the repository:

    git clone https://github.com/yourusername/PGT_LeaderBot.git
    cd PGT_LeaderBot
  2. In the root folder install virtual env and create virtual env:

    pip install virtualenv
    virtualenv venv

    Activate it:

    source venv/bin/activate
  3. Install dependencies with:

    pip install -r requirements.txt
  4. Configure the environment variables

    Create .env file in the root folder and add environment variables as shown in the .env.example file:

    GITHUB_TOKEN='your_github_token'
    DISCORD_TOKEN='your_discord_token'
    OPENAI_API_KEY='your_openai_api_key'
    
    GOOGLE_SHEETS_CREDENTIALS='path_to_your_google_sheets_credentials.json'
    SHARED_SECRET='shared_secret'
    
    MONGO_HOST='mongodb://localhost:27017/'
    MONGO_DB="example_db"
    MONGO_COLLECTION="example_collection"
    
    GTP_ENDPOINT=http://localhost:8000
    
    SPREADSHEET_ID='spread_sheet_id'
    LOG_LEVEL=DEBUG
    
    GUILD_ID=XXXXXXXX
    GMAIL_ADDRESS=xyz@gmail.com
    LEADERBOARD_FORUM_CHANNEL_ID=XXXXXXXXXXXXXXXXX
  5. You need to have google credentials .json file which has access your spreadsheet in the root folder. Need to enable Google Sheets API and Google Drive API. Click for more information.

  6. Run tests:

    invoke test
  7. Run github tracker bot:

    invoke bot

    For other invoke tasks look to: tasks.py

  8. To run Leaderbot discord bot, you need to have Discord bot in a specific server.

    invoke leaderbot

Github Tracker Bot

Overview

Github Tracker Bot fetchs to Google Spreadsheets which includes discord handle, github username and repositories. After getting these informations it fetches github commits data between specific timeframes given by user or day by day for all branches. After pre-processing the commits data. The bot sends total daily commits data(diff file) to OPENAI API to decide are these commits qualified with prompt.

Then gets the decisions data and insert them to MongoDB to further usage.

Date formats are ISO 8601 with Z suffix which is UTC. For example: "2023-01-24T00:00:00Z"

API Usage

bot.py is the main script for running a FastAPI service that provides functionality to schedule and run tasks to fetch results from a spreadsheet within specified time frames. The script includes endpoints to start and stop a scheduler, as well as to run tasks on demand.

API Endpoints

All of them uses headers headers = {"Authorization": AUTH_TOKEN} gotten from .env SHARED_SECRET

1. Run task manually for specific timeframes:

Endpoint: /run-task
Method: POST

This endpoint allows you to run a task immediately and manually for a specified time frame.

Request Body:
Example Request:
{
  "since": "2023-07-24T00:00:00Z",
  "until": "2023-07-25T00:00:00Z"
}
Example Response:
{
  "message": "Task run successfully with provided times"
}

2. Run task for specific user:

Endpoint: /run-task-for-user?username=johndoe
Method: POST

This endpoint allows you to run a task immediately and manually for a specified time frame and specific user.

Request Body:
Example Request:

Endpoint: /run-task-for-user?username=berkingurcan

{
    "since": "2023-07-24T00:00:00Z",
    "until": "2023-07-25T00:00:00Z"
}
Example Response:
{
  "message": "Task run successfully with provided times"
}

3. Control Scheduler

Endpoint: /control-scheduler
Method: POST

This endpoint allows you to start or stop the scheduler that runs tasks at specified minutes intervals. It is minutes for now to test. It will be hours.

Request Body:
Example Requests:
Start Scheduler:
{
  "action": "start",
  "interval_minutes": 5
}
Stop Scheduler:
{
  "action": "stop"
}
Example Responses:
Start Scheduler:
{
  "message": "Scheduler started with interval of 5 minutes"
}
Stop Scheduler:
{
  "message": "Scheduler stopped"
}

Classes

User

The User class is a nested dataclass designed to store and manage information about a user, including their GitHub-related activities and AI decisions regarding their contributions. This class stores 4 necessary data:

Remaining fields can be calculated using helper functions in the helper_functions.py.

AIDecision

The AIDecision Class stores AI decision related to a user's daily contribution for specific github repository. It includes details about the repository, date, and a nested response indicating the qualification status of the contribution which is DailyContributionResponse Class.

DailyContributionResponse

The DailyContributionResponse class is another dataclass to store information about a user's daily contribution response returned by OPENAI API for specific repository. It includes details about the contribution's qualification status and an AI explanation for it.

Click to see full code of User, AIDecision and DailyContributionResponse Classes ```py @dataclass class DailyContributionResponse: username: str date: str is_qualified: bool explanation: str def to_dict(self): """Converts the dataclass to a dictionary.""" return asdict(self) @dataclass class AIDecision: username: str repository: str date: str response: DailyContributionResponse commit_hashes: List[str] = field(default_factory=list) def to_dict(self): """Converts the dataclass to a dictionary, including nested response.""" data = asdict(self) data["response"] = self.response.to_dict() return data @dataclass class User: user_handle: str github_name: str repositories: List[str] ai_decisions: List[List[AIDecision]] = field(default_factory=list) total_daily_contribution_number: int = 0 total_qualified_daily_contribution_number: int = 0 qualified_daily_contribution_number_by_month: Dict[str, int] = field( default_factory=dict ) qualified_daily_contribution_dates: set = field(default_factory=set) qualified_daily_contribution_streak: int = 0 def validate(self) -> bool: """Validates the User instance.""" if not isinstance(self.repositories, list) or not all( isinstance(repo, str) for repo in self.repositories ): logger.error("Invalid repository list") return False return True def to_dict(self): """Converts the dataclass to a dictionary.""" return { "user_handle": self.user_handle, "github_name": self.github_name, "repositories": self.repositories, "ai_decisions": [ [decision.to_dict() for decision in decisions] for decisions in self.ai_decisions ], "total_daily_contribution_number": self.total_daily_contribution_number, "total_qualified_daily_contribution_number": self.total_qualified_daily_contribution_number, "qualified_daily_contribution_number_by_month": self.qualified_daily_contribution_number_by_month, "qualified_daily_contribution_dates": list( self.qualified_daily_contribution_dates ), "qualified_daily_contribution_streak": self.qualified_daily_contribution_streak, } @staticmethod def from_dict(data: Dict[str, Any]) -> "User": """Creates a User instance from a dictionary.""" ai_decisions = [ [ AIDecision( username=decision["username"], repository=decision["repository"], date=decision["date"], response=DailyContributionResponse( username=decision["response"]["username"], date=decision["response"]["date"], is_qualified=decision["response"]["is_qualified"], explanation=decision["response"]["explanation"], ), commit_hashes=decision.get( "commit_hashes", [] ), ) for decision in decisions ] for decisions in data.get("ai_decisions", []) ] return User( user_handle=data["user_handle"], github_name=data["github_name"], repositories=data.get("repositories", []), ai_decisions=ai_decisions, total_daily_contribution_number=data.get( "total_daily_contribution_number", 0 ), total_qualified_daily_contribution_number=data.get( "total_qualified_daily_contribution_number", 0 ), qualified_daily_contribution_number_by_month=data.get( "qualified_daily_contribution_number_by_month", {} ), qualified_daily_contribution_dates=set( data.get("qualified_daily_contribution_dates", []) ), qualified_daily_contribution_streak=data.get( "qualified_daily_contribution_streak", 0 ), ) ```

MongoDBManagement

This class can be used to initalize and use database management. Explained here

Scripts

Scripts Explanation

Helpers

Helper functions explanations

Database Management

This database management script provides functionalities to manage user data and AI decisions in a MongoDB database. It supports creating, reading, updating, and deleting user records, as well as managing AI decisions and contribution data associated with users.

Features

  1. User Management:
    • Create, Read, Update, Delete (CRUD) Operations: Manage user records in the database including creation, retrieval, updating user details, and deletion.
    • Validation: Each user instance undergoes validation to ensure data integrity before any CRUD operation.
  2. AI Decision Handling:
    • Retrieve AI Decisions: Fetch AI decisions based on user identity, with options to filter by date range.
    • Add AI Decisions: Append new AI decisions to a user’s existing record.
    • Update Contribution Data: Recalculates and updates user statistics based on new AI decisions, utilizing helper functions for detailed metrics like total and qualified contributions, monthly breakdowns, and streak calculations. These calculations made in here.
  3. Contribution Data Management:
    • Get/Set Operations for Contribution Metrics: Retrieve or update contribution-related metrics such as total daily contributions, qualified contributions, and contribution streaks.
    • Date-wise Management: Manage specific dates for qualified contributions, allowing for additions, updates, and retrieval.

Leaderbot

Discord Bot for interacting with Google Sheets and data received from Github Scraper Bot to Mongo DB.

Usage

Explained here.

Additionally, need to enable google drive api to use sheet sharing functionality. username variables are discord handles.

Commands

/commits-sheet-create

Description: Creates a Google Sheet with contributions data.

Usage:

/commits-sheet-create spreadsheet_name: <name> email_address: <optional email>

/commits-sheet-update

Description: Updates the Google Sheet with the latest contributions data in the Mongo DB.

Usage:

/commits-sheet-update spreadsheet_id: <id>

/leaderboard-create

Description: Creates and updates a leaderboard sheet in the specified sheet for a specific month by using current data. If spreadsheet_id is empty it will use the last created or updated sheet id. After creating the leaderboard, it will send the leaderboard to discord channel as message. If the leaderboard exists for specified date, it updates the leaderboard.

Usage:

/leaderboard-create spreadsheet_id: <optional id> date: <YYYY-MM>

/leaderboard-view

Description: Displays the leaderboard in the specified Discord Forum thread.

Usage:

/leaderboard-view thread_id: <THREAD_ID> date: <YYYY-MM>

/main-sheet-edit

Description: Creates a modal to edit the Google Sheet which includes commits data from Discord.

Usage:

/main-sheet-edit operation: <operation>

/leaderboard-start-auto-post

Description: Automatically posts the leaderboard and updates the sheet with given id every day at a specified time.

Usage:

/leaderboard-start-auto-post date: <YYYY-MM> time: <HH:MM> spreadsheet_id: <optional id>

/leaderboard-stop-auto-post

Description: Stops the auto-post leaderboard task started for a specific date.

Usage:

/leaderboard-stop-auto-post date: <YYYY-MM>

/leaderboard-closure-month

Description: Opens a thread that includes the Leaderboard for the month. Gets the forum channel ID from the .env file and exports the user data which contributed in the given month as csv.

Usage:

/leaderboard-closure-month date: <YYYY-MM> commit_filter: <commit_filter>

/get-monthly-streaks

Description: Gets monthly streaks of users and creats thread to forum channel.

Usage: /get-monthly-streaks date: <YYYY-MM>

/get-members-and-insert-to-db

Description: Gets and inserts all members of the guild to the db in new collection with their username and discord id.

Usage: /get-members-and-insert-to-db

/run-task

Description: Uses the Github Tracker Bot API /run-task endpoint.

Usage: /run-task since: <since> until: <until>

Note: It is okay to get An Error Occured message after some time in the discord because the API request will take long time.

/run-task-for-user

Description: Uses the Github Tracker Bot API /run-task-for-user endpoint.

Usage: /run-task-for-user username: <username> since: <since> until: <until>

/control-scheduler

Description: Uses the Github Tracker Bot API /control-scheduler endpoint to control the scheduler (start/stop) with an optional interval.

Usage: /control-scheduler action: <action> interval: <interval>

/get-ai-decisions-by-user

Description: Exports AI decisions as csv file for specific user between given dates.

Usage: /get-ai-decisions-by-user username: <username> since: <since> until: <until>

/get-all-data-to-csv

Description: Exports all database user data to csv file.

Usage: /get-all-data-to-csv

/get-blockchain-summary

Description: Fetchs MINA Explorer Rest api and sends blockchain summary as a message

Usage: /get-blockchain-summary

/get-user-monthly-data-to-csv

Description: Export a specific user's monthly qualified contribution data for each day of a month

Usage: /get-user-monthly-data-to-csv username: <username> date: <date>

/delete-all-data

Description: Deletes all data between specific dates

Usage: /delete-all-data from: <from> until: <until>

After using this command, there will be a modal to confirm the deletion process. In order to confirm the deletion, you need to enter your discord username and exact same dates with the command. Warning : This process cannot be reverted.


Contributions

To make a contribution, follow these steps:

  1. Make an issue that includes details about the feature or bug or something else.

    Leaderboard Updates: Ranks contributors based on predefined metrics (KPI): 10+ days of qualified commits within a month.

  2. Get that issue tested by: Cristina Echeverry.
  3. Get that issue approved by the product owners: es92 or Cristina Echeverry.
  4. Write a PR and get it approved by the code owners and Mina devops: Es92 (code owner), berkingurcan (developer & codeco-owner), johnmarcou (Mina devops). Each PR must correspond to an approved issue. By default, PRs should be merged by the PR submitter, though in some cases if changes are needed, they can be merged by code owners.