game_manager_lib\services\recommendation/
profile.rs1use super::core::*;
7use crate::utils::tag_utils::{combined_multiplier, TagKey, TagRole};
8use std::collections::{HashMap, HashSet};
9
10pub fn calculate_user_profile(
12 games: &[GameWithDetails],
13 ignored_ids: &HashSet<String>,
14) -> UserPreferenceVector {
15 let mut genres: HashMap<String, f32> = HashMap::new();
16 let mut tags: HashMap<TagKey, f32> = HashMap::new();
17 let mut series: HashMap<String, f32> = HashMap::new();
18 let mut total_playtime = 0;
19 let total_games = games.len() as i32;
20
21 for game_data in games {
22 if ignored_ids.contains(&game_data.game.id) {
23 continue;
24 }
25
26 let game = &game_data.game;
27 let weight = calculate_game_weight(game);
28 total_playtime += game.playtime.unwrap_or(0);
29
30 accumulate_genres(&mut genres, &game_data.genres, weight);
32
33 accumulate_tags(&mut tags, &game_data.tags, weight);
35
36 accumulate_series(&mut series, &game_data.series, weight);
38 }
39
40 UserPreferenceVector {
41 genres,
42 tags,
43 series,
44 total_playtime,
45 total_games,
46 }
47}
48
49fn accumulate_genres(genres: &mut HashMap<String, f32>, game_genres: &[String], weight: f32) {
52 for genre in game_genres {
53 *genres.entry(genre.clone()).or_insert(0.0) += weight * WEIGHT_GENRE;
54 }
55}
56
57fn accumulate_tags(
58 tags: &mut HashMap<TagKey, f32>,
59 game_tags: &[crate::models::GameTag],
60 weight: f32,
61) {
62 for tag in game_tags {
63 let key = TagKey::new(tag.category.clone(), tag.slug.clone());
64
65 if tag.role == TagRole::Filter {
67 continue;
68 }
69
70 let tag_weight = weight * tag.relevance * combined_multiplier(&tag.category, &tag.role);
71
72 *tags.entry(key).or_insert(0.0) += tag_weight;
73 }
74}
75
76fn accumulate_series(series: &mut HashMap<String, f32>, game_series: &Option<String>, weight: f32) {
77 if let Some(series_name) = game_series {
78 *series.entry(series_name.clone()).or_insert(0.0) += weight * WEIGHT_SERIES;
79 }
80}