124 lines
3.7 KiB
YAML
124 lines
3.7 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;
|
|
}
|
|
|
|
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}`);
|
|
}
|