class Ui_MainWindow(object): # Fonction de setup de la fenetre def setupUi(self, MainWindow): # Initilisation d'1 instance de corpus à vide self.corpus = Corpus("", True) MainWindow.setObjectName("MainWindow") MainWindow.resize(619, 379) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") # On place une frame sur notre fenetre. C'est sur cette frame qu'on va poser les autres composants (bouton...) self.frame = QtWidgets.QFrame(self.centralwidget) self.frame.setGeometry(QtCore.QRect(0, 0, 611, 371)) self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame.setFrameShadow(QtWidgets.QFrame.Raised) self.frame.setObjectName("frame") # setStyleSheet = Personnalisation du look self.frame.setStyleSheet("background-color: white;") self.btnOK = QtWidgets.QPushButton(self.frame) self.btnOK.setGeometry(QtCore.QRect(250, 230, 111, 51)) self.btnOK.setObjectName("btnOK") # Au click du bouton OK, on lancher la fonction launchResearch pour demarrer la recherche de docs self.btnOK.clicked.connect(self.launchResearch) # On personnalise la police du bouton btnFont = QtGui.QFont() btnFont.setFamily("Fantasy") btnFont.setPointSize(14) btnFont.setBold(True) btnFont.setWeight(75) self.btnOK.setFont(btnFont) self.btnOK.setStyleSheet("QPushButton{\n" " background-color:#1976d2;\n" " border-radius: 15px;\n" " color:white;\n" " opacity: 0.9;\n" "}") self.lblArticlesMax = QtWidgets.QLabel(self.frame) self.lblArticlesMax.setGeometry(QtCore.QRect(20, 150, 71, 20)) self.lblArticlesMax.setObjectName("lblArticlesMax") # spArticlesMax = Permet de régler le nombre d'articles maximum à récupérer self.spArticlesMax = QtWidgets.QSpinBox(self.frame) self.spArticlesMax.setGeometry(QtCore.QRect(100, 150, 81, 22)) self.spArticlesMax.setObjectName("spArticlesMax") self.spArticlesMax.setMinimum(10) self.spArticlesMax.setMaximum(100000) # inputTheme = C'est le champ où l'utilisateur va taper son thème self.inputTheme = QtWidgets.QLineEdit(self.frame) self.inputTheme.setGeometry(QtCore.QRect(100, 100, 421, 21)) self.inputTheme.setObjectName("inputTheme") self.lblTitre = QtWidgets.QLabel(self.frame) self.lblTitre.setGeometry(QtCore.QRect(50, 20, 491, 51)) self.lblTitre.setAlignment(QtCore.Qt.AlignCenter) self.lblTitre.setObjectName("lblTitre") # On personnalise la police du titre titleFont = QtGui.QFont() titleFont.setFamily("Fantasy") titleFont.setPointSize(10) titleFont.setBold(True) titleFont.setWeight(75) self.lblTitre.setFont(titleFont) # lblTheme : Label "Thème" accompagnant le champ d'édition self.lblTheme = QtWidgets.QLabel(self.frame) self.lblTheme.setGeometry(QtCore.QRect(20, 100, 71, 20)) self.lblTheme.setObjectName("lblTheme") # progressBar : Barre de progression qui évolue apres le click sur le bouton OK self.progressBar = QtWidgets.QProgressBar(self.frame) self.progressBar.setGeometry(QtCore.QRect(35, 310, 541, 23)) self.progressBar.setProperty("value", 0) # par défaut on la rend visible et à 0% self.progressBar.setValue(0) self.progressBar.setVisible(True) self.progressBar.setObjectName("progressBar") self.progressBar.setStyleSheet("QProgressBar{\n" "background-color: #1976d2;\n" "color: white;\n" "border-style: none;\n" "text-align: center;\n" "\n" "}\n" " \n" "QProgressBar::chunk{\n" "background-color: #63a4ff;\n" "\n" "\n" "}\n" "") # On prévoit un label d'erreur qui s'affiche au dessus de la barre de progression en cas de retour d'erreur sur les appels API self.lblError = QtWidgets.QLabel(self.frame) self.lblError.setGeometry(QtCore.QRect(60, 290, 500, 20)) self.lblError.setText("") self.lblError.setObjectName("lblError") # chkBoxExcludeStopWords : Case à cocher pour permettre à l'utilisateur d'enlever les "mots vides" des documents (stopwords) self.chkBoxExcludeStopWords = QtWidgets.QCheckBox(self.frame) self.chkBoxExcludeStopWords.setChecked(True) self.chkBoxExcludeStopWords.setGeometry(QtCore.QRect( 100, 190, 281, 20)) self.chkBoxExcludeStopWords.setObjectName("chkBoxExcludeStopWords") MainWindow.setCentralWidget(self.centralwidget) # Appel à la fonction pour donner du texte à nos composants ("OK" pour le bouton OK...) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # Fonction générée par PyQt5 UI code generator def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle( _translate("MainWindow", "Projet Python 2021 - Laila DJEBLI / David HUYNH")) self.btnOK.setText(_translate("MainWindow", "OK")) self.lblArticlesMax.setText(_translate("MainWindow", "Articles max")) self.lblTitre.setText( _translate("MainWindow", "PROJET PYTHON LAILA DJEBLI / DAVID HUYNH")) self.lblTheme.setText(_translate("MainWindow", "Thème")) self.chkBoxExcludeStopWords.setText( _translate("MainWindow", "Exclure les stopwords (\"mots vides\")")) # Fonction qui permet d'ouvrir la fenetre d'action def openActions(self): self.window = QtWidgets.QMainWindow() self.uiActionScreen = Ui_ActionScreen( self.corpus ) # Instanciation de la classe Ui_ActionScreen située dans le fichier actionscreen.py self.uiActionScreen.setupUi(self.window) self.window.show() # On affiche cette fenetre # Fonction qui permet d'appeler les API et fait évoluer la barre de progression def launchResearch(self): if (self.inputTheme.text != ''): # Remise à zero du message d'erreur self.lblError.setText("") self.progressBar.setValue(10) # Instanciation du Corpus avec le thème tapé par l'utilisateur et la valeur booleenne de la case à cocher self.corpus = Corpus(self.inputTheme.text(), self.chkBoxExcludeStopWords.isChecked()) self.progressBar.setValue(20) # On englobe les appels dans un try/except. Comme ca en cas d'erreur, on affiche les erreurs. try: # Récupération des documents sur reddit self.getDocsFromReddit(self.inputTheme.text(), self.spArticlesMax.value()) self.progressBar.setValue(60) # Récupération des documents sur Arxiv self.getDocsFromArxiv(self.inputTheme.text(), self.spArticlesMax.value()) # Concaténation de tous les documents et nettoyage + Chargement des propriétés wordsByDoc et wordsStrByDoc self.corpus.fill_dicos_words("reddit") self.progressBar.setValue(80) # Concaténation de tous les documents et nettoyage + Chargement des propriétés wordsByDoc et wordsStrByDoc self.corpus.fill_dicos_words("arxiv") self.progressBar.setValue(100) self.progressBar.setValue(0) # Si aucune erreur, on affiche l'écran des actions self.openActions() except Exception as e: # En cas d'erreur : print(e) # J'affiche dans la console l'erreur self.progressBar.setValue( 0) # Je remet la barre de progression à zero # Enfin j'affiche un message d'erreur à l'utilisateur self.lblError.setText( "Erreur dans la récupération des données. Veuillez essayer avec un autre thème" ) # Appel API Reddit et alimentation du corpus def getDocsFromReddit(self, theme, nbResultatsMax): # Récupération des documents depuis Reddit reddit = praw.Reddit(client_id='0AlqCfHuOc5Hkg', client_secret='80PspjYMdTvF91ti9qZeWzAS2BU', user_agent='Reddit Irambique') hot_posts = reddit.subreddit(theme).hot(limit=nbResultatsMax) # On parcours les post reddit pour créer des docs for post in hot_posts: datet = dt.datetime.fromtimestamp(post.created) txt = post.title + ". " + post.selftext txt = txt.replace('\n', ' ') txt = txt.replace('\r', ' ') # Appel du constructeur RedditDocument (classe enfant de la classe Document) doc = RedditDocument(datet, post.title, txt) # Appel de la fonction add_doc pour ajouter le document tout juste instancié dans l'objet collection (du corpus) self.corpus.add_doc(doc) # Appel API Arxiv et alimentation du corpus def getDocsFromArxiv(self, theme, nbResultatsMax): # Récupération des documents depuis Arxiv url = 'http://export.arxiv.org/api/query?search_query=all:' + theme + '&start=0&max_results=' + str( nbResultatsMax) data = urllib.request.urlopen(url).read().decode() docsFromArxiv = xmltodict.parse(data)['feed']['entry'] # On parcours les post Arxiv pour créer des docs for doc in docsFromArxiv: datet = dt.datetime.strptime(doc['published'], '%Y-%m-%dT%H:%M:%SZ') txt = doc['title'] + ". " + doc['summary'] txt = txt.replace('\n', ' ') txt = txt.replace('\r', ' ') # Appel du constructeur ArxivDocument (classe enfant de la classe Document) doc = ArxivDocument(datet, doc['title'], txt) # Appel de la fonction add_doc pour ajouter le document tout juste instancié dans l'objet collection (du corpus) self.corpus.add_doc(doc)