Spaces:
Sleeping
Sleeping
Mahdiyar
commited on
Commit
Β·
1f38061
1
Parent(s):
8f98e92
Add initial implementation of Hackathon Team Organizer application
Browse files- Created main application structure with `main.py` as the entry point.
- Implemented participant generation script in `generate_participants.py`.
- Set up SQLite database for participant storage with `database.py`.
- Developed AI-powered team matching logic in `matching_agent.py`.
- Added Gradio-based UI in `app.py` for participant registration and team matching.
- Included `.gitignore` to exclude unnecessary files.
- Added `README.md` for project documentation and setup instructions.
- Established requirements in `requirements.txt` for dependencies.
- .gitignore +3 -0
- generate_participants.py +372 -0
- hackathon_organizer/README.md +95 -0
- hackathon_organizer/__init__.py +1 -0
- hackathon_organizer/app.py +229 -0
- hackathon_organizer/database.py +95 -0
- hackathon_organizer/hackathon_participants.db +0 -0
- hackathon_organizer/matching_agent.py +101 -0
- hackathon_organizer/requirements.txt +7 -0
- hackathon_organizer/tests/__init__.py +1 -0
- hackathon_participants.db +0 -0
- main.py +52 -0
- product_manager/organizer.md +37 -0
- requirements.txt +6 -0
.gitignore
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.DS_Store
|
| 2 |
+
**/*.pyc
|
| 3 |
+
*.pyc
|
generate_participants.py
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Generate Synthetic Hackathon Participants
|
| 4 |
+
|
| 5 |
+
This script creates 100 diverse hackathon participants and saves them to the database.
|
| 6 |
+
The participants represent various personas that might attend a hackathon focused on
|
| 7 |
+
"Connected Experiences" and AI agents.
|
| 8 |
+
"""
|
| 9 |
+
import random
|
| 10 |
+
import sys
|
| 11 |
+
import os
|
| 12 |
+
from faker import Faker
|
| 13 |
+
from hackathon_organizer.database import initialize_database, add_participant, get_participants_dataframe
|
| 14 |
+
|
| 15 |
+
# Initialize Faker for generating realistic names and emails
|
| 16 |
+
fake = Faker()
|
| 17 |
+
|
| 18 |
+
# Define various participant personas and attributes
|
| 19 |
+
TECHNICAL_BACKGROUNDS = [
|
| 20 |
+
# Developers
|
| 21 |
+
"Full-stack developer with {years} years of experience in {stack}. {additional}",
|
| 22 |
+
"Backend engineer specializing in {backend_tech}. {additional}",
|
| 23 |
+
"Frontend developer focused on {frontend_tech}. {additional}",
|
| 24 |
+
"Mobile developer with expertise in {mobile_tech}. {additional}",
|
| 25 |
+
"DevOps engineer with experience in {devops_tech}. {additional}",
|
| 26 |
+
"Data scientist working with {ds_tech}. {additional}",
|
| 27 |
+
"Machine learning engineer focused on {ml_tech}. {additional}",
|
| 28 |
+
"AI researcher specializing in {ai_tech}. {additional}",
|
| 29 |
+
"Game developer using {game_tech}. {additional}",
|
| 30 |
+
"Embedded systems engineer working with {embedded_tech}. {additional}",
|
| 31 |
+
|
| 32 |
+
# Technical but not coding-focused
|
| 33 |
+
"UX/UI designer with {years} years of experience. {additional}",
|
| 34 |
+
"Product manager for {product_type} products. {additional}",
|
| 35 |
+
"QA engineer with expertise in {qa_tech}. {additional}",
|
| 36 |
+
"Technical writer specializing in {writing_focus}. {additional}",
|
| 37 |
+
"Solution architect with background in {arch_focus}. {additional}",
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
NON_TECHNICAL_BACKGROUNDS = [
|
| 41 |
+
"Marketing professional with experience in {marketing_focus}. {additional}",
|
| 42 |
+
"Business development specialist in the {industry} industry. {additional}",
|
| 43 |
+
"Project manager with {years} years of experience in {pm_focus}. {additional}",
|
| 44 |
+
"Entrepreneur and founder of a {startup_type} startup. {additional}",
|
| 45 |
+
"Student studying {field} at {university}. {additional}",
|
| 46 |
+
"Design thinking facilitator and innovation consultant. {additional}",
|
| 47 |
+
"Content creator focusing on {content_focus}. {additional}",
|
| 48 |
+
"Sales professional in the {sales_industry} sector. {additional}",
|
| 49 |
+
"HR specialist interested in tech talent and culture. {additional}",
|
| 50 |
+
"Non-profit professional looking to leverage technology for social impact. {additional}",
|
| 51 |
+
]
|
| 52 |
+
|
| 53 |
+
GOALS = [
|
| 54 |
+
# Learning-focused
|
| 55 |
+
"I want to learn about AI and how it can enhance user experiences at events.",
|
| 56 |
+
"I'm here to understand how to build AI agents and apply them to real-world problems.",
|
| 57 |
+
"I hope to gain practical experience with AI technologies and expand my technical skills.",
|
| 58 |
+
"I want to learn from experienced developers and improve my coding abilities.",
|
| 59 |
+
"I'm looking to understand how AI can create more meaningful human connections.",
|
| 60 |
+
|
| 61 |
+
# Project-focused
|
| 62 |
+
"I want to build a prototype that demonstrates the power of AI in connecting people.",
|
| 63 |
+
"I'm hoping to create an innovative solution that addresses the challenges of virtual events.",
|
| 64 |
+
"My goal is to develop an AI agent that enhances real-world social interactions.",
|
| 65 |
+
"I want to build something impressive for my portfolio that showcases my skills.",
|
| 66 |
+
"I'm aiming to create a practical tool that event organizers can actually use.",
|
| 67 |
+
|
| 68 |
+
# Networking-focused
|
| 69 |
+
"I'm primarily here to network with other professionals in the AI and event space.",
|
| 70 |
+
"I want to meet potential co-founders for a startup idea I've been developing.",
|
| 71 |
+
"I'm looking to connect with mentors who can guide my career in tech.",
|
| 72 |
+
"I hope to find collaborators for future projects beyond this hackathon.",
|
| 73 |
+
"I want to expand my professional network in the Toronto tech community.",
|
| 74 |
+
|
| 75 |
+
# Career-focused
|
| 76 |
+
"I'm exploring career opportunities in AI development and looking to showcase my skills.",
|
| 77 |
+
"I want to transition from my current role to a more tech-focused position.",
|
| 78 |
+
"I'm hoping this experience will help me land a job at an innovative tech company.",
|
| 79 |
+
"I want to demonstrate my abilities to potential employers or clients.",
|
| 80 |
+
"I'm building skills that will help me advance in my current organization.",
|
| 81 |
+
|
| 82 |
+
# Fun/Experience-focused
|
| 83 |
+
"I'm here for the creative experience and the thrill of building something in 24 hours.",
|
| 84 |
+
"I want to have fun while challenging myself technically.",
|
| 85 |
+
"I'm curious about hackathons and wanted to experience one firsthand.",
|
| 86 |
+
"I enjoy the collaborative atmosphere of hackathons and the energy they generate.",
|
| 87 |
+
"I'm looking for a break from my routine and a chance to work on something different.",
|
| 88 |
+
]
|
| 89 |
+
|
| 90 |
+
# Technical stack components
|
| 91 |
+
STACK_COMPONENTS = {
|
| 92 |
+
"years": [str(i) for i in range(1, 16)],
|
| 93 |
+
"stack": [
|
| 94 |
+
"JavaScript/TypeScript and Python", "MERN stack", "MEAN stack", "Ruby on Rails",
|
| 95 |
+
"Django and React", "Vue.js and Node.js", "PHP and Laravel", "Java Spring Boot",
|
| 96 |
+
".NET and Angular", "Go and React", "Python Flask and Vue.js"
|
| 97 |
+
],
|
| 98 |
+
"backend_tech": [
|
| 99 |
+
"Node.js and Express", "Django and PostgreSQL", "Ruby on Rails", "Java Spring Boot",
|
| 100 |
+
"ASP.NET Core", "PHP and Laravel", "Go microservices", "Python FastAPI",
|
| 101 |
+
"GraphQL APIs", "Serverless architectures on AWS"
|
| 102 |
+
],
|
| 103 |
+
"frontend_tech": [
|
| 104 |
+
"React and Redux", "Angular and RxJS", "Vue.js and Vuex", "Svelte and SvelteKit",
|
| 105 |
+
"Next.js", "Gatsby", "React Native", "Flutter", "TypeScript and Material UI",
|
| 106 |
+
"Tailwind CSS and Alpine.js"
|
| 107 |
+
],
|
| 108 |
+
"mobile_tech": [
|
| 109 |
+
"React Native", "Flutter", "Swift for iOS", "Kotlin for Android",
|
| 110 |
+
"Xamarin", "Ionic", "PWAs", "Unity for mobile games", "NativeScript",
|
| 111 |
+
"Mobile AR/VR applications"
|
| 112 |
+
],
|
| 113 |
+
"devops_tech": [
|
| 114 |
+
"Kubernetes and Docker", "AWS infrastructure", "Azure DevOps", "Google Cloud Platform",
|
| 115 |
+
"CI/CD pipelines", "Terraform and infrastructure as code", "Jenkins and GitLab CI",
|
| 116 |
+
"Monitoring and observability tools", "Site Reliability Engineering practices",
|
| 117 |
+
"Security automation"
|
| 118 |
+
],
|
| 119 |
+
"ds_tech": [
|
| 120 |
+
"Python, Pandas, and scikit-learn", "R and Tidyverse", "SQL and data warehousing",
|
| 121 |
+
"Tableau and data visualization", "Big data technologies like Spark",
|
| 122 |
+
"ETL pipelines", "Statistical analysis", "A/B testing methodologies",
|
| 123 |
+
"Natural Language Processing", "Computer Vision"
|
| 124 |
+
],
|
| 125 |
+
"ml_tech": [
|
| 126 |
+
"TensorFlow and Keras", "PyTorch", "scikit-learn", "deep learning models",
|
| 127 |
+
"MLOps and model deployment", "reinforcement learning", "computer vision algorithms",
|
| 128 |
+
"NLP models", "recommendation systems", "time series forecasting"
|
| 129 |
+
],
|
| 130 |
+
"ai_tech": [
|
| 131 |
+
"large language models", "generative AI", "conversational agents", "computer vision systems",
|
| 132 |
+
"reinforcement learning", "multimodal AI", "AI ethics and responsible AI",
|
| 133 |
+
"autonomous systems", "AI for social good", "explainable AI"
|
| 134 |
+
],
|
| 135 |
+
"game_tech": [
|
| 136 |
+
"Unity", "Unreal Engine", "Godot", "WebGL", "AR/VR development",
|
| 137 |
+
"mobile game development", "game AI", "procedural generation",
|
| 138 |
+
"multiplayer networking", "game physics"
|
| 139 |
+
],
|
| 140 |
+
"embedded_tech": [
|
| 141 |
+
"Arduino", "Raspberry Pi", "IoT devices", "embedded Linux",
|
| 142 |
+
"RTOS", "C/C++ for microcontrollers", "sensor networks",
|
| 143 |
+
"firmware development", "hardware interfaces", "low-power systems"
|
| 144 |
+
],
|
| 145 |
+
"product_type": [
|
| 146 |
+
"SaaS", "mobile", "enterprise", "consumer", "AI-powered",
|
| 147 |
+
"IoT", "fintech", "healthtech", "edtech", "e-commerce"
|
| 148 |
+
],
|
| 149 |
+
"qa_tech": [
|
| 150 |
+
"automated testing", "Selenium and Cypress", "performance testing",
|
| 151 |
+
"security testing", "mobile app testing", "API testing",
|
| 152 |
+
"test-driven development", "behavior-driven development",
|
| 153 |
+
"continuous integration testing", "accessibility testing"
|
| 154 |
+
],
|
| 155 |
+
"writing_focus": [
|
| 156 |
+
"API documentation", "user guides", "developer tutorials",
|
| 157 |
+
"knowledge bases", "technical blogs", "software requirements",
|
| 158 |
+
"open source documentation", "technical specifications",
|
| 159 |
+
"UX writing", "compliance documentation"
|
| 160 |
+
],
|
| 161 |
+
"arch_focus": [
|
| 162 |
+
"cloud architectures", "microservices", "serverless",
|
| 163 |
+
"enterprise systems", "distributed systems", "API design",
|
| 164 |
+
"security architectures", "data platforms", "IoT systems",
|
| 165 |
+
"mobile and web applications"
|
| 166 |
+
],
|
| 167 |
+
"additional": [
|
| 168 |
+
"I enjoy working in collaborative environments.",
|
| 169 |
+
"I'm passionate about creating accessible technology.",
|
| 170 |
+
"I've contributed to several open source projects.",
|
| 171 |
+
"I'm interested in ethical technology and responsible innovation.",
|
| 172 |
+
"I enjoy mentoring junior developers.",
|
| 173 |
+
"I have a background in design thinking.",
|
| 174 |
+
"I've worked in startups and enterprise environments.",
|
| 175 |
+
"I'm particularly interested in AI ethics.",
|
| 176 |
+
"I love solving complex algorithmic problems.",
|
| 177 |
+
"I focus on creating user-centered solutions.",
|
| 178 |
+
"I have experience leading small technical teams.",
|
| 179 |
+
"I'm self-taught and constantly learning new technologies.",
|
| 180 |
+
"I have a computer science degree but learned most of my skills on the job.",
|
| 181 |
+
"I'm currently transitioning careers into tech.",
|
| 182 |
+
"I'm an advocate for diversity in tech.",
|
| 183 |
+
"I've organized tech meetups and community events.",
|
| 184 |
+
"I'm interested in the intersection of technology and sustainability.",
|
| 185 |
+
"I have experience in both technical and business roles.",
|
| 186 |
+
"I'm passionate about making technology more accessible to everyone.",
|
| 187 |
+
"I enjoy the challenges of working with legacy systems.",
|
| 188 |
+
"", # Empty for some participants
|
| 189 |
+
]
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
# Non-technical components
|
| 193 |
+
NON_TECH_COMPONENTS = {
|
| 194 |
+
"marketing_focus": [
|
| 195 |
+
"digital marketing", "content strategy", "brand development",
|
| 196 |
+
"social media campaigns", "event promotion", "growth hacking",
|
| 197 |
+
"community building", "influencer partnerships", "SEO/SEM",
|
| 198 |
+
"product marketing"
|
| 199 |
+
],
|
| 200 |
+
"industry": [
|
| 201 |
+
"technology", "healthcare", "finance", "education", "retail",
|
| 202 |
+
"entertainment", "manufacturing", "non-profit", "government",
|
| 203 |
+
"hospitality"
|
| 204 |
+
],
|
| 205 |
+
"years": [str(i) for i in range(1, 16)],
|
| 206 |
+
"pm_focus": [
|
| 207 |
+
"agile methodologies", "waterfall approaches", "hybrid frameworks",
|
| 208 |
+
"technical projects", "creative initiatives", "product launches",
|
| 209 |
+
"organizational change", "international teams", "startup environments",
|
| 210 |
+
"enterprise transformations"
|
| 211 |
+
],
|
| 212 |
+
"startup_type": [
|
| 213 |
+
"tech", "social impact", "e-commerce", "healthcare", "education",
|
| 214 |
+
"fintech", "sustainability", "B2B SaaS", "consumer app", "AI/ML"
|
| 215 |
+
],
|
| 216 |
+
"field": [
|
| 217 |
+
"Computer Science", "Business Administration", "Design", "Marketing",
|
| 218 |
+
"Engineering", "Data Science", "Psychology", "Communications",
|
| 219 |
+
"Information Technology", "Entrepreneurship"
|
| 220 |
+
],
|
| 221 |
+
"university": [
|
| 222 |
+
"University of Toronto", "York University", "Ryerson University",
|
| 223 |
+
"Seneca College", "Humber College", "OCAD University",
|
| 224 |
+
"George Brown College", "McMaster University", "Waterloo University",
|
| 225 |
+
"Queen's University"
|
| 226 |
+
],
|
| 227 |
+
"content_focus": [
|
| 228 |
+
"tech tutorials", "industry trends", "career development",
|
| 229 |
+
"product reviews", "educational content", "lifestyle and tech",
|
| 230 |
+
"startup stories", "coding challenges", "design inspiration",
|
| 231 |
+
"thought leadership"
|
| 232 |
+
],
|
| 233 |
+
"sales_industry": [
|
| 234 |
+
"SaaS", "hardware", "consulting services", "enterprise solutions",
|
| 235 |
+
"consumer tech", "B2B technology", "telecommunications",
|
| 236 |
+
"cybersecurity", "cloud services", "digital transformation"
|
| 237 |
+
],
|
| 238 |
+
"additional": [
|
| 239 |
+
"I'm excited to learn more about technology and how it can solve real problems.",
|
| 240 |
+
"I bring a unique perspective from my non-technical background.",
|
| 241 |
+
"I'm interested in the human aspects of technology.",
|
| 242 |
+
"I'm looking to collaborate with technical team members and contribute my skills.",
|
| 243 |
+
"I have strong communication and presentation skills.",
|
| 244 |
+
"I excel at understanding user needs and translating them into requirements.",
|
| 245 |
+
"I'm good at explaining complex concepts to diverse audiences.",
|
| 246 |
+
"I have experience managing stakeholder expectations.",
|
| 247 |
+
"I'm skilled at identifying market opportunities.",
|
| 248 |
+
"I enjoy bridging the gap between technical and non-technical teams.",
|
| 249 |
+
"I have a creative approach to problem-solving.",
|
| 250 |
+
"I'm passionate about user experience and accessibility.",
|
| 251 |
+
"I have a network of industry connections that could be valuable.",
|
| 252 |
+
"I'm experienced in gathering and synthesizing user feedback.",
|
| 253 |
+
"I'm interested in how technology can create social impact.",
|
| 254 |
+
"I have experience in project coordination and team organization.",
|
| 255 |
+
"I'm good at creating compelling narratives around technical products.",
|
| 256 |
+
"I'm curious about AI and its potential applications.",
|
| 257 |
+
"I have a background in psychology and understand human behavior.",
|
| 258 |
+
"I'm skilled at facilitating workshops and brainstorming sessions.",
|
| 259 |
+
"", # Empty for some participants
|
| 260 |
+
]
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
def generate_background(is_technical=True):
|
| 264 |
+
"""Generate a realistic background for a participant."""
|
| 265 |
+
if is_technical:
|
| 266 |
+
template = random.choice(TECHNICAL_BACKGROUNDS)
|
| 267 |
+
components = STACK_COMPONENTS
|
| 268 |
+
else:
|
| 269 |
+
template = random.choice(NON_TECHNICAL_BACKGROUNDS)
|
| 270 |
+
components = NON_TECH_COMPONENTS
|
| 271 |
+
|
| 272 |
+
# Fill in the template with random components
|
| 273 |
+
for key in components:
|
| 274 |
+
if "{" + key + "}" in template:
|
| 275 |
+
template = template.replace("{" + key + "}", random.choice(components[key]))
|
| 276 |
+
|
| 277 |
+
return template
|
| 278 |
+
|
| 279 |
+
def generate_linkedin_profile(name):
|
| 280 |
+
"""Generate a realistic LinkedIn profile URL based on the name."""
|
| 281 |
+
# Remove spaces and special characters, convert to lowercase
|
| 282 |
+
name_part = ''.join(c for c in name if c.isalnum()).lower()
|
| 283 |
+
|
| 284 |
+
# Add some randomness to ensure uniqueness
|
| 285 |
+
if random.random() < 0.3:
|
| 286 |
+
# Some people use just their name
|
| 287 |
+
profile = name_part
|
| 288 |
+
elif random.random() < 0.6:
|
| 289 |
+
# Some add a random number
|
| 290 |
+
profile = f"{name_part}{random.randint(1, 999)}"
|
| 291 |
+
else:
|
| 292 |
+
# Some add their profession or location
|
| 293 |
+
suffixes = ["dev", "tech", "to", "canada", "design", "pm", "product", "marketing", "ai"]
|
| 294 |
+
profile = f"{name_part}-{random.choice(suffixes)}"
|
| 295 |
+
|
| 296 |
+
return f"linkedin.com/in/{profile}"
|
| 297 |
+
|
| 298 |
+
def generate_participants(count=100):
|
| 299 |
+
"""Generate a specified number of diverse hackathon participants."""
|
| 300 |
+
participants = []
|
| 301 |
+
|
| 302 |
+
# Define the distribution of technical vs non-technical participants
|
| 303 |
+
# For a hackathon, we'll have more technical participants but still a good mix
|
| 304 |
+
technical_count = int(count * 0.7) # 70% technical
|
| 305 |
+
non_technical_count = count - technical_count # 30% non-technical
|
| 306 |
+
|
| 307 |
+
# Generate technical participants
|
| 308 |
+
for _ in range(technical_count):
|
| 309 |
+
name = fake.name()
|
| 310 |
+
email = fake.email()
|
| 311 |
+
linkedin = generate_linkedin_profile(name)
|
| 312 |
+
background = generate_background(is_technical=True)
|
| 313 |
+
goals = random.choice(GOALS)
|
| 314 |
+
|
| 315 |
+
participants.append({
|
| 316 |
+
"email": email,
|
| 317 |
+
"name": name,
|
| 318 |
+
"linkedin_profile": linkedin,
|
| 319 |
+
"background": background,
|
| 320 |
+
"goals": goals
|
| 321 |
+
})
|
| 322 |
+
|
| 323 |
+
# Generate non-technical participants
|
| 324 |
+
for _ in range(non_technical_count):
|
| 325 |
+
name = fake.name()
|
| 326 |
+
email = fake.email()
|
| 327 |
+
linkedin = generate_linkedin_profile(name)
|
| 328 |
+
background = generate_background(is_technical=False)
|
| 329 |
+
goals = random.choice(GOALS)
|
| 330 |
+
|
| 331 |
+
participants.append({
|
| 332 |
+
"email": email,
|
| 333 |
+
"name": name,
|
| 334 |
+
"linkedin_profile": linkedin,
|
| 335 |
+
"background": background,
|
| 336 |
+
"goals": goals
|
| 337 |
+
})
|
| 338 |
+
|
| 339 |
+
# Shuffle the participants to mix technical and non-technical
|
| 340 |
+
random.shuffle(participants)
|
| 341 |
+
return participants
|
| 342 |
+
|
| 343 |
+
def main():
|
| 344 |
+
"""Main function to generate participants and save them to the database."""
|
| 345 |
+
print("Initializing database...")
|
| 346 |
+
initialize_database()
|
| 347 |
+
|
| 348 |
+
print("Generating 100 diverse hackathon participants...")
|
| 349 |
+
participants = generate_participants(100)
|
| 350 |
+
|
| 351 |
+
print("Adding participants to the database...")
|
| 352 |
+
for p in participants:
|
| 353 |
+
add_participant(p)
|
| 354 |
+
|
| 355 |
+
print("Participants added successfully.")
|
| 356 |
+
|
| 357 |
+
# Get and display a sample of the participants
|
| 358 |
+
df = get_participants_dataframe()
|
| 359 |
+
print(f"\nTotal participants in database: {len(df)}")
|
| 360 |
+
print("\nSample of participants:")
|
| 361 |
+
print(df.sample(5))
|
| 362 |
+
|
| 363 |
+
if __name__ == "__main__":
|
| 364 |
+
# Check if Faker is installed
|
| 365 |
+
try:
|
| 366 |
+
import faker
|
| 367 |
+
except ImportError:
|
| 368 |
+
print("The 'faker' package is required but not installed.")
|
| 369 |
+
print("Please install it using: pip install faker")
|
| 370 |
+
sys.exit(1)
|
| 371 |
+
|
| 372 |
+
main()
|
hackathon_organizer/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# π€ AI-Powered HackBuddyAI
|
| 2 |
+
|
| 3 |
+
This project is a web application that helps hackathon organizers automatically form balanced teams from a list of participants. It uses a `TinyCodeAgent` to analyze participant skills and goals, creating optimal teams based on criteria defined by the organizer.
|
| 4 |
+
|
| 5 |
+
The application features a two-tab interface:
|
| 6 |
+
1. **Participant Registration**: A form for participants to submit their profile, including skills, background, and what they want to achieve during the hackathon.
|
| 7 |
+
2. **Organizer Dashboard**: A view for the organizer to see all registered participants, define matching criteria, and run the AI-powered team formation process.
|
| 8 |
+
|
| 9 |
+
## Tech Stack
|
| 10 |
+
- **Backend**: Python
|
| 11 |
+
- **AI Agent Framework**: `TinyCodeAgent`
|
| 12 |
+
- **Web UI**: Gradio
|
| 13 |
+
- **Data Handling**: Pandas
|
| 14 |
+
- **Database**: SQLite
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
## Setup and Installation
|
| 19 |
+
|
| 20 |
+
### 1. Prerequisites
|
| 21 |
+
- Python 3.8+
|
| 22 |
+
- An OpenAI API key
|
| 23 |
+
|
| 24 |
+
### 2. Installation
|
| 25 |
+
1. **Clone the repository** (if applicable) or ensure you have the project files in a directory.
|
| 26 |
+
|
| 27 |
+
2. **Navigate to the project directory**:
|
| 28 |
+
```bash
|
| 29 |
+
cd path/to/project
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
3. **Create a virtual environment** (recommended):
|
| 33 |
+
```bash
|
| 34 |
+
python -m venv venv
|
| 35 |
+
source venv/bin/activate # On Windows, use `venv\Scripts\activate`
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
4. **Install dependencies**:
|
| 39 |
+
The project relies on the `tinyagent` library. Assuming it is available in your environment, install the other required packages:
|
| 40 |
+
```bash
|
| 41 |
+
pip install -r hackathon_organizer/requirements.txt
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
### 3. Configure Environment Variables
|
| 45 |
+
You must set your OpenAI API key as an environment variable. The application will not run without it.
|
| 46 |
+
|
| 47 |
+
- **On macOS/Linux**:
|
| 48 |
+
```bash
|
| 49 |
+
export OPENAI_API_KEY="your_api_key_here"
|
| 50 |
+
```
|
| 51 |
+
- **On Windows (Command Prompt)**:
|
| 52 |
+
```bash
|
| 53 |
+
set OPENAI_API_KEY="your_api_key_here"
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
+
|
| 58 |
+
## π Running the Application
|
| 59 |
+
|
| 60 |
+
Once the setup is complete, you can launch the Gradio web application using one of the following methods:
|
| 61 |
+
|
| 62 |
+
### Method 1: Using the main script (recommended)
|
| 63 |
+
|
| 64 |
+
```bash
|
| 65 |
+
python main.py
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
This script handles all the necessary path configurations and launches the application.
|
| 69 |
+
|
| 70 |
+
### Method 2: Running app.py directly
|
| 71 |
+
|
| 72 |
+
```bash
|
| 73 |
+
cd hackathon_organizer
|
| 74 |
+
python app.py
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
Either method will start a local web server, and you can access the application at the URL provided in the console (usually `http://127.0.0.1:7860`).
|
| 78 |
+
|
| 79 |
+
The application will create a `hackathon_participants.db` file in the working directory to store the participant data.
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
## π§ͺ Running Tests
|
| 84 |
+
|
| 85 |
+
The project includes unit tests for the database and the agent setup logic. The tests are located in the `tests/` directory.
|
| 86 |
+
|
| 87 |
+
To run the tests:
|
| 88 |
+
|
| 89 |
+
```bash
|
| 90 |
+
# From the project root directory
|
| 91 |
+
cd hackathon_organizer
|
| 92 |
+
python -m unittest discover tests
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
The tests are designed to run without needing an active internet connection or a valid API key. They use mocks to simulate agent behavior and an in-memory database for testing database operations.
|
hackathon_organizer/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# This file makes the 'hackathon_organizer' directory a Python package.
|
hackathon_organizer/app.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import asyncio
|
| 4 |
+
import logging
|
| 5 |
+
import sys
|
| 6 |
+
import os
|
| 7 |
+
import io
|
| 8 |
+
|
| 9 |
+
# Change from absolute imports to relative imports
|
| 10 |
+
from database import initialize_database, add_participant, get_participants_dataframe
|
| 11 |
+
from matching_agent import create_matching_agent, run_matching
|
| 12 |
+
from tinyagent.hooks.logging_manager import LoggingManager
|
| 13 |
+
|
| 14 |
+
from tinyagent.hooks.logging_manager import LoggingManager
|
| 15 |
+
import logging
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
# --- Logging Setup ---
|
| 19 |
+
log_manager = LoggingManager(default_level=logging.INFO)
|
| 20 |
+
log_manager.set_levels({
|
| 21 |
+
'tinyagent.hooks.gradio_callback': logging.DEBUG,
|
| 22 |
+
'tinyagent.tiny_agent': logging.DEBUG,
|
| 23 |
+
'tinyagent.mcp_client': logging.DEBUG,
|
| 24 |
+
'tinyagent.code_agent': logging.DEBUG,
|
| 25 |
+
})
|
| 26 |
+
|
| 27 |
+
console_handler = logging.StreamHandler(sys.stdout)
|
| 28 |
+
log_manager.configure_handler(
|
| 29 |
+
console_handler,
|
| 30 |
+
format_string='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 31 |
+
level=logging.DEBUG
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
# Gradio log handler
|
| 35 |
+
log_stream = io.StringIO()
|
| 36 |
+
gradio_handler = logging.StreamHandler(log_stream)
|
| 37 |
+
log_manager.configure_handler(
|
| 38 |
+
gradio_handler,
|
| 39 |
+
format_string='%(asctime)s - %(levelname)s - %(name)s - %(message)s',
|
| 40 |
+
level=logging.DEBUG # Capture detailed logs for the UI
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
logger = log_manager.get_logger('app')
|
| 44 |
+
|
| 45 |
+
# --- Initial Setup ---
|
| 46 |
+
logger.info("Initializing database...")
|
| 47 |
+
initialize_database()
|
| 48 |
+
|
| 49 |
+
# Check for API key
|
| 50 |
+
if not os.environ.get("OPENAI_API_KEY"):
|
| 51 |
+
raise ValueError("The OPENAI_API_KEY environment variable is not set. Please set it before running the app.")
|
| 52 |
+
|
| 53 |
+
logger.info("Creating matching agent...")
|
| 54 |
+
agent = create_matching_agent(log_manager=log_manager)
|
| 55 |
+
|
| 56 |
+
# --- Gradio UI Functions ---
|
| 57 |
+
|
| 58 |
+
def register_participant(name, email, linkedin, background, goals):
|
| 59 |
+
"""Callback function to register a new participant."""
|
| 60 |
+
if not all([name, email]):
|
| 61 |
+
return "Please provide at least a name and email.", get_participants_dataframe()
|
| 62 |
+
|
| 63 |
+
participant_data = {
|
| 64 |
+
"name": name,
|
| 65 |
+
"email": email,
|
| 66 |
+
"linkedin_profile": linkedin,
|
| 67 |
+
"background": background,
|
| 68 |
+
"goals": goals
|
| 69 |
+
}
|
| 70 |
+
try:
|
| 71 |
+
add_participant(participant_data)
|
| 72 |
+
feedback = f"β
Success! Participant '{name}' registered."
|
| 73 |
+
logger.info(f"Registered new participant: {email}")
|
| 74 |
+
except Exception as e:
|
| 75 |
+
feedback = f"β Error! Could not register participant. Reason: {e}"
|
| 76 |
+
logger.error(f"Failed to register participant {email}: {e}")
|
| 77 |
+
|
| 78 |
+
return feedback, get_participants_dataframe()
|
| 79 |
+
|
| 80 |
+
def refresh_participants_list():
|
| 81 |
+
"""Callback to reload the participant data from the database."""
|
| 82 |
+
return get_participants_dataframe()
|
| 83 |
+
|
| 84 |
+
async def run_matching_process(organizer_criteria, progress=gr.Progress(track_tqdm=True)):
|
| 85 |
+
"""Async callback to run the team matching process, with live log streaming."""
|
| 86 |
+
# 1. Clear previous logs and show panel
|
| 87 |
+
log_stream.seek(0)
|
| 88 |
+
log_stream.truncate(0)
|
| 89 |
+
progress(0, desc="Initializing...")
|
| 90 |
+
yield {
|
| 91 |
+
log_panel: gr.update(visible=True, open=True),
|
| 92 |
+
log_output: "Starting matching process...\n",
|
| 93 |
+
matching_results_out: "π Setting up the matching process..."
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
# 2. Get participants and perform initial checks
|
| 97 |
+
logger.info("Fetching participants...")
|
| 98 |
+
progress(0, desc="Fetching participants...")
|
| 99 |
+
participants_df = get_participants_dataframe()
|
| 100 |
+
if len(participants_df) < 2:
|
| 101 |
+
warning_msg = "Matching process aborted: not enough participants."
|
| 102 |
+
logger.warning(warning_msg)
|
| 103 |
+
yield {
|
| 104 |
+
log_panel: gr.update(),
|
| 105 |
+
log_output: log_stream.getvalue(),
|
| 106 |
+
matching_results_out: "Cannot run matching with fewer than 2 participants."
|
| 107 |
+
}
|
| 108 |
+
return
|
| 109 |
+
|
| 110 |
+
logger.info(f"Running matching for {len(participants_df)} participants.")
|
| 111 |
+
progress(0.2, desc="π§ Agent is thinking...")
|
| 112 |
+
|
| 113 |
+
# 3. Create a background task for the core matching logic
|
| 114 |
+
match_task = asyncio.create_task(
|
| 115 |
+
run_matching(agent, participants_df, organizer_criteria)
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
# 4. Stream logs while the agent works
|
| 119 |
+
while not match_task.done():
|
| 120 |
+
await asyncio.sleep(0.5) # Poll for new logs every 0.5s
|
| 121 |
+
yield {
|
| 122 |
+
log_panel: gr.update(),
|
| 123 |
+
log_output: log_stream.getvalue(),
|
| 124 |
+
matching_results_out: gr.update() # No change to final output yet
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
# 5. Process the final result from the agent
|
| 128 |
+
try:
|
| 129 |
+
final_report = await match_task
|
| 130 |
+
logger.info("Matching process completed successfully.")
|
| 131 |
+
progress(1.0, desc="β
Done!")
|
| 132 |
+
yield {
|
| 133 |
+
log_panel: gr.update(),
|
| 134 |
+
log_output: log_stream.getvalue(),
|
| 135 |
+
matching_results_out: final_report
|
| 136 |
+
}
|
| 137 |
+
except Exception as e:
|
| 138 |
+
logger.error(f"An error occurred during the matching process: {e}", exc_info=True)
|
| 139 |
+
yield {
|
| 140 |
+
log_panel: gr.update(),
|
| 141 |
+
log_output: log_stream.getvalue(),
|
| 142 |
+
matching_results_out: f"An error occurred: {e}"
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
# --- Gradio App Definition ---
|
| 146 |
+
|
| 147 |
+
with gr.Blocks(theme=gr.themes.Default(
|
| 148 |
+
font=[gr.themes.GoogleFont("Inter"), "Arial", "sans-serif"]
|
| 149 |
+
), title="HackBuddyAI") as app:
|
| 150 |
+
gr.Markdown("# π€ HackBuddyAI")
|
| 151 |
+
|
| 152 |
+
with gr.Tabs():
|
| 153 |
+
with gr.TabItem("π€ Participant Registration"):
|
| 154 |
+
gr.Markdown("## Welcome, Participant!")
|
| 155 |
+
gr.Markdown("Fill out the form below to register for the hackathon.")
|
| 156 |
+
with gr.Row():
|
| 157 |
+
with gr.Column():
|
| 158 |
+
name_in = gr.Textbox(label="Full Name")
|
| 159 |
+
email_in = gr.Textbox(label="Email Address")
|
| 160 |
+
linkedin_in = gr.Textbox(label="LinkedIn Profile URL", placeholder="Optional")
|
| 161 |
+
with gr.Column():
|
| 162 |
+
background_in = gr.Textbox(label="Your Background & Skills", lines=5, placeholder="e.g., Python developer with 3 years of experience, specializing in Django and REST APIs...")
|
| 163 |
+
goals_in = gr.Textbox(label="Your Goals for this Hackathon", lines=5, placeholder="e.g., I want to learn about machine learning and work on a cool data visualization project...")
|
| 164 |
+
|
| 165 |
+
submit_button = gr.Button("Register", variant="primary")
|
| 166 |
+
registration_feedback = gr.Markdown()
|
| 167 |
+
|
| 168 |
+
with gr.TabItem("π Organizer Dashboard"):
|
| 169 |
+
gr.Markdown("## Welcome, Organizer!")
|
| 170 |
+
gr.Markdown("Here you can view registered participants and run the AI-powered team matching process.")
|
| 171 |
+
|
| 172 |
+
with gr.Accordion("View Registered Participants", open=False):
|
| 173 |
+
refresh_button = gr.Button("π Refresh List")
|
| 174 |
+
participants_df_out = gr.DataFrame(value=get_participants_dataframe, interactive=False)
|
| 175 |
+
|
| 176 |
+
gr.Markdown("### Run Matching")
|
| 177 |
+
organizer_criteria_in = gr.Textbox(
|
| 178 |
+
label="Matching Criteria",
|
| 179 |
+
lines=4,
|
| 180 |
+
value="Create teams of 3. Try to balance skills in each team (e.g., frontend, backend, data).",
|
| 181 |
+
placeholder="Describe your ideal team composition..."
|
| 182 |
+
)
|
| 183 |
+
run_button = gr.Button("π Run AI Matching", variant="primary")
|
| 184 |
+
|
| 185 |
+
gr.Markdown("### π€ Matched Teams")
|
| 186 |
+
matching_results_out = gr.Markdown("Matching has not been run yet.")
|
| 187 |
+
|
| 188 |
+
with gr.Accordion("Agent Logs", open=False, visible=False) as log_panel:
|
| 189 |
+
log_output = gr.Code(
|
| 190 |
+
label="Live Logs",
|
| 191 |
+
lines=15,
|
| 192 |
+
interactive=False,
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
gr.Markdown("<p align='center'>Powered by Tiny Agent</p>")
|
| 196 |
+
|
| 197 |
+
# --- Event Handlers ---
|
| 198 |
+
submit_button.click(
|
| 199 |
+
fn=register_participant,
|
| 200 |
+
inputs=[name_in, email_in, linkedin_in, background_in, goals_in],
|
| 201 |
+
outputs=[registration_feedback, participants_df_out]
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
refresh_button.click(
|
| 205 |
+
fn=refresh_participants_list,
|
| 206 |
+
inputs=[],
|
| 207 |
+
outputs=[participants_df_out]
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
run_button.click(
|
| 211 |
+
fn=run_matching_process,
|
| 212 |
+
inputs=[organizer_criteria_in],
|
| 213 |
+
outputs=[matching_results_out, log_output, log_panel]
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
# --- Launching the App ---
|
| 217 |
+
if __name__ == "__main__":
|
| 218 |
+
try:
|
| 219 |
+
logger.info("Launching Gradio app...")
|
| 220 |
+
# queue() is important for handling multiple users and async calls
|
| 221 |
+
app.queue().launch(share=False)
|
| 222 |
+
except KeyboardInterrupt:
|
| 223 |
+
logger.info("Gradio app shutting down.")
|
| 224 |
+
finally:
|
| 225 |
+
# Clean up agent resources
|
| 226 |
+
logger.info("Closing agent resources...")
|
| 227 |
+
# We need to run the async close method
|
| 228 |
+
asyncio.run(agent.close())
|
| 229 |
+
logger.info("Cleanup complete.")
|
hackathon_organizer/database.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sqlite3
|
| 2 |
+
import pandas as pd
|
| 3 |
+
from typing import Dict, Any, List
|
| 4 |
+
|
| 5 |
+
DB_PATH = "hackathon_participants.db"
|
| 6 |
+
TABLE_NAME = "participants"
|
| 7 |
+
|
| 8 |
+
def initialize_database():
|
| 9 |
+
"""
|
| 10 |
+
Initializes the database and creates the participants table if it doesn't exist.
|
| 11 |
+
"""
|
| 12 |
+
with sqlite3.connect(DB_PATH) as conn:
|
| 13 |
+
cursor = conn.cursor()
|
| 14 |
+
cursor.execute(f"""
|
| 15 |
+
CREATE TABLE IF NOT EXISTS {TABLE_NAME} (
|
| 16 |
+
email TEXT PRIMARY KEY,
|
| 17 |
+
name TEXT NOT NULL,
|
| 18 |
+
linkedin_profile TEXT,
|
| 19 |
+
background TEXT,
|
| 20 |
+
goals TEXT
|
| 21 |
+
)
|
| 22 |
+
""")
|
| 23 |
+
conn.commit()
|
| 24 |
+
|
| 25 |
+
def add_participant(participant: Dict[str, Any]):
|
| 26 |
+
"""
|
| 27 |
+
Adds a new participant to the database.
|
| 28 |
+
|
| 29 |
+
Args:
|
| 30 |
+
participant: A dictionary containing participant data.
|
| 31 |
+
Keys should be 'email', 'name', 'linkedin_profile', 'background', 'goals'.
|
| 32 |
+
"""
|
| 33 |
+
with sqlite3.connect(DB_PATH) as conn:
|
| 34 |
+
cursor = conn.cursor()
|
| 35 |
+
cursor.execute(f"""
|
| 36 |
+
INSERT OR REPLACE INTO {TABLE_NAME} (email, name, linkedin_profile, background, goals)
|
| 37 |
+
VALUES (:email, :name, :linkedin_profile, :background, :goals)
|
| 38 |
+
""", participant)
|
| 39 |
+
conn.commit()
|
| 40 |
+
|
| 41 |
+
def get_participants_dataframe() -> pd.DataFrame:
|
| 42 |
+
"""
|
| 43 |
+
Retrieves all participants from the database and returns them as a pandas DataFrame.
|
| 44 |
+
|
| 45 |
+
Returns:
|
| 46 |
+
A pandas DataFrame containing all participant data.
|
| 47 |
+
"""
|
| 48 |
+
with sqlite3.connect(DB_PATH) as conn:
|
| 49 |
+
df = pd.read_sql_query(f"SELECT * FROM {TABLE_NAME}", conn)
|
| 50 |
+
return df
|
| 51 |
+
|
| 52 |
+
if __name__ == '__main__':
|
| 53 |
+
# Example usage and basic test
|
| 54 |
+
print("Initializing database...")
|
| 55 |
+
initialize_database()
|
| 56 |
+
print("Database initialized.")
|
| 57 |
+
|
| 58 |
+
# Sample participants
|
| 59 |
+
participants_to_add = [
|
| 60 |
+
{
|
| 61 |
+
"email": "[email protected]",
|
| 62 |
+
"name": "Alice Wonderland",
|
| 63 |
+
"linkedin_profile": "linkedin.com/in/alicew",
|
| 64 |
+
"background": "5 years of experience in frontend development with React and TypeScript. Interested in UI/UX design.",
|
| 65 |
+
"goals": "I want to build a cool project for my portfolio and learn about backend development."
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"email": "[email protected]",
|
| 69 |
+
"name": "Bob Builder",
|
| 70 |
+
"linkedin_profile": "linkedin.com/in/bobb",
|
| 71 |
+
"background": "Backend developer specializing in Python, Django, and PostgreSQL. I'm also a DevOps enthusiast.",
|
| 72 |
+
"goals": "Looking to work on a challenging problem, maybe involving infrastructure or data engineering."
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"email": "[email protected]",
|
| 76 |
+
"name": "Charlie Chocolate",
|
| 77 |
+
"linkedin_profile": "linkedin.com/in/charliec",
|
| 78 |
+
"background": "Data scientist with expertise in Python, Pandas, Scikit-learn, and TensorFlow. I love creating predictive models.",
|
| 79 |
+
"goals": "I hope to apply my machine learning skills to a real-world problem and collaborate with a diverse team."
|
| 80 |
+
}
|
| 81 |
+
]
|
| 82 |
+
|
| 83 |
+
print(f"Adding {len(participants_to_add)} participants...")
|
| 84 |
+
for p in participants_to_add:
|
| 85 |
+
add_participant(p)
|
| 86 |
+
print("Participants added.")
|
| 87 |
+
|
| 88 |
+
print("\nRetrieving all participants:")
|
| 89 |
+
df = get_participants_dataframe()
|
| 90 |
+
print(df)
|
| 91 |
+
|
| 92 |
+
# Verify data
|
| 93 |
+
assert len(df) == 3
|
| 94 |
+
assert "[email protected]" in df["email"].values
|
| 95 |
+
print("\nData verified successfully.")
|
hackathon_organizer/hackathon_participants.db
ADDED
|
Binary file (41 kB). View file
|
|
|
hackathon_organizer/matching_agent.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import pandas as pd
|
| 3 |
+
from tinyagent import TinyCodeAgent
|
| 4 |
+
from textwrap import dedent
|
| 5 |
+
|
| 6 |
+
organizer_prompt = dedent("""
|
| 7 |
+
You are a brilliant hackathon team-matching AI.
|
| 8 |
+
Your task is to form teams from a list of participants provided in a pandas DataFrame.
|
| 9 |
+
You will be given the DataFrame in a variable named `participants_df`.
|
| 10 |
+
You will also be given the organizer's criteria in a variable named `organizer_criteria`.
|
| 11 |
+
|
| 12 |
+
Your goal is to write and execute Python code using the `run_python` tool to group these participants into balanced teams.
|
| 13 |
+
|
| 14 |
+
Follow these steps:
|
| 15 |
+
1. **Analyze the Data**: Inspect the `participants_df` DataFrame to understand the skills, backgrounds, and goals of the participants.
|
| 16 |
+
2. **Plan Your Logic**: Based on the `organizer_criteria`, decide on a strategy for forming teams. Consider things like team size, skill diversity (e.g., frontend, backend, data science), and aligning participants' goals.
|
| 17 |
+
3. **Implement the Matching**: Write Python code to create the teams. You can iterate through the DataFrame, use clustering algorithms, or any other method you see fit. Your code should produce a list of teams, where each team is a list of participant dictionaries.
|
| 18 |
+
4. **Format the Output**: Once you have the teams, your final step is to generate a user-friendly report in Markdown format. For each team, list the members and write a brief, one-sentence justification for why they are a good match, based on their combined skills and goals.
|
| 19 |
+
|
| 20 |
+
Example of final output format:
|
| 21 |
+
|
| 22 |
+
```markdown
|
| 23 |
+
## Team 1
|
| 24 |
+
|
| 25 |
+
* **Alice Wonderland** (Frontend, React)
|
| 26 |
+
* **Bob Builder** (Backend, Python)
|
| 27 |
+
* **Charlie Chocolate** (Data Science)
|
| 28 |
+
|
| 29 |
+
**Justification**: This team has a strong, well-rounded skill set covering frontend, backend, and data science, making them capable of building a full-stack application.
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
Do not ask for feedback. Execute the plan and provide the final Markdown report using the `final_answer` tool.
|
| 33 |
+
I can only see the final answer, not what happens in tool calls, so provide the full report in the final answer. Do not truncate team information
|
| 34 |
+
""")
|
| 35 |
+
|
| 36 |
+
def create_matching_agent(log_manager=None) -> TinyCodeAgent:
|
| 37 |
+
"""
|
| 38 |
+
Initializes and configures a TinyCodeAgent for matching hackathon participants.
|
| 39 |
+
|
| 40 |
+
Args:
|
| 41 |
+
log_manager: An optional logging manager instance.
|
| 42 |
+
|
| 43 |
+
Returns:
|
| 44 |
+
A configured TinyCodeAgent instance.
|
| 45 |
+
"""
|
| 46 |
+
# Create the agent without the system_prompt parameter
|
| 47 |
+
agent = TinyCodeAgent(
|
| 48 |
+
model="gpt-4.1-mini",
|
| 49 |
+
api_key=os.environ.get("OPENAI_API_KEY"),
|
| 50 |
+
log_manager=log_manager,
|
| 51 |
+
pip_packages=["pandas", "numpy", "scikit-learn"],
|
| 52 |
+
#authorized_imports=["pandas", "numpy", "io", "base64","collections","itertools"],
|
| 53 |
+
local_execution=False, # Use remote Modal for security by default
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
# Set the system prompt separately
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
return agent
|
| 60 |
+
|
| 61 |
+
async def run_matching(
|
| 62 |
+
agent: TinyCodeAgent,
|
| 63 |
+
participants_df: pd.DataFrame,
|
| 64 |
+
organizer_criteria: str
|
| 65 |
+
) -> str:
|
| 66 |
+
"""
|
| 67 |
+
Runs the matching process using the configured agent.
|
| 68 |
+
|
| 69 |
+
Args:
|
| 70 |
+
agent: The TinyCodeAgent instance.
|
| 71 |
+
participants_df: A DataFrame with participant data.
|
| 72 |
+
organizer_criteria: A string containing the organizer's preferences.
|
| 73 |
+
|
| 74 |
+
Returns:
|
| 75 |
+
The final markdown report of the matched teams.
|
| 76 |
+
"""
|
| 77 |
+
# Set the participant data and criteria as variables for the agent's environment
|
| 78 |
+
print(participants_df.head())
|
| 79 |
+
agent.set_user_variables({
|
| 80 |
+
"participants_df": participants_df,
|
| 81 |
+
"organizer_criteria": organizer_criteria
|
| 82 |
+
})
|
| 83 |
+
|
| 84 |
+
# The user prompt is simple, as the main instructions are in the system prompt
|
| 85 |
+
task = dedent("""
|
| 86 |
+
|
| 87 |
+
You are a brilliant hackathon team-matching AI.
|
| 88 |
+
Your task is to form teams from a list of participants provided in a pandas DataFrame.
|
| 89 |
+
You will be given the DataFrame in a variable named `participants_df`.
|
| 90 |
+
|
| 91 |
+
Your goal is to write and execute Python code using the `run_python` tool to group these participants into balanced teams.""")
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
task = organizer_prompt+'\n\n'
|
| 95 |
+
|
| 96 |
+
task += ("Form the teams based on the provided data and criteria."
|
| 97 |
+
f"\n<Organizer Criteria>\n{organizer_criteria}\n</Organizer Criteria>")
|
| 98 |
+
|
| 99 |
+
final_report = await agent.run(task, max_turns=15)
|
| 100 |
+
print(agent.messages)
|
| 101 |
+
return final_report
|
hackathon_organizer/requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
tinyagent-py[all]==0.0.12
|
| 2 |
+
cloudpickle
|
| 3 |
+
modal
|
| 4 |
+
jinja2
|
| 5 |
+
pyyaml
|
| 6 |
+
gradio[mcp]
|
| 7 |
+
pandas
|
hackathon_organizer/tests/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# This file allows the 'tests' directory to be discovered as a package.
|
hackathon_participants.db
ADDED
|
Binary file (41 kB). View file
|
|
|
main.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Hackathon Team Organizer - Main Entry Point
|
| 4 |
+
|
| 5 |
+
This script launches the Hackathon Team Organizer application.
|
| 6 |
+
It ensures the working directory is set correctly before running the app.
|
| 7 |
+
"""
|
| 8 |
+
import os
|
| 9 |
+
import sys
|
| 10 |
+
import subprocess
|
| 11 |
+
|
| 12 |
+
def main():
|
| 13 |
+
# Get the directory where this script is located
|
| 14 |
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
| 15 |
+
|
| 16 |
+
# Change to the script directory to ensure relative paths work
|
| 17 |
+
os.chdir(script_dir)
|
| 18 |
+
|
| 19 |
+
# Add the current directory to the Python path
|
| 20 |
+
sys.path.insert(0, script_dir)
|
| 21 |
+
|
| 22 |
+
print("Starting Hackathon Team Organizer...")
|
| 23 |
+
print(f"Working directory: {os.getcwd()}")
|
| 24 |
+
|
| 25 |
+
# Check for OpenAI API key
|
| 26 |
+
if not os.environ.get("OPENAI_API_KEY"):
|
| 27 |
+
print("\nβ οΈ WARNING: OPENAI_API_KEY environment variable is not set!")
|
| 28 |
+
print("The application requires an OpenAI API key to function properly.")
|
| 29 |
+
print("Please set it using:")
|
| 30 |
+
print(" export OPENAI_API_KEY='your-api-key' (macOS/Linux)")
|
| 31 |
+
print(" set OPENAI_API_KEY='your-api-key' (Windows)\n")
|
| 32 |
+
print("Running simplified version without AI matching...")
|
| 33 |
+
app_script = "hackathon_organizer/app_simple.py"
|
| 34 |
+
else:
|
| 35 |
+
print("OpenAI API key found. Running full version with AI matching...")
|
| 36 |
+
app_script = "hackathon_organizer/app.py"
|
| 37 |
+
|
| 38 |
+
# Run the application
|
| 39 |
+
try:
|
| 40 |
+
print(f"Launching application: {app_script}")
|
| 41 |
+
subprocess.run([sys.executable, app_script], check=True)
|
| 42 |
+
except KeyboardInterrupt:
|
| 43 |
+
print("\nApplication stopped by user.")
|
| 44 |
+
except subprocess.CalledProcessError as e:
|
| 45 |
+
print(f"\nError running the application: {e}")
|
| 46 |
+
sys.exit(1)
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"\nUnexpected error: {e}")
|
| 49 |
+
sys.exit(1)
|
| 50 |
+
|
| 51 |
+
if __name__ == "__main__":
|
| 52 |
+
main()
|
product_manager/organizer.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
#HackBuddyAI
|
| 3 |
+
|
| 4 |
+
Gradio APP for Hackathon Organizer
|
| 5 |
+
|
| 6 |
+
## Problem
|
| 7 |
+
Many people join hackathons individually, and they need to be matched with other individuals to form a team. If the formed team is not suitable, non-of the team members will benefit from the hackathon, they will churn and not participate in the next hackathon.
|
| 8 |
+
|
| 9 |
+
- Help individuals find the right team
|
| 10 |
+
- If a selected team is not suitable, or some of participants didn't show up, the organizer could re-run the matching process to find a new team in no time.
|
| 11 |
+
|
| 12 |
+
## Solution
|
| 13 |
+
1. Web application for participants to fill their profile and goals, e_mail field to be used as a unique identifier, link to their linkedin profile, text field (multilined) for their background, skills, why they like to join the hackathon, etc.
|
| 14 |
+
|
| 15 |
+
### 2. On form submission, the data will be stored in a database/ Google Sheet / SQLite
|
| 16 |
+
|
| 17 |
+
### 3. Organizer part:
|
| 18 |
+
Organizer could define custom system prompt, to navigate the system for matching the participants, for example group size, why organizer looks to have in each group, etc.
|
| 19 |
+
|
| 20 |
+
### 4. Matching Proccess,
|
| 21 |
+
AI Agent, will have access to pandas dataframe, including the participants data and organizer prefrences for matching.
|
| 22 |
+
It use its python code execution tool to actually interact with the data, and match the participants based on defined criteria.
|
| 23 |
+
|
| 24 |
+
## End result
|
| 25 |
+
List of teams with their members, and a short description why they are a good match. in Markdown format.
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
## Tech Stack
|
| 29 |
+
- Gradio
|
| 30 |
+
- Tiny Agent
|
| 31 |
+
- Tiny Code Agent
|
| 32 |
+
- Pandas
|
| 33 |
+
|
| 34 |
+
for developing the agent part we use tiny agent library, you have access to the documentation in the LLM_API_DOC.md file.
|
| 35 |
+
|
| 36 |
+
For the frontend we use gradio, gradio has an integration with tiny agent as well.
|
| 37 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
tinyagent-py[all]==0.0.12
|
| 2 |
+
cloudpickle
|
| 3 |
+
modal
|
| 4 |
+
jinja2
|
| 5 |
+
pyyaml
|
| 6 |
+
gradio[mcp]
|