Spaces:
Running
Running
Mahdiyar
commited on
Commit
Β·
9a255bf
1
Parent(s):
1f38061
initial version
Browse files- README.md +95 -1
- hackathon_organizer/__init__.py β __init__.py +0 -0
- hackathon_organizer/app.py β app.py +0 -0
- app_simple.py +146 -0
- hackathon_organizer/database.py β database.py +0 -0
- generate_participants.py +0 -372
- hackathon_organizer/README.md +0 -95
- hackathon_organizer/hackathon_participants.db +0 -0
- hackathon_organizer/requirements.txt +0 -7
- hackathon_participants.db +0 -0
- main.py +0 -52
- hackathon_organizer/matching_agent.py β matching_agent.py +0 -0
- notebook.ipynb +112 -0
- product_manager/organizer.md +0 -37
- requirements.txt +2 -1
- {hackathon_organizer/tests β tests}/__init__.py +0 -0
- tests/test_database.py +101 -0
- tests/test_matching_agent.py +71 -0
README.md
CHANGED
@@ -11,4 +11,98 @@ license: apache-2.0
|
|
11 |
short_description: Instantly match hackathon participants into ideal teams!
|
12 |
---
|
13 |
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
short_description: Instantly match hackathon participants into ideal teams!
|
12 |
---
|
13 |
|
14 |
+
# π€ AI-Powered HackBuddyAI
|
15 |
+
|
16 |
+
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.
|
17 |
+
|
18 |
+
The application features a two-tab interface:
|
19 |
+
1. **Participant Registration**: A form for participants to submit their profile, including skills, background, and what they want to achieve during the hackathon.
|
20 |
+
2. **Organizer Dashboard**: A view for the organizer to see all registered participants, define matching criteria, and run the AI-powered team formation process.
|
21 |
+
|
22 |
+
## Tech Stack
|
23 |
+
- **Backend**: Python
|
24 |
+
- **AI Agent Framework**: `TinyCodeAgent`
|
25 |
+
- **Web UI**: Gradio
|
26 |
+
- **Data Handling**: Pandas
|
27 |
+
- **Database**: SQLite
|
28 |
+
|
29 |
+
---
|
30 |
+
|
31 |
+
## Setup and Installation
|
32 |
+
|
33 |
+
### 1. Prerequisites
|
34 |
+
- Python 3.8+
|
35 |
+
- An OpenAI API key
|
36 |
+
|
37 |
+
### 2. Installation
|
38 |
+
1. **Clone the repository** (if applicable) or ensure you have the project files in a directory.
|
39 |
+
|
40 |
+
2. **Navigate to the project directory**:
|
41 |
+
```bash
|
42 |
+
cd path/to/project
|
43 |
+
```
|
44 |
+
|
45 |
+
3. **Create a virtual environment** (recommended):
|
46 |
+
```bash
|
47 |
+
python -m venv venv
|
48 |
+
source venv/bin/activate # On Windows, use `venv\Scripts\activate`
|
49 |
+
```
|
50 |
+
|
51 |
+
4. **Install dependencies**:
|
52 |
+
The project relies on the `tinyagent` library. Assuming it is available in your environment, install the other required packages:
|
53 |
+
```bash
|
54 |
+
pip install -r hackathon_organizer/requirements.txt
|
55 |
+
```
|
56 |
+
|
57 |
+
### 3. Configure Environment Variables
|
58 |
+
You must set your OpenAI API key as an environment variable. The application will not run without it.
|
59 |
+
|
60 |
+
- **On macOS/Linux**:
|
61 |
+
```bash
|
62 |
+
export OPENAI_API_KEY="your_api_key_here"
|
63 |
+
```
|
64 |
+
- **On Windows (Command Prompt)**:
|
65 |
+
```bash
|
66 |
+
set OPENAI_API_KEY="your_api_key_here"
|
67 |
+
```
|
68 |
+
|
69 |
+
---
|
70 |
+
|
71 |
+
## π Running the Application
|
72 |
+
|
73 |
+
Once the setup is complete, you can launch the Gradio web application using one of the following methods:
|
74 |
+
|
75 |
+
### Method 1: Using the main script (recommended)
|
76 |
+
|
77 |
+
```bash
|
78 |
+
python main.py
|
79 |
+
```
|
80 |
+
|
81 |
+
This script handles all the necessary path configurations and launches the application.
|
82 |
+
|
83 |
+
### Method 2: Running app.py directly
|
84 |
+
|
85 |
+
```bash
|
86 |
+
cd hackathon_organizer
|
87 |
+
python app.py
|
88 |
+
```
|
89 |
+
|
90 |
+
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`).
|
91 |
+
|
92 |
+
The application will create a `hackathon_participants.db` file in the working directory to store the participant data.
|
93 |
+
|
94 |
+
---
|
95 |
+
|
96 |
+
## π§ͺ Running Tests
|
97 |
+
|
98 |
+
The project includes unit tests for the database and the agent setup logic. The tests are located in the `tests/` directory.
|
99 |
+
|
100 |
+
To run the tests:
|
101 |
+
|
102 |
+
```bash
|
103 |
+
# From the project root directory
|
104 |
+
cd hackathon_organizer
|
105 |
+
python -m unittest discover tests
|
106 |
+
```
|
107 |
+
|
108 |
+
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 β __init__.py
RENAMED
File without changes
|
hackathon_organizer/app.py β app.py
RENAMED
File without changes
|
app_simple.py
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pandas as pd
|
3 |
+
import logging
|
4 |
+
import sys
|
5 |
+
import os
|
6 |
+
|
7 |
+
from database import initialize_database, add_participant, get_participants_dataframe
|
8 |
+
|
9 |
+
# --- Logging Setup ---
|
10 |
+
logging.basicConfig(
|
11 |
+
level=logging.INFO,
|
12 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
13 |
+
handlers=[logging.StreamHandler(sys.stdout)]
|
14 |
+
)
|
15 |
+
logger = logging.getLogger('app_simple')
|
16 |
+
|
17 |
+
# --- Initial Setup ---
|
18 |
+
logger.info("Initializing database...")
|
19 |
+
initialize_database()
|
20 |
+
|
21 |
+
# --- Gradio UI Functions ---
|
22 |
+
|
23 |
+
def register_participant(name, email, linkedin, background, goals):
|
24 |
+
"""Callback function to register a new participant."""
|
25 |
+
if not all([name, email]):
|
26 |
+
return "Please provide at least a name and email.", get_participants_dataframe()
|
27 |
+
|
28 |
+
participant_data = {
|
29 |
+
"name": name,
|
30 |
+
"email": email,
|
31 |
+
"linkedin_profile": linkedin,
|
32 |
+
"background": background,
|
33 |
+
"goals": goals
|
34 |
+
}
|
35 |
+
try:
|
36 |
+
add_participant(participant_data)
|
37 |
+
feedback = f"β
Success! Participant '{name}' registered."
|
38 |
+
logger.info(f"Registered new participant: {email}")
|
39 |
+
except Exception as e:
|
40 |
+
feedback = f"β Error! Could not register participant. Reason: {e}"
|
41 |
+
logger.error(f"Failed to register participant {email}: {e}")
|
42 |
+
|
43 |
+
return feedback, get_participants_dataframe()
|
44 |
+
|
45 |
+
def refresh_participants_list():
|
46 |
+
"""Callback to reload the participant data from the database."""
|
47 |
+
return get_participants_dataframe()
|
48 |
+
|
49 |
+
def mock_matching_process(organizer_criteria):
|
50 |
+
"""Mock function for the matching process (without using TinyCodeAgent)."""
|
51 |
+
participants_df = get_participants_dataframe()
|
52 |
+
if len(participants_df) < 2:
|
53 |
+
logger.warning("Matching process aborted: not enough participants.")
|
54 |
+
return "Cannot run matching with fewer than 2 participants."
|
55 |
+
|
56 |
+
# Create a simple mock output
|
57 |
+
result = f"""
|
58 |
+
## Team Matching Results
|
59 |
+
|
60 |
+
**Criteria used**: {organizer_criteria}
|
61 |
+
|
62 |
+
### Team 1
|
63 |
+
* **{participants_df['name'].iloc[0] if len(participants_df) > 0 else 'No participants'}**
|
64 |
+
* **{participants_df['name'].iloc[1] if len(participants_df) > 1 else 'No participants'}**
|
65 |
+
|
66 |
+
**Justification**: This is a mock team created for demonstration purposes.
|
67 |
+
|
68 |
+
### Team 2
|
69 |
+
* **{participants_df['name'].iloc[2] if len(participants_df) > 2 else 'No participants'}**
|
70 |
+
* **{participants_df['name'].iloc[3] if len(participants_df) > 3 else 'No participants'}**
|
71 |
+
|
72 |
+
**Justification**: This is another mock team created for demonstration purposes.
|
73 |
+
|
74 |
+
*Note: This is a simplified version without the AI matching. The full version would use TinyCodeAgent to create optimized teams.*
|
75 |
+
"""
|
76 |
+
return result
|
77 |
+
|
78 |
+
# --- Gradio App Definition ---
|
79 |
+
|
80 |
+
with gr.Blocks(theme=gr.themes.Soft(), title="HackBuddyAI (Simple)") as app:
|
81 |
+
gr.Markdown("# π€ HackBuddyAI (Simple Version)")
|
82 |
+
gr.Markdown("*This is a simplified version without the AI matching component.*")
|
83 |
+
|
84 |
+
with gr.Tabs():
|
85 |
+
with gr.TabItem("π€ Participant Registration"):
|
86 |
+
gr.Markdown("## Welcome, Participant!")
|
87 |
+
gr.Markdown("Fill out the form below to register for the hackathon.")
|
88 |
+
with gr.Row():
|
89 |
+
with gr.Column():
|
90 |
+
name_in = gr.Textbox(label="Full Name")
|
91 |
+
email_in = gr.Textbox(label="Email Address")
|
92 |
+
linkedin_in = gr.Textbox(label="LinkedIn Profile URL", placeholder="Optional")
|
93 |
+
with gr.Column():
|
94 |
+
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...")
|
95 |
+
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...")
|
96 |
+
|
97 |
+
submit_button = gr.Button("Register", variant="primary")
|
98 |
+
registration_feedback = gr.Markdown()
|
99 |
+
|
100 |
+
with gr.TabItem("π Organizer Dashboard"):
|
101 |
+
gr.Markdown("## Welcome, Organizer!")
|
102 |
+
gr.Markdown("Here you can view registered participants and run the team matching process.")
|
103 |
+
|
104 |
+
with gr.Accordion("View Registered Participants", open=False):
|
105 |
+
refresh_button = gr.Button("π Refresh List")
|
106 |
+
participants_df_out = gr.DataFrame(value=get_participants_dataframe, interactive=False)
|
107 |
+
|
108 |
+
gr.Markdown("### Run Matching")
|
109 |
+
organizer_criteria_in = gr.Textbox(
|
110 |
+
label="Matching Criteria",
|
111 |
+
lines=4,
|
112 |
+
value="Create teams of 3. Try to balance skills in each team (e.g., frontend, backend, data).",
|
113 |
+
placeholder="Describe your ideal team composition..."
|
114 |
+
)
|
115 |
+
run_button = gr.Button("π Run Matching", variant="primary")
|
116 |
+
|
117 |
+
gr.Markdown("### π€ Matched Teams")
|
118 |
+
matching_results_out = gr.Markdown("Matching has not been run yet.")
|
119 |
+
|
120 |
+
# --- Event Handlers ---
|
121 |
+
submit_button.click(
|
122 |
+
fn=register_participant,
|
123 |
+
inputs=[name_in, email_in, linkedin_in, background_in, goals_in],
|
124 |
+
outputs=[registration_feedback, participants_df_out]
|
125 |
+
)
|
126 |
+
|
127 |
+
refresh_button.click(
|
128 |
+
fn=refresh_participants_list,
|
129 |
+
inputs=[],
|
130 |
+
outputs=[participants_df_out]
|
131 |
+
)
|
132 |
+
|
133 |
+
run_button.click(
|
134 |
+
fn=mock_matching_process,
|
135 |
+
inputs=[organizer_criteria_in],
|
136 |
+
outputs=[matching_results_out]
|
137 |
+
)
|
138 |
+
|
139 |
+
# --- Launching the App ---
|
140 |
+
if __name__ == "__main__":
|
141 |
+
try:
|
142 |
+
logger.info("Launching Gradio app (simple version)...")
|
143 |
+
# queue() is important for handling multiple users
|
144 |
+
app.queue().launch(share=False)
|
145 |
+
except KeyboardInterrupt:
|
146 |
+
logger.info("Gradio app shutting down.")
|
hackathon_organizer/database.py β database.py
RENAMED
File without changes
|
generate_participants.py
DELETED
@@ -1,372 +0,0 @@
|
|
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
DELETED
@@ -1,95 +0,0 @@
|
|
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/hackathon_participants.db
DELETED
Binary file (41 kB)
|
|
hackathon_organizer/requirements.txt
DELETED
@@ -1,7 +0,0 @@
|
|
1 |
-
tinyagent-py[all]==0.0.12
|
2 |
-
cloudpickle
|
3 |
-
modal
|
4 |
-
jinja2
|
5 |
-
pyyaml
|
6 |
-
gradio[mcp]
|
7 |
-
pandas
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hackathon_participants.db
CHANGED
Binary files a/hackathon_participants.db and b/hackathon_participants.db differ
|
|
main.py
DELETED
@@ -1,52 +0,0 @@
|
|
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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hackathon_organizer/matching_agent.py β matching_agent.py
RENAMED
File without changes
|
notebook.ipynb
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": null,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [],
|
8 |
+
"source": []
|
9 |
+
},
|
10 |
+
{
|
11 |
+
"cell_type": "code",
|
12 |
+
"execution_count": 1,
|
13 |
+
"metadata": {},
|
14 |
+
"outputs": [],
|
15 |
+
"source": [
|
16 |
+
"%load_ext autoreload\n",
|
17 |
+
"%autoreload 2\n"
|
18 |
+
]
|
19 |
+
},
|
20 |
+
{
|
21 |
+
"cell_type": "code",
|
22 |
+
"execution_count": 2,
|
23 |
+
"metadata": {},
|
24 |
+
"outputs": [
|
25 |
+
{
|
26 |
+
"data": {
|
27 |
+
"text/plain": [
|
28 |
+
"True"
|
29 |
+
]
|
30 |
+
},
|
31 |
+
"execution_count": 2,
|
32 |
+
"metadata": {},
|
33 |
+
"output_type": "execute_result"
|
34 |
+
}
|
35 |
+
],
|
36 |
+
"source": [
|
37 |
+
"import json\n",
|
38 |
+
"\n",
|
39 |
+
"import os\n",
|
40 |
+
"from dotenv import load_dotenv\n",
|
41 |
+
"import nest_asyncio\n",
|
42 |
+
"nest_asyncio.apply()\n",
|
43 |
+
"\n",
|
44 |
+
"# Load environment variables from a .env file\n",
|
45 |
+
"load_dotenv()"
|
46 |
+
]
|
47 |
+
},
|
48 |
+
{
|
49 |
+
"cell_type": "code",
|
50 |
+
"execution_count": 3,
|
51 |
+
"metadata": {},
|
52 |
+
"outputs": [],
|
53 |
+
"source": [
|
54 |
+
"import tinyagent\n",
|
55 |
+
"from textwrap import dedent\n",
|
56 |
+
"import tinyagent.hooks\n",
|
57 |
+
"import tinyagent.hooks.rich_ui_callback\n",
|
58 |
+
"import tinyagent.mcp_client\n",
|
59 |
+
"import tinyagent.storage.json_file_storage\n",
|
60 |
+
"import tinyagent.storage.postgres_storage\n",
|
61 |
+
"import tinyagent.storage.sqlite_storage\n",
|
62 |
+
"from tinyagent import tool"
|
63 |
+
]
|
64 |
+
},
|
65 |
+
{
|
66 |
+
"cell_type": "code",
|
67 |
+
"execution_count": null,
|
68 |
+
"metadata": {},
|
69 |
+
"outputs": [
|
70 |
+
{
|
71 |
+
"ename": "SyntaxError",
|
72 |
+
"evalue": "invalid syntax (1561902338.py, line 1)",
|
73 |
+
"output_type": "error",
|
74 |
+
"traceback": [
|
75 |
+
" \u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[5]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[31m \u001b[39m\u001b[31mimport .create_matching_agent\u001b[39m\n ^\n\u001b[31mSyntaxError\u001b[39m\u001b[31m:\u001b[39m invalid syntax\n"
|
76 |
+
]
|
77 |
+
}
|
78 |
+
],
|
79 |
+
"source": [
|
80 |
+
"import create_matching_agent"
|
81 |
+
]
|
82 |
+
},
|
83 |
+
{
|
84 |
+
"cell_type": "code",
|
85 |
+
"execution_count": null,
|
86 |
+
"metadata": {},
|
87 |
+
"outputs": [],
|
88 |
+
"source": []
|
89 |
+
}
|
90 |
+
],
|
91 |
+
"metadata": {
|
92 |
+
"kernelspec": {
|
93 |
+
"display_name": "Python 3.11 (askdev_p311)",
|
94 |
+
"language": "python",
|
95 |
+
"name": "askdev_p311"
|
96 |
+
},
|
97 |
+
"language_info": {
|
98 |
+
"codemirror_mode": {
|
99 |
+
"name": "ipython",
|
100 |
+
"version": 3
|
101 |
+
},
|
102 |
+
"file_extension": ".py",
|
103 |
+
"mimetype": "text/x-python",
|
104 |
+
"name": "python",
|
105 |
+
"nbconvert_exporter": "python",
|
106 |
+
"pygments_lexer": "ipython3",
|
107 |
+
"version": "3.11.11"
|
108 |
+
}
|
109 |
+
},
|
110 |
+
"nbformat": 4,
|
111 |
+
"nbformat_minor": 2
|
112 |
+
}
|
product_manager/organizer.md
DELETED
@@ -1,37 +0,0 @@
|
|
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
CHANGED
@@ -3,4 +3,5 @@ cloudpickle
|
|
3 |
modal
|
4 |
jinja2
|
5 |
pyyaml
|
6 |
-
gradio[mcp]
|
|
|
|
3 |
modal
|
4 |
jinja2
|
5 |
pyyaml
|
6 |
+
gradio[mcp]
|
7 |
+
pandas
|
{hackathon_organizer/tests β tests}/__init__.py
RENAMED
File without changes
|
tests/test_database.py
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
import os
|
3 |
+
import pandas as pd
|
4 |
+
import sys
|
5 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
6 |
+
from database import initialize_database, add_participant, get_participants_dataframe
|
7 |
+
|
8 |
+
# Use a separate test database
|
9 |
+
TEST_DB_PATH = "test_hackathon.db"
|
10 |
+
|
11 |
+
class TestDatabase(unittest.TestCase):
|
12 |
+
|
13 |
+
@classmethod
|
14 |
+
def setUpClass(cls):
|
15 |
+
"""Set up a test database before any tests run."""
|
16 |
+
cls.db_path = TEST_DB_PATH
|
17 |
+
# Point the database module to the test DB
|
18 |
+
import database
|
19 |
+
database.DB_PATH = cls.db_path
|
20 |
+
|
21 |
+
def setUp(self):
|
22 |
+
"""Initialize a clean database before each test."""
|
23 |
+
if os.path.exists(self.db_path):
|
24 |
+
os.remove(self.db_path)
|
25 |
+
initialize_database()
|
26 |
+
|
27 |
+
def tearDown(self):
|
28 |
+
"""Remove the database file after each test."""
|
29 |
+
if os.path.exists(self.db_path):
|
30 |
+
os.remove(self.db_path)
|
31 |
+
|
32 |
+
def test_01_initialize_database(self):
|
33 |
+
"""Test that the database and table are created."""
|
34 |
+
self.assertTrue(os.path.exists(self.db_path))
|
35 |
+
df = get_participants_dataframe()
|
36 |
+
self.assertIsInstance(df, pd.DataFrame)
|
37 |
+
self.assertEqual(len(df), 0)
|
38 |
+
|
39 |
+
def test_02_add_and_get_participant(self):
|
40 |
+
"""Test adding a single participant and retrieving it."""
|
41 |
+
participant = {
|
42 |
+
"email": "[email protected]",
|
43 |
+
"name": "Test User",
|
44 |
+
"linkedin_profile": "linkedin.com/in/test",
|
45 |
+
"background": "Testing background.",
|
46 |
+
"goals": "Testing goals."
|
47 |
+
}
|
48 |
+
add_participant(participant)
|
49 |
+
|
50 |
+
df = get_participants_dataframe()
|
51 |
+
self.assertEqual(len(df), 1)
|
52 |
+
|
53 |
+
retrieved = df.iloc[0]
|
54 |
+
self.assertEqual(retrieved["email"], participant["email"])
|
55 |
+
self.assertEqual(retrieved["name"], participant["name"])
|
56 |
+
|
57 |
+
def test_03_add_multiple_participants(self):
|
58 |
+
"""Test adding multiple participants."""
|
59 |
+
participants_to_add = [
|
60 |
+
{"email": "[email protected]", "name": "User One", "linkedin_profile": "", "background": "", "goals": ""},
|
61 |
+
{"email": "[email protected]", "name": "User Two", "linkedin_profile": "", "background": "", "goals": ""},
|
62 |
+
]
|
63 |
+
for p in participants_to_add:
|
64 |
+
add_participant(p)
|
65 |
+
|
66 |
+
df = get_participants_dataframe()
|
67 |
+
self.assertEqual(len(df), 2)
|
68 |
+
self.assertIn("[email protected]", df["email"].values)
|
69 |
+
self.assertIn("[email protected]", df["email"].values)
|
70 |
+
|
71 |
+
def test_04_replace_participant(self):
|
72 |
+
"""Test that adding a participant with an existing email updates the record."""
|
73 |
+
original_participant = {
|
74 |
+
"email": "[email protected]",
|
75 |
+
"name": "Original Name",
|
76 |
+
"linkedin_profile": "original_linkedin",
|
77 |
+
"background": "original_background",
|
78 |
+
"goals": "original_goals"
|
79 |
+
}
|
80 |
+
add_participant(original_participant)
|
81 |
+
|
82 |
+
df_before = get_participants_dataframe()
|
83 |
+
self.assertEqual(len(df_before), 1)
|
84 |
+
self.assertEqual(df_before.iloc[0]["name"], "Original Name")
|
85 |
+
|
86 |
+
updated_participant = {
|
87 |
+
"email": "[email protected]",
|
88 |
+
"name": "Updated Name",
|
89 |
+
"linkedin_profile": "updated_linkedin",
|
90 |
+
"background": "updated_background",
|
91 |
+
"goals": "updated_goals"
|
92 |
+
}
|
93 |
+
add_participant(updated_participant)
|
94 |
+
|
95 |
+
df_after = get_participants_dataframe()
|
96 |
+
self.assertEqual(len(df_after), 1)
|
97 |
+
self.assertEqual(df_after.iloc[0]["name"], "Updated Name")
|
98 |
+
self.assertEqual(df_after.iloc[0]["linkedin_profile"], "updated_linkedin")
|
99 |
+
|
100 |
+
if __name__ == '__main__':
|
101 |
+
unittest.main()
|
tests/test_matching_agent.py
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
from unittest.mock import patch, MagicMock, AsyncMock
|
3 |
+
import pandas as pd
|
4 |
+
import os
|
5 |
+
import sys
|
6 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
7 |
+
from tinyagent import TinyCodeAgent
|
8 |
+
from matching_agent import create_matching_agent, run_matching
|
9 |
+
|
10 |
+
class TestMatchingAgent(unittest.TestCase):
|
11 |
+
|
12 |
+
@patch.dict(os.environ, {"OPENAI_API_KEY": "test_key"})
|
13 |
+
def test_01_create_matching_agent(self):
|
14 |
+
"""
|
15 |
+
Test the creation and configuration of the matching agent.
|
16 |
+
"""
|
17 |
+
agent = create_matching_agent()
|
18 |
+
|
19 |
+
self.assertIsInstance(agent, TinyCodeAgent)
|
20 |
+
self.assertEqual(agent.model, "gpt-4.1-mini")
|
21 |
+
self.assertIn("You are a brilliant hackathon team-matching AI.", agent.system_prompt)
|
22 |
+
self.assertIn("participants_df", agent.system_prompt)
|
23 |
+
self.assertIn("organizer_criteria", agent.system_prompt)
|
24 |
+
|
25 |
+
# Check code execution environment settings
|
26 |
+
self.assertIn("pandas", agent.pip_packages)
|
27 |
+
self.assertIn("scikit-learn", agent.pip_packages)
|
28 |
+
self.assertIn("pandas", agent.authorized_imports)
|
29 |
+
|
30 |
+
@patch.dict(os.environ, {"OPENAI_API_KEY": "test_key"})
|
31 |
+
def test_02_run_matching(self):
|
32 |
+
"""
|
33 |
+
Test the run_matching function to ensure it configures the agent
|
34 |
+
and calls the run method correctly.
|
35 |
+
"""
|
36 |
+
# Create a mock agent to isolate the test from the actual TinyCodeAgent implementation
|
37 |
+
mock_agent = MagicMock(spec=TinyCodeAgent)
|
38 |
+
mock_agent.run = AsyncMock(return_value="## Mocked Team Report")
|
39 |
+
|
40 |
+
# Sample data
|
41 |
+
participants_df = pd.DataFrame({
|
42 |
+
"name": ["Alice", "Bob"],
|
43 |
+
"skills": ["Frontend", "Backend"]
|
44 |
+
})
|
45 |
+
organizer_criteria = "Create teams of 2."
|
46 |
+
|
47 |
+
# Define an async test function to run the coroutine
|
48 |
+
async def do_run_matching():
|
49 |
+
result = await run_matching(mock_agent, participants_df, organizer_criteria)
|
50 |
+
|
51 |
+
# --- Assertions ---
|
52 |
+
# 1. Check that user_variables were set correctly on the agent
|
53 |
+
self.assertIn("participants_df", mock_agent.user_variables)
|
54 |
+
self.assertIn("organizer_criteria", mock_agent.user_variables)
|
55 |
+
pd.testing.assert_frame_equal(mock_agent.user_variables["participants_df"], participants_df)
|
56 |
+
self.assertEqual(mock_agent.user_variables["organizer_criteria"], organizer_criteria)
|
57 |
+
|
58 |
+
# 2. Check that agent.run was called correctly
|
59 |
+
mock_agent.run.assert_called_once()
|
60 |
+
# The first argument to run should be the user prompt
|
61 |
+
self.assertEqual(mock_agent.run.call_args[0][0], "Form the teams based on the provided data and criteria.")
|
62 |
+
|
63 |
+
# 3. Check the result
|
64 |
+
self.assertEqual(result, "## Mocked Team Report")
|
65 |
+
|
66 |
+
# Run the async test function
|
67 |
+
import asyncio
|
68 |
+
asyncio.run(do_run_matching())
|
69 |
+
|
70 |
+
if __name__ == '__main__':
|
71 |
+
unittest.main()
|