Résolue

Interface graphique Streamlit

# Interface graphique # Streamlit

Bonsoir,

Je souhaite distributer une appli à d'autres utilisateurs, et pour cela j'utilise streamlit, mais je galère depuis quelques jours.

Le programme doit permettre de charger un ou plusieurs fichiers .pdf sur le site, et ensuite j'ai un bouton qui boucle sur chaque fichier et exécute le script.
Sauf que une fois les fichiers chargés sur streamlit via un st.uploader (qui ne permet de sélectionner que des fichiers et non des dossiers), je n'ai pas de répertoire dans lequel boucler puisque les fichiers sont stockés temporairement sur un serveur streamlit. Mon idée était donc de permettre la sélection d'un dossier (via tkinter ou pyqt, afin de contourner le fait que streamlit ne dispose pas de widget pour la sélection de dossier), et d'enregistrer les fichiers sélectionnés dans ce dossier. Ensuite, je peux théoriquement boucler sur chaque fichier afin d'exécuter le script.

J'ai testé ce script en créant une simple interface graphique avec PyQt6:

import sys
import streamlit as st
from PyQt6.QtWidgets import (QApplication, QWidget, QPushButton, QTextEdit, QFileDialog, QVBoxLayout)


class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.window_width, self.window_height = 800, 100
        self.setMinimumSize(self.window_width, self.window_height)

        layout = QVBoxLayout()
        self.setLayout(layout)

        btn = QPushButton('Select folder')
        btn.clicked.connect(self.getFolder)
        layout.addWidget(btn)

        self.textbox = QTextEdit()
        layout.addWidget(self.textbox)


    def getFolder(self):
        response = QFileDialog.getExistingDirectory(self)
        self.textbox.setText(str(response))


if __name__ == '__main__':

    st.title("Renaming .pdf files")
    st.markdown("---")

    with st.form(key = 'renameOC'):
        folder_btn = st.form_submit_button(label="Select your output folder")

    if folder_btn:
        app = QApplication(sys.argv)
        myApp = MyWindow()
        myApp.show()
        sys.exit(app.exec())

Mais ce script plante au bout d'un moment avec les messages suivants:

WARNING: QApplication was not created in the main() thread.
WARNING: QApplication was not created in the main() thread.
QObject::killTimer: Timers cannot be stopped from another thread
QObject::startTimer: Timers can only be used with threads started with QThread
QObject::startTimer: Timers can only be used with threads started with QThread

Précision: je passe par streamlit pour ne pas avoir à installer certains packages en local sur les machines de chaque user (comme pytesseract dont j'ai besoin pour mon script...)

Ou il y a peut-être une méthode bien plus simple que ce que j'ai en tête...

Merci d'avance pour votre aide.

Salut David, désolé mais du coup je ne suis pas sûr de comprendre: ta question pose sur streamlit ou sur ce script ?

Salut PA,
Désolé pas très clair en effet, mon script fonctionne bien (même s'il mérite très certainement des optimisations 🙂), la question porte sur streamlit en effet. J'arrive à charger plusieurs fichiers via le widget st.uploader, mais comment après exécuter mon script sur chacun de ces fichiers ? dans mon script d'origine je boucle chaque fichier d'un dossier, mais sur streamlit je ne vois pas bien comment faire. C'est la raison pour laquelle je passais par une interface graphique "intermédiaire" afin de sauvegarder les fichiers chargés dans un dossier choisi. Carl le

car le st.uploader ne permet pas de pointer vers un dossier.

Hello,

oui j'ai déjà eu ce problème du fait que le st.uploader ne permet pas de faire comme QFileDialog pour importer tout un dossier.

As tu vu dans les paramètres de la fonction st.uploader qu'il y a une option qui est false par défaut accept_multiple_files

st.file_uploader(label, type=None, accept_multiple_files=False, key=None, help=None, on_change=None, args=None, kwargs=None, *, disabled=False, label_visibility="visible")

Si tu mets cette option à True tu pourras charger plusieurs fichier.

Dis moi si ça peut résoudre ton problème, sinon on trouvera une autre solution.

Salut,
Oui j'avais noté ce paramètre accept_multiple_files et je l'ai bien mis à True, et je bloque précisément juste après.
Après avoir chargé les fichiers dans le cache, je n'arrive pas à utiliser mon script, dans lequel je balaye normalement chaque fichier d'un dossier (avec pathlib). Dans mon script python, pour chaque fichier je récupère la date de création, je scanne le fichier avec pytesseract si le fichier est scanné, et avec PdfReader si pdf natif, et je récupère un numéro avec un format bien précis. J'utilise la date de création récupérée + le numéro trouvé afin de renommer chaque fichier. Mais pour ça j'ai besoin de manipuler des chemins, et des fichiers avec pathlib. Comment faire avec mes fichiers qui sont dans le cache? Est-ce que une fois chargés, je peux les sauvegarder vers un dossier de mon choix?

Hello,

j'avais une fois eu à fair eun truc du genre et pour contourner le problème, j'ai mis un champs st.text_input() dans lequel je rentre le path du dossier dans lequel il y a ton fichier. Quand tu vas utiliser ls st.upload() tu vas pouvoir récupérer le nom du fichier que tu as chargé avec file.name ou quelque chose du genre. Tu fais ton extraction de date etc, et ensuite tu réengistre ton fichier avec son nouveaux nom et en faisant un path.join avec le chemin de dossier que tu as rensigné dans ton st.text_input() .

J'espère que c'est clair et que ça répond à ta question. Sinon on essaiera de faire ça en mentorat.

Salut PA,

OK merci pour le retour, j'ai en effet réussi à faire quelque chose avec le st.text_input(), et aussi avec les "st.form" car sinon streamlit relance le code une autre fois...
Donc top, même si ce serait cool que Streamlit intègre un widget pour sélectionner un dossier. Mais Streamlit c'est quand même un outil vraiment top pour faire des interfaces graphiques rapidement.

# FONCTION POUR SAUVEGARDER LES FICHIERS DANS UN DOSSIER CHOISI
def save_uploaded_file(file, path):
    with open(path / file.name, 'wb') as f:
        f.write(file.getbuffer())
    return st.success(f'File saved successfully: {file.name}')


#INTERFACE STREAMLIT
st.title("Rename .pdf files")
st.markdown("---")
output_folder = Path(st.text_input(label="Select output folder"))
uploaded_files = st.file_uploader("Select files to rename", type="pdf", accept_multiple_files=True)

with st.form(key='MyApp'):

    if uploaded_files is not None:
        for file in uploaded_files:
            save_uploaded_file(file, output_folder)

    pdf_files_list = [file for file in output_folder.iterdir() if (file.is_file() and file.suffix == ".pdf")]

        def convert_btn_func():... #Script pour renommer chaque fichier en fonction du contenu

        convert_btn = st.form_submit_button("Process files")

if convert_btn:
    convert_btn_func()

Du coup j'ai d'autres petits problèmes qui sont apparus, comme la récupération de la date de création des fichiers pdf. Mais je vais regarder ça.

Inscris-toi

(c'est gratuit !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.