Spaces:
Running
Running
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]
|