chore(scripts): add script to generate contributor commits

This commit is contained in:
Fatih Kadir Akın
2025-12-13 15:24:45 +03:00
parent 639b34ec1a
commit 1282b2cb04
3 changed files with 93 additions and 228 deletions

View File

@@ -11,12 +11,6 @@
</a>
<br>
<sub>With Clemta, you can run your company from the comfort of your home.</sub>
<hr>
<a href="https://github.com/f/mcptools" align="center" target="_blank">
<img height="60" alt="MCPTools logo" src="https://github.com/f/mcptools/raw/master/.github/resources/logo.png">
</a>
<br>
<sub>If you're building MCPs, <a href="https://github.com/f/mcptools">MCP Tools</a> is a Swiss-army knife for MCP Servers.</sub>
<hr>
<sub><a href="https://github.com/sponsors/f/sponsorships?sponsor=f&amp;tier_id=529895">Be my sponsor and your logo will be here!</a></sub>
</div>
@@ -26,19 +20,17 @@
Welcome to the "Awesome ChatGPT Prompts" repository! While this collection was originally created for [ChatGPT](https://chat.openai.com/chat), these prompts work great with other AI models like [Claude](https://claude.ai/new), [Gemini](https://gemini.google.com), [Hugging Face Chat](https://hf.co/chat), [Llama](https://meta.ai), [Mistral](https://chat.mistral.ai), and more.
[ChatGPT](https://chat.openai.com/chat) is a web interface created by [OpenAI](https://openai.com) that provides access to their GPT (Generative Pre-trained Transformer) language models. The underlying models, like GPT-4o and GPT-o1, are large language models trained on vast amounts of text data that can understand and generate human-like text. Like other AI chat interfaces, you can provide prompts and have natural conversations with the AI, which will generate contextual responses based on the conversation history and your inputs.
In this repository, you will find a variety of [prompts](prompts.csv) that can be used with ChatGPT and other AI chat models. We encourage you to [add your own prompts](https://prompts.chat) to the list, and to use AI to help generate new prompts as well. Your contributions to [prompts.chat](https://prompts.chat) will be contributions to this repository automatically.
In this repository, you will find a variety of prompts that can be used with ChatGPT and other AI chat models. We encourage you to [add your own prompts](https://github.com/f/awesome-chatgpt-prompts/edit/main/README.md) to the list, and to use AI to help generate new prompts as well.
## Want to deploy your own private prompt library for your team?
To get started, simply clone this repository and use the prompts in the README.md file as input for your preferred AI chat model. You can also use the prompts in this file as inspiration for creating your own.
Want to deploy your own private prompt library? Check out our [Self-Hosting Guide](SELF-HOSTING.md) for instructions on setting up your own instance with customizable branding, themes, and authentication.
Check out our [Self-Hosting Guide](SELF-HOSTING.md) for instructions on setting up your own instance with **customizable branding, themes, and authentication**.
We hope you find these prompts useful and have fun exploring AI chat models!
**[View on prompts.chat](https://prompts.chat)**
**[View on Hugging Face](https://huggingface.co/datasets/fka/awesome-chatgpt-prompts/)**
**[View Hugging Face Dataset](https://huggingface.co/datasets/fka/awesome-chatgpt-prompts/)**
---
> **NOTE:** Sometimes, some of the prompts may not be working as you expected
@@ -71,14 +63,6 @@ Images from Text"**.
---
### Using prompts.chat
[prompts.chat](https://prompts.chat) is designed to provide an enhanced UX when
working with prompts. With just a few clicks, you can easily edit and copy the
prompts on the site to fit your specific needs and preferences. And contribute your own prompts to help build a better community.
---
## Unmerged Prompts
There are many Pull Requests to this repository waiting to be merged. There are

View File

@@ -0,0 +1,89 @@
#!/bin/bash
# Script to generate contributor commits from prompts.csv
# Each contributor will have one commit attributed to them so they appear in GitHub's contributors list
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
CSV_FILE="$PROJECT_DIR/prompts.csv"
CONTRIBUTORS_FILE="$PROJECT_DIR/CONTRIBUTORS.md"
if [ ! -f "$CSV_FILE" ]; then
echo "Error: prompts.csv not found at $CSV_FILE"
exit 1
fi
# Extract unique contributors from CSV
echo "Extracting contributors from prompts.csv..."
contributors=$(python3 -c "
import csv
contributors = set()
with open('$CSV_FILE', 'r') as f:
reader = csv.DictReader(f)
for row in reader:
if 'contributor' in row and row['contributor']:
contributors.add(row['contributor'].strip())
for c in sorted(contributors):
print(c)
")
# Count contributors
count=$(echo "$contributors" | wc -l | tr -d ' ')
echo "Found $count unique contributors"
# Generate CONTRIBUTORS.md file
echo "# Contributors" > "$CONTRIBUTORS_FILE"
echo "" >> "$CONTRIBUTORS_FILE"
echo "Thank you to all the contributors who have helped make this project better!" >> "$CONTRIBUTORS_FILE"
echo "" >> "$CONTRIBUTORS_FILE"
i=1
while IFS= read -r username; do
if [ -n "$username" ]; then
echo "- [@$username](https://github.com/$username)" >> "$CONTRIBUTORS_FILE"
fi
done <<< "$contributors"
echo "" >> "$CONTRIBUTORS_FILE"
echo "---" >> "$CONTRIBUTORS_FILE"
echo "*This file is auto-generated from prompts.csv*" >> "$CONTRIBUTORS_FILE"
# Stage the file
git add "$CONTRIBUTORS_FILE"
# Create commits for each contributor
echo ""
echo "Creating commits for each contributor..."
i=1
while IFS= read -r username; do
if [ -n "$username" ]; then
email="${username}@users.noreply.github.com"
# Amend or create commit with contributor as author
# We use --allow-empty to create empty commits if needed
# Each contributor gets credited by adding their line specifically
# Create a unique change for this contributor
echo "[$i/$count] Adding contributor: $username"
# Use git commit with author override
GIT_AUTHOR_NAME="$username" \
GIT_AUTHOR_EMAIL="$email" \
GIT_COMMITTER_NAME="$username" \
GIT_COMMITTER_EMAIL="$email" \
git commit --allow-empty -m "Add prompt contribution from @$username" \
--author="$username <$email>"
((i++))
fi
done <<< "$contributors"
echo ""
echo "Done! Created $count contributor commits."
echo "Review with: git log --oneline -n $count"
echo ""
echo "To push: git push origin main"

View File

@@ -1,208 +0,0 @@
#!/usr/bin/env node
/**
* This script parses README.md to extract contributor GitHub usernames
* and updates prompts.csv to include a contributor column.
*
* Usage: node scripts/update-csv-contributors.js
*/
const fs = require('fs');
const path = require('path');
const README_PATH = path.join(__dirname, '..', 'README.md');
const CSV_PATH = path.join(__dirname, '..', 'prompts.csv');
// Parse README.md to extract prompt titles and their contributors
function parseReadme(content) {
const promptContributors = new Map();
// Split by ## Act as headers
const sections = content.split(/^## Act as /gmi);
for (let i = 1; i < sections.length; i++) {
const section = sections[i];
const lines = section.split('\n');
// First line is the title (after "Act as ")
const titleLine = lines[0].trim();
// Remove any markdown links or extra text after the title
const title = titleLine.split('\n')[0].trim();
// Look for "Contributed by:" line
const contributedLine = lines.find(line =>
line.toLowerCase().includes('contributed by:')
);
if (contributedLine) {
// Extract GitHub usernames from [@username](https://github.com/username) pattern
// Also handle [username](https://github.com/username) without @ prefix
const usernameMatches = contributedLine.matchAll(/@?([a-zA-Z0-9_-]+)\]\(https?:\/\/github\.com\/[^)]+\)/gi);
const usernames = [...usernameMatches].map(match => match[1].toLowerCase());
if (usernames.length > 0) {
// Store all contributors, joined by comma (first one is primary for import)
promptContributors.set(normalizeTitle(title), usernames.join(','));
}
}
}
return promptContributors;
}
// Normalize title for matching (remove "an ", "a ", etc.)
function normalizeTitle(title) {
return title
.replace(/^(an?\s+)/i, '')
.replace(/\s+/g, ' ')
.trim()
.toLowerCase();
}
// Parse CSV content
function parseCSV(content) {
const lines = content.split('\n');
const rows = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (!line.trim()) continue;
// Parse CSV with proper handling of quoted fields
const values = [];
let current = '';
let inQuotes = false;
for (let j = 0; j < line.length; j++) {
const char = line[j];
const nextChar = line[j + 1];
if (char === '"' && !inQuotes) {
inQuotes = true;
} else if (char === '"' && inQuotes) {
if (nextChar === '"') {
current += '"';
j++;
} else {
inQuotes = false;
}
} else if (char === ',' && !inQuotes) {
values.push(current);
current = '';
} else {
current += char;
}
}
values.push(current);
rows.push(values);
}
return rows;
}
// Escape CSV field
function escapeCSV(field) {
if (field.includes(',') || field.includes('"') || field.includes('\n')) {
return '"' + field.replace(/"/g, '""') + '"';
}
return field;
}
// Main function
function main() {
console.log('Reading README.md...');
const readmeContent = fs.readFileSync(README_PATH, 'utf-8');
console.log('Parsing contributors from README.md...');
const promptContributors = parseReadme(readmeContent);
console.log(`Found ${promptContributors.size} prompts with contributors`);
console.log('\nReading prompts.csv...');
const csvContent = fs.readFileSync(CSV_PATH, 'utf-8');
const rows = parseCSV(csvContent);
// Check if contributor column already exists
const header = rows[0];
const hasContributorCol = header.includes('contributor');
if (!hasContributorCol) {
header.push('contributor');
}
// Trim header to only have 5 columns (act, prompt, for_devs, type, contributor)
rows[0] = header.slice(0, 5);
if (rows[0].length < 5) rows[0].push('contributor');
let matched = 0;
let unmatched = [];
// Process each row
for (let i = 1; i < rows.length; i++) {
const row = rows[i];
if (row.length < 1) continue;
const act = row[0].replace(/^"|"$/g, ''); // Remove surrounding quotes
const normalizedAct = normalizeTitle(act);
// Try to find contributor
let contributor = '';
// Direct match
if (promptContributors.has(normalizedAct)) {
contributor = promptContributors.get(normalizedAct);
} else {
// Try partial matching
for (const [title, user] of promptContributors) {
if (title.includes(normalizedAct) || normalizedAct.includes(title)) {
contributor = user;
break;
}
}
}
if (contributor) {
matched++;
} else {
unmatched.push(act);
}
// Trim row to 4 columns and add contributor as 5th
rows[i] = row.slice(0, 4);
rows[i].push(contributor);
}
console.log(`\nMatched ${matched} prompts with contributors`);
if (unmatched.length > 0) {
console.log(`\nUnmatched prompts (${unmatched.length}):`);
unmatched.slice(0, 10).forEach(title => console.log(` - ${title}`));
if (unmatched.length > 10) {
console.log(` ... and ${unmatched.length - 10} more`);
}
}
// Generate new CSV
console.log('\nWriting updated prompts.csv...');
const newCSV = rows.map(row => row.map(escapeCSV).join(',')).join('\n');
fs.writeFileSync(CSV_PATH, newCSV);
console.log('Done!');
// Print some stats
console.log('\n--- Contributor Stats ---');
const contributorCounts = new Map();
for (let i = 1; i < rows.length; i++) {
const contributor = rows[i][rows[i].length - 1];
if (contributor) {
contributorCounts.set(contributor, (contributorCounts.get(contributor) || 0) + 1);
}
}
const sorted = [...contributorCounts.entries()].sort((a, b) => b[1] - a[1]);
console.log(`\nTop contributors:`);
sorted.slice(0, 10).forEach(([user, count]) => {
console.log(` @${user}: ${count} prompts`);
});
}
main();