From 1d93ca7e2ee54187f683f312a5be7b70df42da73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Mon, 5 Feb 2024 22:55:12 -0500 Subject: [PATCH 01/13] ajout woodpecker --- CHANGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGE b/CHANGE index d8263ee..e440e5c 100644 --- a/CHANGE +++ b/CHANGE @@ -1 +1 @@ -2 \ No newline at end of file +3 \ No newline at end of file From 4765b1dc9aaa438a279fe42b5474e0f00e3cef27 Mon Sep 17 00:00:00 2001 From: Francois Pelletier Date: Tue, 6 Feb 2024 04:13:46 +0000 Subject: [PATCH 02/13] Actualiser .woodpecker.yaml --- .woodpecker.yaml => .woodpecker.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .woodpecker.yaml => .woodpecker.yaml (100%) diff --git a/ .woodpecker.yaml b/.woodpecker.yaml similarity index 100% rename from .woodpecker.yaml rename to .woodpecker.yaml From eeda1c49161c0265c05010e44c03ce1bba525574 Mon Sep 17 00:00:00 2001 From: Francois Pelletier Date: Tue, 6 Feb 2024 04:37:44 +0000 Subject: [PATCH 03/13] Actualiser .woodpecker.yaml --- .woodpecker.yaml => .woodpecker.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .woodpecker.yaml => .woodpecker.yaml (100%) diff --git a/ .woodpecker.yaml b/.woodpecker.yaml similarity index 100% rename from .woodpecker.yaml rename to .woodpecker.yaml From 2478d4172935dbe7411db9c2190c8d8043050e17 Mon Sep 17 00:00:00 2001 From: francois Date: Wed, 26 Jun 2024 00:07:04 -0400 Subject: [PATCH 04/13] =?UTF-8?q?version=20corrig=C3=A9e=20de=20l'app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.template | 1 + .gitignore | 1 + docker-run-macos.sh | 2 +- docker-run.sh | 2 +- main.py | 48 +++++++++++++++++++++++---------------------- requirements.txt | 7 ++++--- 6 files changed, 33 insertions(+), 28 deletions(-) create mode 100644 .env.template diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..1f80b25 --- /dev/null +++ b/.env.template @@ -0,0 +1 @@ +FABRIQUEDOC_ENDPOINT= diff --git a/.gitignore b/.gitignore index 85e7c1d..a8fba92 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /.idea/ +/.env diff --git a/docker-run-macos.sh b/docker-run-macos.sh index 85647e7..a60f847 100644 --- a/docker-run-macos.sh +++ b/docker-run-macos.sh @@ -1,4 +1,4 @@ docker stop fabriquedoc-frontend docker rm fabriquedoc-frontend # Ce programme sert à lancer le job_dispatcher dans un docker localement pour tester -docker run -p 8051:8051 --name fabriquedoc-frontend --network fabriquedoc --env FABRIQUEDOC_ENDPOINT=http://fabriquedoc:8000 local/fabriquedoc-frontend \ No newline at end of file +docker run -p 8051:8051 --env-file=.env --name fabriquedoc-frontend --network fabriquedoc --env FABRIQUEDOC_ENDPOINT=http://fabriquedoc:8000 local/fabriquedoc-frontend \ No newline at end of file diff --git a/docker-run.sh b/docker-run.sh index b79d113..2572b12 100644 --- a/docker-run.sh +++ b/docker-run.sh @@ -1,4 +1,4 @@ docker stop fabriquedoc-frontend docker rm fabriquedoc-frontend # Ce programme sert à lancer le job_dispatcher dans un docker localement pour tester -docker run -p 8051:8051 --name fabriquedoc-frontend --network host local/fabriquedoc-frontend \ No newline at end of file +docker run -p 8051:8051 --env-file=.env --name fabriquedoc-frontend --network host local/fabriquedoc-frontend \ No newline at end of file diff --git a/main.py b/main.py index 40b1537..c7cb723 100644 --- a/main.py +++ b/main.py @@ -17,13 +17,15 @@ """ import datetime - +import dotenv import streamlit as st import requests from pydantic import BaseModel import mdformat import os +dotenv.load_dotenv() + class DocumentSpecs(BaseModel): format: str @@ -58,7 +60,9 @@ if 'options' not in st.session_state: st.title("Fabrique à documents") -fabriquedoc_endpoint = os.environ.get("FABRIQUEDOC_ENDPOINT", "http://0.0.0.0:8000") +fabriquedoc_endpoint = os.environ.get("FABRIQUEDOC_ENDPOINT", "http://127.0.0.1:8000") + +st.write(f"Endpoint : {fabriquedoc_endpoint}") tab1, tab2, tab3, tab4 = st.tabs(["Markdown", "Aperçu", "Paramètres", "Images"]) @@ -80,53 +84,51 @@ with tab2: with tab3: st.header("Paramètres") # Styles - response_styles = requests.get(f"{fabriquedoc_endpoint}/styles") - styles = response_styles.json()["styles"] + response_styles = requests.get(f"{fabriquedoc_endpoint}/styles/").json() + styles = response_styles.get("styles") selected_style = st.selectbox("Select a style:", styles) # Formats - response_formats = requests.get(f"{fabriquedoc_endpoint}/formats/{selected_style}/") - formats = response_formats.json()["formats"] + response_formats = requests.get(f"{fabriquedoc_endpoint}/formats/{selected_style}/").json() + formats = response_formats.get("formats") selected_format = st.selectbox("Select a format:", formats) # Autres paramètres response_format_parameters = requests.get( - f"{fabriquedoc_endpoint}/format_parameters/{selected_style}/{selected_format}") - format_parameters = response_format_parameters.json() - st.write(format_parameters) + f"{fabriquedoc_endpoint}/format_parameters/{selected_style}/{selected_format}/").json() linkcolor = st.text_input("Link color:", - value=format_parameters.get("linkcolor")) + value=response_format_parameters.get("linkcolor")) tocdepth = st.number_input("Table of Contents depth:", - value=int(format_parameters.get("tocdepth")), + value=int(response_format_parameters.get("tocdepth")), min_value=1, max_value=5, step=1) pdfengine = st.text_input("PDF engine:", - value=format_parameters.get("pdfengine")) + value=response_format_parameters.get("pdfengine")) fontsize = st.number_input("Font size:", - value=int(format_parameters.get("fontsize")), + value=int(response_format_parameters.get("fontsize")), step=1) paperwidth = st.number_input("Paper width:", - value=int(format_parameters.get("paperwidth")), + value=int(response_format_parameters.get("paperwidth")), step=30) paperheight = st.number_input("Paper height:", - value=int(format_parameters.get("paperheight")), + value=int(response_format_parameters.get("paperheight")), step=30) ratio = st.number_input("Ratio:", - value=int(format_parameters.get("ratio")), + value=int(response_format_parameters.get("ratio")), step=10) margin = st.number_input("Margin:", - value=int(format_parameters.get("margin")), + value=int(response_format_parameters.get("margin")), step=10) vmargin = st.number_input("Vertical margin:", - value=int(format_parameters.get("vmargin")), + value=int(response_format_parameters.get("vmargin")), step=10) - extension = st.selectbox("Extension:", ["png", "jpg", "pdf", "mp4"]) + extension = st.selectbox("Extension:", ["jpg", "pdf", "mp4"]) if extension == "mp4": fps = st.number_input("FPS:", - value=int(format_parameters.get("fps")), + value=int(response_format_parameters.get("fps")), step=1) stilltime = st.number_input("Still time:", - value=int(format_parameters.get("stilltime")), + value=int(response_format_parameters.get("stilltime")), step=1) else: fps = 0 @@ -163,7 +165,7 @@ with tab3: file_data = response.content datef = datetime.datetime.now().strftime("%m-%d-%Y") - if document_specs.extension in ["jpg", 'png']: + if document_specs.extension in ["jpg"]: extn = "zip" else: extn = document_specs.extension @@ -189,7 +191,7 @@ with tab4: st.write("Envoyer une image") uploaded_files = st.file_uploader("Choisis un fichier image", - type=["png", "jpg", "jpeg"], + type=["jpg", "jpeg"], accept_multiple_files=True) if uploaded_files is not None: for uploaded_file in uploaded_files: diff --git a/requirements.txt b/requirements.txt index 93e9fb5..944ac5d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ -streamlit~=1.24.0 -requests~=2.28.2 +streamlit~=1.30.0 +requests~=2.31.0 pydantic~=2.0.1 -mdformat~=0.7.16 \ No newline at end of file +mdformat~=0.7.16 +python-dotenv~=1.0.1 \ No newline at end of file From 9857d6fb21ab9f53a3987337fb3dd0f9515e401c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Sat, 24 Aug 2024 00:26:59 -0400 Subject: [PATCH 05/13] Ajout de Oauth2 --- main.py | 36 +++++++++++++++++++++++++----------- requirements.txt | 4 ++-- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/main.py b/main.py index c7cb723..aaa7dbf 100644 --- a/main.py +++ b/main.py @@ -64,7 +64,20 @@ fabriquedoc_endpoint = os.environ.get("FABRIQUEDOC_ENDPOINT", "http://127.0.0.1: st.write(f"Endpoint : {fabriquedoc_endpoint}") -tab1, tab2, tab3, tab4 = st.tabs(["Markdown", "Aperçu", "Paramètres", "Images"]) +tab0, tab1, tab2, tab3, tab4 = st.tabs(["Login", "Markdown", "Aperçu", "Paramètres", "Images"]) + +with tab0: + with st.form(key='authentication'): + username = st.text_input("Username") + password = st.text_input("Password", type="password") + submit_button = st.form_submit_button(label='Login') + if submit_button: + # Send a POST request to your authentication endpoint + response = requests.post(f'{fabriquedoc_endpoint}/token/', data={"username": username, "password": password}) + if response.status_code == 200: + bearer_token = response.json()["access_token"] + # Store the bearer token in the session state + st.session_state['bearer_token'] = bearer_token with tab1: def button1_callback(): @@ -83,18 +96,19 @@ with tab2: with tab3: st.header("Paramètres") + http_headers = {"Authorization": f"Bearer {st.session_state['bearer_token']}"} # Styles - response_styles = requests.get(f"{fabriquedoc_endpoint}/styles/").json() + response_styles = requests.get(f"{fabriquedoc_endpoint}/styles/", headers=http_headers).json() styles = response_styles.get("styles") selected_style = st.selectbox("Select a style:", styles) # Formats - response_formats = requests.get(f"{fabriquedoc_endpoint}/formats/{selected_style}/").json() + response_formats = requests.get(f"{fabriquedoc_endpoint}/formats/{selected_style}/", headers=http_headers).json() formats = response_formats.get("formats") selected_format = st.selectbox("Select a format:", formats) # Autres paramètres response_format_parameters = requests.get( - f"{fabriquedoc_endpoint}/format_parameters/{selected_style}/{selected_format}/").json() + f"{fabriquedoc_endpoint}/format_parameters/{selected_style}/{selected_format}/", headers=http_headers).json() linkcolor = st.text_input("Link color:", value=response_format_parameters.get("linkcolor")) tocdepth = st.number_input("Table of Contents depth:", @@ -154,11 +168,11 @@ with tab3: stilltime=stilltime ) - headers = {"Content-Type": "application/json"} + post_headers = http_headers | {"Content-Type": "application/json"} # Send the POST request with the JSON data in the request body - response = requests.get(f"{fabriquedoc_endpoint}/generer/", - json=document_specs.model_dump(), - headers=headers) + response = requests.post(f"{fabriquedoc_endpoint}/generer/", + json=document_specs.model_dump(), + headers=http_headers) # Check the response status code if 200 <= response.status_code <= 299: # If the request is successful, get the file data from the response @@ -182,10 +196,10 @@ with tab4: st.write("Images disponibles") # list uploaded files with a request to the GET /images endpoint - response = requests.get(f"{fabriquedoc_endpoint}/images/") + response = requests.get(f"{fabriquedoc_endpoint}/images/", headers=http_headers) images = response.json()["images"] selected_image = st.selectbox("Choisis une image:", images) - image_response = requests.get(f"{fabriquedoc_endpoint}/images/{selected_image}") + image_response = requests.get(f"{fabriquedoc_endpoint}/images/{selected_image}", headers=http_headers) image_data = image_response.content st.image(image_data) @@ -200,7 +214,7 @@ with tab4: files = {"file": uploaded_file} # Submit the file to the endpoint - response = requests.post(url, files=files) + response = requests.post(url, files=files, headers=http_headers) # Check the response status if response.status_code < 300: diff --git a/requirements.txt b/requirements.txt index 944ac5d..5dd8e8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ streamlit~=1.30.0 requests~=2.31.0 -pydantic~=2.0.1 -mdformat~=0.7.16 +pydantic~=2.0.3 +mdformat~=0.7.17 python-dotenv~=1.0.1 \ No newline at end of file From 19953b84296d237027179aa2ff6000589fb5bd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Sat, 24 Aug 2024 10:45:06 -0400 Subject: [PATCH 06/13] Ajout de Oauth2 --- main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.py b/main.py index aaa7dbf..b7e32b9 100644 --- a/main.py +++ b/main.py @@ -57,6 +57,8 @@ Ceci est un emoji :heart_eyes:\n\n if 'options' not in st.session_state: st.session_state['options'] = "" +if 'bearer_token' not in st.session_state: + st.session_state['bearer_token'] = "" st.title("Fabrique à documents") From c7e193b912f5d1f5e23bc7f604659e0ea646b3b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Sat, 24 Aug 2024 10:46:10 -0400 Subject: [PATCH 07/13] =?UTF-8?q?Ajout=20d'un=20message=20de=20connexion?= =?UTF-8?q?=20r=C3=A9ussie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.py b/main.py index b7e32b9..85e3387 100644 --- a/main.py +++ b/main.py @@ -77,9 +77,13 @@ with tab0: # Send a POST request to your authentication endpoint response = requests.post(f'{fabriquedoc_endpoint}/token/', data={"username": username, "password": password}) if response.status_code == 200: + st.write("Connexion réussie!") bearer_token = response.json()["access_token"] # Store the bearer token in the session state st.session_state['bearer_token'] = bearer_token + else: + st.error("Connexion échouée!") + st.session_state['bearer_token'] = "" with tab1: def button1_callback(): From e8b82a1f3dfd2e846e125da1936911a78d7c0278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Sat, 24 Aug 2024 11:42:43 -0400 Subject: [PATCH 08/13] changer les headers pour generer --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 85e3387..c185bfb 100644 --- a/main.py +++ b/main.py @@ -178,7 +178,7 @@ with tab3: # Send the POST request with the JSON data in the request body response = requests.post(f"{fabriquedoc_endpoint}/generer/", json=document_specs.model_dump(), - headers=http_headers) + headers=post_headers) # Check the response status code if 200 <= response.status_code <= 299: # If the request is successful, get the file data from the response From a50bf9e59867fb7fedaa0a2435064dac1e553047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Sat, 24 Aug 2024 12:43:35 -0400 Subject: [PATCH 09/13] =?UTF-8?q?refactoring=20pour=20que=20l'application?= =?UTF-8?q?=20soit=20plus=20facile=20=C3=A0=20entretenir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- app_tab1.py | 16 ++++ app_tab2.py | 6 ++ app_tab3.py | 104 ++++++++++++++++++++++ app_tab4.py | 35 ++++++++ demo_text.py | 9 ++ login_form.py | 23 +++++ main.py | 220 ++++++----------------------------------------- models.py | 19 ++++ requirements.txt | 2 +- 10 files changed, 239 insertions(+), 197 deletions(-) create mode 100644 app_tab1.py create mode 100644 app_tab2.py create mode 100644 app_tab3.py create mode 100644 app_tab4.py create mode 100644 demo_text.py create mode 100644 login_form.py create mode 100644 models.py diff --git a/Dockerfile b/Dockerfile index e8e283c..fafefc9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ COPY requirements.txt . RUN pip install -r requirements.txt # Copy the app's code -COPY main.py . +COPY *.py . # Set the entrypoint to run the app ENTRYPOINT [ "streamlit", "run" ] diff --git a/app_tab1.py b/app_tab1.py new file mode 100644 index 0000000..7abf730 --- /dev/null +++ b/app_tab1.py @@ -0,0 +1,16 @@ +import mdformat +import streamlit as st + +from demo_text import demo_text + + +def app_tab1(): + def button1_callback(): + st.session_state['markdown'] = mdformat.text(st.session_state['markdown'], + options={"number": True}) + + st.session_state['content'] = st.text_area( + "Entre ton texte ici. Les images sont dans ./images/", demo_text, + height=450, + key='markdown') + st.button("Formater le texte", on_click=button1_callback) diff --git a/app_tab2.py b/app_tab2.py new file mode 100644 index 0000000..11fd18a --- /dev/null +++ b/app_tab2.py @@ -0,0 +1,6 @@ +import streamlit as st + + +def app_tab2(): + st.write("Aperçu") + st.markdown(st.session_state['content']) diff --git a/app_tab3.py b/app_tab3.py new file mode 100644 index 0000000..59fcfa5 --- /dev/null +++ b/app_tab3.py @@ -0,0 +1,104 @@ +import datetime + +import requests +import streamlit as st + +from models import DocumentSpecs + + +def app_tab3(): + st.header("Paramètres") + http_headers = {"Authorization": f"Bearer {st.session_state['bearer_token']}"} + # Styles + response_styles = requests.get(f"{st.session_state['fabriquedoc_endpoint']}/styles/", headers=http_headers).json() + styles = response_styles.get("styles") + selected_style = st.selectbox("Select a style:", styles) + # Formats + response_formats = requests.get(f"{st.session_state['fabriquedoc_endpoint']}/formats/{selected_style}/", headers=http_headers).json() + formats = response_formats.get("formats") + selected_format = st.selectbox("Select a format:", formats) + + # Autres paramètres + response_format_parameters = requests.get( + f"{st.session_state['fabriquedoc_endpoint']}/format_parameters/{selected_style}/{selected_format}/", headers=http_headers).json() + linkcolor = st.text_input("Link color:", + value=response_format_parameters.get("linkcolor")) + tocdepth = st.number_input("Table of Contents depth:", + value=int(response_format_parameters.get("tocdepth")), + min_value=1, + max_value=5, + step=1) + pdfengine = st.text_input("PDF engine:", + value=response_format_parameters.get("pdfengine")) + fontsize = st.number_input("Font size:", + value=int(response_format_parameters.get("fontsize")), + step=1) + paperwidth = st.number_input("Paper width:", + value=int(response_format_parameters.get("paperwidth")), + step=30) + paperheight = st.number_input("Paper height:", + value=int(response_format_parameters.get("paperheight")), + step=30) + ratio = st.number_input("Ratio:", + value=int(response_format_parameters.get("ratio")), + step=10) + margin = st.number_input("Margin:", + value=int(response_format_parameters.get("margin")), + step=10) + vmargin = st.number_input("Vertical margin:", + value=int(response_format_parameters.get("vmargin")), + step=10) + extension = st.selectbox("Extension:", ["jpg", "pdf", "mp4"]) + if extension == "mp4": + fps = st.number_input("FPS:", + value=int(response_format_parameters.get("fps")), + step=1) + stilltime = st.number_input("Still time:", + value=int(response_format_parameters.get("stilltime")), + step=1) + else: + fps = 0 + stilltime = 0 + + # Envoi + if st.button("Generate post"): + document_specs = DocumentSpecs( + format=selected_format, + style=selected_style, + linkcolor=linkcolor, + tocdepth=tocdepth, + pdfengine=pdfengine, + content=st.session_state['content'], + fontsize=fontsize, + paperwidth=paperwidth, + paperheight=paperheight, + ratio=ratio, + margin=margin, + vmargin=vmargin, + extension=extension, + fps=fps, + stilltime=stilltime + ) + + post_headers = http_headers | {"Content-Type": "application/json"} + # Send the POST request with the JSON data in the request body + response = requests.post(f"{st.session_state['fabriquedoc_endpoint']}/generer/", + json=document_specs.model_dump(), + headers=post_headers) + # Check the response status code + if 200 <= response.status_code <= 299: + # If the request is successful, get the file data from the response + file_data = response.content + datef = datetime.datetime.now().strftime("%m-%d-%Y") + + if document_specs.extension in ["jpg"]: + extn = "zip" + else: + extn = document_specs.extension + + file_name = f"{document_specs.style}-{document_specs.format}-{datef}-output.{extn}" + + st.download_button('Télécharger', file_data, file_name=file_name) + else: + # If the request is unsuccessful, display the error status code and message + st.error(f"Request failed with status code {response.status_code}: {response.text}") diff --git a/app_tab4.py b/app_tab4.py new file mode 100644 index 0000000..403f4f2 --- /dev/null +++ b/app_tab4.py @@ -0,0 +1,35 @@ +import requests +import streamlit as st + + +def app_tab4(): + st.header("Images") + http_headers = {"Authorization": f"Bearer {st.session_state['bearer_token']}"} + + st.write("Images disponibles") + # list uploaded files with a request to the GET /images endpoint + response = requests.get(f"{st.session_state['fabriquedoc_endpoint']}/images/", headers=http_headers) + images = response.json()["images"] + selected_image = st.selectbox("Choisis une image:", images) + image_response = requests.get(f"{st.session_state['fabriquedoc_endpoint']}/images/{selected_image}", headers=http_headers) + image_data = image_response.content + st.image(image_data) + + st.write("Envoyer une image") + uploaded_files = st.file_uploader("Choisis un fichier image", + type=["jpg", "jpeg"], + accept_multiple_files=True) + if uploaded_files is not None: + for uploaded_file in uploaded_files: + url = f"{st.session_state['fabriquedoc_endpoint']}/images/" + # Create a FormData object + files = {"file": uploaded_file} + + # Submit the file to the endpoint + response = requests.post(url, files=files, headers=http_headers) + + # Check the response status + if response.status_code < 300: + st.write(f"File {uploaded_file.name} sent successfully!") + else: + st.write(f"File {uploaded_file.name} upload failed.") diff --git a/demo_text.py b/demo_text.py new file mode 100644 index 0000000..858c359 --- /dev/null +++ b/demo_text.py @@ -0,0 +1,9 @@ +demo_text = """ +# Ceci est un titre\n +## Ceci est un sous-titre\n\n +Ceci est un paragraphe\n\n +## Ceci est un autre sous-titre\n\n +> Ceci est du code\n\n +Ceci est un emoji :heart_eyes:\n\n +::: {.center}\nCeci est centré\n::: +""" diff --git a/login_form.py b/login_form.py new file mode 100644 index 0000000..5f9ec09 --- /dev/null +++ b/login_form.py @@ -0,0 +1,23 @@ +import streamlit as st +import requests + + +def login_form(): + with st.form(key='authentication'): + username = st.text_input("Username") + password = st.text_input("Password", type="password") + submit_button = st.form_submit_button(label='Login') + if submit_button: + # Send a POST request to your authentication endpoint + response = requests.post(f"{st.session_state['fabriquedoc_endpoint']}/token/", + data={"username": username, "password": password}) + if response.status_code == 200: + st.write("Connexion réussie!") + bearer_token = response.json()["access_token"] + # Store the bearer token in the session state + st.session_state['bearer_token'] = bearer_token + st.session_state['logged_in'] = True + else: + st.error("Connexion échouée!") + st.session_state['bearer_token'] = "" + st.session_state['logged_in'] = False diff --git a/main.py b/main.py index c185bfb..f929f09 100644 --- a/main.py +++ b/main.py @@ -16,214 +16,44 @@ along with this program. If not, see . """ -import datetime -import dotenv import streamlit as st -import requests -from pydantic import BaseModel -import mdformat +import dotenv import os +import app_tab1 +import app_tab2 +import app_tab3 +import app_tab4 +import login_form -dotenv.load_dotenv() - - -class DocumentSpecs(BaseModel): - format: str - style: str - linkcolor: str - tocdepth: int - pdfengine: str - content: str - fontsize: int - paperwidth: int - paperheight: int - ratio: int - margin: int - vmargin: int - extension: str - fps: int - stilltime: int - - -demo_text = """ -# Ceci est un titre\n -## Ceci est un sous-titre\n\n -Ceci est un paragraphe\n\n -## Ceci est un autre sous-titre\n\n -> Ceci est du code\n\n -Ceci est un emoji :heart_eyes:\n\n -::: {.center}\nCeci est centré\n::: -""" - +if 'fabriquedoc_endpoint' not in st.session_state: + dotenv.load_dotenv() + st.session_state['fabriquedoc_endpoint'] = os.environ.get("FABRIQUEDOC_ENDPOINT", + "http://127.0.0.1:8000") if 'options' not in st.session_state: st.session_state['options'] = "" if 'bearer_token' not in st.session_state: st.session_state['bearer_token'] = "" +if 'logged_in' not in st.session_state: + st.session_state['logged_in'] = False st.title("Fabrique à documents") -fabriquedoc_endpoint = os.environ.get("FABRIQUEDOC_ENDPOINT", "http://127.0.0.1:8000") +st.write(f"Endpoint : {st.session_state['fabriquedoc_endpoint']}") -st.write(f"Endpoint : {fabriquedoc_endpoint}") +if not st.session_state['logged_in']: + login_form.login_form() -tab0, tab1, tab2, tab3, tab4 = st.tabs(["Login", "Markdown", "Aperçu", "Paramètres", "Images"]) +if st.session_state['logged_in']: + tab1, tab2, tab3, tab4 = st.tabs(["Markdown", "Aperçu", "Paramètres", "Images"]) -with tab0: - with st.form(key='authentication'): - username = st.text_input("Username") - password = st.text_input("Password", type="password") - submit_button = st.form_submit_button(label='Login') - if submit_button: - # Send a POST request to your authentication endpoint - response = requests.post(f'{fabriquedoc_endpoint}/token/', data={"username": username, "password": password}) - if response.status_code == 200: - st.write("Connexion réussie!") - bearer_token = response.json()["access_token"] - # Store the bearer token in the session state - st.session_state['bearer_token'] = bearer_token - else: - st.error("Connexion échouée!") - st.session_state['bearer_token'] = "" + with tab1: + app_tab1.app_tab1() -with tab1: - def button1_callback(): - st.session_state['markdown'] = mdformat.text(st.session_state['markdown'], - options={"number": True}) + with tab2: + app_tab2.app_tab2() + with tab3: + app_tab3.app_tab3() - content = st.text_area("Entre ton texte ici. Les images sont dans ./images/", demo_text, - height=450, - key='markdown') - st.button("Formater le texte", on_click=button1_callback) - -with tab2: - st.write("Aperçu") - st.markdown(content) - -with tab3: - st.header("Paramètres") - http_headers = {"Authorization": f"Bearer {st.session_state['bearer_token']}"} - # Styles - response_styles = requests.get(f"{fabriquedoc_endpoint}/styles/", headers=http_headers).json() - styles = response_styles.get("styles") - selected_style = st.selectbox("Select a style:", styles) - # Formats - response_formats = requests.get(f"{fabriquedoc_endpoint}/formats/{selected_style}/", headers=http_headers).json() - formats = response_formats.get("formats") - selected_format = st.selectbox("Select a format:", formats) - - # Autres paramètres - response_format_parameters = requests.get( - f"{fabriquedoc_endpoint}/format_parameters/{selected_style}/{selected_format}/", headers=http_headers).json() - linkcolor = st.text_input("Link color:", - value=response_format_parameters.get("linkcolor")) - tocdepth = st.number_input("Table of Contents depth:", - value=int(response_format_parameters.get("tocdepth")), - min_value=1, - max_value=5, - step=1) - pdfengine = st.text_input("PDF engine:", - value=response_format_parameters.get("pdfengine")) - fontsize = st.number_input("Font size:", - value=int(response_format_parameters.get("fontsize")), - step=1) - paperwidth = st.number_input("Paper width:", - value=int(response_format_parameters.get("paperwidth")), - step=30) - paperheight = st.number_input("Paper height:", - value=int(response_format_parameters.get("paperheight")), - step=30) - ratio = st.number_input("Ratio:", - value=int(response_format_parameters.get("ratio")), - step=10) - margin = st.number_input("Margin:", - value=int(response_format_parameters.get("margin")), - step=10) - vmargin = st.number_input("Vertical margin:", - value=int(response_format_parameters.get("vmargin")), - step=10) - extension = st.selectbox("Extension:", ["jpg", "pdf", "mp4"]) - if extension == "mp4": - fps = st.number_input("FPS:", - value=int(response_format_parameters.get("fps")), - step=1) - stilltime = st.number_input("Still time:", - value=int(response_format_parameters.get("stilltime")), - step=1) - else: - fps = 0 - stilltime = 0 - - # Envoi - if st.button("Generate post"): - document_specs = DocumentSpecs( - format=selected_format, - style=selected_style, - linkcolor=linkcolor, - tocdepth=tocdepth, - pdfengine=pdfengine, - content=content, - fontsize=fontsize, - paperwidth=paperwidth, - paperheight=paperheight, - ratio=ratio, - margin=margin, - vmargin=vmargin, - extension=extension, - fps=fps, - stilltime=stilltime - ) - - post_headers = http_headers | {"Content-Type": "application/json"} - # Send the POST request with the JSON data in the request body - response = requests.post(f"{fabriquedoc_endpoint}/generer/", - json=document_specs.model_dump(), - headers=post_headers) - # Check the response status code - if 200 <= response.status_code <= 299: - # If the request is successful, get the file data from the response - file_data = response.content - datef = datetime.datetime.now().strftime("%m-%d-%Y") - - if document_specs.extension in ["jpg"]: - extn = "zip" - else: - extn = document_specs.extension - - file_name = f"{document_specs.style}-{document_specs.format}-{datef}-output.{extn}" - - st.download_button('Télécharger', file_data, file_name=file_name) - else: - # If the request is unsuccessful, display the error status code and message - st.error(f"Request failed with status code {response.status_code}: {response.text}") - -with tab4: - st.header("Images") - - st.write("Images disponibles") - # list uploaded files with a request to the GET /images endpoint - response = requests.get(f"{fabriquedoc_endpoint}/images/", headers=http_headers) - images = response.json()["images"] - selected_image = st.selectbox("Choisis une image:", images) - image_response = requests.get(f"{fabriquedoc_endpoint}/images/{selected_image}", headers=http_headers) - image_data = image_response.content - st.image(image_data) - - st.write("Envoyer une image") - uploaded_files = st.file_uploader("Choisis un fichier image", - type=["jpg", "jpeg"], - accept_multiple_files=True) - if uploaded_files is not None: - for uploaded_file in uploaded_files: - url = f"{fabriquedoc_endpoint}/images/" - # Create a FormData object - files = {"file": uploaded_file} - - # Submit the file to the endpoint - response = requests.post(url, files=files, headers=http_headers) - - # Check the response status - if response.status_code < 300: - st.write(f"File {uploaded_file.name} sent successfully!") - else: - st.write(f"File {uploaded_file.name} upload failed.") + with tab4: + app_tab4.app_tab4() diff --git a/models.py b/models.py new file mode 100644 index 0000000..f35183d --- /dev/null +++ b/models.py @@ -0,0 +1,19 @@ +from pydantic import BaseModel + + +class DocumentSpecs(BaseModel): + format: str + style: str + linkcolor: str + tocdepth: int + pdfengine: str + content: str + fontsize: int + paperwidth: int + paperheight: int + ratio: int + margin: int + vmargin: int + extension: str + fps: int + stilltime: int diff --git a/requirements.txt b/requirements.txt index 5dd8e8c..6e92d1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -streamlit~=1.30.0 +streamlit~=1.37.1 requests~=2.31.0 pydantic~=2.0.3 mdformat~=0.7.17 From 2b1173156115c361239a06b18209031c619b0ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Mon, 7 Oct 2024 23:37:46 -0400 Subject: [PATCH 10/13] ajouter network --- docker-run-macos.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-run-macos.sh b/docker-run-macos.sh index a60f847..222100f 100644 --- a/docker-run-macos.sh +++ b/docker-run-macos.sh @@ -1,3 +1,4 @@ +docker network create fabriquedoc docker stop fabriquedoc-frontend docker rm fabriquedoc-frontend # Ce programme sert à lancer le job_dispatcher dans un docker localement pour tester From 62cd159d0fa056b630d09cbec4d8585fd31621d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Sat, 26 Oct 2024 14:00:54 -0400 Subject: [PATCH 11/13] =?UTF-8?q?Am=C3=A9liorer=20le=20Demo=20Text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo_text.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/demo_text.py b/demo_text.py index 858c359..3ce30ae 100644 --- a/demo_text.py +++ b/demo_text.py @@ -1,9 +1,49 @@ demo_text = """ -# Ceci est un titre\n -## Ceci est un sous-titre\n\n -Ceci est un paragraphe\n\n -## Ceci est un autre sous-titre\n\n -> Ceci est du code\n\n -Ceci est un emoji :heart_eyes:\n\n +## Guide rapide Markdown + +- Texte simple + - **Gras** + - *Italique* + - ~~Barré~~ + - `Code en ligne` + ::: {.center}\nCeci est centré\n::: + +- Titres + - # Titre 1 + - ## Titre 2 + - ### Titre 3 + - #### Titre 4 + - ##### Titre 5 + - ###### Titre 6 + +- Listes + - Liste non ordonnée + - Sous-élément + - Autre sous-élément + - Liste ordonnée + 1. Premier élément + 2. Deuxième élément + 3. Troisième élément + +- Liens + - [Lien texte](https://www.example.com) + - [Lien avec titre](https://www.example.com "Titre du lien") + - URL directe : + +- Images + - ![Texte alternatif](url-de-l-image.jpg) + - [![Image avec lien](url-de-l-image-miniature.jpg)](url-de-l-image-complete.jpg) + +- Citations + > Ceci est une citation + > + > Elle peut s'étendre sur plusieurs lignes + +- Code + ```python + def hello_world(): + print("Hello, World!") + ``` + """ From a0e2067f2b4fff64391b05b8a159b847fafc1fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Mon, 11 Nov 2024 01:11:18 -0500 Subject: [PATCH 12/13] =?UTF-8?q?Changement=20dans=20le=20tab=203,=20on=20?= =?UTF-8?q?envoie=20toujours=20pour=20mp4=20et=20on=20re=C3=A7oit=20un=20z?= =?UTF-8?q?ip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_tab3.py | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/app_tab3.py b/app_tab3.py index 59fcfa5..8f2f013 100644 --- a/app_tab3.py +++ b/app_tab3.py @@ -48,17 +48,13 @@ def app_tab3(): vmargin = st.number_input("Vertical margin:", value=int(response_format_parameters.get("vmargin")), step=10) - extension = st.selectbox("Extension:", ["jpg", "pdf", "mp4"]) - if extension == "mp4": - fps = st.number_input("FPS:", - value=int(response_format_parameters.get("fps")), - step=1) - stilltime = st.number_input("Still time:", - value=int(response_format_parameters.get("stilltime")), - step=1) - else: - fps = 0 - stilltime = 0 + extension = "mp4" + fps = st.number_input("FPS:", + value=int(response_format_parameters.get("fps")), + step=1) + stilltime = st.number_input("Still time:", + value=int(response_format_parameters.get("stilltime")), + step=1) # Envoi if st.button("Generate post"): @@ -91,14 +87,9 @@ def app_tab3(): file_data = response.content datef = datetime.datetime.now().strftime("%m-%d-%Y") - if document_specs.extension in ["jpg"]: - extn = "zip" - else: - extn = document_specs.extension - - file_name = f"{document_specs.style}-{document_specs.format}-{datef}-output.{extn}" + file_name = f"{document_specs.style}-{document_specs.format}-{datef}-output.zip" st.download_button('Télécharger', file_data, file_name=file_name) else: # If the request is unsuccessful, display the error status code and message - st.error(f"Request failed with status code {response.status_code}: {response.text}") + st.error(f"Request failed with status code {response.status_code}: {response.text}") \ No newline at end of file From 7a9ef6d974b706acbe7576fdd387cd180fa697c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Sun, 24 Nov 2024 21:40:53 -0500 Subject: [PATCH 13/13] =?UTF-8?q?Ajustements=20interface=20pour=20accepter?= =?UTF-8?q?=20PNG=20et=20=C3=A9viter=20timeouts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_tab3.py | 3 ++- app_tab4.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app_tab3.py b/app_tab3.py index 8f2f013..96845f1 100644 --- a/app_tab3.py +++ b/app_tab3.py @@ -80,7 +80,8 @@ def app_tab3(): # Send the POST request with the JSON data in the request body response = requests.post(f"{st.session_state['fabriquedoc_endpoint']}/generer/", json=document_specs.model_dump(), - headers=post_headers) + headers=post_headers, + timeout=(30, 3000)) # 30 seconds connect timeout, 5 minutes read timeout # Check the response status code if 200 <= response.status_code <= 299: # If the request is successful, get the file data from the response diff --git a/app_tab4.py b/app_tab4.py index 403f4f2..1a76488 100644 --- a/app_tab4.py +++ b/app_tab4.py @@ -17,7 +17,6 @@ def app_tab4(): st.write("Envoyer une image") uploaded_files = st.file_uploader("Choisis un fichier image", - type=["jpg", "jpeg"], accept_multiple_files=True) if uploaded_files is not None: for uploaded_file in uploaded_files: