Spaces:
Running
Running
import streamlit as st | |
import markdown2 | |
import pdfkit | |
from io import BytesIO | |
from IPython.display import display, FileLink | |
import base64 | |
from langchain_core.messages import AIMessage, HumanMessage | |
from datetime import datetime | |
from download_chart import construct_plot | |
from kaleido.scopes.plotly import PlotlyScope | |
import pandas as pd | |
import markdown | |
from comparateur import get_table_empreintes_detailed | |
from empreinte_export import get_carbon_footprint_html | |
def colored_circle(color): | |
return f'<span style="display: inline-block; width: 15px; height: 15px; border-radius: 50%; background-color: {color};"></span>' | |
def list_to_markdown(lst): | |
return "\n".join([f'<p>{colored_circle(item["color"])} <b>{item["name"]}</b>: Pouvoir:{item["y"]}% Influence:{item["x"]}%</p>' for item in lst[:20]]) | |
def categorize(row): | |
if 50 <= row['pouvoir'] <= 100 and 0 <= row['influence'] < 50: | |
return 'Rendre satisfait' | |
elif 50 <= row['pouvoir'] <= 100 and 50 <= row['influence'] <= 100: | |
return 'Gérer étroitement' | |
elif 0 <= row['pouvoir'] < 50 and 0 <= row['influence'] < 50: | |
return 'Suivre de près' | |
elif 0 <= row['pouvoir'] < 50 and 50 <= row['influence'] <= 100: | |
return 'Tenir informé' | |
else: | |
return 'Non catégorisé' | |
def convert_pp_to_csv(pp_grouped): | |
if pp_grouped is None or len(pp_grouped) == 0: | |
st.error("Aucune partie prenante n'a été définie") | |
return None | |
pp_df = pd.DataFrame(pp_grouped) | |
pp_df.index.name = 'N°' | |
pp_df.rename(columns={"name": "parties prenantes", "x": "influence", "y": "pouvoir"}, inplace=True) | |
pp_df.drop(columns=['color'], inplace=True) | |
# Apply the function to the DataFrame to create a new column 'categorie' | |
pp_df['categorie'] = pp_df.apply(categorize, axis=1) | |
pp_df = pp_df[["parties prenantes","categorie", "pouvoir", "influence"]] | |
pp_df.rename_axis('N°', axis=1) | |
return pp_df.to_csv(index=True,encoding="utf-8") | |
def create_pdf_from_markdown(logo_path, conversation,summary,brand_name,graph_html,app_url,list_pps,used_models=None): | |
# Convertir la conversation en markdown | |
markdown_text = "\n".join([f"### {entry['speaker']}:\n {entry['text']}\n ---" for entry in conversation]) | |
if not used_models: | |
used_models = ["Aucun modèle IA n'a été utilisé"] | |
html_used_models = "".join([f"<p>{model}</p>" for model in used_models]) | |
markdown_summary = f"{summary}\n --- \n ---" | |
markdown_list_pps = list_to_markdown(list_pps) | |
# Convertir le markdown en HTML | |
html_content = markdown.markdown(markdown_text,extensions=['markdown.extensions.tables']) | |
html_summary = markdown2.markdown(markdown_summary) | |
html_list_pps = markdown2.markdown(markdown_list_pps) | |
html_table = get_table_empreintes_detailed().to_html() | |
analysis_date = datetime.now().strftime("%Y-%m-%d") | |
# image_base64 = base64.b64encode(image_path).decode('utf-8') | |
graph_html.update_layout(showlegend=False) | |
img_bytes = PlotlyScope().transform( | |
figure=graph_html, | |
format="png", | |
) | |
fig1 = f"data:image/png;base64,{base64.b64encode(img_bytes).decode('utf8')}" | |
# Créer le HTML complet avec les images et le texte | |
html_template = f""" | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Cartographie des parties prenantes {brand_name}</title> | |
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> | |
<style> | |
body {{ | |
font-family: 'Roboto', sans-serif; | |
margin: 20px; | |
}} | |
h1, h2, h3, h4, h5, h6 {{ | |
font-weight: bold; | |
}} | |
.page-break {{ | |
page-break-before: always; | |
margin: 50px; | |
height: 50px; | |
}} | |
</style> | |
</head> | |
<body> | |
<div style="text-align: center;"> | |
<h1>Cartographie des parties prenantes "{brand_name}"</h1> | |
<p>Date de l'analyse IA RSE : {analysis_date}</p> | |
<p>IA utilisées :</p> | |
{html_used_models} | |
<img src="{logo_path}" alt="Logo" style="width: 150px;"/> | |
</div> | |
<div class="page-break"></div> | |
<div style="text-align: center; margin-top: 20px;"> | |
<img src="{fig1}"> | |
</div> | |
{html_list_pps} | |
<div class="page-break"></div> | |
<h2>RESUME</h2> | |
{html_summary} | |
<div class="page-break"></div> | |
<h2>Historique de la Conversation</h2> | |
{html_content} | |
<div class="page-break"></div> | |
<h2>Emission de CO2</h2> | |
{html_table} | |
<div class="page-break"></div> | |
{get_carbon_footprint_html()} | |
</body> | |
</html> | |
""" | |
with open("temp.html", "w",encoding="utf-8") as f: | |
f.write(html_template) | |
# Create the footer HTML with the logo and app_url | |
footer_html = f""" | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> | |
<meta charset="UTF-8"> | |
<style> | |
body {{ | |
font-family: 'Roboto', sans-serif; | |
margin-top: 20px; | |
}} | |
.footer {{ | |
width: 100%; | |
font-size: 16px; | |
display: flex; | |
align-items: center; | |
justify-content: space-between; | |
padding: 10px 20px; | |
}} | |
.footer img {{ | |
width: 100px; | |
vertical-align: middle; | |
margin-bottom: 0px; | |
padding-bottom: 0px; | |
}} | |
.footer .center-text {{ | |
text-align: center; | |
}} | |
.footer .page-number {{ | |
text-align: right; | |
}} | |
.footer a {{ | |
color: #0000EE; | |
text-decoration: none; | |
}} | |
.page {{ | |
font-weight: bold; | |
font-size: 10px; | |
margin-bottom: 0px; | |
padding-bottom: 0px; | |
}} | |
</style> | |
</head> | |
<body> | |
<div class="footer"> | |
<img src="{logo_path}" alt="Logo" /> | |
<div class="center-text"> | |
bziiit | Open data & IA RSE | <a href="{app_url}">{app_url}</a> | |
</div> | |
<div class="page-number"> | |
<span class="page"></span> | |
</div> | |
</div> | |
</body> | |
</html> | |
""" | |
# Save the footer HTML to a temporary file | |
with open("footer.html", "w",encoding="utf-8") as f: | |
f.write(footer_html) | |
# Convert HTML to PDF with header and footer | |
pdf = pdfkit.from_file("temp.html", options={ | |
'footer-html': 'footer.html', | |
'footer-right': '[page]/[toPage]', | |
'footer-font-size': '10', | |
'footer-spacing': '5', | |
'footer-line': True, | |
'margin-top': '5', | |
}) | |
return pdf | |
def get_conversation(): | |
conversation = [] | |
for message in st.session_state.chat_history: | |
if isinstance(message, AIMessage): | |
conversation.append({"speaker": "AI", "text": message.content}) | |
elif isinstance(message, HumanMessage): | |
conversation.append({"speaker": "Moi", "text": message.content}) | |
return conversation | |
def export_conversation(summary,used_models=None): | |
brand_name = st.session_state["Nom de la marque"] | |
app_url = "https://huggingface.co/spaces/bziiit/OpenData-Bordeaux-RSE" | |
logo_path = "https://static.wixstatic.com/media/d7d3da_b69e03ae99224f7d8b6e358918e60071~mv2.png/v1/crop/x_173,y_0,w_1906,h_938/fill/w_242,h_119,al_c,q_85,usm_0.66_1.00_0.01,enc_auto/BZIIIT_LOGO-HORIZ-COULEUR.png" # Replace with your image path | |
list_pps = st.session_state['pp_grouped'] | |
with st.spinner("Génération du PDF..."): | |
conversation = get_conversation() | |
image_path = "newplot.png" | |
try: | |
graph = construct_plot() | |
# graph = graph.to_html(full_html=False, include_plotlyjs='cdn') | |
except Exception as e: | |
st.error("Erreur lors de la génération de la cartographie") | |
graph = "" | |
try: | |
pdf = create_pdf_from_markdown(logo_path=logo_path, conversation=conversation,summary=summary,brand_name=brand_name,graph_html=graph,app_url=app_url,list_pps=list_pps,used_models=used_models) | |
except Exception as e: | |
pdf = None | |
if pdf: | |
st.success("PDF généré avec succès!}") | |
else: | |
st.error("Erreur lors de la génération du PDF") | |
return pdf | |