diff --git a/API/app.py b/API/app.py index 0db090e..707195a 100644 --- a/API/app.py +++ b/API/app.py @@ -35,9 +35,9 @@ def get_recommended_movies(user_id): also triggers sending recommender outputs to front """ from recommend_movies import RecommendMovies - return RecommendMovies(user_id, None, None).recommend() + return RecommendMovies(user_id).recommend() @app.post("/rating") def post_user_rating(user_id, movie_id, rating): from recommend_movies import RecommendMovies - return RecommendMovies(user_id, None, None).rate_movie(movie_id, rating) \ No newline at end of file + return RecommendMovies(user_id).rate_movie(movie_id, rating) \ No newline at end of file diff --git a/API/connect_db.py b/API/connect_db.py index d2d127c..5726fd4 100644 --- a/API/connect_db.py +++ b/API/connect_db.py @@ -55,3 +55,19 @@ def delete_user_entry(self, user_id, movie_id): def get_movie(self, movie_id): return self.get_one_info({"movie_id": movie_id}) + + def get_sequential_model(self): + return self.get_info({"model":"sequential"}) + + def get_explicit_model(self): + return self.get_info({"model": "explicit"}) + + def load_db_access_credentials(self): + with open("./credentials.txt", "r") as fh: + for line in fh: + if "user=" in line: + user = line.strip().split("=")[-1] + self.db_access_key = user + elif "pass=" in line: + passw = line.strip().split("=")[-1] + self.db_pass = passw diff --git a/API/recommend_movies.py b/API/recommend_movies.py index 456ea8b..1abb2b7 100644 --- a/API/recommend_movies.py +++ b/API/recommend_movies.py @@ -1,13 +1,16 @@ +import os.path + +import torch from connect_db import MongoDB from typing import List, Dict class RecommendMovies: - MONGO_ACCESS = MongoDB() + MONGO_ACCESS = MongoDB(collection="models") - def __init__(self, user_id, explicit_model, sequential_model): + def __init__(self, user_id): self.user_id = user_id self.user_data:List[Dict] = self.get_user_data(user_id) - self.explicit_model = explicit_model - self.sequential_model= sequential_model + self.explicit_model = self.load_explicit_model() + self.sequential_model= self.load_sequential_model() def recommend(self): if not self.user_data: @@ -15,8 +18,8 @@ def recommend(self): previous_movies = self.get_previously_watched_movies() exp_recommend_movies = self.get_recommendations_from_explicit_model() seq_recommend_movies = self.get_recommendations_from_sequential_model() - #exp_recommend_movies = set() - filtered_movies = self.filter_previously_watched_movies(exp_recommend_movies, previous_movies) + recommended_movies = exp_recommend_movies + seq_recommend_movies + filtered_movies = self.filter_previously_watched_movies(recommended_movies, previous_movies) return self.get_movie_title_and_genre(filtered_movies) def rate_movie(self, movie_id, rating): @@ -27,17 +30,17 @@ def rate_movie(self, movie_id, rating): def get_user_data(self,user_id): return self.MONGO_ACCESS.get_user(user_id) - def get_recommendations_from_explicit_model(self): - ##TODO: load explicit model, ask user_id, get movie ids - ##TODO: connect it to the explicit model thing - return ["12", "11", "99"] - #return self.explicit_model(self.user_id) - + def get_recommendations_from_explicit_model(self, n_movies=10): + import numpy as np + from process_data.process_movie_data import MovieLens + dataset=MovieLens.download_data_from_db() + ratings = self.sequential_model.predict(user_ids=self.user_id) + indices = np.argpartition(ratings, -n_movies)[-n_movies:] + best_movie_ids = indices[np.argsort(ratings[indices])] + return [dataset.item_ids[i] for i in best_movie_ids] def get_recommendations_from_sequential_model(self): - ##TODO: load sequential model, ask user_id, get movie ids - pass - #return self.sequential_model(self.user_id) + return self.sequential_model(self.user_id) def get_previously_watched_movies(self): return [movie_data["movie_id"] for movie_data in self.user_data] @@ -46,6 +49,16 @@ def get_previously_watched_movies(self): def filter_previously_watched_movies(recommended_movies, previous_movies): return list(set(recommended_movies).difference(set(previous_movies))) + def load_sequential_model(self): + seq_model_path = self.MONGO_ACCESS.get_sequential_model() + return torch.load(seq_model_path) + + def load_explicit_model(self): + #exp_model_path = self.MONGO_ACCESS.get_explicit_model() + from config import DATA_PATH + exp_model_path = os.path.join(DATA_PATH, "explicit.pt") + return torch.load(exp_model_path) + def get_movie_title_and_genre(self, movie_ids:List): recommended_movies = [] for movie_id in movie_ids: diff --git a/requirements.txt b/requirements.txt index 7c4f52c..2b9a5cb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ uvicorn fastapi pymongo[srv] pytest +mlflow h5py tables cython \ No newline at end of file