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