Skip to content
Snippets Groups Projects
recommendation.js 9.14 KiB
Newer Older
  • Learn to ignore specific revisions
  • sacha's avatar
    sacha committed
    
    
    sacha's avatar
    sacha committed
    const Movie = require("../models/class_film.js");
    
    Bastien's avatar
    Bastien committed
    const User = require("../models/class_user.js");
    const { getUserInformations, getUserSeenMovies } = require("../services/user.js");
    
    const { getMovieAuthor, getMovieActors, getMovieStyles, getMovieById , getFilmsByAAS } = require("../services/movies.js");
    
    sacha's avatar
    sacha committed
    const controllers = require("./userController.js");
    
    exports.getRecommandations = (req,  res,  next) => {
    
        let username = req.session.username;
        let infos = recommendationForUser(username);
        res.status(200).json(infos);
    };
    
    
    /**
     * Cette fonction selectionne les 3 meilleurs films pour un utilisateur.
     *
     * @param {string} user_login - Login de l'utilisateur.
     * @returns {Movie[]} - La liste des 3 films.
     */
    
    sacha's avatar
    sacha committed
    
    
    async function recommendationForUser(user_login, max_number = 3) {
    
    Bastien's avatar
    Bastien committed
        // let person = controllers.get_user(user_login);
    
        //console.log("testtest");
    
        let user = User.toUser(await getUserInformations(user_login));
    
    Bastien's avatar
    Bastien committed
    
    
        let movies = await getSeenMoviesInfos(user_login);
    
    Bastien's avatar
    Bastien committed
    
    
        user.movies = movies;
    
    Bastien's avatar
    Bastien committed
    
    
        //let fav_duration;
    
    sacha's avatar
    sacha committed
        let seen = user.movies;
    
        let authors = getAllAuthors(seen).slice(0, 3);
        for (let i = 0; i < authors.length; i++) {
    
    sacha's avatar
    sacha committed
            fav_authors[i] = authors[i][0]; //recuperer seulement l'auteur, pas le reste
    
        let actors = getAllElement(seen, getActors).slice(0, 3);
        for (let i = 0; i < actors.length; i++) {
    
    sacha's avatar
    sacha committed
            fav_actors[i] = actors[i][0]; //recuperer seulement l'acteur, pas le reste
    
    sacha's avatar
    sacha committed
        /* Ya des films sans genre donc faut adapter :'(
    
    sacha's avatar
    sacha committed
        let styles = getAllElement(seen, getStyles).slice(0,3);
    
        for (let i = 0; i < styles.length; i++) { 
    
    sacha's avatar
    sacha committed
            fav_styles[i] = styles[i][0]; //recuperer seulement le style, pas le reste
    
    sacha's avatar
    sacha committed
        }*/
    
    sacha's avatar
    sacha committed
        let points_films = [[]];
    
        let all_films_sql = await getFilmsByAAS(fav_actors, fav_authors/*, fav_styles*/);
        let all_films = [];
        all_films_sql.forEach(film => {
            all_films.push(Movie.toMovie(film));
        });
    
    sacha's avatar
    sacha committed
        //chaques films a un nombre de points dans chaques catégorie : 
    
        //indice 0: films - indice 1: points_auteurs - indice 2: points_acteurs - indice 3: points_styles - indice 4: note total (%)
    
    
        let max_point_author = fav_authors.length * fav_authors.length;
        let max_point_actor = fav_actors.length * fav_actors.length;
    
        //let max_point_style = fav_styles.length*fav_styles.length;
        for (let i = 0; i < all_films.length; i++) {
            points_films[i][0] = all_films[i];
            for (let j = 0; j < fav_authors.length; j++) {
    
                if (all_films[i].author == fav_authors[j]) points_films[i][1] = (fav_authors.length - j) * fav_authors.length;
    
            }
            for (let j = 0; j < fav_actors.length; j++) {
                all_films[i].actors.forEach(actor => {
    
                    if (actor == fav_actors[j]) points_films[i][2] = (fav_actors.length - j) * fav_actors.length / all_films[i].actors.length;
    
                });
            }
            /*for (let j = 0; j < fav_styles.length; j++) {
                all_films[i].styles.forEach(style => {
                    if(style == fav_styles[j])points_films[i][3] = (fav_styles.length-j) * fav_styles.length/all_films[i].styles.length;
                });
            }*/
    
            points_films[i][4] = points_films[i][1] / max_point_author + points_films[i][2] / max_point_actor/* + points_films[i][3]/max_point_style*/;
    
            points_films[i][4] /= 3;
        }
        let res = [];
        for (let i = 0; i < max_number; i++) {
            res.push(getHighestScore(points_films, res));
        }
    
    sacha's avatar
    ok  
    sacha committed
    
    
    
        return res;
    
    sacha's avatar
    sacha committed
    }
    
    
    /**
     * trier une matrice par l'indice 1, puis par l'indice 2, puis par l'indice 0.
     *
     * @param {[string, Number, Number]} a - ligne d'une matrice
     * @param {[string, Number, Number]} b - ligne d'une matrice
     * @returns {Number} - 1 si a est plus grand, 0 si a=b, -1 si b est plus grand.
     */
    
    sacha's avatar
    sacha committed
    
    
    function comparerLignes(a, b) {
        // trier par le nombre d'apparition de l'auteur dans la liste de film vus (int)
        if (a[1] < b[1]) return -1;
        if (a[1] > b[1]) return 1;
    
        // Si le nombre d'apparition est le même, trier par la moyenne de notes des films de l'auteur (float)
        if (a[2] < b[2]) return -1;
        if (a[2] > b[2]) return 1;
    
        // Si la moyenne est la même, trier par le nom de l'auteur (string)
        if (a[0] < b[0]) return -1;
        if (a[0] > b[0]) return 1;
    
        // Les lignes sont égales
    
    sacha's avatar
    sacha committed
        console.log("doublon d'auteur !!");
    
        return 0;
    
    sacha's avatar
    sacha committed
    }
    
    
    /**
     * renvoie une liste d'auteurs, avec leur nombre d'apparition dans la liste des films vus par un utilisateur, puis leur note moyenne
     *
     * @param {Movie[]} movies - Liste de film vus par un utilisateur.
     * @returns {[[string, Number, Number]]} - La liste des auteurs.
     */
    
    sacha's avatar
    sacha committed
    
    
    function getAllAuthors(seen) {
    
        let authors = [[]];
    
        console.log("getAllAuthors(seen)");
        console.log(seen);
    
    sacha's avatar
    sacha committed
        //1er indice = indice du couple auteur/nombre d'apparition/moyenne notes films, 2e indice: 0 auteur, 1 nbr apparition, 2 mpyenne films
    
        for (let i = 0; i < seen.length; i++) {
            let j = 0;
            let found = false;
    
            while (j < authors.length && !found) {
    
                if (authors[j][0] == seen[i].author) {
                    found = true;
                    authors[j][1] += 1;
                    authors[j][2] += seen[i].note;
                }
                j++;
            }
    
            if (!found) {
    
    sacha's avatar
    sacha committed
                authors.push([seen[i].author, 1, seen[i].note]);
    
            }
        }
        for (let i = 0; i < authors.length; i++) {
    
            authors[i][2] /= authors[i][1];
    
        console.log(authors);
    
        authors.sort(comparerLignes);
    
        console.log(authors);
        console.log("fin");
    
        return authors;
    }
    
    sacha's avatar
    sacha committed
    
    
    /**
     * renvoie une liste d'acteurs/styles, avec leur nombre d'apparition dans la liste des films vus par un utilisateur, puis leur note moyenne
     *
     * @param {Movie[]} movies - Liste de film vus par un utilisateur.
     * @param {string(Movie)} recupElement - Fonction qui recupere un element d'un film (pour generaliser à allElement) (acteurs ou styles).
     * @returns {[[string, Number, Number]]} - La liste des auteurs.
     */
    
    sacha's avatar
    sacha committed
    
    
    function getAllElement(seen, recupElement) {
    
        let elements = [[]];
        //premier indice = couple element/nombre d'apparition/moyenne notes films, 2e indice: 0 auteur, 1 nbr apparition, 2 mpyenne films
        for (let i = 0; i < seen.length; i++) {
            let j = 0;
            let found = false;
            temp_elements = recupElement(seen[i]);
    
    sacha's avatar
    sacha committed
            console.log(temp_elements); //liste d'acteurs
    
            for (let h = 0; h < temp_elements.length; h++) {
    
                while (j < elements.length && !found) {
    
                    if (elements[j][0] == recupElement(temp_elements[h])) {
                        found = true;
                        elements[j][1] += 1;
                        elements[j][2] += temp_elements[h].note;
                    }
                    j++;
                }
    
                if (!found) {
    
    sacha's avatar
    sacha committed
                    elements.push([recupElement(temp_elements[h]), 1, temp_elements[h].note]);
    
                }
            }
        }
        for (let i = 0; i < elements.length; i++) {
    
            elements[i][2] /= elements[i][1];
    
        }
    
        elements.sort(comparerLignes);
        return elements;
    
    sacha's avatar
    sacha committed
    }
    
    function getAuthor(movie) {
    
        return movie.author;
    
    function getActors(movie) {
    
        return movie.actors;
    }
    
    sacha's avatar
    sacha committed
    
    
    function getStyles(movie) {
    
        return movie.styles;
    
    sacha's avatar
    sacha committed
    }
    
    
    /**
     * Renvoie les informations du film avec ses acteurs, auteur et styles en classe Movie
     *
     * @param {string} movieId - L'id du film (tconst)
     * @returns {Promise<Movie>} - Le film en classe Movie avec l'auteur, les acteurs et les styles
     */
    async function getMovieEveryInfos(movieId) {
        let movie = Movie.toMovie(await getMovieById(movieId));
        movie.author = (await getMovieAuthor(movieId))?.nconst;
        movie.actors = (await getMovieActors(movieId)).map(actor => actor.nconst);
        movie.styles = (await getMovieStyles(movieId)).map(style => style.idGen);
    
        return movie;
    
    }
    
    
    /**
     * Renvoie la liste des films vus par l'utilisateur avec leurs auteurs, acteurs et styles en classe Movie
     *
     * @param {string} userId - Le nom d'utilisateur
     * @returns {Promise<Array<Movie>>} - La liste des films en classe Movie avec l'auteur, les acteurs et les styles
     */
    async function getSeenMoviesInfos(userId) {
    
        let seenMovies = await getUserSeenMovies(userId);
        let res = seenMovies.map(async movie => {
            let movieRes = Movie.toMovie(movie);
            movieRes.author = (await getMovieAuthor(movie.id))?.nconst;
            movieRes.actors = (await getMovieActors(movie.id)).map(actor => actor.nconst);
            movieRes.styles = (await getMovieStyles(movie.id)).map(style => style.idGen);
            return movieRes
        })
    
        return res;
    
    }
    
    function getHighestScore(points_films, blacklist){
        let found = false;
        let i = 0;
        let res;
        let highscore = 0;
        while (i < points_films.length && !found) {
            if (points_films[i][4] > highscore) {
                if (!isIn(points_films[i][0], blacklist)) {
                    highscore = points_films[i][4];
                    res = points_films[i][0];
                }
            }
        }
        return res;
    }
    
    /**
     * Vérifie qu'un object est dans une liste
     *
     * @param {Object} objet - objet a trouver
     * @param {Object[]} liste - liste dans laquelle chercher
     * 
     * @returns {boolean} - true Si l'objet est dans la liste
     */
    
    function isIn(objet, liste) {
    
        let res = false;
        let i = 0;
    
        while (res == false && i < liste.length) if (objet == liste[i++]) res = true;