Ali Hashhash commited on
Commit
2c06845
Β·
2 Parent(s): 06803fa914b21c

Merge branch 'main' of https://huggingface.co/spaces/ATInc1/AIdea-Server

Browse files
Files changed (2) hide show
  1. src/api/recommendation_routes.py +110 -12
  2. src/db/models.py +1 -0
src/api/recommendation_routes.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi import APIRouter, Depends
2
  from typing import Dict, Any
3
  from src.auth.dependencies import get_current_user
4
  from src.db.firebase import get_firebase_db
@@ -9,20 +9,118 @@ logger = setup_logger(__name__)
9
  router = APIRouter(prefix="/recommendations", tags=["Recommendations"])
10
  recommendation_service = RecommendationService()
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  @router.get("")
13
- async def get_general_recommendations(
14
  current_user=Depends(get_current_user),
15
- db=Depends(get_firebase_db)
 
16
  ) -> Dict[str, Any]:
17
- logger.info(f"🎯 Getting recommendations for user: {current_user['uid']}")
18
-
19
- recommendations = await recommendation_service.get_recommendations_for_user(
20
- db=db,
21
- user_id=current_user['uid'],
22
- limit=5
23
- )
24
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  return {
26
  "status": "success",
27
- "recommendations": recommendations
 
 
 
 
28
  }
 
1
+ from fastapi import APIRouter, Depends, HTTPException, Query
2
  from typing import Dict, Any
3
  from src.auth.dependencies import get_current_user
4
  from src.db.firebase import get_firebase_db
 
9
  router = APIRouter(prefix="/recommendations", tags=["Recommendations"])
10
  recommendation_service = RecommendationService()
11
 
12
+ GENERAL_VIDEOS = [
13
+ {
14
+ "videoId": "aircAruvnKk",
15
+ "title": "But what is a neural network?",
16
+ "channelTitle": "3Blue1Brown",
17
+ "thumbnail": "https://img.youtube.com/vi/aircAruvnKk/hqdefault.jpg",
18
+ },
19
+ {
20
+ "videoId": "rfscVS0vtbw",
21
+ "title": "Learn Python in 4 hours",
22
+ "channelTitle": "freeCodeCamp",
23
+ "thumbnail": "https://img.youtube.com/vi/rfscVS0vtbw/hqdefault.jpg",
24
+ },
25
+ {
26
+ "videoId": "8jLOx1hD3_o",
27
+ "title": "Harvard CS50 2023",
28
+ "channelTitle": "CS50",
29
+ "thumbnail": "https://img.youtube.com/vi/8jLOx1hD3_o/hqdefault.jpg",
30
+ },
31
+ {
32
+ "videoId": "kqtD5dpn9C8",
33
+ "title": "Python for Beginners – Full Course",
34
+ "channelTitle": "Programming with Mosh",
35
+ "thumbnail": "https://img.youtube.com/vi/kqtD5dpn9C8/hqdefault.jpg",
36
+ },
37
+ {
38
+ "videoId": "Ke90Tje7VS0",
39
+ "title": "React JS Crash Course",
40
+ "channelTitle": "Traversy Media",
41
+ "thumbnail": "https://img.youtube.com/vi/Ke90Tje7VS0/hqdefault.jpg",
42
+ },
43
+ {
44
+ "videoId": "bMknfKXIFA8",
45
+ "title": "Machine Learning Course for Beginners",
46
+ "channelTitle": "freeCodeCamp",
47
+ "thumbnail": "https://img.youtube.com/vi/bMknfKXIFA8/hqdefault.jpg",
48
+ },
49
+ {
50
+ "videoId": "ua-CiDNNj30",
51
+ "title": "Fullstack Web Dev in 2024",
52
+ "channelTitle": "Fireship",
53
+ "thumbnail": "https://img.youtube.com/vi/ua-CiDNNj30/hqdefault.jpg",
54
+ },
55
+ {
56
+ "videoId": "qiQR5rTSshw",
57
+ "title": "C++ Tutorial for Beginners",
58
+ "channelTitle": "freeCodeCamp",
59
+ "thumbnail": "https://img.youtube.com/vi/qiQR5rTSshw/hqdefault.jpg",
60
+ },
61
+ {
62
+ "videoId": "zOjov-2OZ0E",
63
+ "title": "100+ Linux Things You Should Know",
64
+ "channelTitle": "Fireship",
65
+ "thumbnail": "https://img.youtube.com/vi/zOjov-2OZ0E/hqdefault.jpg",
66
+ },
67
+ {
68
+ "videoId": "W6NZfCO5SIk",
69
+ "title": "JavaScript Tutorial for Beginners",
70
+ "channelTitle": "Programming with Mosh",
71
+ "thumbnail": "https://img.youtube.com/vi/W6NZfCO5SIk/hqdefault.jpg",
72
+ },
73
+ ]
74
+
75
+ MIN_INTERACTIONS_FOR_PERSONALIZATION = 5
76
+
77
+
78
  @router.get("")
79
+ async def get_recommendations(
80
  current_user=Depends(get_current_user),
81
+ db=Depends(get_firebase_db),
82
+ limit: int = Query(default=5, ge=1, le=20),
83
  ) -> Dict[str, Any]:
84
+
85
+ user_id = current_user.id # βœ… your model uses "id"
86
+
87
+ if not user_id:
88
+ raise HTTPException(status_code=401, detail="Invalid user")
89
+
90
+ logger.info(f"🎯 Getting recommendations for user: {user_id}")
91
+
92
+ try:
93
+ # βœ… Use notesCount directly from user
94
+ notes_count = getattr(current_user, "notesCount", 0) or 0
95
+
96
+ is_personalized = notes_count >= MIN_INTERACTIONS_FOR_PERSONALIZATION
97
+
98
+ if is_personalized:
99
+ logger.info(f"βœ… Personalized mode for {user_id} ({notes_count} notes)")
100
+
101
+ # ⚠️ for now you can still return general videos
102
+ # until you build real recommender
103
+ recommendations = await recommendation_service.get_recommendations_for_user(
104
+ db=db,
105
+ user_id=user_id,
106
+ limit=limit,
107
+ )
108
+ else:
109
+ logger.info(f"🌱 General mode for {user_id} ({notes_count}/{MIN_INTERACTIONS_FOR_PERSONALIZATION} notes)")
110
+ recommendations = GENERAL_VIDEOS[:limit]
111
+
112
+ except Exception as e:
113
+ logger.error(f"❌ Failed to get recommendations for {user_id}: {e}")
114
+ raise HTTPException(
115
+ status_code=500,
116
+ detail="Failed to fetch recommendations.",
117
+ )
118
+
119
  return {
120
  "status": "success",
121
+ "is_personalized": is_personalized,
122
+ "interactions_count": notes_count, # βœ… mapped correctly
123
+ "interactions_needed": MIN_INTERACTIONS_FOR_PERSONALIZATION,
124
+ "count": len(recommendations),
125
+ "recommendations": recommendations,
126
  }
src/db/models.py CHANGED
@@ -19,6 +19,7 @@ class User(BaseModel):
19
  age: Optional[int] = Field(default=None)
20
  gender: Optional[str] = Field(default=None)
21
  created_at: datetime = Field(default_factory=datetime.utcnow)
 
22
 
23
  class Config:
24
  from_attributes = True
 
19
  age: Optional[int] = Field(default=None)
20
  gender: Optional[str] = Field(default=None)
21
  created_at: datetime = Field(default_factory=datetime.utcnow)
22
+ notesCount: Optional[int] = Field(default=0)
23
 
24
  class Config:
25
  from_attributes = True