Skip to content
Snippets Groups Projects
recommendation.js 8.1 KiB
Newer Older
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");
sacha's avatar
sacha committed
const { getMovieAuthor, getMovieActors, getMovieStyles} = 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");
Bastien's avatar
Bastien committed
    let person = await getUserInformations(user_login);

    let user = User.toUser(person);

sacha's avatar
sacha committed
    let movies = await getUserSeenMovies(user_login);
    movies.forEach(async movie => {
        movie = Movie.toMovie(movie);
        movie.author = await getMovieAuthor(movie.id);
        movie.actors = await getMovieActors(movie.id);
        movie.styles = await getMovieStyles(movie.id);
        user.addMovies(movie);
Bastien's avatar
Bastien committed
    });

    let fav_styles = []; //styles des films présents dans les films aimés par l'utilisateur
    let fav_authors = []; //auteurs récurents dans les films aimés par l'utilisateur : moyenne (auteur * note du film)
    let fav_actors = []; //acteurs récurents dans les films aimés par l'utilisateur : moyenne (acteur * note du film (* %temps écran))
    //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
sacha's avatar
sacha committed
    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 = getFilmsBy(actors, authors/*, styles*/);
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

sacha's avatar
sacha committed
function getAllAuthors(seen){
    let authors = [[]];
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];        
    }

    authors.sort(comparerLignes);
    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

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
}
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
}

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;
}