Last active
April 27, 2023 15:12
-
-
Save 0x666c6f/cc020f0ac4cb603b044e69b1a8893008 to your computer and use it in GitHub Desktop.
OD Committee scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const Airtable = require('airtable'); | |
| // Configure the Airtable base | |
| const apiKey = '<API_KEY>'; | |
| const baseId = '<BASE_ID>'; | |
| const committeeId = '<COMMITTEE_ID>'; | |
| const base = new Airtable({ apiKey: apiKey }).base(baseId); | |
| // Define the tables | |
| const committeesTable = base('Committees'); | |
| const jurorsTable = base('Jurys'); | |
| const projectsTable = base('Projects'); | |
| const votesTable = base('Votes'); | |
| function chunkArray(array, size) { | |
| return Array.from({ length: Math.ceil(array.length / size) }, (_, index) => | |
| array.slice(index * size, (index + 1) * size) | |
| ); | |
| } | |
| // Define a function to shuffle an array | |
| function shuffleArray(array) { | |
| for (let i = array.length - 1; i > 0; i--) { | |
| const j = Math.floor(Math.random() * (i + 1)); | |
| [array[i], array[j]] = [array[j], array[i]]; | |
| } | |
| } | |
| // Retrieve all records from the committees table | |
| committeesTable | |
| .select({ view: 'Grid view' }) | |
| .all() | |
| .then(committees => { | |
| // Retrieve all records from the jurors table | |
| jurorsTable | |
| .select({ view: 'Grid view' }) | |
| .all() | |
| .then(jurors => { | |
| // Retrieve all records from the projects table | |
| projectsTable | |
| .select({ view: 'Grid view' }) | |
| .all() | |
| .then(projects => { | |
| const committee_projects = projects.filter(project => { | |
| return project.fields.Committee && project.fields.Committee.includes(committeeId); | |
| }); | |
| // Create an array of all the project IDs | |
| const projectIds = committee_projects.map(project => project.id); | |
| // Create an array to store all the votes to create | |
| let votesToCreate = []; | |
| // Assign projects to jurors ensuring even distribution | |
| const assignedProjects = new Map(); | |
| for (let i = 0; i < projectIds.length; i++) { | |
| assignedProjects.set(projectIds[i], []); | |
| } | |
| // Assign projects to jurors | |
| const assignments = new Map(); | |
| jurors.forEach(jury => { | |
| assignments.set(jury.id, []); | |
| }); | |
| // Assign projects to jurors using a round-robin approach | |
| let jurorIndex = 0; | |
| for (let i = 0; i < 12 * jurors.length; i++) { | |
| const projectId = projectIds[i % projectIds.length]; | |
| const jurorId = jurors[jurorIndex].id; | |
| if (!assignments.get(jurorId).includes(projectId)) { | |
| assignedProjects.get(projectId).push(jurorId); | |
| assignments.get(jurorId).push(projectId); | |
| } else { | |
| i--; | |
| } | |
| jurorIndex = (jurorIndex + 1) % jurors.length; | |
| } | |
| // Ensure each project has at least 4 jurors | |
| projectIds.forEach(projectId => { | |
| const jurorsAssigned = assignedProjects.get(projectId); | |
| let attempts = 0; | |
| while (jurorsAssigned.length < 4 && attempts < 1000) { | |
| const randomJurorIndex = Math.floor(Math.random() * jurors.length); | |
| const randomJurorId = jurors[randomJurorIndex].id; | |
| if (!jurorsAssigned.includes(randomJurorId) && assignments.get(randomJurorId).length < 12) { | |
| jurorsAssigned.push(randomJurorId); | |
| assignments.get(randomJurorId).push(projectId); | |
| } | |
| attempts++; | |
| } | |
| }); | |
| // Create vote objects for each juror-project assignment | |
| for (const [projectId, jurorIds] of assignedProjects.entries()) { | |
| jurorIds.forEach(jurorId => { | |
| const vote = { | |
| fields: { | |
| Committee: [committeeId], // Only one committee available in example data | |
| Jury: [jurorId], | |
| Project: [projectId], | |
| }, | |
| }; | |
| votesToCreate.push(vote); | |
| }); | |
| } | |
| // Chunk the votes into groups of 10 to create them in batches | |
| const chunkedVotesToCreate = chunkArray(votesToCreate, 10); | |
| // Create the votes in batches | |
| chunkedVotesToCreate.forEach(chunk => { | |
| votesTable.create(chunk, (err, records) => { | |
| if (err) { | |
| console.error(err); | |
| return; | |
| } | |
| }); | |
| }); | |
| }).catch((error) => { | |
| console.log(error); | |
| }); | |
| }).catch((error) => { | |
| console.log(error); | |
| }); | |
| }).catch((error) => { | |
| console.log(error); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import csv | |
| import locale | |
| # Set the locale to use a comma as the decimal separator | |
| locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8') | |
| # Open the CSV file for reading | |
| with open('votes.csv', newline='', encoding='utf-8') as csvfile: | |
| reader = csv.DictReader(csvfile, delimiter=';') | |
| # Create a dictionary to store the total note and count for each project | |
| project_totals = {} | |
| # Iterate over each row in the CSV file | |
| for row in reader: | |
| # Check if the row has missing data | |
| if not row['Project name'] or not row['Note']: | |
| print(f'Skipping row with missing data: {row}') | |
| continue | |
| # Extract the project name and note from the row | |
| project_name = row['Project name'] | |
| note = float(row['Note'].replace(',', '.')) | |
| # If this is the first vote for the project, create a new entry in the dictionary | |
| if project_name not in project_totals: | |
| project_totals[project_name] = {'total_note': note, 'vote_count': 1} | |
| # If the project already exists in the dictionary, update the total note and vote count | |
| else: | |
| project_totals[project_name]['total_note'] += note | |
| project_totals[project_name]['vote_count'] += 1 | |
| # Calculate the average note for each project | |
| project_averages = {project_name: totals['total_note'] / totals['vote_count'] for project_name, totals in project_totals.items()} | |
| # Sort the projects by descending order of the average note | |
| sorted_projects = sorted(project_averages.items(), key=lambda x: x[1], reverse=True) | |
| # Write the results to a CSV file | |
| with open('average_notes.csv', 'w', newline='', encoding='utf-8') as outfile: | |
| writer = csv.writer(outfile, delimiter=';') | |
| writer.writerow(['Project', 'Average Note']) | |
| # Sort the lines in the output by descending order of the average note | |
| for project_name, average_note in sorted(sorted_projects, key=lambda x: x[1], reverse=True): | |
| writer.writerow([project_name, locale.format_string('%.2f', average_note, grouping=True)]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import csv | |
| import os | |
| def create_raw_text_file(row): | |
| raw_text = "" | |
| raw_text += f"{row[2]}\n\n\n" # project name | |
| raw_text += f"Project lead\n{'-' * len('Project lead')}\n{row[1]}\n\n" # project lead | |
| raw_text += f"Project description\n{'-' * len('Project description')}\n{row[3]}\n\n" # project website | |
| raw_text += f"Project repositories\n{'-' * len('Project repositories')}\n{row[4]}\n\n" # project repositories | |
| raw_text += f"Project website\n{'-' * len('Project website')}\n{row[5]}\n\n" # project website | |
| raw_text += f"Project lead and team members\n{'-' * len('Project lead and team members')}\n{row[6]}\n\n" # project lead and team members | |
| raw_text += f"How does the project add value to the Starknet ecosystem?\n{'-' * len('How does the project add value to the Starknet ecosystem?')}\n{row[7]}\n\n" # how does the project add value | |
| raw_text += f"Project status\n{'-' * len('Project status')}\n{row[8]}\n\n" # project status | |
| raw_text += f"Project license\n{'-' * len('Project license')}\n{row[9]}\n\n" # project license | |
| raw_text += f"Project timeline and milestones\n{'-' * len('Project timeline and milestones')}\n{row[10]}\n\n" # project timeline and milestones | |
| raw_text += f"Funding request and usage\n{'-' * len('Funding request and usage')}\n{row[11]}\n\n" # funding request and usage | |
| raw_text += f"Funding or grants received\n{'-' * len('Funding or grants received')}\n{row[12]}\n\n" # funding or grants received | |
| raw_text += f"Project metrics\n{'-' * len('Project metrics')}\n{row[13]}\n\n" # project metrics | |
| raw_text += f"Additional information or comments\n{'-' * len('Additional information or comments')}\n{row[14]}\n\n" # additional information or comments | |
| filename = row[2][:30] + ".txt" # max 30 characters for filename | |
| with open(os.path.join("output", filename), "w") as f: | |
| f.write(raw_text) | |
| if not os.path.exists("output"): # create output directory if it doesn't exist | |
| os.mkdir("output") | |
| with open("input.csv", newline="", encoding="utf-8") as csvfile: | |
| reader = csv.reader(csvfile, delimiter=",", quotechar='"') | |
| next(reader) # skip header row | |
| for row in reader: | |
| create_raw_text_file(row) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const Airtable = require('airtable'); | |
| // Configure the Airtable base | |
| const apiKey = '<API_KEY>'; | |
| const baseId = '<BASE_ID>'; | |
| const committeeId = '<COMMITTEE_ID>'; | |
| const base = new Airtable({ apiKey: apiKey }).base(baseId); | |
| // Define the tables | |
| const jurorsTable = base('Jurys'); | |
| const projectsTable = base('Projects'); | |
| const votesTable = base('Votes'); | |
| // Initialize counts | |
| const projectsAssignedByJurors = {}; | |
| const jurorsPerProject = {}; | |
| // Retrieve all records from the jurors table | |
| jurorsTable | |
| .select({ view: 'Grid view' }) | |
| .all() | |
| .then(jurors => { | |
| // Retrieve all records from the projects table | |
| projectsTable | |
| .select({ view: 'Grid view' }) | |
| .all() | |
| .then(projects => { | |
| // Retrieve all records from the votes table | |
| votesTable | |
| .select({ view: 'Grid view' }) | |
| .all() | |
| .then(votes => { | |
| const committee_votes = votes.filter(vote => { | |
| return vote.fields.Committee && vote.fields.Committee.includes(committeeId); | |
| }); | |
| // Process the votes | |
| committee_votes.forEach(vote => { | |
| const jurorId = vote.get('Jury')[0]; | |
| const projectId = vote.get('Project')[0]; | |
| // Count the number of projects assigned by jurors | |
| projectsAssignedByJurors[jurorId] = (projectsAssignedByJurors[jurorId] || 0) + 1; | |
| // Count the number of jurors per project | |
| jurorsPerProject[projectId] = (jurorsPerProject[projectId] || 0) + 1; | |
| }); | |
| // Output the number of projects assigned by jurors | |
| console.log('Projects assigned by jurors:'); | |
| Object.entries(projectsAssignedByJurors).forEach(([jurorId, count]) => { | |
| const juror = jurors.find(j => j.id === jurorId); | |
| console.log(`${juror.get('Name')}: ${count} projects`); | |
| }); | |
| console.log('\n'); | |
| // Output the number of jurors per project | |
| console.log('Jurors per project:'); | |
| Object.entries(jurorsPerProject).forEach(([projectId, count]) => { | |
| const project = projects.find(p => p.id === projectId); | |
| if (project != undefined) { | |
| console.log(`${project.get('Name')}: ${count} jurors`); | |
| } | |
| }); | |
| }); | |
| }); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment