ci(icons): Add ChatGPT tags suggestions on icon PRs (#3372)

* Add gpt tags

* Add github actions flow

* Add link so people can use the chat

* Fix workflow

* Add openai dep

* Add actions core

* Try gh pr review in actions

* Try with octokit

* Remove changed files part

* Try with createReview function

* Try this

* fix broken json file

* Turn on review by gh action

* Try this

* Update icons/trash.json

* Update the runner

* Remove added tags

* Add more checks
This commit is contained in:
Eric Fennis
2025-06-27 17:11:00 +02:00
committed by GitHub
parent 110d8cce27
commit 0e54626bdb
6 changed files with 366 additions and 2 deletions

124
scripts/suggestTags.mts Normal file
View File

@@ -0,0 +1,124 @@
import OpenAI from "openai";
import { Octokit } from "@octokit/rest";
import { zodTextFormat } from "openai/helpers/zod";
import path from "node:path";
import fs from "node:fs/promises";
import z from "zod";
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const pullRequestNumber = Number(process.env.PULL_REQUEST_NUMBER);
const username = process.env.REVIEWER ?? 'github-actions[bot]';
const commitSha = process.env.COMMIT_SHA ?? "HEAD";
const owner = 'lucide-icons';
const repo = 'lucide';
const tagsSchema = z.object({
tags: z.array(z.string()),
})
const { data: files } = await octokit.pulls.listFiles({
owner,
repo,
pull_number: pullRequestNumber,
});
const { data: reviews } = await octokit.pulls.listReviews({
owner,
repo,
pull_number: pullRequestNumber,
query: `in:body author:github-actions[bot]`,
});
const hasUserReviews = reviews.some(review => review.user?.login === username);
// TODO: Find a better way to check if the PR has been updated since the last review
if(hasUserReviews) {
console.log(`Pull request #${pullRequestNumber} already has reviews from ${username}. Skipping...`);
process.exit(0);
}
const changedFiles = files
.map((file) => file.filename)
.filter((file) => file.startsWith('icons/') && file.includes('.json'))
.filter((file, idx, arr) => arr.indexOf(file) === idx);;
if (changedFiles.length === 0) {
console.log('No changed icons found');
process.exit(0);
}
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const suggestionsByFile = changedFiles.map(async (file) => {
const filePath = file.replace('.json', '');
const iconName = filePath.split('/').pop();
const input = `Create a list of tags for a \`${iconName}\` icon. Don't include words like: 'icon' and preferably use single words.`;
const response = await client.responses.create({
model: "gpt-4.1-nano",
input,
text: {
format: zodTextFormat(tagsSchema, "tags"),
},
});
const { tags: suggestedTags } = JSON.parse(response.output_text);
console.log(`Suggesting tags for ${iconName}:`, suggestedTags);
// const currentContent = require(`../${filePath}`);
const jsonFile = path.join(process.cwd(), file);
const currentFileContent = await fs.readFile(jsonFile, 'utf-8') as unknown as string;
const metaData = JSON.parse(currentFileContent);
console.log(`Current tags for ${iconName}:`, metaData.tags || []);
const tagSuggestionsWithoutDuplicates = suggestedTags.filter((tag) => {
return !metaData.tags?.includes(tag) && tag !== iconName;
});
console.log(`Tag suggestions for ${iconName} without duplicates:`, tagSuggestionsWithoutDuplicates);
if (tagSuggestionsWithoutDuplicates.length === 0) {
console.log(`No new tags to suggest for ${iconName}. Skipping...`);
return Promise.resolve(null);
}
// Find the startLine in the json file
const startLine = currentFileContent.split('\n').findIndex((line) => line.includes('"tags":')) + 1;
const codeSuggestion = tagSuggestionsWithoutDuplicates.map((tag) => ` "${tag}"`).join(',\n');
const message = `Suggestions for the \`${iconName}\` icon.
Try asking it your self if you want more suggestions. [Open ChatGPT](https://chatgpt.com/?q=${encodeURIComponent(input)})
Here are the suggestions:
\`\`\`suggestion\n "tags": [\n${codeSuggestion},`;
return {
path: file,
line: startLine,
body: message,
}
})
const comments = (await Promise.all(suggestionsByFile)).filter(comment => comment !== null)
if (comments.length === 0) {
console.log('No new tags to suggest for any icons.');
process.exit(0);
}
await octokit.pulls.createReview({
owner,
repo,
pull_number: pullRequestNumber,
body: `### 🤖 ChatGPT Tags suggestions ✨
I've asked ChatGPT for some suggestions for tags.`,
event: "COMMENT",
comments,
commit_id: commitSha,
});