Upload app.py
Browse files
app.py
CHANGED
|
@@ -1,886 +1,399 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
@dataclass
|
| 7 |
class Challenge:
|
| 8 |
-
"""Challenge data structure"""
|
| 9 |
id: str
|
| 10 |
title: str
|
| 11 |
description: str
|
| 12 |
technologies: List[str]
|
| 13 |
difficulty: str
|
| 14 |
-
prize:
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
def __init__(self):
|
| 23 |
-
|
| 24 |
-
self.
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
|
| 88 |
-
def
|
| 89 |
-
"""
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
-
#
|
| 93 |
-
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
challenge_techs = set(tech.lower() for tech in challenge.technologies)
|
| 104 |
-
skill_overlap = len(user_skills.intersection(challenge_techs))
|
| 105 |
-
if challenge_techs:
|
| 106 |
-
# Bonus for exact matches, partial credit for related skills
|
| 107 |
-
exact_match_score = (skill_overlap / len(challenge_techs)) * 30
|
| 108 |
-
coverage_score = min(skill_overlap * 10, 10) # Bonus for multiple matches
|
| 109 |
-
score += exact_match_score + coverage_score
|
| 110 |
-
|
| 111 |
-
# Experience level compatibility (30% weight)
|
| 112 |
-
level_mapping = {'beginner': 1, 'intermediate': 2, 'advanced': 3}
|
| 113 |
-
user_level_num = level_mapping.get(user_level, 2)
|
| 114 |
-
challenge_level_num = level_mapping.get(challenge.difficulty.lower(), 2)
|
| 115 |
-
|
| 116 |
-
# Perfect match gets full points, adjacent levels get partial
|
| 117 |
-
level_diff = abs(user_level_num - challenge_level_num)
|
| 118 |
-
if level_diff == 0:
|
| 119 |
-
level_score = 30
|
| 120 |
-
elif level_diff == 1:
|
| 121 |
-
level_score = 20
|
| 122 |
-
else:
|
| 123 |
-
level_score = 5
|
| 124 |
-
score += level_score
|
| 125 |
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
else:
|
| 140 |
-
score += 10 # Base score when no specific query
|
| 141 |
|
| 142 |
-
#
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
competition_bonus = 2 if 20 <= challenge.registrants <= 50 else 0 # Sweet spot
|
| 146 |
-
score += prize_score + competition_bonus
|
| 147 |
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
|
|
|
| 154 |
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
|
| 159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
-
def
|
| 162 |
-
"""
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
backend_skills = ['python', 'java', 'node', 'fastapi', 'django', 'flask']
|
| 170 |
-
data_skills = ['sql', 'postgresql', 'mongodb', 'redis', 'elasticsearch']
|
| 171 |
-
devops_skills = ['docker', 'kubernetes', 'aws', 'azure', 'terraform']
|
| 172 |
-
|
| 173 |
-
user_skills_lower = [skill.lower() for skill in skills]
|
| 174 |
-
|
| 175 |
-
# Calculate strengths
|
| 176 |
-
frontend_count = sum(1 for skill in user_skills_lower if any(fs in skill for fs in frontend_skills))
|
| 177 |
-
backend_count = sum(1 for skill in user_skills_lower if any(bs in skill for bs in backend_skills))
|
| 178 |
-
data_count = sum(1 for skill in user_skills_lower if any(ds in skill for ds in data_skills))
|
| 179 |
-
devops_count = sum(1 for skill in user_skills_lower if any(ds in skill for ds in devops_skills))
|
| 180 |
-
|
| 181 |
-
# Determine profile type
|
| 182 |
-
if frontend_count >= 2 and backend_count >= 1:
|
| 183 |
-
profile_type = "Full-Stack Developer"
|
| 184 |
-
elif frontend_count >= 2:
|
| 185 |
-
profile_type = "Frontend Specialist"
|
| 186 |
-
elif backend_count >= 2:
|
| 187 |
-
profile_type = "Backend Developer"
|
| 188 |
-
elif data_count >= 2:
|
| 189 |
-
profile_type = "Data Engineer"
|
| 190 |
-
else:
|
| 191 |
-
profile_type = "Versatile Developer"
|
| 192 |
-
|
| 193 |
-
# Generate insights
|
| 194 |
-
insights = {
|
| 195 |
-
'profile_type': profile_type,
|
| 196 |
-
'strengths': f"Strong {profile_type.lower()} with expertise in {', '.join(skills[:3]) if skills else 'multiple technologies'}",
|
| 197 |
-
'growth_areas': self._suggest_growth_areas(user_skills_lower, frontend_count, backend_count, data_count, devops_count),
|
| 198 |
-
'skill_progression': f"Ready for {level.lower()} to advanced challenges based on current skill set",
|
| 199 |
-
'market_trends': self._get_market_trends(skills),
|
| 200 |
-
'time_optimization': f"With {time_available}, you can complete 1-2 medium challenges or 1 large project",
|
| 201 |
-
'success_probability': self._calculate_success_probability(level, len(skills))
|
| 202 |
}
|
| 203 |
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
def _suggest_growth_areas(self, user_skills: List[str], frontend: int, backend: int, data: int, devops: int) -> str:
|
| 208 |
-
"""Suggest areas for skill growth"""
|
| 209 |
-
suggestions = []
|
| 210 |
-
|
| 211 |
-
if devops < 1:
|
| 212 |
-
suggestions.append("cloud technologies (AWS, Docker)")
|
| 213 |
-
if data < 1 and backend >= 1:
|
| 214 |
-
suggestions.append("database optimization and caching")
|
| 215 |
-
if frontend >= 1 and "typescript" not in str(user_skills):
|
| 216 |
-
suggestions.append("TypeScript for better code quality")
|
| 217 |
-
if backend >= 1 and "api" not in str(user_skills):
|
| 218 |
-
suggestions.append("API design and microservices")
|
| 219 |
-
|
| 220 |
-
if not suggestions:
|
| 221 |
-
suggestions = ["emerging technologies", "system design", "performance optimization"]
|
| 222 |
-
|
| 223 |
-
return "Consider exploring " + ", ".join(suggestions[:3])
|
| 224 |
|
| 225 |
-
def
|
| 226 |
-
"""
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
}
|
| 234 |
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
elif total >= 70:
|
| 250 |
-
return f"{total}% - Good probability of success"
|
| 251 |
-
else:
|
| 252 |
-
return f"{total}% - Consider skill development first"
|
| 253 |
-
|
| 254 |
-
# Initialize the intelligence engine
|
| 255 |
-
print("🚀 Starting Topcoder Intelligence Assistant...")
|
| 256 |
-
intelligence_engine = SimpleIntelligenceEngine()
|
| 257 |
-
|
| 258 |
-
def format_challenge_card(challenge: Challenge) -> str:
|
| 259 |
-
"""Format challenge as professional HTML card"""
|
| 260 |
-
tech_badges = " ".join([
|
| 261 |
-
f"<span style='background:#e74c3c;color:white;padding:4px 10px;border-radius:15px;font-size:0.8em;margin:2px;display:inline-block;font-weight:500'>{tech}</span>"
|
| 262 |
-
for tech in challenge.technologies
|
| 263 |
-
])
|
| 264 |
-
|
| 265 |
-
# Dynamic score coloring
|
| 266 |
-
if challenge.score >= 80:
|
| 267 |
-
score_color = "#00b894"
|
| 268 |
-
score_label = "Excellent Match"
|
| 269 |
-
elif challenge.score >= 65:
|
| 270 |
-
score_color = "#f39c12"
|
| 271 |
-
score_label = "Good Match"
|
| 272 |
-
else:
|
| 273 |
-
score_color = "#e74c3c"
|
| 274 |
-
score_label = "Fair Match"
|
| 275 |
-
|
| 276 |
-
return f"""
|
| 277 |
-
<div style='border:1px solid #e0e6ed;border-radius:12px;padding:25px;margin:15px 0;background:white;box-shadow:0 3px 10px rgba(0,0,0,0.1);transition:transform 0.2s ease'>
|
| 278 |
-
<div style='display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:15px'>
|
| 279 |
-
<h3 style='margin:0;color:#2c3e50;font-size:1.3em;font-weight:600'>{challenge.title}</h3>
|
| 280 |
-
<div style='text-align:center'>
|
| 281 |
-
<div style='background:{score_color};color:white;padding:8px 16px;border-radius:25px;font-weight:600;font-size:1em'>{challenge.score}%</div>
|
| 282 |
-
<div style='color:{score_color};font-size:0.8em;margin-top:4px;font-weight:500'>{score_label}</div>
|
| 283 |
-
</div>
|
| 284 |
-
</div>
|
| 285 |
-
|
| 286 |
-
<p style='color:#6c757d;margin:15px 0;line-height:1.6;font-size:0.95em'>{challenge.description}</p>
|
| 287 |
-
|
| 288 |
-
<div style='margin:20px 0'>
|
| 289 |
-
<strong style='color:#2c3e50;font-size:0.9em'>Technologies:</strong><br>
|
| 290 |
-
<div style='margin-top:8px'>{tech_badges}</div>
|
| 291 |
-
</div>
|
| 292 |
-
|
| 293 |
-
<div style='display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:15px;margin-top:20px;padding-top:20px;border-top:1px solid #f8f9fa'>
|
| 294 |
-
<div style='text-align:center;padding:10px'>
|
| 295 |
-
<div style='font-size:1.2em;font-weight:600;color:#27ae60'>${challenge.prize:,}</div>
|
| 296 |
-
<div style='font-size:0.8em;color:#6c757d;margin-top:2px'>Prize</div>
|
| 297 |
-
</div>
|
| 298 |
-
<div style='text-align:center;padding:10px'>
|
| 299 |
-
<div style='font-size:1.1em;font-weight:600;color:#3498db'>{challenge.difficulty}</div>
|
| 300 |
-
<div style='font-size:0.8em;color:#6c757d;margin-top:2px'>Level</div>
|
| 301 |
-
</div>
|
| 302 |
-
<div style='text-align:center;padding:10px'>
|
| 303 |
-
<div style='font-size:1.1em;font-weight:600;color:#e67e22'>{challenge.timeline}</div>
|
| 304 |
-
<div style='font-size:0.8em;color:#6c757d;margin-top:2px'>Timeline</div>
|
| 305 |
-
</div>
|
| 306 |
-
<div style='text-align:center;padding:10px'>
|
| 307 |
-
<div style='font-size:1.1em;font-weight:600;color:#9b59b6'>{challenge.registrants}</div>
|
| 308 |
-
<div style='font-size:0.8em;color:#6c757d;margin-top:2px'>Registered</div>
|
| 309 |
-
</div>
|
| 310 |
-
</div>
|
| 311 |
-
</div>
|
| 312 |
-
"""
|
| 313 |
-
|
| 314 |
-
def format_insights_panel(insights: Dict) -> str:
|
| 315 |
-
"""Format insights as comprehensive dashboard"""
|
| 316 |
-
return f"""
|
| 317 |
-
<div style='background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;padding:25px;border-radius:12px;margin:15px 0;box-shadow:0 4px 15px rgba(102,126,234,0.3)'>
|
| 318 |
-
<h3 style='margin:0 0 20px 0;font-size:1.4em;text-align:center'>🎯 Your Intelligence Profile</h3>
|
| 319 |
-
|
| 320 |
-
<div style='display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px'>
|
| 321 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:8px'>
|
| 322 |
-
<div style='font-weight:600;margin-bottom:8px'>👤 Developer Type</div>
|
| 323 |
-
<div style='opacity:0.9'>{insights['profile_type']}</div>
|
| 324 |
-
</div>
|
| 325 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:8px'>
|
| 326 |
-
<div style='font-weight:600;margin-bottom:8px'>💪 Core Strengths</div>
|
| 327 |
-
<div style='opacity:0.9'>{insights['strengths']}</div>
|
| 328 |
-
</div>
|
| 329 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:8px'>
|
| 330 |
-
<div style='font-weight:600;margin-bottom:8px'>📈 Growth Focus</div>
|
| 331 |
-
<div style='opacity:0.9'>{insights['growth_areas']}</div>
|
| 332 |
-
</div>
|
| 333 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:8px'>
|
| 334 |
-
<div style='font-weight:600;margin-bottom:8px'>🚀 Progression Path</div>
|
| 335 |
-
<div style='opacity:0.9'>{insights['skill_progression']}</div>
|
| 336 |
-
</div>
|
| 337 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:8px'>
|
| 338 |
-
<div style='font-weight:600;margin-bottom:8px'>📊 Market Intelligence</div>
|
| 339 |
-
<div style='opacity:0.9'>{insights['market_trends']}</div>
|
| 340 |
-
</div>
|
| 341 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:8px'>
|
| 342 |
-
<div style='font-weight:600;margin-bottom:8px'>🎯 Success Probability</div>
|
| 343 |
-
<div style='opacity:0.9'>{insights['success_probability']}</div>
|
| 344 |
-
</div>
|
| 345 |
-
</div>
|
| 346 |
-
</div>
|
| 347 |
-
"""
|
| 348 |
-
|
| 349 |
-
def get_recommendations(skills_input: str, experience_level: str, time_available: str, interests: str) -> Tuple[str, str]:
|
| 350 |
-
"""Main recommendation function with enhanced error handling"""
|
| 351 |
-
start_time = time.time()
|
| 352 |
-
|
| 353 |
-
print(f"\n🎯 NEW RECOMMENDATION REQUEST:")
|
| 354 |
-
print(f" Skills: {skills_input}")
|
| 355 |
-
print(f" Level: {experience_level}")
|
| 356 |
-
print(f" Time: {time_available}")
|
| 357 |
-
print(f" Interests: {interests}")
|
| 358 |
-
|
| 359 |
-
# Input validation
|
| 360 |
-
if not skills_input.strip():
|
| 361 |
-
error_msg = """
|
| 362 |
-
<div style='background:#fff3cd;border:1px solid #ffeaa7;color:#856404;padding:20px;border-radius:8px;text-align:center'>
|
| 363 |
-
⚠️ <strong>Please enter at least one skill</strong><br>
|
| 364 |
-
<small>Example: Python, JavaScript, React, CSS</small>
|
| 365 |
-
</div>
|
| 366 |
-
"""
|
| 367 |
-
return error_msg, ""
|
| 368 |
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
|
| 381 |
-
#
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
print(f"✅ Request completed successfully in {processing_time}s")
|
| 407 |
-
print(f"📊 Returned {len(recommendations)} recommendations with comprehensive insights\n")
|
| 408 |
-
|
| 409 |
-
return recommendations_html, insights_html
|
| 410 |
-
|
| 411 |
-
except Exception as e:
|
| 412 |
-
error_msg = f"""
|
| 413 |
-
<div style='background:#f8d7da;border:1px solid #f5c6cb;color:#721c24;padding:20px;border-radius:8px;text-align:center'>
|
| 414 |
-
❌ <strong>Processing Error</strong><br>
|
| 415 |
-
<small>{str(e)}</small><br>
|
| 416 |
-
<small>Please try again or contact support</small>
|
| 417 |
-
</div>
|
| 418 |
-
"""
|
| 419 |
-
print(f"❌ Error processing request: {str(e)}")
|
| 420 |
-
return error_msg, ""
|
| 421 |
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
"hello": "Hi there! 🚀 I'm your Topcoder Challenge Intelligence Assistant! I help developers like you discover perfect challenges that match your skills and career goals. Try the recommendations tab above to get started!",
|
| 429 |
-
"help": "I can help you:\n• Find challenges perfectly matched to your skills\n• Analyze your developer profile and strengths\n• Recommend career growth paths\n• Provide market insights and trends\n\nUse the 'Challenge Recommendations' tab to get personalized suggestions!",
|
| 430 |
-
"python": "Python is fantastic! 🐍 It's one of the most in-demand skills right now. I have many Python challenges from web APIs to data science projects. What's your experience level and what type of Python work interests you most?",
|
| 431 |
-
"react": "React is hot in the market! ⚛️ Perfect choice for frontend development. I can recommend React challenges from component libraries to full-stack applications. The demand for React developers is consistently high!",
|
| 432 |
-
"javascript": "JavaScript opens so many doors! 🌟 From frontend to backend (Node.js), it's incredibly versatile. What type of JavaScript projects interest you most - web apps, APIs, or maybe mobile development?",
|
| 433 |
-
"beginner": "Welcome to your development journey! 🌱 I specialize in finding beginner-friendly challenges that build confidence while teaching real-world skills. What technologies are you most excited to learn?",
|
| 434 |
-
"intermediate": "Great level to be at! 🚀 You're ready for some really interesting challenges. I can help you find projects that push your skills to the next level. What's your main focus area?",
|
| 435 |
-
"advanced": "Impressive! 💪 You're ready for complex, high-value challenges. I can recommend advanced projects with substantial prizes and technical depth. What cutting-edge technologies interest you?",
|
| 436 |
-
"test": "All systems running perfectly! ✅\n• Intelligence Engine: Operational\n• Challenge Database: 6 sample challenges loaded\n• Recommendation Algorithm: Multi-factor scoring active\n• Performance: Sub-2-second response times\n\nReady to find your perfect challenge!",
|
| 437 |
-
"skills": "I analyze many skills including:\n• Frontend: React, JavaScript, CSS, HTML, Vue, Angular\n• Backend: Python, Java, Node.js, PHP, C#\n• Database: SQL, MongoDB, PostgreSQL, Redis\n• Cloud: AWS, Azure, Docker, Kubernetes\n• Design: UI/UX, Figma, Adobe Creative Suite\n\nWhat's your strongest skill area?",
|
| 438 |
-
"prize": "Challenge prizes in our database range from $2,000 to $7,500! 💰 Higher prizes typically mean:\n• More complex technical requirements\n• Longer timelines (2-4 weeks)\n• Advanced skill levels needed\n• Greater competition\n\nI match you with challenges where you have the best chance of success!"
|
| 439 |
-
}
|
| 440 |
|
| 441 |
-
|
| 442 |
-
message_lower = message.lower()
|
| 443 |
-
response = "That's a great question! For the most personalized help, try using the 'Challenge Recommendations' tab above where I can analyze your specific skills and goals. You can also ask me about specific technologies, experience levels, or challenge types!"
|
| 444 |
|
| 445 |
-
#
|
| 446 |
-
|
| 447 |
-
if keyword in message_lower:
|
| 448 |
-
response = reply
|
| 449 |
-
break
|
| 450 |
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
|
|
|
|
|
|
| 460 |
|
| 461 |
-
#
|
| 462 |
-
|
| 463 |
-
.
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
.tab-nav {
|
| 468 |
-
border-radius: 8px !important;
|
| 469 |
-
}
|
| 470 |
-
.submit-btn {
|
| 471 |
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
| 472 |
-
border: none !important;
|
| 473 |
-
}
|
| 474 |
-
"""
|
| 475 |
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
) as interface:
|
| 481 |
-
|
| 482 |
-
# Header with enhanced styling
|
| 483 |
-
gr.Markdown("""
|
| 484 |
-
# 🚀 Topcoder Challenge Intelligence Assistant
|
| 485 |
-
|
| 486 |
-
### **Your AI-powered guide to discovering and succeeding in Topcoder challenges**
|
| 487 |
-
|
| 488 |
-
Get **personalized challenge recommendations** powered by advanced algorithms that analyze your skills, experience level, and career goals. Built with the **Model Context Protocol (MCP)** for real-time challenge data.
|
| 489 |
-
|
| 490 |
-
---
|
| 491 |
-
""")
|
| 492 |
-
|
| 493 |
-
with gr.Tabs():
|
| 494 |
-
# Tab 1: Enhanced Challenge Recommendations
|
| 495 |
-
with gr.TabItem("🎯 Personalized Recommendations", elem_id="recommendations-tab"):
|
| 496 |
-
gr.Markdown("### 🤖 AI-Powered Challenge Discovery")
|
| 497 |
-
|
| 498 |
-
with gr.Row():
|
| 499 |
-
with gr.Column(scale=1):
|
| 500 |
-
gr.Markdown("**Tell me about yourself:**")
|
| 501 |
-
|
| 502 |
-
skills_input = gr.Textbox(
|
| 503 |
-
label="🛠️ Your Skills & Technologies",
|
| 504 |
-
placeholder="Python, React, JavaScript, CSS, Git, Docker...",
|
| 505 |
-
info="Enter your skills separated by commas",
|
| 506 |
-
lines=2,
|
| 507 |
-
value="Python, JavaScript" # Default for quick testing
|
| 508 |
-
)
|
| 509 |
-
|
| 510 |
-
experience_level = gr.Dropdown(
|
| 511 |
-
choices=["Beginner", "Intermediate", "Advanced"],
|
| 512 |
-
label="📊 Experience Level",
|
| 513 |
-
value="Intermediate",
|
| 514 |
-
info="Your overall development experience"
|
| 515 |
-
)
|
| 516 |
-
|
| 517 |
-
time_available = gr.Dropdown(
|
| 518 |
-
choices=["1-5 days", "1-2 weeks", "2-4 weeks", "1+ months"],
|
| 519 |
-
label="⏰ Time Available",
|
| 520 |
-
value="1-2 weeks",
|
| 521 |
-
info="How much time can you dedicate?"
|
| 522 |
-
)
|
| 523 |
-
|
| 524 |
-
interests = gr.Textbox(
|
| 525 |
-
label="🎯 Current Interests & Goals",
|
| 526 |
-
placeholder="web development, mobile apps, API development, UI/UX...",
|
| 527 |
-
info="What type of projects excite you most?",
|
| 528 |
-
lines=2,
|
| 529 |
-
value="web development" # Default for testing
|
| 530 |
-
)
|
| 531 |
-
|
| 532 |
-
recommend_btn = gr.Button(
|
| 533 |
-
"🚀 Get My Personalized Recommendations",
|
| 534 |
-
variant="primary",
|
| 535 |
-
size="lg",
|
| 536 |
-
elem_classes="submit-btn"
|
| 537 |
-
)
|
| 538 |
-
|
| 539 |
-
gr.Markdown("""
|
| 540 |
-
**💡 Pro Tips:**
|
| 541 |
-
- Be specific with your skills for better matches
|
| 542 |
-
- Include both technical and soft skills
|
| 543 |
-
- Mention any particular domains you're interested in
|
| 544 |
-
""")
|
| 545 |
-
|
| 546 |
-
with gr.Column(scale=2):
|
| 547 |
-
insights_output = gr.HTML(
|
| 548 |
-
label="🧠 Your Intelligence Profile",
|
| 549 |
-
visible=True
|
| 550 |
-
)
|
| 551 |
-
recommendations_output = gr.HTML(
|
| 552 |
-
label="🏆 Recommended Challenges",
|
| 553 |
-
visible=True
|
| 554 |
-
)
|
| 555 |
-
|
| 556 |
-
# Connect the recommendation system
|
| 557 |
-
recommend_btn.click(
|
| 558 |
-
get_recommendations,
|
| 559 |
-
inputs=[skills_input, experience_level, time_available, interests],
|
| 560 |
-
outputs=[recommendations_output, insights_output]
|
| 561 |
-
)
|
| 562 |
-
|
| 563 |
-
# Tab 2: Enhanced Chat Assistant
|
| 564 |
-
with gr.TabItem("💬 AI Assistant Chat"):
|
| 565 |
-
gr.Markdown("""
|
| 566 |
-
### 🤖 Chat with Your Intelligence Assistant
|
| 567 |
-
|
| 568 |
-
Ask me anything about Topcoder challenges, skill development, or career growth. I'm here to help!
|
| 569 |
-
""")
|
| 570 |
-
|
| 571 |
-
chatbot = gr.Chatbot(
|
| 572 |
-
label="🚀 Topcoder Intelligence Assistant",
|
| 573 |
-
height=450,
|
| 574 |
-
placeholder="Hi! Ask me about challenges, skills, career advice, or anything else!",
|
| 575 |
-
show_label=True
|
| 576 |
-
)
|
| 577 |
-
|
| 578 |
-
with gr.Row():
|
| 579 |
-
chat_input = gr.Textbox(
|
| 580 |
-
placeholder="Try: 'hello', 'help', 'python challenges', 'what skills are hot?', or 'test'",
|
| 581 |
-
container=False,
|
| 582 |
-
scale=4,
|
| 583 |
-
show_label=False
|
| 584 |
-
)
|
| 585 |
-
chat_btn = gr.Button("Send", variant="primary", scale=1)
|
| 586 |
-
|
| 587 |
-
# Enhanced chat examples
|
| 588 |
-
gr.Examples(
|
| 589 |
-
examples=[
|
| 590 |
-
"Hello! How can you help me?",
|
| 591 |
-
"What Python challenges do you recommend?",
|
| 592 |
-
"I'm a beginner, where should I start?",
|
| 593 |
-
"What skills are most in demand?",
|
| 594 |
-
"Show me high-prize challenges",
|
| 595 |
-
"Test your systems"
|
| 596 |
-
],
|
| 597 |
-
inputs=chat_input
|
| 598 |
-
)
|
| 599 |
-
|
| 600 |
-
# Connect chat functionality
|
| 601 |
-
chat_btn.click(
|
| 602 |
-
chat_with_agent,
|
| 603 |
-
inputs=[chat_input, chatbot],
|
| 604 |
-
outputs=[chatbot, chat_input]
|
| 605 |
-
)
|
| 606 |
-
|
| 607 |
-
chat_input.submit(
|
| 608 |
-
chat_with_agent,
|
| 609 |
-
inputs=[chat_input, chatbot],
|
| 610 |
-
outputs=[chatbot, chat_input]
|
| 611 |
-
)
|
| 612 |
-
|
| 613 |
-
# Tab 3: Performance & Technical Details
|
| 614 |
-
with gr.TabItem("⚡ System Performance"):
|
| 615 |
-
gr.Markdown("""
|
| 616 |
-
### 🧪 Test Intelligence Engine Performance
|
| 617 |
-
|
| 618 |
-
Monitor system performance and verify all components are working correctly.
|
| 619 |
-
""")
|
| 620 |
-
|
| 621 |
-
with gr.Row():
|
| 622 |
-
with gr.Column():
|
| 623 |
-
test_btn = gr.Button("🧪 Run Comprehensive Performance Test", variant="secondary", size="lg")
|
| 624 |
-
benchmark_btn = gr.Button("📊 Run Benchmark Test", variant="secondary")
|
| 625 |
-
|
| 626 |
-
with gr.Column():
|
| 627 |
-
test_output = gr.Textbox(
|
| 628 |
-
label="📋 Test Results & Performance Metrics",
|
| 629 |
-
lines=12,
|
| 630 |
-
show_label=True
|
| 631 |
-
)
|
| 632 |
-
|
| 633 |
-
def run_performance_test():
|
| 634 |
-
"""Comprehensive system performance test"""
|
| 635 |
-
results = []
|
| 636 |
-
results.append("🧪 COMPREHENSIVE PERFORMANCE TEST")
|
| 637 |
-
results.append("=" * 50)
|
| 638 |
-
results.append(f"⏰ Started at: {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
| 639 |
-
results.append("")
|
| 640 |
-
|
| 641 |
-
total_start = time.time()
|
| 642 |
-
|
| 643 |
-
# Test 1: Basic Intelligence Engine
|
| 644 |
-
results.append("🔍 Test 1: Basic Recommendation Engine")
|
| 645 |
-
start = time.time()
|
| 646 |
-
test_profile = {
|
| 647 |
-
'skills': ['Python', 'React'],
|
| 648 |
-
'experience_level': 'Intermediate',
|
| 649 |
-
'time_available': '1-2 weeks',
|
| 650 |
-
'interests': 'web development'
|
| 651 |
-
}
|
| 652 |
-
recs = intelligence_engine.get_personalized_recommendations(test_profile)
|
| 653 |
-
test1_time = round(time.time() - start, 3)
|
| 654 |
-
results.append(f" ✅ Generated {len(recs)} recommendations in {test1_time}s")
|
| 655 |
-
results.append(f" 📊 Top match: {recs[0].title} ({recs[0].score}%)")
|
| 656 |
-
results.append("")
|
| 657 |
-
|
| 658 |
-
# Test 2: Complex Profile Analysis
|
| 659 |
-
results.append("🔍 Test 2: Complex Profile Analysis")
|
| 660 |
-
start = time.time()
|
| 661 |
-
complex_profile = {
|
| 662 |
-
'skills': ['Python', 'JavaScript', 'React', 'Docker', 'PostgreSQL', 'AWS'],
|
| 663 |
-
'experience_level': 'Advanced',
|
| 664 |
-
'time_available': '2-4 weeks',
|
| 665 |
-
'interests': 'full-stack development microservices cloud architecture'
|
| 666 |
-
}
|
| 667 |
-
recs = intelligence_engine.get_personalized_recommendations(complex_profile, complex_profile['interests'])
|
| 668 |
-
test2_time = round(time.time() - start, 3)
|
| 669 |
-
results.append(f" ✅ Processed {len(complex_profile['skills'])} skills in {test2_time}s")
|
| 670 |
-
results.append(f" 🎯 Best match score: {recs[0].score}%")
|
| 671 |
-
results.append("")
|
| 672 |
-
|
| 673 |
-
# Test 3: Insights Generation
|
| 674 |
-
results.append("🔍 Test 3: User Insights Generation")
|
| 675 |
-
start = time.time()
|
| 676 |
-
insights = intelligence_engine.get_user_insights(complex_profile)
|
| 677 |
-
test3_time = round(time.time() - start, 3)
|
| 678 |
-
results.append(f" ✅ Generated comprehensive insights in {test3_time}s")
|
| 679 |
-
results.append(f" 👤 Profile Type: {insights['profile_type']}")
|
| 680 |
-
results.append(f" 🎯 Success Rate: {insights['success_probability']}")
|
| 681 |
-
results.append("")
|
| 682 |
-
|
| 683 |
-
# Test 4: Load Testing
|
| 684 |
-
results.append("🔍 Test 4: Load Testing (10 concurrent requests)")
|
| 685 |
-
start = time.time()
|
| 686 |
-
for i in range(10):
|
| 687 |
-
test_profile_load = {
|
| 688 |
-
'skills': ['Python', 'JavaScript', 'React'][:(i%3)+1],
|
| 689 |
-
'experience_level': ['Beginner', 'Intermediate', 'Advanced'][i%3],
|
| 690 |
-
'interests': 'testing'
|
| 691 |
-
}
|
| 692 |
-
intelligence_engine.get_personalized_recommendations(test_profile_load)
|
| 693 |
-
test4_time = round(time.time() - start, 3)
|
| 694 |
-
avg_time = round(test4_time / 10, 3)
|
| 695 |
-
results.append(f" ✅ Completed 10 requests in {test4_time}s")
|
| 696 |
-
results.append(f" ⚡ Average response time: {avg_time}s")
|
| 697 |
-
results.append("")
|
| 698 |
-
|
| 699 |
-
# Summary
|
| 700 |
-
total_time = round(time.time() - total_start, 3)
|
| 701 |
-
results.append("📊 PERFORMANCE SUMMARY")
|
| 702 |
-
results.append("-" * 30)
|
| 703 |
-
results.append(f"🕐 Total Test Duration: {total_time}s")
|
| 704 |
-
results.append(f"⚡ Average Response Time: {round((test1_time + test2_time + test3_time) / 3, 3)}s")
|
| 705 |
-
results.append(f"🧠 Intelligence Engine: ✅ OPERATIONAL")
|
| 706 |
-
results.append(f"💾 Memory Usage: ✅ OPTIMAL")
|
| 707 |
-
results.append(f"🔍 Algorithm Accuracy: ✅ HIGH")
|
| 708 |
-
results.append(f"🚀 Ready for Production: ✅ YES")
|
| 709 |
-
results.append("")
|
| 710 |
-
results.append("🎯 All systems performing excellently!")
|
| 711 |
-
|
| 712 |
-
return "\n".join(results)
|
| 713 |
-
|
| 714 |
-
def run_benchmark_test():
|
| 715 |
-
"""Quick benchmark test"""
|
| 716 |
-
results = []
|
| 717 |
-
results.append("📊 QUICK BENCHMARK TEST")
|
| 718 |
-
results.append("=" * 30)
|
| 719 |
-
|
| 720 |
-
start = time.time()
|
| 721 |
-
test_profile = {'skills': ['Python'], 'experience_level': 'Intermediate'}
|
| 722 |
-
recs = intelligence_engine.get_personalized_recommendations(test_profile)
|
| 723 |
-
benchmark_time = round(time.time() - start, 3)
|
| 724 |
-
|
| 725 |
-
results.append(f"⚡ Response Time: {benchmark_time}s")
|
| 726 |
-
results.append(f"🎯 Recommendations: {len(recs)}")
|
| 727 |
-
results.append(f"📊 Status: {'✅ EXCELLENT' if benchmark_time < 1.5 else '⚠️ ACCEPTABLE' if benchmark_time < 3 else '❌ SLOW'}")
|
| 728 |
-
|
| 729 |
-
return "\n".join(results)
|
| 730 |
-
|
| 731 |
-
# Connect test functions
|
| 732 |
-
test_btn.click(run_performance_test, outputs=test_output)
|
| 733 |
-
benchmark_btn.click(run_benchmark_test, outputs=test_output)
|
| 734 |
-
|
| 735 |
-
# Tab 4: About & Documentation
|
| 736 |
-
with gr.TabItem("ℹ️ About & Technical Details"):
|
| 737 |
-
gr.Markdown("""
|
| 738 |
-
## 🚀 About This AI Agent
|
| 739 |
-
|
| 740 |
-
### 🎯 **Mission Statement**
|
| 741 |
-
This **Topcoder Challenge Intelligence Assistant** revolutionizes how developers discover and engage with coding challenges. Instead of browsing through thousands of opportunities manually, get AI-powered recommendations tailored to your exact skills, experience level, and career goals.
|
| 742 |
-
|
| 743 |
-
### ✨ **Core Capabilities**
|
| 744 |
-
|
| 745 |
-
#### 🧠 **Advanced Intelligence Engine**
|
| 746 |
-
- **Multi-Factor Scoring Algorithm**: Analyzes skills, experience, time availability, and interests
|
| 747 |
-
- **Natural Language Processing**: Understands your goals and matches them with relevant challenges
|
| 748 |
-
- **Market Intelligence**: Provides insights on trending technologies and career opportunities
|
| 749 |
-
- **Success Probability Analysis**: Calculates your likelihood of success for each challenge
|
| 750 |
-
|
| 751 |
-
#### 🎯 **Personalized Recommendations**
|
| 752 |
-
- **Smart Skill Matching**: Advanced algorithms consider skill overlaps and related technologies
|
| 753 |
-
- **Experience-Level Optimization**: Matches challenges to your exact proficiency level
|
| 754 |
-
- **Interest Alignment**: Finds projects that match your passions and career goals
|
| 755 |
-
- **Time-Constraint Awareness**: Recommends challenges that fit your available time
|
| 756 |
-
|
| 757 |
-
#### 📊 **Comprehensive Analytics**
|
| 758 |
-
- **Developer Profile Analysis**: Identifies your strengths and growth areas
|
| 759 |
-
- **Market Trend Insights**: Shows current demand for your skills
|
| 760 |
-
- **Career Progression Paths**: Suggests next steps for professional development
|
| 761 |
-
- **Success Metrics**: Tracks compatibility scores and success probability
|
| 762 |
-
|
| 763 |
-
### 🔧 **Technical Architecture**
|
| 764 |
-
|
| 765 |
-
#### **Model Context Protocol (MCP) Integration**
|
| 766 |
-
```
|
| 767 |
-
Server Endpoint: https://api.topcoder-dev.com/v6/mcp
|
| 768 |
-
Protocol: JSON-RPC 2.0
|
| 769 |
-
Transport: HTTP with SSE capability
|
| 770 |
-
Authentication: Session-based (when available)
|
| 771 |
-
```
|
| 772 |
-
|
| 773 |
-
#### **Available MCP Tools**
|
| 774 |
-
- **`query-tc-challenges`**: Access to 4,596+ active challenges with rich metadata
|
| 775 |
-
- **`query-tc-skills`**: Comprehensive database of 6,535+ categorized skills
|
| 776 |
-
- **Real-time Updates**: Live challenge data and registration statistics
|
| 777 |
-
|
| 778 |
-
#### **Intelligence Algorithm**
|
| 779 |
-
```python
|
| 780 |
-
def calculate_compatibility_score(user_profile, challenge):
|
| 781 |
-
# Multi-factor scoring system:
|
| 782 |
-
skill_match_score = analyze_skill_overlap(user_skills, challenge_tech) * 0.4
|
| 783 |
-
experience_score = calculate_level_compatibility(user_level, challenge_difficulty) * 0.3
|
| 784 |
-
interest_score = nlp_analyze_relevance(user_interests, challenge_content) * 0.2
|
| 785 |
-
market_score = assess_market_factors(challenge_prize, competition) * 0.1
|
| 786 |
-
|
| 787 |
-
return skill_match_score + experience_score + interest_score + market_score
|
| 788 |
-
```
|
| 789 |
-
|
| 790 |
-
### 🚀 **Deployment & Performance**
|
| 791 |
-
|
| 792 |
-
#### **Platform Specifications**
|
| 793 |
-
- **Hosting**: Hugging Face Spaces with CPU Basic hardware
|
| 794 |
-
- **Framework**: Gradio 5.39.0 for optimal user experience
|
| 795 |
-
- **Dependencies**: Minimal, Windows-compatible package selection
|
| 796 |
-
- **Performance**: Sub-2-second response times for recommendations
|
| 797 |
-
|
| 798 |
-
#### **Quality Metrics**
|
| 799 |
-
- **Recommendation Accuracy**: 90%+ user satisfaction in testing
|
| 800 |
-
- **System Uptime**: 99.9% availability target
|
| 801 |
-
- **Response Time**: < 2 seconds for standard queries
|
| 802 |
-
- **Memory Efficiency**: Optimized for CPU Basic constraints
|
| 803 |
-
|
| 804 |
-
### 💼 **Business Value Proposition**
|
| 805 |
-
|
| 806 |
-
#### **For Individual Developers**
|
| 807 |
-
- **80% Time Savings**: Skip manual challenge browsing
|
| 808 |
-
- **Higher Success Rates**: Match challenges to your exact skill level
|
| 809 |
-
- **Accelerated Growth**: Structured progression paths and skill recommendations
|
| 810 |
-
- **Market Intelligence**: Stay informed about in-demand technologies
|
| 811 |
-
|
| 812 |
-
#### **For the Topcoder Ecosystem**
|
| 813 |
-
- **Improved Engagement**: Better challenge-developer matching increases participation
|
| 814 |
-
- **Quality Improvement**: More qualified participants lead to better solutions
|
| 815 |
-
- **Data Insights**: Analytics help understand developer needs and market trends
|
| 816 |
-
- **Community Growth**: Easier entry point for new developers
|
| 817 |
-
|
| 818 |
-
### 🔮 **Future Roadmap**
|
| 819 |
-
|
| 820 |
-
#### **Planned Enhancements**
|
| 821 |
-
- **Team Formation AI**: Intelligent matching for collaborative challenges
|
| 822 |
-
- **Skill Gap Analysis**: Detailed assessments for career planning
|
| 823 |
-
- **Progress Tracking**: Long-term development monitoring
|
| 824 |
-
- **Community Features**: Developer networking and mentorship matching
|
| 825 |
-
|
| 826 |
-
#### **Technical Expansion**
|
| 827 |
-
- **Multi-MCP Integration**: GitHub, web search, and calendar integration
|
| 828 |
-
- **Advanced ML Models**: Predictive success modeling and personalization
|
| 829 |
-
- **API Development**: RESTful endpoints for third-party integrations
|
| 830 |
-
- **Mobile Application**: Native iOS and Android apps
|
| 831 |
-
|
| 832 |
-
### 🏆 **Awards & Recognition**
|
| 833 |
-
|
| 834 |
-
**Built for the Topcoder MCP Challenge** - Showcasing the power of the Model Context Protocol for creating intelligent, context-aware applications that genuinely improve developer experiences.
|
| 835 |
-
|
| 836 |
-
---
|
| 837 |
-
|
| 838 |
-
<div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 10px; text-align: center; margin: 20px 0;'>
|
| 839 |
-
<h3 style='margin: 0; color: white;'>🤖 Powered by Model Context Protocol (MCP)</h3>
|
| 840 |
-
<p style='margin: 10px 0 0 0; opacity: 0.9;'>Empowering developers to discover their next great challenge and accelerate career growth through intelligent AI assistance.</p>
|
| 841 |
-
</div>
|
| 842 |
-
""")
|
| 843 |
-
|
| 844 |
-
# Enhanced footer
|
| 845 |
-
gr.Markdown("""
|
| 846 |
-
---
|
| 847 |
-
<div style='text-align: center; opacity: 0.8; font-size: 0.9em; padding: 20px;'>
|
| 848 |
-
<strong>🚀 Topcoder Challenge Intelligence Assistant</strong><br>
|
| 849 |
-
🤖 Powered by Model Context Protocol (MCP) | 🎯 Deployed on Hugging Face Spaces | ⚡ Built with Gradio 5.39.0<br>
|
| 850 |
-
<em>Revolutionizing challenge discovery through AI-powered personalization</em>
|
| 851 |
-
</div>
|
| 852 |
-
""")
|
| 853 |
|
| 854 |
-
|
| 855 |
-
|
|
|
|
|
|
|
| 856 |
|
| 857 |
-
# Launch the application
|
| 858 |
if __name__ == "__main__":
|
| 859 |
-
|
| 860 |
-
print("🚀 TOPCODER CHALLENGE INTELLIGENCE ASSISTANT")
|
| 861 |
-
print("🤖 Enhanced Version with Gradio 5.39.0")
|
| 862 |
-
print("="*60)
|
| 863 |
-
|
| 864 |
-
try:
|
| 865 |
-
interface = create_interface()
|
| 866 |
-
print("\n🎯 Starting enhanced Gradio server...")
|
| 867 |
-
print("📊 Initializing AI intelligence engine...")
|
| 868 |
-
print("🚀 Preparing personalized recommendation system...")
|
| 869 |
-
|
| 870 |
-
interface.launch(
|
| 871 |
-
share=False, # Set to True to get public shareable link
|
| 872 |
-
debug=True, # Show detailed logs for troubleshooting
|
| 873 |
-
show_error=True, # Display any errors in the UI
|
| 874 |
-
server_port=7860, # Standard Gradio port
|
| 875 |
-
show_api=False, # Hide API documentation for cleaner interface
|
| 876 |
-
favicon_path=None, # Can add custom favicon later
|
| 877 |
-
max_threads=10 # Handle multiple concurrent users
|
| 878 |
-
)
|
| 879 |
-
|
| 880 |
-
except Exception as e:
|
| 881 |
-
print(f"❌ Error starting application: {str(e)}")
|
| 882 |
-
print("\n🔧 Troubleshooting suggestions:")
|
| 883 |
-
print("1. Verify all dependencies are installed correctly")
|
| 884 |
-
print("2. Check if port 7860 is available (try different port if needed)")
|
| 885 |
-
print("3. Ensure you're in the correct virtual environment")
|
| 886 |
-
print("4. Try running: pip install --upgrade gradio httpx python-dotenv")
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Real MCP Integration - Replace Mock Data with Live Topcoder MCP
|
| 3 |
+
This replaces your SimpleIntelligenceEngine with real MCP integration
|
| 4 |
+
"""
|
| 5 |
+
import asyncio
|
| 6 |
+
import httpx
|
| 7 |
+
import json
|
| 8 |
+
import logging
|
| 9 |
+
from typing import List, Dict, Any, Optional
|
| 10 |
+
from dataclasses import dataclass, asdict
|
| 11 |
+
from datetime import datetime, timedelta
|
| 12 |
+
|
| 13 |
+
# Configure logging
|
| 14 |
+
logging.basicConfig(level=logging.INFO)
|
| 15 |
+
logger = logging.getLogger(__name__)
|
| 16 |
|
| 17 |
@dataclass
|
| 18 |
class Challenge:
|
|
|
|
| 19 |
id: str
|
| 20 |
title: str
|
| 21 |
description: str
|
| 22 |
technologies: List[str]
|
| 23 |
difficulty: str
|
| 24 |
+
prize: str
|
| 25 |
+
time_estimate: str
|
| 26 |
+
compatibility_score: float = 0.0
|
| 27 |
+
rationale: str = ""
|
| 28 |
|
| 29 |
+
@dataclass
|
| 30 |
+
class Skill:
|
| 31 |
+
name: str
|
| 32 |
+
category: str
|
| 33 |
+
description: str
|
| 34 |
+
relevance_score: float = 0.0
|
| 35 |
+
|
| 36 |
+
@dataclass
|
| 37 |
+
class UserProfile:
|
| 38 |
+
skills: List[str]
|
| 39 |
+
experience_level: str
|
| 40 |
+
time_available: str
|
| 41 |
+
interests: List[str]
|
| 42 |
+
|
| 43 |
+
class RealMCPIntelligenceEngine:
|
| 44 |
+
"""Production MCP Integration - Real Topcoder Data"""
|
| 45 |
|
| 46 |
def __init__(self):
|
| 47 |
+
self.mcp_url = "https://api.topcoder-dev.com/v6/mcp"
|
| 48 |
+
self.session_id = None
|
| 49 |
+
self.is_connected = False
|
| 50 |
+
self.challenges_cache = {}
|
| 51 |
+
self.skills_cache = {}
|
| 52 |
+
self.cache_expiry = None
|
| 53 |
+
|
| 54 |
+
# Initialize connection
|
| 55 |
+
asyncio.create_task(self.initialize_connection())
|
| 56 |
+
|
| 57 |
+
async def initialize_connection(self):
|
| 58 |
+
"""Initialize MCP connection and authenticate if needed"""
|
| 59 |
+
try:
|
| 60 |
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
| 61 |
+
|
| 62 |
+
# Step 1: Try initialization
|
| 63 |
+
init_request = {
|
| 64 |
+
"jsonrpc": "2.0",
|
| 65 |
+
"id": 1,
|
| 66 |
+
"method": "initialize",
|
| 67 |
+
"params": {
|
| 68 |
+
"protocolVersion": "2024-11-05",
|
| 69 |
+
"capabilities": {
|
| 70 |
+
"roots": {"listChanged": True},
|
| 71 |
+
"sampling": {}
|
| 72 |
+
},
|
| 73 |
+
"clientInfo": {
|
| 74 |
+
"name": "topcoder-intelligence-assistant",
|
| 75 |
+
"version": "1.0.0"
|
| 76 |
+
}
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
headers = {
|
| 81 |
+
"Content-Type": "application/json",
|
| 82 |
+
"Accept": "application/json, text/event-stream"
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
response = await client.post(
|
| 86 |
+
f"{self.mcp_url}/mcp",
|
| 87 |
+
json=init_request,
|
| 88 |
+
headers=headers
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
if response.status_code == 200:
|
| 92 |
+
result = response.json()
|
| 93 |
+
if "result" in result:
|
| 94 |
+
self.is_connected = True
|
| 95 |
+
logger.info("✅ MCP Connection established")
|
| 96 |
+
|
| 97 |
+
# Extract session info if provided
|
| 98 |
+
server_info = result["result"].get("serverInfo", {})
|
| 99 |
+
if "sessionId" in server_info:
|
| 100 |
+
self.session_id = server_info["sessionId"]
|
| 101 |
+
logger.info(f"🔑 Session ID obtained: {self.session_id[:10]}...")
|
| 102 |
+
|
| 103 |
+
return True
|
| 104 |
+
|
| 105 |
+
logger.warning(f"⚠️ MCP initialization failed: {response.status_code}")
|
| 106 |
+
return False
|
| 107 |
+
|
| 108 |
+
except Exception as e:
|
| 109 |
+
logger.error(f"❌ MCP connection failed: {e}")
|
| 110 |
+
return False
|
| 111 |
|
| 112 |
+
async def call_mcp_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Optional[Dict]:
|
| 113 |
+
"""Call an MCP tool with proper error handling"""
|
| 114 |
+
|
| 115 |
+
if not self.is_connected:
|
| 116 |
+
await self.initialize_connection()
|
| 117 |
+
|
| 118 |
+
try:
|
| 119 |
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
| 120 |
+
|
| 121 |
+
request_data = {
|
| 122 |
+
"jsonrpc": "2.0",
|
| 123 |
+
"id": datetime.now().timestamp(),
|
| 124 |
+
"method": "tools/call",
|
| 125 |
+
"params": {
|
| 126 |
+
"name": tool_name,
|
| 127 |
+
"arguments": arguments
|
| 128 |
+
}
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
headers = {
|
| 132 |
+
"Content-Type": "application/json",
|
| 133 |
+
"Accept": "application/json"
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
# Add session ID if we have one
|
| 137 |
+
if self.session_id:
|
| 138 |
+
headers["X-Session-ID"] = self.session_id
|
| 139 |
+
|
| 140 |
+
response = await client.post(
|
| 141 |
+
f"{self.mcp_url}/mcp",
|
| 142 |
+
json=request_data,
|
| 143 |
+
headers=headers
|
| 144 |
+
)
|
| 145 |
+
|
| 146 |
+
if response.status_code == 200:
|
| 147 |
+
result = response.json()
|
| 148 |
+
if "result" in result:
|
| 149 |
+
return result["result"]
|
| 150 |
+
elif "error" in result:
|
| 151 |
+
logger.error(f"MCP tool error: {result['error']}")
|
| 152 |
+
return None
|
| 153 |
+
else:
|
| 154 |
+
logger.error(f"MCP tool call failed: {response.status_code} - {response.text}")
|
| 155 |
+
return None
|
| 156 |
+
|
| 157 |
+
except Exception as e:
|
| 158 |
+
logger.error(f"MCP tool call exception: {e}")
|
| 159 |
+
return None
|
| 160 |
+
|
| 161 |
+
async def fetch_challenges(self, limit: int = 50, technologies: List[str] = None) -> List[Challenge]:
|
| 162 |
+
"""Fetch real challenges from Topcoder MCP"""
|
| 163 |
|
| 164 |
+
# Check cache first
|
| 165 |
+
cache_key = f"challenges_{limit}_{technologies}"
|
| 166 |
+
if (self.cache_expiry and datetime.now() < self.cache_expiry and
|
| 167 |
+
cache_key in self.challenges_cache):
|
| 168 |
+
return self.challenges_cache[cache_key]
|
| 169 |
|
| 170 |
+
arguments = {"limit": limit}
|
| 171 |
+
if technologies:
|
| 172 |
+
arguments["technologies"] = technologies
|
| 173 |
|
| 174 |
+
result = await self.call_mcp_tool("query-tc-challenges", arguments)
|
| 175 |
+
|
| 176 |
+
if result and "content" in result:
|
| 177 |
+
challenges_data = result["content"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
+
challenges = []
|
| 180 |
+
for item in challenges_data:
|
| 181 |
+
if isinstance(item, dict):
|
| 182 |
+
challenge = Challenge(
|
| 183 |
+
id=str(item.get("id", "")),
|
| 184 |
+
title=item.get("title", "Unknown Challenge"),
|
| 185 |
+
description=item.get("description", "")[:200] + "...",
|
| 186 |
+
technologies=item.get("technologies", []),
|
| 187 |
+
difficulty=item.get("difficulty", "Unknown"),
|
| 188 |
+
prize=f"${item.get('prize', 0):,}",
|
| 189 |
+
time_estimate=f"{item.get('duration', 0)} hours"
|
| 190 |
+
)
|
| 191 |
+
challenges.append(challenge)
|
|
|
|
|
|
|
| 192 |
|
| 193 |
+
# Cache results for 1 hour
|
| 194 |
+
self.challenges_cache[cache_key] = challenges
|
| 195 |
+
self.cache_expiry = datetime.now() + timedelta(hours=1)
|
|
|
|
|
|
|
| 196 |
|
| 197 |
+
logger.info(f"✅ Fetched {len(challenges)} real challenges from MCP")
|
| 198 |
+
return challenges
|
| 199 |
+
|
| 200 |
+
logger.warning("❌ Failed to fetch challenges, returning empty list")
|
| 201 |
+
return []
|
| 202 |
+
|
| 203 |
+
async def fetch_skills(self, category: str = None) -> List[Skill]:
|
| 204 |
+
"""Fetch real skills from Topcoder MCP"""
|
| 205 |
|
| 206 |
+
cache_key = f"skills_{category}"
|
| 207 |
+
if (self.cache_expiry and datetime.now() < self.cache_expiry and
|
| 208 |
+
cache_key in self.skills_cache):
|
| 209 |
+
return self.skills_cache[cache_key]
|
| 210 |
|
| 211 |
+
arguments = {}
|
| 212 |
+
if category:
|
| 213 |
+
arguments["category"] = category
|
| 214 |
|
| 215 |
+
result = await self.call_mcp_tool("query-tc-skills", arguments)
|
| 216 |
+
|
| 217 |
+
if result and "content" in result:
|
| 218 |
+
skills_data = result["content"]
|
| 219 |
+
|
| 220 |
+
skills = []
|
| 221 |
+
for item in skills_data:
|
| 222 |
+
if isinstance(item, dict):
|
| 223 |
+
skill = Skill(
|
| 224 |
+
name=item.get("name", "Unknown Skill"),
|
| 225 |
+
category=item.get("category", "General"),
|
| 226 |
+
description=item.get("description", "")
|
| 227 |
+
)
|
| 228 |
+
skills.append(skill)
|
| 229 |
+
|
| 230 |
+
self.skills_cache[cache_key] = skills
|
| 231 |
+
logger.info(f"✅ Fetched {len(skills)} real skills from MCP")
|
| 232 |
+
return skills
|
| 233 |
+
|
| 234 |
+
logger.warning("❌ Failed to fetch skills, returning empty list")
|
| 235 |
+
return []
|
| 236 |
|
| 237 |
+
def extract_technologies_from_query(self, query: str) -> List[str]:
|
| 238 |
+
"""Extract technology keywords from user query"""
|
| 239 |
+
tech_keywords = {
|
| 240 |
+
'python', 'java', 'javascript', 'react', 'node', 'angular', 'vue',
|
| 241 |
+
'aws', 'docker', 'kubernetes', 'api', 'rest', 'graphql', 'sql',
|
| 242 |
+
'mongodb', 'postgresql', 'machine learning', 'ai', 'blockchain',
|
| 243 |
+
'ios', 'android', 'flutter', 'swift', 'kotlin', 'c++', 'c#',
|
| 244 |
+
'ruby', 'php', 'go', 'rust', 'typescript', 'html', 'css'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
}
|
| 246 |
|
| 247 |
+
query_lower = query.lower()
|
| 248 |
+
found_techs = [tech for tech in tech_keywords if tech in query_lower]
|
| 249 |
+
return found_techs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
|
| 251 |
+
def calculate_compatibility_score(self, challenge: Challenge, user_profile: UserProfile, query: str) -> float:
|
| 252 |
+
"""Calculate compatibility score using real challenge data"""
|
| 253 |
+
|
| 254 |
+
score = 0.0
|
| 255 |
+
factors = []
|
| 256 |
+
|
| 257 |
+
# 1. Skill matching (40%)
|
| 258 |
+
user_skills_lower = [skill.lower() for skill in user_profile.skills]
|
| 259 |
+
challenge_techs_lower = [tech.lower() for tech in challenge.technologies]
|
| 260 |
+
|
| 261 |
+
skill_matches = len(set(user_skills_lower) & set(challenge_techs_lower))
|
| 262 |
+
skill_score = min(skill_matches / max(len(challenge.technologies), 1), 1.0) * 0.4
|
| 263 |
+
score += skill_score
|
| 264 |
+
factors.append(f"Skill match: {skill_matches}/{len(challenge.technologies)} technologies")
|
| 265 |
+
|
| 266 |
+
# 2. Experience level matching (30%)
|
| 267 |
+
experience_mapping = {
|
| 268 |
+
"beginner": {"Beginner": 1.0, "Intermediate": 0.7, "Advanced": 0.3},
|
| 269 |
+
"intermediate": {"Beginner": 0.5, "Intermediate": 1.0, "Advanced": 0.8},
|
| 270 |
+
"advanced": {"Beginner": 0.3, "Intermediate": 0.8, "Advanced": 1.0}
|
| 271 |
}
|
| 272 |
|
| 273 |
+
exp_score = experience_mapping.get(user_profile.experience_level.lower(), {}).get(challenge.difficulty, 0.5) * 0.3
|
| 274 |
+
score += exp_score
|
| 275 |
+
factors.append(f"Experience match: {user_profile.experience_level} → {challenge.difficulty}")
|
| 276 |
+
|
| 277 |
+
# 3. Query relevance (20%)
|
| 278 |
+
query_techs = self.extract_technologies_from_query(query)
|
| 279 |
+
query_matches = len(set([tech.lower() for tech in query_techs]) & set(challenge_techs_lower))
|
| 280 |
+
query_score = min(query_matches / max(len(query_techs), 1), 1.0) * 0.2 if query_techs else 0.1
|
| 281 |
+
score += query_score
|
| 282 |
+
factors.append(f"Query relevance: {query_matches} matches")
|
| 283 |
+
|
| 284 |
+
# 4. Time availability (10%)
|
| 285 |
+
time_mapping = {
|
| 286 |
+
"2-4 hours": {"1-2 hours": 1.0, "2-4 hours": 1.0, "4+ hours": 0.7},
|
| 287 |
+
"4-8 hours": {"2-4 hours": 0.8, "4+ hours": 1.0, "1-2 hours": 0.6},
|
| 288 |
+
"8+ hours": {"4+ hours": 1.0, "2-4 hours": 0.7, "1-2 hours": 0.4}
|
| 289 |
+
}
|
| 290 |
|
| 291 |
+
time_score = 0.1 # Default
|
| 292 |
+
for user_time, challenge_map in time_mapping.items():
|
| 293 |
+
if user_time in user_profile.time_available:
|
| 294 |
+
time_score = challenge_map.get(challenge.time_estimate, 0.5) * 0.1
|
| 295 |
+
break
|
| 296 |
+
|
| 297 |
+
score += time_score
|
| 298 |
+
factors.append(f"Time fit: {user_profile.time_available} vs {challenge.time_estimate}")
|
| 299 |
+
|
| 300 |
+
return min(score, 1.0), factors
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
|
| 302 |
+
async def get_personalized_recommendations(self, user_profile: UserProfile, query: str = "") -> Dict[str, Any]:
|
| 303 |
+
"""Get personalized recommendations using real MCP data"""
|
| 304 |
+
|
| 305 |
+
start_time = datetime.now()
|
| 306 |
+
|
| 307 |
+
# Fetch real challenges with technology filter if possible
|
| 308 |
+
query_techs = self.extract_technologies_from_query(query)
|
| 309 |
+
challenges = await self.fetch_challenges(limit=100, technologies=query_techs if query_techs else None)
|
| 310 |
+
|
| 311 |
+
if not challenges:
|
| 312 |
+
# Fallback message
|
| 313 |
+
return {
|
| 314 |
+
"recommendations": [],
|
| 315 |
+
"insights": {
|
| 316 |
+
"total_challenges": 0,
|
| 317 |
+
"processing_time": f"{(datetime.now() - start_time).total_seconds():.3f}s",
|
| 318 |
+
"data_source": "MCP (No data available)",
|
| 319 |
+
"message": "Unable to fetch real challenge data. Please check MCP connection."
|
| 320 |
+
}
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
# Score and rank challenges
|
| 324 |
+
scored_challenges = []
|
| 325 |
+
for challenge in challenges:
|
| 326 |
+
score, factors = self.calculate_compatibility_score(challenge, user_profile, query)
|
| 327 |
+
challenge.compatibility_score = score
|
| 328 |
+
challenge.rationale = f"Score: {score:.1%}. " + "; ".join(factors[:2])
|
| 329 |
+
scored_challenges.append(challenge)
|
| 330 |
|
| 331 |
+
# Sort by compatibility score
|
| 332 |
+
scored_challenges.sort(key=lambda x: x.compatibility_score, reverse=True)
|
| 333 |
+
|
| 334 |
+
# Take top 5 recommendations
|
| 335 |
+
recommendations = scored_challenges[:5]
|
| 336 |
+
|
| 337 |
+
# Get skills for gap analysis
|
| 338 |
+
skills = await self.fetch_skills()
|
| 339 |
+
|
| 340 |
+
# Processing time
|
| 341 |
+
processing_time = (datetime.now() - start_time).total_seconds()
|
| 342 |
+
|
| 343 |
+
return {
|
| 344 |
+
"recommendations": [asdict(rec) for rec in recommendations],
|
| 345 |
+
"insights": {
|
| 346 |
+
"total_challenges": len(challenges),
|
| 347 |
+
"average_score": sum(c.compatibility_score for c in challenges) / len(challenges),
|
| 348 |
+
"processing_time": f"{processing_time:.3f}s",
|
| 349 |
+
"data_source": "Real Topcoder MCP",
|
| 350 |
+
"top_score": recommendations[0].compatibility_score if recommendations else 0,
|
| 351 |
+
"skills_available": len(skills),
|
| 352 |
+
"technologies_detected": query_techs,
|
| 353 |
+
"cache_status": "Fresh data" if not self.cache_expiry else "Cached data"
|
| 354 |
+
}
|
| 355 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
|
| 357 |
+
# Example usage and testing
|
| 358 |
+
async def test_real_mcp_engine():
|
| 359 |
+
"""Test the real MCP integration"""
|
| 360 |
|
| 361 |
+
print("🚀 Testing Real MCP Integration")
|
| 362 |
+
print("=" * 50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
|
| 364 |
+
engine = RealMCPIntelligenceEngine()
|
|
|
|
|
|
|
| 365 |
|
| 366 |
+
# Wait for connection
|
| 367 |
+
await asyncio.sleep(2)
|
|
|
|
|
|
|
|
|
|
| 368 |
|
| 369 |
+
if not engine.is_connected:
|
| 370 |
+
print("❌ MCP connection failed - check authentication")
|
| 371 |
+
return
|
| 372 |
|
| 373 |
+
# Test user profile
|
| 374 |
+
user_profile = UserProfile(
|
| 375 |
+
skills=["Python", "JavaScript", "API"],
|
| 376 |
+
experience_level="Intermediate",
|
| 377 |
+
time_available="4-8 hours",
|
| 378 |
+
interests=["web development", "API integration"]
|
| 379 |
+
)
|
| 380 |
|
| 381 |
+
# Test recommendations
|
| 382 |
+
print("\n🧠 Getting Real Recommendations...")
|
| 383 |
+
recommendations = await engine.get_personalized_recommendations(
|
| 384 |
+
user_profile,
|
| 385 |
+
"I want to work on Python API challenges"
|
| 386 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
|
| 388 |
+
print(f"\n📊 Results:")
|
| 389 |
+
print(f" Challenges found: {recommendations['insights']['total_challenges']}")
|
| 390 |
+
print(f" Processing time: {recommendations['insights']['processing_time']}")
|
| 391 |
+
print(f" Data source: {recommendations['insights']['data_source']}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
|
| 393 |
+
for i, rec in enumerate(recommendations['recommendations'][:3], 1):
|
| 394 |
+
print(f"\n {i}. {rec['title']}")
|
| 395 |
+
print(f" Score: {rec['compatibility_score']:.1%}")
|
| 396 |
+
print(f" Technologies: {', '.join(rec['technologies'][:3])}")
|
| 397 |
|
|
|
|
| 398 |
if __name__ == "__main__":
|
| 399 |
+
asyncio.run(test_real_mcp_engine())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|