Compare commits

..

11 commits

Author SHA1 Message Date
François Pelletier
7a9ef6d974 Ajustements interface pour accepter PNG et éviter timeouts 2024-11-24 21:40:53 -05:00
François Pelletier
a0e2067f2b Changement dans le tab 3, on envoie toujours pour mp4 et on reçoit un zip 2024-11-11 01:11:18 -05:00
François Pelletier
62cd159d0f Améliorer le Demo Text 2024-10-26 14:00:54 -04:00
François Pelletier
2b11731561 ajouter network 2024-10-07 23:37:46 -04:00
François Pelletier
a50bf9e598 refactoring pour que l'application soit plus facile à entretenir 2024-08-24 12:43:35 -04:00
François Pelletier
e8b82a1f3d changer les headers pour generer 2024-08-24 11:42:43 -04:00
François Pelletier
c7e193b912 Ajout d'un message de connexion réussie 2024-08-24 10:46:10 -04:00
François Pelletier
19953b8429 Ajout de Oauth2 2024-08-24 10:45:06 -04:00
François Pelletier
9857d6fb21 Ajout de Oauth2 2024-08-24 00:26:59 -04:00
francois
2478d41729 version corrigée de l'app 2024-06-26 00:07:04 -04:00
4765b1dc9a Actualiser .woodpecker.yaml
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-06 04:13:46 +00:00
15 changed files with 282 additions and 183 deletions

1
.env.template Normal file
View file

@ -0,0 +1 @@
FABRIQUEDOC_ENDPOINT=

1
.gitignore vendored
View file

@ -1 +1,2 @@
/.idea/
/.env

2
CHANGE
View file

@ -1 +1 @@
3
2

View file

@ -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" ]

16
app_tab1.py Normal file
View file

@ -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)

6
app_tab2.py Normal file
View file

@ -0,0 +1,6 @@
import streamlit as st
def app_tab2():
st.write("Aperçu")
st.markdown(st.session_state['content'])

96
app_tab3.py Normal file
View file

@ -0,0 +1,96 @@
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 = "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"):
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,
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
file_data = response.content
datef = datetime.datetime.now().strftime("%m-%d-%Y")
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}")

34
app_tab4.py Normal file
View file

@ -0,0 +1,34 @@
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",
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.")

49
demo_text.py Normal file
View file

@ -0,0 +1,49 @@
demo_text = """
## 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 : <https://www.example.com>
- 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!")
```
"""

View file

@ -1,4 +1,5 @@
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
docker run -p 8051:8051 --name fabriquedoc-frontend --network fabriquedoc --env FABRIQUEDOC_ENDPOINT=http://fabriquedoc:8000 local/fabriquedoc-frontend
docker run -p 8051:8051 --env-file=.env --name fabriquedoc-frontend --network fabriquedoc --env FABRIQUEDOC_ENDPOINT=http://fabriquedoc:8000 local/fabriquedoc-frontend

View file

@ -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
docker run -p 8051:8051 --env-file=.env --name fabriquedoc-frontend --network host local/fabriquedoc-frontend

23
login_form.py Normal file
View file

@ -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

202
main.py
View file

@ -16,192 +16,44 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import datetime
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
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://0.0.0.0:8000")
st.write(f"Endpoint : {st.session_state['fabriquedoc_endpoint']}")
tab1, tab2, tab3, tab4 = st.tabs(["Markdown", "Aperçu", "Paramètres", "Images"])
if not st.session_state['logged_in']:
login_form.login_form()
with tab1:
def button1_callback():
st.session_state['markdown'] = mdformat.text(st.session_state['markdown'],
options={"number": True})
if st.session_state['logged_in']:
tab1, tab2, tab3, tab4 = st.tabs(["Markdown", "Aperçu", "Paramètres", "Images"])
with tab1:
app_tab1.app_tab1()
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:
app_tab2.app_tab2()
with tab2:
st.write("Aperçu")
st.markdown(content)
with tab3:
app_tab3.app_tab3()
with tab3:
st.header("Paramètres")
# Styles
response_styles = requests.get(f"{fabriquedoc_endpoint}/styles")
styles = response_styles.json()["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"]
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)
linkcolor = st.text_input("Link color:",
value=format_parameters.get("linkcolor"))
tocdepth = st.number_input("Table of Contents depth:",
value=int(format_parameters.get("tocdepth")),
min_value=1,
max_value=5,
step=1)
pdfengine = st.text_input("PDF engine:",
value=format_parameters.get("pdfengine"))
fontsize = st.number_input("Font size:",
value=int(format_parameters.get("fontsize")),
step=1)
paperwidth = st.number_input("Paper width:",
value=int(format_parameters.get("paperwidth")),
step=30)
paperheight = st.number_input("Paper height:",
value=int(format_parameters.get("paperheight")),
step=30)
ratio = st.number_input("Ratio:",
value=int(format_parameters.get("ratio")),
step=10)
margin = st.number_input("Margin:",
value=int(format_parameters.get("margin")),
step=10)
vmargin = st.number_input("Vertical margin:",
value=int(format_parameters.get("vmargin")),
step=10)
extension = st.selectbox("Extension:", ["png", "jpg", "pdf", "mp4"])
if extension == "mp4":
fps = st.number_input("FPS:",
value=int(format_parameters.get("fps")),
step=1)
stilltime = st.number_input("Still time:",
value=int(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
)
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)
# 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", 'png']:
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/")
images = response.json()["images"]
selected_image = st.selectbox("Choisis une image:", images)
image_response = requests.get(f"{fabriquedoc_endpoint}/images/{selected_image}")
image_data = image_response.content
st.image(image_data)
st.write("Envoyer une image")
uploaded_files = st.file_uploader("Choisis un fichier image",
type=["png", "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)
# 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()

19
models.py Normal file
View file

@ -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

View file

@ -1,4 +1,5 @@
streamlit~=1.24.0
requests~=2.28.2
pydantic~=2.0.1
mdformat~=0.7.16
streamlit~=1.37.1
requests~=2.31.0
pydantic~=2.0.3
mdformat~=0.7.17
python-dotenv~=1.0.1