fix: swap AI moderator from GitHub Models to Groq (free tier)

This commit is contained in:
2026-07-30 19:01:49 +02:00
parent bf72bb5bf4
commit dc44cfcba2
+105 -13
View File
@@ -1,31 +1,123 @@
name: AI Community Moderator
name: AI Moderator
on:
issues:
types: [opened]
pull_request:
types: [opened]
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
discussion:
types: [created]
discussion_comment:
types: [created]
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
models: read
contents: read
jobs:
moderate:
runs-on: ubuntu-latest
steps:
- uses: benbalter/ai-community-moderator@main
- uses: actions/checkout@v4
- uses: actions/github-script@v9
env:
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
severity-threshold: 5
script: |
const fs = require('fs');
const content = context.payload.issue?.body
|| context.payload.comment?.body
|| '';
if (!content.trim()) {
console.log('No content to analyze');
return;
}
const coc = fs.readFileSync('.github/CODE_OF_CONDUCT.md', 'utf8');
const prompt = `You are a community moderator for the Antergos NeXT project.
Code of Conduct:
${coc}
Analyze the following content for violations of this Code of Conduct.
Respond with ONLY valid JSON — no markdown, no backticks, no explanation.
{
"violation": true/false,
"reason": "short reason if violation else empty",
"severity": 1-10
}
Content:
${content}`;
const model = 'llama-3.1-8b-instant';
let decision;
try {
const response = await fetch('https://api.groq.com/openai/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.GROQ_API_KEY}`
},
body: JSON.stringify({
model,
messages: [
{ role: 'system', content: 'You are a helpful community moderator. Respond only with valid JSON as instructed.' },
{ role: 'user', content: prompt }
],
temperature: 0.1,
max_tokens: 150
})
});
const data = await response.json();
const raw = data.choices?.[0]?.message?.content || '{}';
decision = JSON.parse(raw.replace(/```json|```/g, '').trim());
console.log(`Decision: ${JSON.stringify(decision)}`);
} catch (err) {
console.log(`API error: ${err}`);
return;
}
if (!decision.violation) {
console.log('Content deemed acceptable');
return;
}
const issueNumber = context.payload.issue?.number
|| context.payload.pull_request?.number;
if (!issueNumber) {
console.log('No issue/PR number found');
return;
}
const warning = `**AI Moderator Notice**
Your comment appears to violate the project's [Code of Conduct](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/blob/master/.github/CODE_OF_CONDUCT.md).
Reason: ${decision.reason}
Please keep discussions respectful and constructive. Repeated violations may result in moderation actions.`;
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: warning
});
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: ['ai-moderated']
});
console.log('Warning posted and label added');
} catch (err) {
console.log(`GitHub API error: ${err}`);
}