Files
euri-iso/.github/workflows/ai-moderator.yml
T

131 lines
4.3 KiB
YAML

name: AI Moderator
on:
issues:
types: [opened]
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
permissions:
issues: write
pull-requests: write
contents: read
jobs:
moderate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/github-script@v9
env:
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
with:
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;
}
let coc = '';
let contributing = '';
try { coc = fs.readFileSync('.github/CODE_OF_CONDUCT.md', 'utf8'); } catch (e) {}
try { contributing = fs.readFileSync('CONTRIBUTING.md', 'utf8'); } catch (e) {}
const prompt = [
'You are a community moderator for the Antergos NeXT project.',
'',
'Code of Conduct:',
coc,
'',
'Contributing Guidelines:',
contributing,
'',
'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 or empty", "severity": 1-10}',
'',
'Content:',
content
].join('\n');
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.'
].join('\n');
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}`);
}