@@ -4,13 +4,11 @@ import { UserRepository } from '../user/user.repository';
44@Injectable ( )
55export class WhoToFollowService {
66 private readonly CONFIG = {
7- // thresholds
87 MAX_MUTUAL_CONNECTIONS_THRESHOLD : 10 ,
98 MAX_LIKES_THRESHOLD : 10 ,
109 MAX_REPLIES_THRESHOLD : 10 ,
1110 MAX_COMMON_CATEGORIES_THRESHOLD : 2 ,
1211
13- // Distribution percentages
1412 DISTRIBUTION : {
1513 FRIENDS_OF_FRIENDS : 40 ,
1614 LIKES : 25 ,
@@ -23,9 +21,7 @@ export class WhoToFollowService {
2321 CANDIDATE_MULTIPLIER : 3 ,
2422 } ;
2523
26- /* istanbul ignore start */
2724 constructor ( private readonly user_repository : UserRepository ) { }
28- /* istanbul ignore stop */
2925
3026 async getWhoToFollow ( current_user_id ?: string , limit : number = 30 ) {
3127 if ( ! current_user_id ) {
@@ -34,12 +30,11 @@ export class WhoToFollowService {
3430
3531 const recommendations = await this . getPersonalizedRecommendations ( current_user_id , limit ) ;
3632
37- // If we don't have enough recommendations, fill with popular users
3833 if ( recommendations . length < limit ) {
3934 const needed = limit - recommendations . length ;
4035 const existing_ids = new Set ( recommendations . map ( ( r ) => r . id ) ) ;
4136
42- const additional_users = await this . getPopularUsers ( needed * 2 ) ; // Get extra to filter
37+ const additional_users = await this . getPopularUsers ( needed * 2 , current_user_id ) ;
4338 const filtered_additional = additional_users
4439 . filter ( ( user ) => ! existing_ids . has ( user . id ) )
4540 . slice ( 0 , needed ) ;
@@ -50,8 +45,8 @@ export class WhoToFollowService {
5045 return recommendations ;
5146 }
5247
53- private async getPopularUsers ( limit : number ) {
54- const users = await this . user_repository
48+ private async getPopularUsers ( limit : number , current_user_id ?: string ) {
49+ let query = this . user_repository
5550 . createQueryBuilder ( 'user' )
5651 . select ( [
5752 'user.id' ,
@@ -63,7 +58,18 @@ export class WhoToFollowService {
6358 'user.followers' ,
6459 'user.following' ,
6560 ] )
66- . where ( 'user.deleted_at IS NULL' )
61+ . where ( 'user.deleted_at IS NULL' ) ;
62+
63+ if ( current_user_id ) {
64+ query = query . andWhere ( 'user.id != :current_user_id' , { current_user_id } ) . andWhere (
65+ `user.id NOT IN (
66+ SELECT followed_id FROM user_follows WHERE follower_id = :current_user_id
67+ )` ,
68+ { current_user_id }
69+ ) ;
70+ }
71+
72+ const users = await query
6773 . orderBy ( 'user.followers' , 'DESC' )
6874 . addOrderBy ( 'user.verified' , 'DESC' )
6975 . limit ( limit )
@@ -97,7 +103,6 @@ export class WhoToFollowService {
97103 candidate_multiplier ,
98104 } ;
99105
100- //queries in parallel
101106 const [
102107 friends_of_friends ,
103108 interest_based ,
@@ -112,14 +117,6 @@ export class WhoToFollowService {
112117 this . getFollowersNotFollowed ( current_user_id , limits . followers ) ,
113118 ] ) ;
114119
115- // console.log('\n=== WHO TO FOLLOW DEBUG ===');
116- // console.log(`Friends of Friends: ${friends_of_friends.length} users`);
117- // console.log(`Interest-Based: ${interest_based.length} users`);
118- // console.log(`Liked Users: ${liked_users.length} users`);
119- // console.log(`Replied Users: ${replied_users.length} users`);
120- // console.log(`Followers Not Followed: ${followers_not_followed.length} users`);
121-
122- // Combine users from different sources with distribution-based approach
123120 const combined_users_with_metadata = this . combineByDistribution (
124121 friends_of_friends ,
125122 interest_based ,
@@ -168,7 +165,6 @@ export class WhoToFollowService {
168165
169166 const user_map = new Map ( users . map ( ( u ) => [ u . user_id , u ] ) ) ;
170167
171- // Map with metadata and filter out missing users
172168 const users_with_scores = combined_users_with_metadata
173169 . map ( ( metadata ) => {
174170 const user = user_map . get ( metadata . user_id ) ;
@@ -182,15 +178,6 @@ export class WhoToFollowService {
182178 } )
183179 . filter ( ( u ) => u !== null ) ;
184180
185- // console.log('\n=== FINAL RECOMMENDATIONS (ordered by score) ===');
186- // users_with_scores.forEach((item, index) => {
187- // console.log(
188- // `${index + 1}. @${item.user.user_username} - Score: ${item.score.toFixed(2)} - Source: ${item.source} - Data:`,
189- // item.source_data
190- // );
191- // });
192- // console.log('=========================\n');
193-
194181 return users_with_scores . map ( ( item ) => ( {
195182 id : item . user . user_id ,
196183 username : item . user . user_username ,
@@ -325,7 +312,6 @@ export class WhoToFollowService {
325312 [ ] ;
326313 const seen = new Set < string > ( ) ;
327314
328- // Take top users from each source according to distribution
329315 const add_from_source = ( users : any [ ] , count : number ) => {
330316 let added = 0 ;
331317 for ( const user of users ) {
0 commit comments