Dev9893/encoder
0
1import streamlit as st2import json3import os4import numpy as np5from sklearn.metrics.pairwise import cosine_similarity6import re7from datetime import datetime, date, timedelta8import pandas as pd9from PIL import Image10import plotly.express as px11import plotly.graph_objects as go12import random13 14# Configuration15st.set_page_config(16 page_title="HackMate - CYHI Quick Teams",17 page_icon="โก",18 layout="wide",19 initial_sidebar_state="expanded"20)21 22# Custom CSS for better styling23st.markdown("""24<style>25 .main-header {26 background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);27 padding: 2rem 1rem;28 border-radius: 10px;29 color: white;30 text-align: center;31 margin-bottom: 2rem;32 }33 .profile-card {34 background: #1a1a2e;35 padding: 1.5rem;36 border-radius: 15px;37 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);38 border-left: 5px solid #667eea;39 margin: 1rem 0;40 color: white;41 }42 .team-card {43 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);44 padding: 1.5rem;45 border-radius: 15px;46 color: white;47 margin: 1rem 0;48 position: relative;49 overflow: hidden;50 }51 .team-card::before {52 content: '';53 position: absolute;54 top: -50%;55 left: -50%;56 width: 200%;57 height: 200%;58 background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);59 animation: pulse 3s ease-in-out infinite;60 }61 @keyframes pulse {62 0%, 100% { transform: scale(1); opacity: 0.5; }63 50% { transform: scale(1.1); opacity: 0.8; }64 }65 .quick-match-card {66 background: linear-gradient(45deg, #ff6b6b, #feca57);67 padding: 1rem;68 border-radius: 10px;69 color: white;70 text-align: center;71 margin: 0.5rem 0;72 }73 .skill-badge {74 display: inline-block;75 background: #667eea;76 color: white;77 padding: 0.3rem 0.8rem;78 border-radius: 20px;79 margin: 0.2rem;80 font-size: 0.8rem;81 }82 .urgent-badge {83 background: #ff4757 !important;84 animation: blink 1s infinite;85 }86 @keyframes blink {87 0%, 50% { opacity: 1; }88 51%, 100% { opacity: 0.5; }89 }90 .metric-card {91 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);92 padding: 1rem;93 border-radius: 10px;94 color: white;95 text-align: center;96 }97 .score-badge {98 display: inline-block;99 padding: 0.5rem 1rem;100 border-radius: 20px;101 color: white;102 font-weight: bold;103 margin: 0.2rem;104 font-size: 0.9rem;105 }106 .score-excellent { background: #2ecc71; }107 .score-good { background: #f39c12; }108 .score-average { background: #e67e22; }109 .score-poor { background: #e74c3c; }110 .single-score-card {111 background: #2c2c54;112 border: 2px solid #667eea;113 border-radius: 15px;114 padding: 1rem;115 margin: 0.5rem 0;116 color: white;117 text-align: center;118 }119 .stButton > button {120 background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);121 color: white;122 border-radius: 25px;123 border: none;124 padding: 0.5rem 2rem;125 font-weight: bold;126 transition: all 0.3s;127 }128 .stButton > button:hover {129 transform: translateY(-2px);130 box-shadow: 0 4px 8px rgba(0,0,0,0.2);131 }132 /* Remove white backgrounds globally */133 .stApp {134 background-color: #0f0f1a;135 }136 .main .block-container {137 background-color: transparent;138 }139 div[data-testid="stVerticalBlock"] > div {140 background-color: transparent;141 }142 .element-container {143 background-color: transparent;144 }145 .pending-request {146 background: linear-gradient(45deg, #ff9a3c, #ff6b6b) !important;147 border-left: 5px solid #ff9a3c;148 }149 .accepted-request {150 background: linear-gradient(45deg, #2ecc71, #27ae60) !important;151 border-left: 5px solid #2ecc71;152 }153 .rejected-request {154 background: linear-gradient(45deg, #e74c3c, #c0392b) !important;155 border-left: 5px solid #e74c3c;156 }157</style>158""", unsafe_allow_html=True)159 160# File paths161CATEGORIES_FILE = 'categories.json'162USERS_FILE = 'users.json'163TEAMS_FILE = 'teams.json'164QUICK_TEAMS_FILE = 'quick_teams.json'165HACKATHONS_FILE = 'hackathons.json'166TEAM_REQUESTS_FILE = 'team_requests.json'167UPLOAD_DIR = 'src'168 169# Create upload directory if it doesn't exist170if not os.path.exists(UPLOAD_DIR):171 os.makedirs(UPLOAD_DIR)172 173# Initialize session state174if 'show_instant_match' not in st.session_state:175 st.session_state['show_instant_match'] = False176if 'show_create_team' not in st.session_state:177 st.session_state['show_create_team'] = False178if 'selected_team' not in st.session_state:179 st.session_state['selected_team'] = None180 181def load_json(file_path):182 """Load JSON data from file with error handling"""183 try:184 if os.path.exists(file_path):185 with open(file_path, 'r', encoding='utf-8') as f:186 return json.load(f)187 else:188 return {}189 except Exception as e:190 st.error(f"Error loading {file_path}: {str(e)}")191 return {}192 193def save_json(file_path, data):194 """Save JSON data to file with error handling"""195 try:196 with open(file_path, 'w', encoding='utf-8') as f:197 json.dump(data, f, indent=4, ensure_ascii=False)198 except Exception as e:199 st.error(f"Error saving {file_path}: {str(e)}")200 201def add_user_profile(profile):202 """Add user profile to the database"""203 users = load_json(USERS_FILE)204 users[profile['name']] = profile205 save_json(USERS_FILE, users)206 207def get_all_users():208 """Get all user profiles"""209 users = load_json(USERS_FILE)210 return list(users.values())211 212def save_team(team_data):213 """Save team data"""214 teams = load_json(TEAMS_FILE)215 team_id = f"team_{len(teams) + 1}_{datetime.now().strftime('%Y%m%d%H%M%S')}"216 teams[team_id] = team_data217 save_json(TEAMS_FILE, teams)218 return team_id219 220def get_all_teams():221 """Get all teams"""222 teams = load_json(TEAMS_FILE)223 return list(teams.values())224 225def save_quick_team(quick_team_data):226 """Save quick team data"""227 quick_teams = load_json(QUICK_TEAMS_FILE)228 team_id = f"quick_{len(quick_teams) + 1}_{datetime.now().strftime('%Y%m%d%H%M%S')}"229 quick_teams[team_id] = quick_team_data230 save_json(QUICK_TEAMS_FILE, quick_teams)231 return team_id232 233def get_quick_teams():234 """Get all quick teams"""235 quick_teams = load_json(QUICK_TEAMS_FILE)236 return list(quick_teams.values())237 238def get_team_requests():239 """Get all team requests"""240 return load_json(TEAM_REQUESTS_FILE)241 242def save_team_request(request_data):243 """Save a team request"""244 requests = get_team_requests()245 request_id = f"request_{len(requests) + 1}_{datetime.now().strftime('%Y%m%d%H%M%S')}"246 requests[request_id] = request_data247 save_json(TEAM_REQUESTS_FILE, requests)248 return request_id249 250def update_team_request(request_id, updates):251 """Update a team request"""252 requests = get_team_requests()253 if request_id in requests:254 requests[request_id].update(updates)255 save_json(TEAM_REQUESTS_FILE, requests)256 return True257 return False258 259def get_user_team_requests(username):260 """Get all team requests for a specific user"""261 requests = get_team_requests()262 user_requests = []263 264 for req_id, req_data in requests.items():265 if req_data.get('to_user') == username or req_data.get('from_user') == username:266 user_requests.append((req_id, req_data))267 268 return user_requests269 270def get_team_by_id(team_id):271 """Get a specific team by ID"""272 teams = load_json(TEAMS_FILE)273 return teams.get(team_id)274 275def update_team(team_id, updates):276 """Update a team"""277 teams = load_json(TEAMS_FILE)278 if team_id in teams:279 teams[team_id].update(updates)280 save_json(TEAMS_FILE, teams)281 return True282 return False283 284# ML Skillset Enhancer Functions285def vectorize_profiles(profiles, all_skills):286 """Convert profiles to vector representation based on skills"""287 matrix = []288 for p in profiles:289 skills_lower = [s.lower() for s in p.get('skills', [])]290 row = [1 if skill in skills_lower else 0 for skill in all_skills]291 matrix.append(row)292 return np.array(matrix)293 294def find_best_matches(user_profile, profiles, top_k=5):295 """Find best matches using cosine similarity"""296 all_skills = set()297 for p in profiles:298 all_skills.update([s.lower() for s in p.get('skills', [])])299 all_skills.update([s.lower() for s in user_profile.get('skills', [])])300 all_skills = sorted(list(all_skills))301 302 if not all_skills:303 return []304 305 try:306 matrix = vectorize_profiles(profiles, all_skills)307 user_vec = np.array([[1 if s in [sk.lower() for sk in user_profile.get('skills', [])] else 0 for s in all_skills]])308 309 if matrix.size > 0 and user_vec.size > 0:310 sims = cosine_similarity(user_vec, matrix)[0]311 idx_sim = sorted([(i, s) for i, s in enumerate(sims) if s < 0.999], key=lambda x: x[1], reverse=True)[:top_k]312 313 user_avail = set(user_profile.get('availability', []))314 matches = []315 for idx, sim in idx_sim:316 if idx < len(profiles):317 candidate = profiles[idx]318 cand_avail = set(candidate.get('availability', []))319 # Check overlapping availability320 if user_avail and cand_avail and user_avail.isdisjoint(cand_avail):321 continue322 matches.append((candidate, sim))323 return matches324 except Exception as e:325 st.error(f"Error in finding matches: {str(e)}")326 return []327 328 return []329 330def analyze_fit(cat_sel, dom_sel, selected_skills, categories):331 """Analyze skill fit for a specific domain"""332 if not categories or cat_sel not in categories or dom_sel not in categories[cat_sel]['domains']:333 return None334 335 domain_skills = set(s.lower() for s in categories[cat_sel]['domains'][dom_sel])336 user_skills = set(s.lower() for s in selected_skills)337 338 matched = user_skills.intersection(domain_skills)339 missing = domain_skills.difference(user_skills)340 341 max_score = max(len(domain_skills), 10)342 score = min(100, (len(matched) / max_score) * 100) if max_score > 0 else 0343 344 if score >= 80:345 rec = "Excellent fit! Strong skills for this role."346 elif score >= 60:347 rec = f"Good fit; consider improving missing skills: {', '.join(list(missing)[:3])}"348 elif score >= 40:349 rec = f"Moderate fit; focus on acquiring key skills: {', '.join(list(missing)[:3])}"350 else:351 rec = f"Low fit; strongly recommend gaining these skills: {', '.join(list(missing)[:3])}"352 353 return {354 "score": score,355 "matched": matched,356 "missing": missing,357 "recommendation": rec,358 }359 360def calculate_domain_scores(user_profile, categories):361 """Calculate domain match scores for a user"""362 user_skills = set(skill.lower() for skill in user_profile.get('skills', []))363 domain_scores = {}364 365 for cat, cat_info in categories.items():366 for domain, skills in cat_info.get("domains", {}).items():367 domain_skills = set(skill.lower() for skill in skills)368 if domain_skills:369 matched = user_skills.intersection(domain_skills)370 score = (len(matched) / len(domain_skills)) * 100371 domain_scores[domain] = {372 'score': score,373 'matched': matched,374 'missing': domain_skills - user_skills,375 'category': cat376 }377 378 return domain_scores379 380def get_score_class(score):381 """Get CSS class for score badge"""382 if score >= 80:383 return "score-excellent"384 elif score >= 60:385 return "score-good"386 elif score >= 40:387 return "score-average"388 else:389 return "score-poor"390 391def get_score_label(score):392 """Get label for score"""393 if score >= 80:394 return "Excellent"395 elif score >= 60:396 return "Good"397 elif score >= 40:398 return "Average"399 else:400 return "Needs Work"401 402def display_profile_card_with_scores(user, categories, show_scores=True, role=None):403 """Display a profile card with single domain score"""404 with st.container():405 role_emoji = {"Team Lead": "๐", "Tech Lead": "๐", "Designer": "๐จ", "Backend Dev": "โ", 406 "Frontend Dev": "๐ป", "Data Specialist": "๐", "Business Analyst": "๐"}.get(role, "๐ค")407 408 col1, col2 = st.columns([3, 1])409 410 with col1:411 st.markdown(f"""412 <div class="profile-card">413 <h3>{role_emoji} {user['name']} {f"({role})" if role else ""}</h3>414 <p><strong>๐ Bio:</strong> {user.get('bio', 'Ready to hack!')[:100]}...</p>415 <p><strong>๐ฏ Domain:</strong> {', '.join(user.get('domain', ['General']))}</p>416 <p><strong>๐ Experience:</strong> {user.get('experience_level', 'Intermediate')}</p>417 <p><strong>โฐ Availability:</strong> {', '.join(user.get('availability', ['Flexible']))}</p>418 </div>419 """, unsafe_allow_html=True)420 421 # Skills as badges422 if user.get('skills'):423 skills_html = ""424 for skill in user['skills'][:8]: # Limit to 8 skills for display425 skills_html += f'<span class="skill-badge">{skill}</span>'426 if len(user['skills']) > 8:427 skills_html += f'<span class="skill-badge">+{len(user["skills"]) - 8} more</span>'428 st.markdown(skills_html, unsafe_allow_html=True)429 430 with col2:431 if show_scores and categories:432 domain_scores = calculate_domain_scores(user, categories)433 434 if domain_scores:435 # Get the highest scoring domain only436 best_domain, best_data = max(domain_scores.items(), key=lambda x: x[1]['score'])437 score = best_data['score']438 score_class = get_score_class(score)439 score_label = get_score_label(score)440 441 st.markdown(f"""442 <div class="single-score-card">443 <h4>๐ฏ Best Match</h4>444 <strong>{best_domain}</strong><br>445 <span class="score-badge {score_class}">{score:.0f}% - {score_label}</span>446 </div>447 """, unsafe_allow_html=True)448 449def create_instant_team_match(user_profile, hackathon_context=None):450 """Create instant team matches based on complementary skills and hackathon needs"""451 users = get_all_users()452 453 if len(users) < 2:454 return None455 456 user_skills = set(s.lower() for s in user_profile.get('skills', []))457 matches = []458 459 for candidate in users:460 if candidate['name'] == user_profile['name']:461 continue462 463 candidate_skills = set(s.lower() for s in candidate.get('skills', []))464 465 # Calculate complementary score (different skills are better for teams)466 complement_score = len(user_skills.symmetric_difference(candidate_skills))467 overlap_penalty = len(user_skills.intersection(candidate_skills)) * 0.5468 469 # Availability match470 user_avail = set(user_profile.get('availability', []))471 cand_avail = set(candidate.get('availability', []))472 avail_score = len(user_avail.intersection(cand_avail)) if user_avail and cand_avail else 0.5473 474 # Experience diversity bonus475 exp_levels = {"Beginner": 1, "Intermediate": 2, "Advanced": 3, "Expert": 4}476 user_exp = exp_levels.get(user_profile.get('experience_level', 'Intermediate'), 2)477 cand_exp = exp_levels.get(candidate.get('experience_level', 'Intermediate'), 2)478 exp_diversity = abs(user_exp - cand_exp) * 0.3 # Reward diversity479 480 total_score = complement_score + avail_score * 2 + exp_diversity - overlap_penalty481 482 if total_score > 0:483 matches.append((candidate, total_score))484 485 matches.sort(key=lambda x: x[1], reverse=True)486 return matches[:3] # Return top 3 matches487 488def generate_team_roles(team_members, hackathon_theme=None):489 """Generate optimal role assignments for team members"""490 roles = {491 'Team Lead': {'skills': ['leadership', 'project management', 'communication'], 'assigned': None},492 'Tech Lead': {'skills': ['programming', 'software development', 'architecture'], 'assigned': None},493 'Designer': {'skills': ['ui/ux', 'design', 'figma', 'adobe', 'graphics'], 'assigned': None},494 'Backend Dev': {'skills': ['python', 'java', 'node.js', 'database', 'api'], 'assigned': None},495 'Frontend Dev': {'skills': ['react', 'javascript', 'html', 'css', 'vue'], 'assigned': None},496 'Data Specialist': {'skills': ['data science', 'machine learning', 'analytics', 'sql'], 'assigned': None},497 'Business Analyst': {'skills': ['business', 'strategy', 'marketing', 'finance'], 'assigned': None}498 }499 500 # Score each member for each role501 for role, role_info in roles.items():502 best_score = 0503 best_member = None504 505 for member in team_members:506 member_skills = [s.lower() for s in member.get('skills', [])]507 score = sum(1 for skill in role_info['skills'] if any(skill in ms for ms in member_skills))508 509 # Bonus for experience level510 exp_bonus = {'Expert': 3, 'Advanced': 2, 'Intermediate': 1, 'Beginner': 0.5}511 score += exp_bonus.get(member.get('experience_level', 'Intermediate'), 1)512 513 if score > best_score:514 best_score = score515 best_member = member516 517 if best_member:518 roles[role]['assigned'] = best_member['name']519 roles[role]['score'] = best_score520 521 return roles522 523def calculate_team_compatibility(members):524 """Calculate overall team compatibility score"""525 if len(members) < 2:526 return 0527 528 # Skill diversity score529 all_skills = set()530 for member in members:531 all_skills.update(s.lower() for s in member.get('skills', []))532 533 total_skills = sum(len(member.get('skills', [])) for member in members)534 skill_diversity = len(all_skills) / (total_skills + 1) if total_skills > 0 else 0535 536 # Experience level balance537 exp_levels = [member.get('experience_level', 'Intermediate') for member in members]538 exp_variety = len(set(exp_levels)) / len(exp_levels) if exp_levels else 0539 540 # Availability overlap541 avail_sets = [set(member.get('availability', [])) for member in members if member.get('availability')]542 if avail_sets:543 common_avail = set.intersection(*avail_sets) if len(avail_sets) > 1 else avail_sets[0]544 avail_score = len(common_avail) / 5 # Assuming max 5 availability options545 else:546 avail_score = 0.5547 548 # Domain diversity549 domains = set()550 for member in members:551 domains.update(member.get('domain', []))552 domain_diversity = len(domains) / len(members) if members else 0553 554 total_score = (skill_diversity * 0.4 + exp_variety * 0.2 + avail_score * 0.2 + domain_diversity * 0.2) * 100555 return min(100, total_score)556 557def show_browse_users_with_ml():558 """Enhanced user browsing with ML-powered domain scoring - FIXED VERSION"""559 st.markdown("## ๐ฅ Browse Hackers with Smart Matching")560 561 users = get_all_users()562 categories = load_json(CATEGORIES_FILE)563 564 if not users:565 st.info("No users registered yet. Be the first!")566 return567 568 # Enhanced filters with ML features569 col1, col2, col3, col4 = st.columns(4)570 571 with col1:572 available_now = st.checkbox("โก Available Now", help="Show only users available for immediate team formation")573 574 with col2:575 experience_filter = st.selectbox("๐ Min Experience", ["Any", "Beginner", "Intermediate", "Advanced", "Expert"])576 577 with col3:578 all_domains = set()579 for user in users:580 all_domains.update(user.get('domain', []))581 domain_filter = st.selectbox("๐ฏ Domain Filter", ["Any"] + sorted(list(all_domains)))582 583 with col4:584 min_domain_score = st.slider("๐ฏ Min Domain Score", 0, 100, 0, help="Minimum domain match score")585 586 # Domain-based matching587 search_domain = ""588 if categories:589 st.markdown("### ๐ค Domain-Based Smart Search")590 col1, col2 = st.columns(2)591 592 with col1:593 search_category = st.selectbox("Search by Category", [""] + list(categories.keys()))594 595 with col2:596 if search_category:597 domain_options = list(categories[search_category].get("domains", {}).keys())598 search_domain = st.selectbox("Search by Domain", [""] + domain_options)599 600 # Apply filters601 filtered_users = users.copy()602 603 if available_now:604 filtered_users = [u for u in filtered_users if 'Flexible' in u.get('availability', []) or 'Right Now' in u.get('availability', [])]605 606 if experience_filter != "Any":607 filtered_users = [u for u in filtered_users if u.get('experience_level') == experience_filter]608 609 if domain_filter != "Any":610 filtered_users = [u for u in filtered_users if domain_filter in u.get('domain', [])]611 612 # Filter by domain score if ML search is active613 if categories and search_domain and min_domain_score > 0:614 scored_users = []615 for user in filtered_users:616 domain_scores = calculate_domain_scores(user, categories)617 if search_domain in domain_scores and domain_scores[search_domain]['score'] >= min_domain_score:618 scored_users.append((user, domain_scores[search_domain]['score']))619 620 # Sort by domain score621 scored_users.sort(key=lambda x: x[1], reverse=True)622 filtered_users = [user for user, score in scored_users]623 624 # Display results625 st.markdown(f"### ๐ฅ {len(filtered_users)} Hackers Found")626 627 if search_domain and categories:628 st.info(f"๐ฏ Showing users ranked by {search_domain} domain expertise")629 630 for i, user in enumerate(filtered_users):631 col1, col2 = st.columns([4, 1])632 633 with col1:634 # Show domain score for searched domain only if searching635 if search_domain and categories:636 domain_scores = calculate_domain_scores(user, categories)637 if search_domain in domain_scores:638 score = domain_scores[search_domain]['score']639 score_class = get_score_class(score)640 score_label = get_score_label(score)641 st.markdown(f"""642 <div style="margin-bottom: 1rem;">643 <strong>๐ฏ {search_domain} Match:</strong>644 <span class="score-badge {score_class}">{score:.0f}% - {score_label}</span>645 </div>646 """, unsafe_allow_html=True)647 648 display_profile_card_with_scores(user, categories, show_scores=True)649 650 with col2:651 st.markdown("<br><br>", unsafe_allow_html=True)652 if st.button(f"โก Quick Team", key=f"qt_{user['name']}_{i}", help="Form instant team with this user"):653 # Simulate quick team formation654 matches = create_instant_team_match(user)655 if matches:656 st.success(f"โ
Team formed with {user['name']}!")657 # Store the team formation658 team_data = {659 'name': f"QuickTeam_{datetime.now().strftime('%H%M%S')}",660 'members': [user] + [match[0] for match in matches[:2]],661 'formation_time': datetime.now().strftime('%H:%M:%S'),662 'compatibility': calculate_team_compatibility([user] + [match[0] for match in matches[:2]]),663 'type': 'instant_match'664 }665 save_quick_team(team_data)666 else:667 st.warning("No immediate matches found")668 669 if st.button(f"๐ฌ Contact", key=f"contact_{user['name']}_{i}"):670 st.info(f"Contact request sent to {user['name']}")671 672 if st.button(f"๐ View All Scores", key=f"scores_{user['name']}_{i}", help="View detailed domain scores"):673 with st.expander(f"{user['name']}'s All Domain Scores", expanded=True):674 if categories:675 domain_scores = calculate_domain_scores(user, categories)676 677 if domain_scores:678 # Show top 5 domains only679 sorted_domains = sorted(domain_scores.items(), key=lambda x: x[1]['score'], reverse=True)[:5]680 681 for domain, data in sorted_domains:682 score = data['score']683 score_class = get_score_class(score)684 score_label = get_score_label(score)685 686 st.markdown(f"""687 <div style="background: #2c2c54; padding: 0.8rem; border-radius: 10px; margin: 0.3rem 0; color: white;">688 <strong>{domain}</strong> ({data['category']})<br>689 <span class="score-badge {score_class}">{score:.0f}% - {score_label}</span>690 <br><small>{len(data['matched'])} matched skills, {len(data['missing'])} missing</small>691 </div>692 """, unsafe_allow_html=True)693 694def show_group_management():695 """Manage groups and categories"""696 st.markdown("## ๐ข Group & Category Management")697 698 categories = load_json(CATEGORIES_FILE)699 if not categories:700 categories = {}701 702 tab1, tab2 = st.tabs(["๐ View Groups", "โ Add New Group"])703 704 with tab1:705 st.markdown("### Existing Groups & Categories")706 707 if not categories:708 st.info("No groups created yet. Add some groups to get started!")709 else:710 for category, cat_info in categories.items():711 with st.expander(f"๐ {category}"):712 if "domains" in cat_info:713 for domain, skills in cat_info["domains"].items():714 st.markdown(f"**{domain}**")715 st.write(f"Skills: {', '.join(skills)}")716 if st.button(f"Delete {domain}", key=f"del_{category}_{domain}"):717 if category in categories and domain in categories[category]["domains"]:718 del categories[category]["domains"][domain]719 if not categories[category]["domains"]:720 del categories[category]721 save_json(CATEGORIES_FILE, categories)722 st.success(f"Deleted {domain} from {category}")723 st.rerun()724 725 with tab2:726 st.markdown("### Add New Group or Category")727 728 with st.form("group_form"):729 new_cat = st.text_input("New Group Type (Category)", max_chars=50)730 new_dom = st.text_input("New Domain/Subgroup", max_chars=50)731 new_sk = st.text_area("Skills (comma separated)")732 subm = st.form_submit_button("Add Group")733 734 if subm:735 if not (new_cat and new_dom):736 st.warning("Category and domain are required.")737 else:738 new_cat = new_cat.strip()739 new_dom = new_dom.strip()740 sk_list = [s.strip() for s in new_sk.split(",") if s.strip()]741 742 if new_cat not in categories:743 categories[new_cat] = {"domains": {}}744 745 if new_dom in categories[new_cat]["domains"]:746 st.warning(f"Domain '{new_dom}' already exists in '{new_cat}'.")747 else:748 categories[new_cat]["domains"][new_dom] = sk_list749 save_json(CATEGORIES_FILE, categories)750 st.success(f"Added '{new_dom}' under '{new_cat}'.")751 752def show_create_team_form():753 """Form to create a new team"""754 st.markdown("## ๐ Create a New Team")755 756 users = get_all_users()757 if not users:758 st.warning("No users available to form a team. Create profiles first!")759 return760 761 with st.form("create_team_form"):762 team_name = st.text_input("Team Name", placeholder="Awesome Hackers Team")763 team_description = st.text_area("Team Description", placeholder="What's your team's mission?")764 765 col1, col2 = st.columns(2)766 with col1:767 target_size = st.slider("Target Team Size", 2, 8, 4)768 focus_area = st.selectbox("Primary Focus Area", 769 ["Web Development", "Mobile App", "AI/ML", "Data Science", 770 "IoT", "Blockchain", "Game Development", "Open Choice"])771 with col2:772 project_type = st.selectbox("Project Type", 773 ["New Idea", "Existing Project", "Open Source Contribution", "Research"])774 hackathon_name = st.text_input("Hackathon Name (if applicable)", placeholder="e.g., Hack the North")775 776 # Team members selection777 st.markdown("### ๐ฅ Select Team Members")778 available_members = [user for user in users]779 selected_members = st.multiselect("Choose team members", 780 [user['name'] for user in available_members],781 help="Select other hackers to join your team")782 783 # Privacy settings784 st.markdown("### ๐ Team Privacy")785 col1, col2 = st.columns(2)786 with col1:787 team_privacy = st.selectbox("Team Visibility", 788 ["Public - Anyone can join", 789 "Private - Approval required", 790 "Invite only"])791 with col2:792 application_required = st.checkbox("Require application", value=True)793 794 submitted = st.form_submit_button("๐ Create Team", use_container_width=True)795 796 if submitted:797 if not team_name:798 st.error("Team name is required!")799 return800 801 if not selected_members:802 st.error("Please select at least one team member!")803 return804 805 # Get full user objects for selected members806 team_members = []807 for member_name in selected_members:808 member = next((u for u in users if u['name'] == member_name), None)809 if member:810 team_members.append(member)811 812 # Create team data813 team_data = {814 'name': team_name,815 'description': team_description,816 'members': team_members,817 'target_size': target_size,818 'focus_area': focus_area,819 'project_type': project_type,820 'hackathon_name': hackathon_name,821 'privacy': team_privacy,822 'application_required': application_required,823 'created_date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),824 'status': 'active',825 'compatibility': calculate_team_compatibility(team_members)826 }827 828 # Save team829 team_id = save_team(team_data)830 st.success(f"โ
Team '{team_name}' created successfully!")831 832 # Send join requests to selected members if private team833 if team_privacy != "Public - Anyone can join":834 for member in team_members:835 request_data = {836 'team_id': team_id,837 'team_name': team_name,838 'from_user': "System", # Or the creator's name if available839 'to_user': member['name'],840 'status': 'pending',841 'message': f"You've been invited to join {team_name}",842 'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S")843 }844 save_team_request(request_data)845 846 st.info("๐จ Join requests sent to selected members!")847 848 st.session_state['show_create_team'] = False849 850def show_team_requests(username):851 """Show team requests for a user"""852 st.markdown("## ๐จ Team Requests")853 854 user_requests = get_user_team_requests(username)855 if not user_requests:856 st.info("You don't have any team requests yet.")857 return858 859 pending_requests = [(req_id, req) for req_id, req in user_requests if req.get('status') == 'pending']860 accepted_requests = [(req_id, req) for req_id, req in user_requests if req.get('status') == 'accepted']861 rejected_requests = [(req_id, req) for req_id, req in user_requests if req.get('status') == 'rejected']862 863 if pending_requests:864 st.markdown("### โณ Pending Requests")865 for req_id, request in pending_requests:866 status_class = "pending-request"867 st.markdown(f"""868 <div class="profile-card {status_class}">869 <h3>๐ฅ {request.get('team_name', 'Unknown Team')}</h3>870 <p><strong>From:</strong> {request.get('from_user', 'Unknown')}</p>871 <p><strong>Message:</strong> {request.get('message', 'No message')}</p>872 <p><strong>Date:</strong> {request.get('timestamp', 'Unknown')}</p>873 </div>874 """, unsafe_allow_html=True)875 876 col1, col2 = st.columns(2)877 with col1:878 if st.button(f"โ
Accept", key=f"accept_{req_id}"):879 update_team_request(req_id, {'status': 'accepted'})880 st.success("Request accepted!")881 st.rerun()882 with col2:883 if st.button(f"โ Reject", key=f"reject_{req_id}"):884 update_team_request(req_id, {'status': 'rejected'})885 st.info("Request rejected.")886 st.rerun()887 888 if accepted_requests:889 st.markdown("### โ
Accepted Requests")890 for req_id, request in accepted_requests:891 status_class = "accepted-request"892 st.markdown(f"""893 <div class="profile-card {status_class}">894 <h3>๐ฅ {request.get('team_name', 'Unknown Team')}</h3>895 <p><strong>From:</strong> {request.get('from_user', 'Unknown')}</p>896 <p><strong>Status:</strong> Accepted</p>897 <p><strong>Date:</strong> {request.get('timestamp', 'Unknown')}</p>898 </div>899 """, unsafe_allow_html=True)900 901 if rejected_requests:902 st.markdown("### โ Rejected Requests")903 for req_id, request in rejected_requests:904 status_class = "rejected-request"905 st.markdown(f"""906 <div class="profile-card {status_class}">907 <h3>๐ฅ {request.get('team_name', 'Unknown Team')}</h3>908 <p><strong>From:</strong> {request.get('from_user', 'Unknown')}</p>909 <p><strong>Status:</strong> Rejected</p>910 <p><strong>Date:</strong> {request.get('timestamp', 'Unknown')}</p>911 </div>912 """, unsafe_allow_html=True)913 914def main():915 # Header with CYHI branding916 st.markdown("""917 <div class="main-header">918 <h1>โก HackMate - CYHI Quick Teams</h1>919 <p>Capture Your Hackathon Idea & Find Your Perfect Team in Minutes!</p>920 </div>921 """, unsafe_allow_html=True)922 923 # Load or create sample data924 categories = load_json(CATEGORIES_FILE)925 if not categories:926 categories = create_sample_categories()927 928 # Navigation929 st.sidebar.markdown("## โก Quick Actions")930 931 if st.sidebar.button("๐ INSTANT TEAM MATCH", help="Get matched with a team in under 60 seconds!"):932 st.session_state['show_instant_match'] = True933 934 st.sidebar.markdown("---")935 st.sidebar.markdown("## ๐งญ Navigation")936 937 page = st.sidebar.radio("Choose your action:", 938 ["๐ Home", "โก Quick Teams", "๐ค Create Profile", "๐ Find/Create Teams", 939 "๐ Team Analytics", "๐ฅ Smart Browse", "๐ข Group Management", "๐จ My Requests"])940 941 if page == "๐ Home":942 show_home_page()943 elif page == "โก Quick Teams":944 show_quick_teams_page()945 elif page == "๐ค Create Profile":946 show_create_profile_page(categories)947 elif page == "๐ Find Teams":948 show_find_teams_page()949 elif page == "๐ Team Analytics":950 show_team_analytics_page()951 elif page == "๐ฅ Smart Browse":952 show_browse_users_with_ml()953 elif page == "๐ข Group Management":954 show_group_management()955 elif page == "๐จ My Requests":956 # Get current user (for demo, using first user)957 users = get_all_users()958 if users:959 show_team_requests(users[0]['name'])960 else:961 st.info("No users found. Create a profile first!")962 963 # Handle instant team matching964 if st.session_state.get('show_instant_match', False):965 show_instant_team_match()966 967def show_home_page():968 """Enhanced home page with quick team stats"""969 col1, col2, col3, col4 = st.columns(4)970 971 users = get_all_users()972 teams = get_all_teams()973 quick_teams = get_quick_teams()974 975 with col1:976 st.markdown(f"""977 <div class="metric-card">978 <h2>๐ฅ</h2>979 <h3>{len(users)}</h3>980 <p>Active Hackers</p>981 </div>982 """, unsafe_allow_html=True)983 984 with col2:985 st.markdown(f"""986 <div class="metric-card">987 <h2>โก</h2>988 <h3>{len(quick_teams)}</h3>989 <p>Quick Teams Formed</p>990 </div>991 """, unsafe_allow_html=True)992 993 with col3:994 avg_team_time = "< 2 min"995 st.markdown(f"""996 <div class="metric-card">997 <h2>โฑ</h2>998 <h3>{avg_team_time}</h3>999 <p>Avg Team Formation</p>1000 </div>1001 """, unsafe_allow_html=True)1002 1003 with col4:1004 success_rate = 711005 st.markdown(f"""1006 <div class="metric-card">1007 <h2>๐ฏ</h2>1008 <h3>{success_rate}%</h3>1009 <p>Match Success Rate</p>1010 </div>1011 """, unsafe_allow_html=True)1012 1013 st.markdown("---")1014 1015 # Quick team formation CTA1016 st.markdown("""1017 ## ๐ Ready to Form a Team in Under 2 Minutes?1018 1019 *CYHI Quick Teams* uses advanced matching algorithms to instantly connect you with compatible teammates based on:1020 - ๐ฏ Complementary skills (not just similar ones!)1021 - โฐ Real-time availability1022 - ๐จ Role optimization1023 - ๐ง Experience level balance1024 """)1025 1026 col1, col2, col3 = st.columns([1, 2, 1])1027 with col2:1028 if st.button("โก START QUICK TEAM FORMATION", key="main_quick_team"):1029 st.session_state['page'] = 'quick_teams'1030 st.rerun()1031 1032 # Recent quick teams1033 if quick_teams:1034 st.markdown("## ๐ฅ Recently Formed Quick Teams")1035 for team in quick_teams[-3:]:1036 display_quick_team_card(team)1037 1038def display_quick_team_card(team_data):1039 """Display quick team formation card"""1040 compatibility = calculate_team_compatibility(team_data.get('members', []))1041 urgency_class = "urgent-badge" if team_data.get('urgency', 'normal') == 'high' else ""1042 1043 st.markdown(f"""1044 <div class="team-card">1045 <h3>โก {team_data.get('name', 'Quick Team')}</h3>1046 <p><strong>๐ฏ Goal:</strong> {team_data.get('goal', 'Build something amazing!')}</p>1047 <p><strong>๐ฅ Size:</strong> {len(team_data.get('members', []))} / {team_data.get('target_size', 4)} members</p>1048 <p><strong>๐ฅ Compatibility:</strong> {compatibility:.0f}%</p>1049 <p><strong>โฑ Formation Time:</strong> {team_data.get('formation_time', 'Just now')}</p>1050 </div>1051 """, unsafe_allow_html=True)1052 1053def show_quick_teams_page():1054 """Enhanced quick team formation page"""1055 st.markdown("## โก CYHI Quick Teams - Form Teams in Minutes!")1056 1057 # Quick stats at top1058 col1, col2, col3 = st.columns(3)1059 with col1:1060 st.markdown("""1061 <div class="quick-match-card">1062 <h3>โฑ Average Time</h3>1063 <h2>90 seconds</h2>1064 </div>1065 """, unsafe_allow_html=True)1066 1067 with col2:1068 st.markdown("""1069 <div class="quick-match-card">1070 <h3>๐ฏ Match Accuracy</h3>1071 <h2>68%</h2>1072 </div>1073 """, unsafe_allow_html=True)1074 1075 with col3:1076 st.markdown("""1077 <div class="quick-match-card">1078 <h3>๐ฅ Teams Formed</h3>1079 <h2>{}</h2>1080 </div>1081 """.format(len(get_quick_teams())), unsafe_allow_html=True)1082 1083 # Quick team formation form1084 st.markdown("### ๐ Form Your Team Now")1085 1086 users = get_all_users()1087 if len(users) < 2:1088 st.warning("Need at least 2 registered users for team matching. Create profiles first!")1089 return1090 1091 with st.form("instant_match_form"):1092 col1, col2 = st.columns(2)1093 1094 with col1:1095 user_name = st.selectbox("๐ค Your Name", [user['name'] for user in users])1096 team_size = st.slider("๐ฅ Desired Team Size", 2, 6, 3)1097 urgency = st.selectbox("๐ฅ Urgency Level", ["normal", "high", "critical"])1098 1099 with col2:1100 focus_area = st.selectbox("๐ฏ Project Focus", 1101 ["Web Development", "Mobile App", "AI/ML", "Data Science", 1102 "IoT", "Blockchain", "Game Development", "Open Choice"])1103 time_commitment = st.selectbox("โฐ Time Commitment", 1104 ["2-4 hours", "Half day", "Full day", "Weekend", "Week+"])1105 1106 project_idea = st.text_area("๐ก Quick Project Idea (Optional)", 1107 placeholder="Briefly describe what you want to build...")1108 1109 match_button = st.form_submit_button("โก FIND MY TEAM NOW!", use_container_width=True)1110 1111 if match_button:1112 user_profile = next((u for u in users if u['name'] == user_name), None)1113 if user_profile:1114 with st.spinner("๐ Finding your perfect teammates..."):1115 import time1116 time.sleep(2)1117 1118 matches = create_instant_team_match(user_profile)1119 1120 if matches:1121 st.success("๐ Team formed successfully!")1122 1123 team_members = [user_profile] + [match[0] for match in matches[:team_size-1]]1124 roles = generate_team_roles(team_members, focus_area)1125 compatibility = calculate_team_compatibility(team_members)1126 1127 quick_team_data = {1128 'name': f"QuickTeam_{datetime.now().strftime('%H%M%S')}",1129 'members': team_members,1130 'goal': project_idea or f"Build amazing {focus_area} solution",1131 'focus_area': focus_area,1132 'urgency': urgency,1133 'target_size': team_size,1134 'formation_time': datetime.now().strftime('%H:%M:%S'),1135 'compatibility': compatibility,1136 'roles': roles,1137 'time_commitment': time_commitment1138 }1139 1140 team_id = save_quick_team(quick_team_data)1141 1142 st.markdown(f"""1143 ### ๐ Your Team: QuickTeam_{datetime.now().strftime('%H%M%S')}1144 *๐ฅ Compatibility Score: {compatibility:.0f}%*1145 """)1146 1147 categories = load_json(CATEGORIES_FILE)1148 for i, member in enumerate(team_members):1149 role = None1150 for role_name, role_info in roles.items():1151 if role_info.get('assigned') == member['name']:1152 role = role_name1153 break1154 display_profile_card_with_scores(member, categories, show_scores=True, role=role)1155 1156 # Next steps1157 st.markdown("### ๐ Next Steps:")1158 col1, col2, col3 = st.columns(3)1159 1160 with col1:1161 if st.button("๐ฌ Start Team Chat"):1162 st.info("Team chat initiated!")1163 1164 with col2:1165 if st.button("๐ Create Project Board"):1166 st.info("Project board created!")1167 1168 with col3:1169 if st.button("๐
Schedule Kickoff"):1170 st.info("Kickoff meeting scheduled!")1171 1172 else:1173 st.warning("No compatible teammates found right now. Try adjusting your preferences!")1174 1175def show_create_profile_page(categories):1176 """Enhanced profile creation with team formation focus"""1177 st.markdown("## ๐ค Create Your Hacker Profile")1178 st.markdown("Build your profile to get instant team matches!")1179 1180 with st.form("profile_form", clear_on_submit=True):1181 col1, col2 = st.columns(2)1182 1183 with col1:1184 name = st.text_input("๐ฌ Full Name *", placeholder="Your name")1185 1186 all_domains = []1187 for cat in categories.values():1188 all_domains.extend(cat.get("domains", {}).keys())1189 1190 primary_domain = st.selectbox("๐ฏ Primary Domain *", [""] + all_domains)1191 secondary_domain = st.selectbox("๐ฏ Secondary Domain", ["None"] + all_domains)1192 1193 experience_level = st.selectbox("๐ Experience Level *", 1194 ["Beginner", "Intermediate", "Advanced", "Expert"])1195 1196 availability = st.multiselect("โฐ Availability *", 1197 ["Right Now", "Weekends", "Evenings", "Flexible", 1198 "Full-time", "Part-time", "Remote Only"])1199 1200 with col2: