suryanshupaul commited on
Commit
413d080
·
verified ·
1 Parent(s): 91ebc74

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +745 -0
app.py ADDED
@@ -0,0 +1,745 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import json
4
+ from typing import Dict, List, Optional, Union, Any
5
+ import os
6
+ import requests
7
+ from dotenv import load_dotenv
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+ from rich.panel import Panel
11
+ from rich.tree import Tree
12
+ from rich import box
13
+ import time
14
+ from tqdm import tqdm
15
+ import openai
16
+ import gradio as gr
17
+ from huggingface_hub import HfApi, HfFolder
18
+
19
+ # Load environment variables from .env file
20
+ load_dotenv()
21
+
22
+ class CourseRecommender:
23
+ def __init__(self, dataframe: pd.DataFrame):
24
+ """
25
+ Initialize the course recommender with course data
26
+ """
27
+ self.courses = dataframe.drop(columns=['Unnamed: 1', 'Unnamed: 5'], errors='ignore')
28
+ self._preprocess_data()
29
+ self.console = Console()
30
+
31
+ # Initialize OpenAI client
32
+ api_key = os.getenv("OPENAI_API_KEY")
33
+ if api_key:
34
+ self.openai_client = openai.OpenAI(api_key=api_key)
35
+ self.ai_enabled = True
36
+ else:
37
+ self.console.print("[yellow]Warning: OpenAI API key not found. AI-enhanced features will be disabled.[/yellow]")
38
+ self.ai_enabled = False
39
+
40
+ def _preprocess_data(self):
41
+ """
42
+ Preprocess the course data for better recommendations
43
+ """
44
+ text_columns = ['Course Name', 'Description', 'Skills', 'Difficulty Level']
45
+ for col in text_columns:
46
+ if col in self.courses.columns:
47
+ self.courses[col] = self.courses[col].astype(str).str.lower()
48
+
49
+ self.courses['Course Rating'] = pd.to_numeric(self.courses['Course Rating'], errors='coerce').fillna(0)
50
+ self.courses['keyword_match_score'] = 0
51
+
52
+ # Add course ID for easy reference
53
+ self.courses['Course ID'] = range(1, len(self.courses) + 1)
54
+
55
+ def recommend_courses(self, topic: Optional[str] = None, skill_level: Optional[str] = None,
56
+ top_n: int = 5, personalized: bool = False, user_goals: Optional[str] = None) -> pd.DataFrame:
57
+ """
58
+ Recommend courses based on topic, skill level, and optional user goals
59
+
60
+ Parameters:
61
+ - topic: Subject area of interest
62
+ - skill_level: User's current proficiency level
63
+ - top_n: Number of recommendations to return
64
+ - personalized: Whether to use AI for personalized recommendations
65
+ - user_goals: Specific learning objectives or career goals
66
+ """
67
+ filtered_courses = self.courses.copy()
68
+
69
+ # Show processing indicator
70
+ with self.console.status("[bold green]Finding the best courses for you...", spinner="dots"):
71
+ time.sleep(1) # Simulate processing time
72
+
73
+ if topic:
74
+ topic = topic.lower()
75
+ filtered_courses['keyword_match_score'] = (
76
+ filtered_courses['Course Name'].str.contains(topic).astype(int) * 3 +
77
+ filtered_courses['Description'].str.contains(topic).astype(int) * 2 +
78
+ filtered_courses['Skills'].str.contains(topic).astype(int)
79
+ )
80
+ filtered_courses = filtered_courses[filtered_courses['keyword_match_score'] > 0]
81
+
82
+ if skill_level:
83
+ skill_level = skill_level.lower()
84
+ difficulty_map = {
85
+ 'beginner': ['beginner', 'intro', 'basic', 'level 1', 'fundamentals'],
86
+ 'intermediate': ['intermediate', 'mid-level', 'level 2', 'advanced beginner'],
87
+ 'advanced': ['advanced', 'expert', 'professional', 'level 3', 'master']
88
+ }
89
+ filtered_courses = filtered_courses[
90
+ filtered_courses['Difficulty Level'].apply(
91
+ lambda x: any(diff in str(x) for diff in difficulty_map.get(skill_level, [skill_level]))
92
+ )
93
+ ]
94
+
95
+ if personalized and user_goals and self.ai_enabled:
96
+ # Use AI to enhance recommendation scores based on user goals
97
+ for idx, course in filtered_courses.iterrows():
98
+ relevance_score = self._get_ai_relevance_score(course, topic, user_goals)
99
+ filtered_courses.at[idx, 'ai_relevance_score'] = relevance_score
100
+ else:
101
+ filtered_courses['ai_relevance_score'] = 0
102
+
103
+ if not filtered_courses.empty:
104
+ filtered_courses['recommendation_score'] = (
105
+ filtered_courses['Course Rating'] * 0.4 +
106
+ filtered_courses['keyword_match_score'] * 0.3 +
107
+ filtered_courses['ai_relevance_score'] * 0.2 +
108
+ np.random.rand(len(filtered_courses)) * 0.1
109
+ )
110
+ filtered_courses = filtered_courses.sort_values('recommendation_score', ascending=False)
111
+
112
+ return filtered_courses.head(top_n)
113
+
114
+ def _get_ai_relevance_score(self, course: pd.Series, topic: str, user_goals: str) -> float:
115
+ """
116
+ Use AI to determine how relevant a course is to user's specific goals
117
+ """
118
+ try:
119
+ prompt = f"""
120
+ Rate how relevant this course is to a learner with these goals on a scale of 0-10:
121
+
122
+ Topic of interest: {topic}
123
+ User's learning goals: {user_goals}
124
+
125
+ Course details:
126
+ - Name: {course['Course Name']}
127
+ - Description: {course['Description']}
128
+ - Skills taught: {course['Skills']}
129
+ - Difficulty: {course['Difficulty Level']}
130
+
131
+ Return only a number from 0-10.
132
+ """
133
+
134
+ response = self.openai_client.chat.completions.create(
135
+ model="gpt-3.5-turbo",
136
+ messages=[
137
+ {"role": "system", "content": "You are an educational advisor helping match courses to learner goals."},
138
+ {"role": "user", "content": prompt}
139
+ ],
140
+ max_tokens=10,
141
+ temperature=0.3
142
+ )
143
+
144
+ try:
145
+ score = float(response.choices[0].message.content.strip())
146
+ return min(max(score, 0), 10) / 10 # Normalize to 0-1 range
147
+ except ValueError:
148
+ return 0.5 # Default value if parsing fails
149
+
150
+ except Exception as e:
151
+ self.console.print(f"[red]Error getting AI relevance score: {e}[/red]")
152
+ return 0.5
153
+
154
+ def generate_roadmap(self, topic: str, skill_level: Optional[str] = None,
155
+ user_goals: Optional[str] = None, detailed: bool = False) -> Dict:
156
+ """
157
+ Generate a personalized learning roadmap based on the topic and user goals
158
+
159
+ Parameters:
160
+ - topic: Subject area of interest
161
+ - skill_level: User's current proficiency level
162
+ - user_goals: Specific learning objectives or career goals
163
+ - detailed: Whether to generate a more detailed roadmap with AI
164
+ """
165
+ self.console.print(Panel(f"[bold cyan]Generating your personalized learning roadmap for [green]{topic}[/green]...[/bold cyan]"))
166
+
167
+ # Display a progress bar for visual effect
168
+ for _ in tqdm(range(5), desc="Processing roadmap data"):
169
+ time.sleep(0.3)
170
+
171
+ if detailed and self.ai_enabled and user_goals:
172
+ roadmap = self._generate_ai_roadmap(topic, skill_level, user_goals)
173
+ else:
174
+ # Fallback to static roadmap if AI is not available
175
+ roadmap = self._generate_default_roadmap(topic)
176
+
177
+ return roadmap
178
+
179
+ def _generate_ai_roadmap(self, topic: str, skill_level: str, user_goals: str) -> Dict:
180
+ """
181
+ Use AI to generate a personalized and detailed learning roadmap with improved structure
182
+ """
183
+ try:
184
+ # Enhanced prompt with more specific structure and guidance
185
+ prompt = f"""
186
+ Create a comprehensive learning roadmap for someone wanting to master {topic}.
187
+
188
+ Learner information:
189
+ - Current skill level: {skill_level}
190
+ - Learning goals: {user_goals}
191
+
192
+ The roadmap should be detailed, actionable, and specifically tailored to the learner's
193
+ skill level and goals. Provide a clear progression path that breaks down the journey
194
+ into logical stages with specific concepts to learn at each stage.
195
+
196
+ Format the response as a JSON object with exactly this structure:
197
+ {{
198
+ "learningPath": [
199
+ {{
200
+ "step": "Step name (be specific)",
201
+ "difficulty": "Beginner/Intermediate/Advanced",
202
+ "description": "Detailed description of this learning stage (2-3 sentences)",
203
+ "time_estimate": "Estimated completion time (weeks/months)",
204
+ "key_concepts": ["Specific concept 1", "Specific concept 2", "Specific concept 3"],
205
+ "milestones": ["Practical milestone 1", "Practical milestone 2"],
206
+ "practice_activities": ["Activity 1", "Activity 2"]
207
+ }},
208
+ // 3-5 steps total, progressing from fundamentals to mastery
209
+ ],
210
+ "projectSuggestions": [
211
+ {{
212
+ "name": "Project name (be specific to {topic})",
213
+ "description": "Detailed project description (2-3 sentences)",
214
+ "complexity": "Low/Medium/High",
215
+ "skills_practiced": ["Skill 1", "Skill 2", "Skill 3"],
216
+ "resources": ["Specific resource 1", "Specific resource 2"],
217
+ "estimated_time": "Project completion time estimate"
218
+ }},
219
+ // 3-4 projects of increasing complexity
220
+ ],
221
+ "resources": {{
222
+ "books": ["Specific book title 1", "Specific book title 2", "Specific book title 3"],
223
+ "online_courses": ["Specific course 1", "Specific course 2"],
224
+ "communities": ["Specific community 1", "Specific community 2"],
225
+ "tools": ["Specific tool 1", "Specific tool 2", "Specific tool 3"],
226
+ "practice_platforms": ["Specific platform 1", "Specific platform 2"]
227
+ }},
228
+ "career_insights": [
229
+ "Specific insight about {topic} career opportunities",
230
+ "Skill demand information",
231
+ "Industry application of {topic} skills"
232
+ ]
233
+ }}
234
+
235
+ Ensure all content is specific to {topic} (not generic) and appropriate for a {skill_level}
236
+ with these goals: {user_goals}. Focus on practical, actionable advice.
237
+ """
238
+
239
+ response = self.openai_client.chat.completions.create(
240
+ model="gpt-4o", # Using more capable model for better roadmaps
241
+ messages=[
242
+ {"role": "system", "content": "You are an expert educational curriculum designer with deep knowledge across technical and non-technical subjects. You create detailed, actionable learning plans that are practical and tailored to individual needs."},
243
+ {"role": "user", "content": prompt}
244
+ ],
245
+ max_tokens=2500,
246
+ temperature=0.5,
247
+ response_format={"type": "json_object"} # Enforce JSON response
248
+ )
249
+
250
+ try:
251
+ roadmap_text = response.choices[0].message.content
252
+ roadmap = json.loads(roadmap_text)
253
+ return roadmap
254
+ except json.JSONDecodeError as e:
255
+ self.console.print(f"[yellow]Warning: Could not parse AI response as JSON: {e}. Using default roadmap.[/yellow]")
256
+ return self._generate_default_roadmap(topic)
257
+
258
+ except Exception as e:
259
+ self.console.print(f"[red]Error generating AI roadmap: {e}[/red]")
260
+ return self._generate_default_roadmap(topic)
261
+
262
+ def _generate_default_roadmap(self, topic: str) -> Dict:
263
+ """
264
+ Generate a default roadmap when AI generation fails or is not available
265
+ """
266
+ return {
267
+ "learningPath": [
268
+ {
269
+ "step": f"Foundations of {topic}",
270
+ "difficulty": "Beginner",
271
+ "description": f"Build core knowledge and fundamental skills in {topic}. Focus on understanding basic principles and becoming familiar with essential tools.",
272
+ "time_estimate": "4-6 weeks",
273
+ "key_concepts": [f"{topic} basics", "Core principles", "Fundamental tools and techniques"],
274
+ "milestones": [f"Complete first {topic} exercise", f"Build simple {topic} project"],
275
+ "practice_activities": [f"Daily {topic} exercises", "Follow beginner tutorials"]
276
+ },
277
+ {
278
+ "step": f"{topic} Skill Development",
279
+ "difficulty": "Intermediate",
280
+ "description": f"Deepen understanding of {topic} and apply more advanced concepts. Focus on building practical skills through hands-on projects and implementation.",
281
+ "time_estimate": "8-12 weeks",
282
+ "key_concepts": [f"Advanced {topic} techniques", "Applied projects", "Specialized tools"],
283
+ "milestones": [f"Complete medium complexity {topic} project", "Solve real-world problems"],
284
+ "practice_activities": ["Implement sample projects", "Participate in forums/discussions"]
285
+ },
286
+ {
287
+ "step": f"{topic} Mastery & Specialization",
288
+ "difficulty": "Advanced",
289
+ "description": f"Develop expert-level skills in {topic} with focus on real-world application. Specialize in specific areas and build a professional portfolio.",
290
+ "time_estimate": "12-16 weeks",
291
+ "key_concepts": ["Industry best practices", "Complex problem-solving", "Portfolio development"],
292
+ "milestones": ["Create capstone project", "Contribute to community"],
293
+ "practice_activities": ["Build complex projects", "Mentor beginners"]
294
+ }
295
+ ],
296
+ "projectSuggestions": [
297
+ {
298
+ "name": f"Beginner Project: {topic} Fundamentals Application",
299
+ "description": f"Apply basic {topic} concepts in a simple project to practice fundamentals and gain confidence.",
300
+ "complexity": "Low",
301
+ "skills_practiced": [f"Basic {topic} principles", "Problem-solving", "Tool familiarity"],
302
+ "resources": ["Online tutorials", "Documentation", "Starter templates"],
303
+ "estimated_time": "1-2 weeks"
304
+ },
305
+ {
306
+ "name": f"Intermediate Project: Interactive {topic} Application",
307
+ "description": f"Create a more complex application using intermediate {topic} skills with greater functionality and sophistication.",
308
+ "complexity": "Medium",
309
+ "skills_practiced": [f"Intermediate {topic} techniques", "Code organization", "Testing"],
310
+ "resources": ["GitHub repositories", "Online coding platforms", "Community forums"],
311
+ "estimated_time": "3-4 weeks"
312
+ },
313
+ {
314
+ "name": f"Capstone Project: Advanced {topic} Implementation",
315
+ "description": f"Apply all learned skills in a comprehensive {topic} project that showcases mastery and solves a real-world problem.",
316
+ "complexity": "High",
317
+ "skills_practiced": [f"Advanced {topic} mastery", "System design", "Optimization"],
318
+ "resources": ["Industry case studies", "Research papers", "Expert communities"],
319
+ "estimated_time": "6-8 weeks"
320
+ }
321
+ ],
322
+ "resources": {
323
+ "books": [f"Introduction to {topic}", f"Advanced {topic} Techniques", f"Mastering {topic}"],
324
+ "online_courses": [f"{topic} for Beginners", f"Professional {topic} Masterclass"],
325
+ "communities": ["Stack Overflow", "Reddit", f"{topic} Discord Servers"],
326
+ "tools": [f"{topic} Development Environment", "Version Control", "Testing Frameworks"],
327
+ "practice_platforms": ["Codecademy", "Exercism", "LeetCode"]
328
+ },
329
+ "career_insights": [
330
+ f"Proficiency in {topic} is valuable for roles in software development, data science, and IT operations",
331
+ f"Entry-level {topic} positions typically require demonstrated project experience",
332
+ f"{topic} specialists can pursue careers in consulting, education, or product development"
333
+ ]
334
+ }
335
+
336
+ def get_course_details(self, course: pd.Series) -> Dict[str, str]:
337
+ """
338
+ Get detailed course information
339
+ """
340
+ return {
341
+ "name": course.get('Course Name', 'N/A'),
342
+ "difficulty": course.get('Difficulty Level', 'N/A'),
343
+ "rating": str(course.get('Course Rating', 'N/A')),
344
+ "url": course.get('Course URL', '#'),
345
+ "skills": course.get('Skills', 'N/A'),
346
+ "description": course.get('Description', 'No description available'),
347
+ "id": str(course.get('Course ID', '0'))
348
+ }
349
+
350
+ def display_roadmap(self, roadmap: Dict):
351
+ """
352
+ Display the learning roadmap in a beautiful format using rich
353
+ """
354
+ self.console.print("\n")
355
+ self.console.print(Panel("[bold cyan]YOUR PERSONALIZED LEARNING JOURNEY[/bold cyan]",
356
+ box=box.DOUBLE, expand=False))
357
+
358
+ # Create a tree for learning path
359
+ learning_tree = Tree("[bold yellow]Learning Path[/bold yellow]")
360
+ for stage in roadmap["learningPath"]:
361
+ stage_node = learning_tree.add(f"[bold green]{stage['step']}[/bold green] ({stage['difficulty']}) - {stage['time_estimate']}")
362
+ stage_node.add(f"[italic]{stage['description']}[/italic]")
363
+
364
+ concepts_node = stage_node.add("[bold blue]Key Concepts:[/bold blue]")
365
+ for concept in stage.get("key_concepts", []):
366
+ concepts_node.add(concept)
367
+
368
+ if "milestones" in stage:
369
+ milestones_node = stage_node.add("[bold magenta]Milestones:[/bold magenta]")
370
+ for milestone in stage["milestones"]:
371
+ milestones_node.add(milestone)
372
+
373
+ if "practice_activities" in stage:
374
+ activities_node = stage_node.add("[bold cyan]Practice Activities:[/bold cyan]")
375
+ for activity in stage["practice_activities"]:
376
+ activities_node.add(activity)
377
+
378
+ self.console.print(learning_tree)
379
+ self.console.print("\n")
380
+
381
+ # Project suggestions table
382
+ project_table = Table(title="Recommended Projects", box=box.ROUNDED)
383
+ project_table.add_column("Project Name", style="cyan", no_wrap=True)
384
+ project_table.add_column("Description", style="white")
385
+ project_table.add_column("Complexity", style="magenta")
386
+ project_table.add_column("Est. Time", style="yellow")
387
+
388
+ for project in roadmap["projectSuggestions"]:
389
+ project_table.add_row(
390
+ project["name"],
391
+ project["description"],
392
+ project["complexity"],
393
+ project.get("estimated_time", "N/A")
394
+ )
395
+
396
+ self.console.print(project_table)
397
+ self.console.print("\n")
398
+
399
+ # Resources panel
400
+ resources = roadmap.get("resources", {})
401
+ resources_text = ""
402
+
403
+ resource_categories = {
404
+ "books": "Recommended Books",
405
+ "online_courses": "Online Courses",
406
+ "communities": "Communities",
407
+ "tools": "Essential Tools",
408
+ "practice_platforms": "Practice Platforms"
409
+ }
410
+
411
+ for category, title in resource_categories.items():
412
+ if category in resources and resources[category]:
413
+ resources_text += f"[bold yellow]{title}:[/bold yellow]\n"
414
+ for item in resources[category]:
415
+ resources_text += f"• {item}\n"
416
+ resources_text += "\n"
417
+
418
+ self.console.print(Panel(resources_text, title="[bold cyan]Learning Resources[/bold cyan]",
419
+ box=box.ROUNDED, expand=False))
420
+
421
+ # Career insights
422
+ if "career_insights" in roadmap and roadmap["career_insights"]:
423
+ career_text = "[bold yellow]Career Insights:[/bold yellow]\n"
424
+ for insight in roadmap["career_insights"]:
425
+ career_text += f"• {insight}\n"
426
+
427
+ self.console.print(Panel(career_text, title="[bold cyan]Career Opportunities[/bold cyan]",
428
+ box=box.ROUNDED, expand=False))
429
+
430
+ def display_recommended_courses(self, courses: pd.DataFrame):
431
+ """
432
+ Display recommended courses in a beautiful format
433
+ """
434
+ if courses.empty:
435
+ self.console.print("[yellow]No courses match your criteria. Try broader search terms.[/yellow]")
436
+ return
437
+
438
+ table = Table(title="Recommended Courses", box=box.ROUNDED)
439
+ table.add_column("ID", style="dim")
440
+ table.add_column("Course Name", style="cyan")
441
+ table.add_column("Rating", style="yellow")
442
+ table.add_column("Difficulty", style="green")
443
+
444
+ for _, course in courses.iterrows():
445
+ table.add_row(
446
+ str(course.get('Course ID', 'N/A')),
447
+ course.get('Course Name', 'N/A').title(),
448
+ f"{course.get('Course Rating', 0):.1f} ★",
449
+ course.get('Difficulty Level', 'N/A').title()
450
+ )
451
+
452
+ self.console.print(table)
453
+ self.console.print("\n[dim]Use the course ID to get more details about a specific course.[/dim]")
454
+
455
+ def roadmap_to_markdown(self, roadmap: Dict, topic: str, skill_level: str) -> str:
456
+ """
457
+ Convert a roadmap to markdown format for export or display
458
+ """
459
+ markdown = f"# Personalized Learning Roadmap: {topic.title()}\n\n"
460
+ markdown += f"*Skill Level: {skill_level.title()}*\n\n"
461
+
462
+ # Learning Path
463
+ markdown += "## Learning Path\n\n"
464
+ for i, stage in enumerate(roadmap["learningPath"]):
465
+ markdown += f"### {i+1}. {stage['step']} ({stage['difficulty']}) - {stage['time_estimate']}\n\n"
466
+ markdown += f"{stage['description']}\n\n"
467
+
468
+ markdown += "**Key Concepts:**\n"
469
+ for concept in stage.get("key_concepts", []):
470
+ markdown += f"- {concept}\n"
471
+ markdown += "\n"
472
+
473
+ if "milestones" in stage:
474
+ markdown += "**Milestones:**\n"
475
+ for milestone in stage["milestones"]:
476
+ markdown += f"- {milestone}\n"
477
+ markdown += "\n"
478
+
479
+ if "practice_activities" in stage:
480
+ markdown += "**Practice Activities:**\n"
481
+ for activity in stage["practice_activities"]:
482
+ markdown += f"- {activity}\n"
483
+ markdown += "\n"
484
+
485
+ # Project Suggestions
486
+ markdown += "## Recommended Projects\n\n"
487
+ for i, project in enumerate(roadmap["projectSuggestions"]):
488
+ markdown += f"### {i+1}. {project['name']} ({project['complexity']})\n\n"
489
+ markdown += f"{project['description']}\n\n"
490
+
491
+ if "skills_practiced" in project:
492
+ markdown += "**Skills Practiced:**\n"
493
+ for skill in project["skills_practiced"]:
494
+ markdown += f"- {skill}\n"
495
+ markdown += "\n"
496
+
497
+ markdown += "**Resources:**\n"
498
+ for resource in project.get("resources", []):
499
+ markdown += f"- {resource}\n"
500
+ markdown += "\n"
501
+
502
+ if "estimated_time" in project:
503
+ markdown += f"**Estimated Time:** {project['estimated_time']}\n\n"
504
+
505
+ # Resources
506
+ markdown += "## Learning Resources\n\n"
507
+ resources = roadmap.get("resources", {})
508
+
509
+ resource_categories = {
510
+ "books": "Recommended Books",
511
+ "online_courses": "Online Courses",
512
+ "communities": "Communities",
513
+ "tools": "Essential Tools",
514
+ "practice_platforms": "Practice Platforms"
515
+ }
516
+
517
+ for category, title in resource_categories.items():
518
+ if category in resources and resources[category]:
519
+ markdown += f"### {title}\n"
520
+ for item in resources[category]:
521
+ markdown += f"- {item}\n"
522
+ markdown += "\n"
523
+
524
+ # Career Insights
525
+ if "career_insights" in roadmap and roadmap["career_insights"]:
526
+ markdown += "## Career Opportunities\n\n"
527
+ for insight in roadmap["career_insights"]:
528
+ markdown += f"- {insight}\n"
529
+
530
+ return markdown
531
+
532
+ def load_courses(file_path: str = 'Coursera.csv') -> CourseRecommender:
533
+ """
534
+ Load courses from CSV and create a CourseRecommender instance
535
+ """
536
+ console = Console()
537
+
538
+ try:
539
+ with console.status("[bold green]Loading course data...", spinner="dots"):
540
+ df = pd.read_csv(file_path)
541
+ time.sleep(1) # Simulate loading time for visual effect
542
+ console.print(f"[green]Successfully loaded {len(df)} courses![/green]")
543
+ return CourseRecommender(df)
544
+ except FileNotFoundError:
545
+ console.print(f"[red]Error: {file_path} file not found.[/red]")
546
+ return None
547
+ except Exception as e:
548
+ console.print(f"[red]An error occurred while reading the CSV: {e}[/red]")
549
+ return None
550
+
551
+ def main():
552
+ console = Console()
553
+
554
+ # Print welcome message
555
+ console.print(Panel.fit(
556
+ "[bold cyan]Course Recommender & Learning Roadmap Generator[/bold cyan]\n"
557
+ "[yellow]Find the perfect courses and create your personalized learning journey[/yellow]",
558
+ box=box.DOUBLE))
559
+
560
+ recommender = load_courses()
561
+ if recommender:
562
+ console.print("[bold]Let's find the perfect learning path for you![/bold]\n")
563
+
564
+ topic = console.input("[bold green]Enter the topic you want to learn about: [/bold green]")
565
+ skill_level = console.input("[bold green]Enter your skill level (Beginner, Intermediate, Advanced): [/bold green]")
566
+
567
+ use_ai = False
568
+ user_goals = None
569
+
570
+ if recommender.ai_enabled:
571
+ use_ai = console.input("[bold green]Would you like AI-enhanced personalized recommendations? (y/n): [/bold green]").lower() == 'y'
572
+ if use_ai:
573
+ user_goals = console.input("[bold green]What are your learning goals or career objectives with this topic? [/bold green]")
574
+
575
+ # Generate and display roadmap
576
+ roadmap = recommender.generate_roadmap(topic, skill_level, user_goals, detailed=use_ai)
577
+ recommender.display_roadmap(roadmap)
578
+
579
+ # Option to export roadmap
580
+ export = console.input("\n[bold green]Would you like to export this roadmap to a markdown file? (y/n): [/bold green]").lower() == 'y'
581
+ if export:
582
+ markdown = recommender.roadmap_to_markdown(roadmap, topic, skill_level)
583
+ filename = f"{topic.lower().replace(' ', '_')}_roadmap.md"
584
+ with open(filename, "w") as f:
585
+ f.write(markdown)
586
+ console.print(f"[green]Roadmap exported to {filename}[/green]")
587
+
588
+ console.print("\n[bold]Press Enter to see recommended courses...[/bold]")
589
+ input()
590
+
591
+ # Get and display recommended courses
592
+ recommended_courses = recommender.recommend_courses(topic, skill_level, personalized=use_ai, user_goals=user_goals)
593
+ recommender.display_recommended_courses(recommended_courses)
594
+
595
+ # Allow user to view detailed course info
596
+ while True:
597
+ course_id = console.input("\n[bold green]Enter a course ID for more details (or 'q' to quit): [/bold green]")
598
+ if course_id.lower() == 'q':
599
+ break
600
+
601
+ try:
602
+ course_id = int(course_id)
603
+ course = recommended_courses[recommended_courses['Course ID'] == course_id]
604
+ if not course.empty:
605
+ details = recommender.get_course_details(course.iloc[0])
606
+
607
+ console.print(Panel(
608
+ f"[bold cyan]{details['name'].title()}[/bold cyan]\n\n"
609
+ f"[yellow]Rating:[/yellow] {details['rating']} ★\n"
610
+ f"[yellow]Difficulty:[/yellow] {details['difficulty'].title()}\n\n"
611
+ f"[yellow]Skills:[/yellow] {details['skills'].title()}\n\n"
612
+ f"[yellow]Description:[/yellow]\n{details['description']}\n\n"
613
+ f"[link={details['url']}]View Course[/link]",
614
+ title="Course Details", box=box.ROUNDED, width=100
615
+ ))
616
+ else:
617
+ console.print("[yellow]Course ID not found. Please try again.[/yellow]")
618
+ except ValueError:
619
+ console.print("[yellow]Please enter a valid course ID.[/yellow]")
620
+
621
+ console.print(Panel("[bold cyan]Thank you for using the Course Recommender![/bold cyan]", box=box.ROUNDED))
622
+
623
+ # Gradio interface for Hugging Face deployment
624
+ def create_gradio_interface(recommender: CourseRecommender):
625
+ """
626
+ Create a Gradio interface for the course recommender
627
+ """
628
+ def recommend_and_generate(topic, skill_level, goals, use_ai):
629
+ try:
630
+ # Generate roadmap
631
+ roadmap = recommender.generate_roadmap(
632
+ topic=topic,
633
+ skill_level=skill_level,
634
+ user_goals=goals if goals else None,
635
+ detailed=use_ai
636
+ )
637
+
638
+ # Get course recommendations
639
+ recommended_courses = recommender.recommend_courses(
640
+ topic=topic,
641
+ skill_level=skill_level,
642
+ personalized=use_ai,
643
+ user_goals=goals if goals else None
644
+ )
645
+
646
+ # Convert roadmap to markdown
647
+ roadmap_md = recommender.roadmap_to_markdown(roadmap, topic, skill_level)
648
+
649
+ # Format course recommendations as markdown
650
+ courses_md = "# Recommended Courses\n\n"
651
+ for i, (_, course) in enumerate(recommended_courses.iterrows()):
652
+ courses_md += f"## {i+1}. {course.get('Course Name', 'N/A').title()}\n\n"
653
+ courses_md += f"**Rating:** {course.get('Course Rating', 0):.1f} ★\n\n"
654
+ courses_md += f"**Difficulty:** {course.get('Difficulty Level', 'N/A').title()}\n\n"
655
+ courses_md += f"**Skills:** {course.get('Skills', 'N/A').title()}\n\n"
656
+ courses_md += f"**Description:**\n{course.get('Description', 'No description available')}\n\n"
657
+ if 'Course URL' in course and course['Course URL'] != '#':
658
+ courses_md += f"[View Course]({course['Course URL']})\n\n"
659
+ courses_md += "---\n\n"
660
+
661
+ return roadmap_md, courses_md
662
+ except Exception as e:
663
+ return f"Error: {str(e)}", "Could not generate course recommendations"
664
+
665
+ with gr.Blocks(title="Learning Roadmap Generator") as demo:
666
+ gr.Markdown("# 🎓 Learning Roadmap & Course Recommender")
667
+ gr.Markdown("Generate a personalized learning roadmap and course recommendations.")
668
+
669
+ with gr.Row():
670
+ with gr.Column():
671
+ topic_input = gr.Textbox(label="Topic you want to learn", placeholder="e.g. Python, Data Science, Machine Learning")
672
+ skill_level = gr.Dropdown(
673
+ ["Beginner", "Intermediate", "Advanced"],
674
+ label="Your current skill level"
675
+ )
676
+ goals_input = gr.Textbox(
677
+ label="Your learning goals (optional)",
678
+ placeholder="e.g. Career change, specific project, skill enhancement",
679
+ lines=3
680
+ )
681
+ use_ai = gr.Checkbox(label="Use AI for enhanced personalization", value=recommender.ai_enabled)
682
+
683
+ submit_btn = gr.Button("Generate Learning Roadmap", variant="primary")
684
+
685
+ with gr.Row():
686
+ with gr.Column():
687
+ roadmap_output = gr.Markdown(label="Your Learning Roadmap")
688
+ with gr.Column():
689
+ courses_output = gr.Markdown(label="Recommended Courses")
690
+
691
+ submit_btn.click(
692
+ recommend_and_generate,
693
+ inputs=[topic_input, skill_level, goals_input, use_ai],
694
+ outputs=[roadmap_output, courses_output]
695
+ )
696
+
697
+ return demo
698
+
699
+ def deploy_to_huggingface():
700
+ """
701
+ Deploy the application to Hugging Face Spaces
702
+ """
703
+ try:
704
+ # Load environment variables
705
+ load_dotenv()
706
+
707
+ # Initialize HuggingFace API
708
+ hf_token = os.getenv("HF_TOKEN")
709
+ if not hf_token:
710
+ print("Error: HF_TOKEN not found in environment variables")
711
+ return
712
+
713
+ api = HfApi(token=hf_token)
714
+
715
+ # Create recommender
716
+ recommender = load_courses()
717
+ if not recommender:
718
+ print("Error: Could not load course data")
719
+ return
720
+
721
+ # Create and launch Gradio interface
722
+ demo = create_gradio_interface(recommender)
723
+
724
+ # Launch the app
725
+ demo.launch(share=True)
726
+
727
+ except Exception as e:
728
+ print(f"Error deploying to Hugging Face: {e}")
729
+
730
+ if __name__ == "__main__":
731
+ # Check if this is being run on Hugging Face Spaces
732
+ if os.getenv("SPACE_ID"):
733
+ # Initialize for Hugging Face
734
+ try:
735
+ recommender = load_courses()
736
+ if recommender:
737
+ demo = create_gradio_interface(recommender)
738
+ demo.launch()
739
+ else:
740
+ print("Error: Could not load course data")
741
+ except Exception as e:
742
+ print(f"Error initializing Gradio app: {e}")
743
+ else:
744
+ # Run the CLI version
745
+ main()