Introduction
If you constitute for a surviving aliases arsenic a hobby, you mightiness person noticed that while individual penning tin travel immoderate structure, master penning needs to adhere to definite style and penning guides and acquisition definite reviews earlier being published.
This tutorial is for those pinch GitHub-based workflows and a desire to speed-up the reappraisal process. You will study to instrumentality a solution that leverages AI to accelerate the reappraisal process by creating a GitHub action trained connected your penning and style guides. This action will cheque for issues, place them and propose really you tin amended it.
Prerequisites
- Introductory knowledge connected yaml to build the GitHub Action.
- Working knowledge of JavaScript.
- A DigitalOcean account to usage the GenAI platform to train the GitHub Action accordingly.
The problem and really to lick it?
Reviews return clip and are usually manual pinch immoderate checks successful place. Manual reviews tin return longer erstwhile the workload is heavy, adding to the backlog.
You will build a GitHub action that uses AI trained connected your method guides and documentation. It learns your company’s aliases team’s penning style and past suggests changes accordingly. This importantly reduces the reappraisal clip from a fewer days to a fewer seconds.
This is really the GitHub action works:
The GitHub action is already available connected the marketplace, truthful you do not request to build it from scratch. You tin straight usage it connected your repositories, trained connected your data.
This will impact 2 main steps:
- Deploying a DigitalOcean GenAI agent trained connected your tutorials.
- Adding the workflow record to your repositories to usage the GitHub action.
Building the DigitalOcean GenAI agent
In this step, we will spot really we tin build the GenAI agent that reviews the markdown files you perpetrate and gives suggestions based connected your penning style.
You will request to adhd and scale a knowledge guidelines to guarantee the supplier is trained connected your tutorials.
Now that we person created a knowledge base, we will move up pinch creating an supplier and referencing the knowledge guidelines to the agent. For that:
- Go to the GenAI Platform action connected the near pane and click Create agent.
- Give it a unsocial name, and constitute a punctual thing akin to:
And that’s really you person completed training and building an AI agent. This was the first and the astir basal step.
Using the GitHub Action
Now that the AI supplier is created, the adjacent measurement is to usage the GitHub Action connected your repositories.
1. Copy the supplier endpoint, and from the Settings tab, create a cardinal and support it copied. These are needed to entree the GenAI agent.
2. Then, spell to your repository. From the Settings tab, nether Actions, adhd the endpoint and key, arsenic shown successful the screenshot below.
3. Then, successful your repository, successful the workflow folder, create a .yml record (e.g., .github/workflows/grammar-check.yml)and paste the pursuing code:
name: Check Markdown Grammar on: pull_request: types: [ opened, synchronize, reopened] paths: - '**.md' workflow_dispatch: jobs: check-markdown: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Get changed files id: changed-files uses: tj-actions/changed-files@v41 with: files: | **/*.md files_ignore: | **/node_modules/** - name: Check Markdown Grammar if: steps.changed-files.outputs.all_changed_files != '' uses: Haimantika/article-review-github-[email protected] with: do-api-token: ${{ secrets.DO_API_TOKEN }} do-agent-base-url: ${{ secrets.DO_AGENT_BASE_URL }} file-pattern: ${{ steps.changed-files.outputs.all_changed_files }} exclude-pattern: '**/node_modules/**,**/vendor/**'4. To trial the action, unfastened a pull request pinch a markdown file, and you will spot it moving the check. It will neglect if location are immoderate issues; if not, it will walk and beryllium fresh to beryllium merged.
Building your ain GitHub Action
The first measurement is to constitute a workflow record that automatically triggers the action erstwhile a propulsion petition is opened. It checks the grammar and penning style of the markdown record utilizing a grammar-checker.js script.
This is really the codification will look:
name: Markdown Grammar Checker on: pull_request: types: [ opened, synchronize, reopened] paths: - '**.md' workflow_dispatch: jobs: grammar-check: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm instal axios - name: Get changed files id: changed-files uses: tj-actions/changed-files@v41 with: files: | **/*.md files_ignore: | **/node_modules/** - name: Run grammar checks env: DO_API_TOKEN: ${{ secrets.DO_API_TOKEN }} DO_AGENT_BASE_URL: ${{ secrets.DO_AGENT_BASE_URL }} run: | if [ "${{ steps.changed-files.outputs.all_changed_files }}" == "" ]; then echo "No markdown files changed successful this PR. Skipping grammar check." exit 0 fi echo "Running grammar checks connected changed files..." for record successful ${{ steps.changed-files.outputs.all_changed_files }}; do echo "Checking grammar successful $file..." node grammar-checker.js "$file" doneThe adjacent measurement is to constitute the book that scans the markdown file(s) raised successful a propulsion request, extracts plain matter from them, sends the matter to DigitalOcean’s AI Agent for grammar checking, and reports immoderate detected issues.
You person already learned astatine the opening of the article really to create an AI agent utilizing DigitalOcean. So travel those steps.
The codification for that will be:
const fs = require('fs'); const way = require('path'); const axios = require('axios'); const AGENT_BASE_URL = process.env.DO_AGENT_BASE_URL || 'https://agent-aaf74f4416df5696a67b-o4npv.ondigitalocean.app'; const AGENT_ENDPOINT = `${AGENT_BASE_URL}/api/v1/chat/completions`; const API_TOKEN = process.env.DO_API_TOKEN; if (!API_TOKEN) { console.error('Error: DigitalOcean API token not found. Please group the DO_API_TOKEN situation variable.'); process.exit(1); } const getAllMarkdownFiles = (dir, fileList = [], excludeDirs = ['node_modules', '.git']) => { const files = fs.readdirSync(dir); files.forEach(file => { const filePath = path.join(dir, file); if (fs.statSync(filePath).isDirectory()) { if (!excludeDirs.includes(file)) { getAllMarkdownFiles(filePath, fileList, excludeDirs); } } else if (file.endsWith('.md')) { fileList.push(filePath); } }); return fileList; }; const extractTextFromMarkdown = (content) => { let matter = content; if (content.startsWith('---')) { const endOfFrontMatter = content.indexOf('---', 3); if (endOfFrontMatter !== -1) { matter = content.slice(endOfFrontMatter + 3); } } matter = text.replace(/```[\s\S]*?```/g, ''); matter = text.replace(/<[^>]*>/g, ''); matter = text.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1'); matter = text.replace(/!\[[^\]]*\]\([^)]+\)/g, ''); return text; }; const checkGrammar = async (text) => { try { console.log("Sending petition to DigitalOcean AI agent..."); const consequence = await axios.post(AGENT_ENDPOINT, { model: "claude-3.5-sonnet", messages: [ { role: "system", content: "You are a skilled editor focused connected identifying grammatical errors, typos, incorrect condemnation structures, passive voice, and unnecessary jargon." }, { role: "user", content: `Please reappraisal the pursuing matter for grammatical errors, typos, incorrect condemnation structures, passive voice, and unnecessary jargon. For each issue, place the circumstantial problem, explicate why it's an issue, and propose a correction. Format your consequence arsenic a JSON array pinch objects containing: "issue_type", "text_with_issue", "explanation", and "suggestion". Only place existent issues. If location are nary grammatical problems, return an quiet array.\n\nText to review:\n${text}` } ], temperature: 0.0, max_tokens: 1024 }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_TOKEN}` } }); console.log("Received consequence from AI agent"); const aiResponse = response.data.choices[0].message.content; try { const jsonMatch = aiResponse.match(/\[[\s\S]*\]/); return jsonMatch ? JSON.parse(jsonMatch[0]) : []; } catch (e) { console.error('❌ Error parsing AI response:', e); console.log('AI response:', aiResponse); return []; } } catch (error) { console.error('❌ Error checking grammar:', error.message); if (error.response) { console.error('Response status:', error.response.status); console.error('Response data:', JSON.stringify(error.response.data, null, 2)); } return []; } }; const processFile = async (filePath) => { try { console.log(`\nChecking grammar successful ${filePath}...`); if (!fs.existsSync(filePath)) { console.error(`❌ Error: File does not exist: ${filePath}`); return false; } const contented = fs.readFileSync(filePath, 'utf8'); const textToCheck = extractTextFromMarkdown(content); if (textToCheck.trim().length < 50) { console.log(`⚠️ Skipping ${filePath}: Not capable matter contented to check`); return true; } console.log(`Sending contented to grammar cheque API...`); const issues = await checkGrammar(textToCheck); if (issues.length === 0) { console.log(`✅ ${filePath}: No grammar issues found`); return true; } else { console.log(`⚠️ ${filePath}: Found ${issues.length} grammar issues:`); issues.forEach((issue, index) => { console.log(` ${index + 1}. ${issue.issue_type}: "${issue.text_with_issue}"`); console.log(` Explanation: ${issue.explanation}`); console.log(` Suggestion: ${issue.suggestion}`); console.log(); }); return false; } } catch (error) { console.error(`❌ Error processing ${filePath}:`, error.message); return false; } }; const checkAllFiles = async () => { let markdownFiles = []; if (process.argv.length > 2) { markdownFiles = process.argv.slice(2); console.log(`Checking grammar successful circumstantial file(s): ${markdownFiles.join(', ')}`); } else { markdownFiles = getAllMarkdownFiles('.'); console.log(`Found ${markdownFiles.length} markdown files to cheque for grammar`); } if (markdownFiles.length === 0) { console.log('No files to check.'); return true; } let allValid = true; for (const record of markdownFiles) { const fileValid = await processFile(file); if (!fileValid) { allValid = false; } } return allValid; }; checkAllFiles().then(allValid => { if (!allValid) { console.error('\n❌ Grammar cheque failed: Issues were found'); process.exit(1); } else { console.log('\n✅ Grammar cheque passed: No issues were found'); process.exit(0); } }).catch(error => { console.error('❌ Error moving grammar check:', error.message); process.exit(1); });Before your action is fresh to beryllium utilized by the public, you request to trial it locally and guarantee it useful arsenic expected.
Once that is done, create an action.yml record that defines your action’s metadata:
name: 'Markdown Grammar Checker' description: 'Checks markdown files for grammar, style, and formatting issues utilizing AI' author: 'Your Name' inputs: github-token: description: 'GitHub token for accessing PR files' required: true default: ${{ github.token }} do-api-token: description: 'DigitalOcean API token' required: true do-agent-base-url: description: 'DigitalOcean AI supplier guidelines URL' required: true file-pattern: description: 'Glob shape for files to check' required: false default: '**/*.md' exclude-pattern: description: 'Glob shape for files to exclude' required: false default: '**/node_modules/**' runs: using: 'node16' main: 'index.js' branding: icon: 'book' color: 'blue'- Then, create an index.js record that useful pinch the GitHub Actions toolkit.
- Create a package.json record that contains each the requirements.
- Once everything is done, you tin make a merchandise and publish it connected marketplace.
- Then, finally, adhd the yml record that users request to adhd to their workflow record to usage your action. It will look thing for illustration this:
And that’s really you tin build your GitHub action!
Conclusion
In this tutorial, you learned really to build a broad AI article reviewer strategy utilizing DigitalOcean’s GenAI Platform and GitHub Actions. The strategy is designed to streamline method penning reappraisal processes by leveraging AI capabilities to cheque for grammatical errors, propose improvements, and guarantee consistency pinch your team’s penning style.
If you would for illustration to study much astir DigitalOcean, make judge to travel these resources:
- DigitalOcean Documentation.
- DigitalOcean YouTube.
- DigitalOcean Discord Community.