# -*- coding: utf-8 -*- """ Created on Tue Apr 28 10:46:49 2020 @author: Leopold @version = 2.0 module permetant une annalyse des conversations Mesenger """ import datetime import json class Conv(): """ Representation en machine d'une conversation. ## Utilisation Utiliser `Conv.from_list` de preference. """ def __init__(self, cible): """ ## Initialisation cible : str Emplacement du fichier `.json` de la conversation. """ file = open(cible) datas = json.load(file) file.close() try: self.nom = datas["title"].encode('cp1252').decode('utf8') except UnicodeEncodeError: self.nom = datas["title"] self.membres = {} """Liste des utilisaeur dans la conversation.""" self.messages = [] """Liste des messages de la conversation.""" for elem in datas['participants']: self.membres[elem['name']] = User(elem['name'], self) self._ajout_list_msg(datas['messages']) def _ajout_list_msg(self, list_msg): for msg in list_msg: try: user = self.membres[msg['sender_name']] self.messages.append(Messages.bon_type( msg, user, self, msg['timestamp_ms'])) except KeyError: pass def __repr__(self): return "{}:\n{}\n-{} messages".format(self.nom, self.membres, len(self.messages)) def classement(self): """ Crée un classment des membres de la conversation en fonction de leur nombre de participation. Returns ------- chaine : str Ladite chaine de la forme `numero : nom, n message`. """ users = [self.membres[elem] for elem in self.membres] users.sort(key=User.n_msg, reverse=True) chaine = "" for n, usr in enumerate(users): chaine += "{} : {} - {} messages\n".format(n+1, usr.nom, usr.n_msg()) return chaine def add_fichier(self, cible): """ Rajoute un fichier a l'objet `Conv`. """ file = open(cible) datas = json.load(file) file.close() self._ajout_list_msg(datas['messages']) def pie_participation(self): """ Camembert du nombre de participation des participants de la conv. """ from matplotlib import pyplot as plt plt.xkcd() fig = plt.figure() fig.title = self.nom ax = fig.add_axes([0, 0, 1, 1]) ax.axis('equal') users = [self.membres[elem] for elem in self.membres] users.sort(key=User.n_msg) noms = [usr.nom for usr in users] participations = [usr.n_msg() for usr in users] ax.pie(participations, labels=noms, autopct='%1.2f%%') plt.title("Participation des membres de la conv {}".format(self.nom)) return fig def hist_heure(self): """ histogramme de l'utilisation de la `Conv` en fonction de l'heure. """ list_des_minutes = [] def convertisseur_timestamps(datetime_object: datetime.datetime) -> float: time = datetime_object.time() minutes = 0 minutes += 60 * time.hour minutes += time.minute minutes += 1/60 * time.second return minutes for message in self.messages: list_des_minutes.append(convertisseur_timestamps(message.datetime)) from matplotlib import pyplot as plt plt.xkcd() plt.hist(list_des_minutes, density=True, bins=4*24, range=(0, 24*60)) plt.xticks( [i*60*2 for i in range(0, 13)], ["{}h00".format(i*2) for i in range(0, 13)], rotation=45) plt.xlim(0, 24*60) plt.title("""activité de la conv "{}" en fonction de l'heure""".format(self.nom)) return plt def __len__(self): return len(self.messages) def bar_nom_ocurence_mot(self, chaine_cible: str): """ BarGraph du nombre d'utilisation de la chaine `chaine_cible`. Insensible à la case. """ from matplotlib import pyplot as plt plt.xkcd() chaine_cible = chaine_cible.lower() liste_user = [] liste_occurence = [] for msg in self.messages: if isinstance(msg, MsgTexte): if chaine_cible in msg.content.lower(): if msg.user in liste_user: for n, user in enumerate(liste_user): if msg.user == user: liste_occurence[n] += 1 else: liste_user.append(msg.user) liste_occurence.append(1) plt.bar([str(user) for user in liste_user], liste_occurence) plt.xticks(rotation=25) plt.title("""Utilisation du terme "{}" """.format(chaine_cible)) return plt @classmethod def from_list(cls, liste_adresse): """Permet d'initialiser une conversation à partir d'une liste de fichier""" if not liste_adresse: raise ValueError conv = cls(liste_adresse[0]) for elem in liste_adresse[1:]: conv.add_fichier(elem) return conv class User(): """ Objet representant un utiliateur dans une `Conv`. """ def __init__(self, nom, conv=None): """ ## Initialisation nom : str Nom de l'utilisateur. conv : `Conv Conversation associé, optionel. """ self.nom = None """Nom de l'utilisateur.""" try: self.nom = nom.encode('cp1252').decode('utf8') except UnicodeEncodeError: self.nom = nom self.conv = conv """`Conv` où se trouve l'utilisateur.""" self.messages = [] """Liste des messages de l'utilisateur.""" def add_msg(self, msg): self.messages.append(msg) def n_msg(self): return len(self.messages) def __repr__(self): return "{} - {} messages".format(self.nom, self.n_msg()) def __str__(self): return self.nom class Messages(): """ Class representant les messages d'une conversation. """ def __init__(self, msg_data, user: User, conv: Conv, timestamp): self.datetime = datetime.datetime.fromtimestamp(timestamp/1000) """Temps POSIX de parution du message.""" self.user = user """`User` ayant poster le message.""" self.reactionaire = [] """Liste des personnes ayant reagit au message.""" try: for elem in msg_data["reactions"]: self.reactionaire.append(conv.membres[elem["actor"]]) except KeyError: pass user.add_msg(self) @classmethod def bon_type(cls, msg_data, user: User, conv: Conv, timestamp): """ Permet de creer un message avec la bonne sous-class en fonction de son contenu. Soit `MsgTexe`, `MsgPhoto`. Si le message n'a pas de class particulière `Messages`. """ if 'content' in msg_data: msg = MsgTexte(msg_data, user, conv, timestamp) elif 'photos' in msg_data: msg = MsgPhoto(msg_data, user, conv, timestamp) else: msg = Messages(msg_data, user, conv, timestamp) return msg @property def nombre_react(self): """ Nombre de personne ayant reagit à ce message. """ return len(self.reactionaire) class MsgTexte(Messages): """ Message comportant du texte. """ def __init__(self, msg_data, user: User, conv: Conv, timestamp): Messages.__init__(self, msg_data, user, conv, timestamp) contenu = msg_data['content'] self.content = None """Texte du message.""" try: self.content = contenu.encode('cp1252').decode('utf8') except UnicodeEncodeError: self.content = contenu class MsgPhoto(Messages): """ Message comportant une image. """ def __init__(self, msg_data, user: User, conv: Conv, timestamp): Messages.__init__(self, msg_data, user, conv, timestamp) self.contenu = [elem["uri"] for elem in msg_data['photos']] """Emplacement de l'image dans l'archive des données FaceBook.""" EEA = Conv.from_list(["msg/EEA/message_{}.json".format(n+1) for n in range(2)])