Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -27,6 +27,7 @@ import matplotlib.pyplot as plt
|
|
| 27 |
import seaborn as sns
|
| 28 |
from src.embeddings.modelos_nlp_db import search
|
| 29 |
from src.embeddings.mass_modelos_nlp_db import search_mass
|
|
|
|
| 30 |
from huggingface_hub import InferenceClient
|
| 31 |
# import pandas as pd
|
| 32 |
import re
|
|
@@ -848,6 +849,167 @@ def tab_inicio(df_ods, df_metas, df_indicador):
|
|
| 848 |
"""
|
| 849 |
return html
|
| 850 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 851 |
def tab_inicio_mass(df_ods=None, df_metas=None, df_indicador=None):
|
| 852 |
# def tab_inicio():
|
| 853 |
"""Pestaña de inicio con resumen general"""
|
|
@@ -1875,6 +2037,68 @@ def crear_app():
|
|
| 1875 |
return True
|
| 1876 |
|
| 1877 |
# PESTAÑA: CONSULTA
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1878 |
with gr.Tab("CONSULTA INDIVIDUAL"):
|
| 1879 |
|
| 1880 |
txt_ods = gr.Textbox(value="ods", visible=False)
|
|
|
|
| 27 |
import seaborn as sns
|
| 28 |
from src.embeddings.modelos_nlp_db import search
|
| 29 |
from src.embeddings.mass_modelos_nlp_db import search_mass
|
| 30 |
+
from src.llm_clasificador_HF import procesar_lote
|
| 31 |
from huggingface_hub import InferenceClient
|
| 32 |
# import pandas as pd
|
| 33 |
import re
|
|
|
|
| 849 |
"""
|
| 850 |
return html
|
| 851 |
|
| 852 |
+
def tab_inicio_prompt(df_ods, df_metas, df_indicador):
|
| 853 |
+
# def tab_inicio():
|
| 854 |
+
"""Pestaña de inicio con resumen general"""
|
| 855 |
+
if not DATOS_CARGADOS:
|
| 856 |
+
return "⚠️ Error: No se pudieron cargar los datos."
|
| 857 |
+
|
| 858 |
+
# Estadísticas básicas
|
| 859 |
+
|
| 860 |
+
# total_ods = df_ods['ODS_ID'].nunique()
|
| 861 |
+
# total_metas = df_metas['META_ID'].nunique()
|
| 862 |
+
# total_indicadores = df_indicador['INDICADOR_ID'].nunique()
|
| 863 |
+
# sim_media = df_ods['ods_similaridad_cos_normalized'].mean()
|
| 864 |
+
# sim_max = df_ods['ods_similaridad_cos_normalized'].max()
|
| 865 |
+
# sim_min = df_ods['ods_similaridad_cos_normalized'].min()
|
| 866 |
+
# correlacion = df_ods['ods_rank'].corr(df_ods['ods_similaridad_cos_normalized'])
|
| 867 |
+
|
| 868 |
+
# Top 4 ODS
|
| 869 |
+
top_ods = df_ods.nsmallest(4, 'ods_rank')[['rank', 'ODS_ID', 'score', 'frecuencia']]
|
| 870 |
+
top_ods['logo_id'] = top_ods['ODS_ID'].apply(lambda _: f"ods_{str(_)}")
|
| 871 |
+
# top_ods = df_ods.groupby('ODS_ID').agg({
|
| 872 |
+
# 'ods_similaridad_cos_normalized': 'mean'
|
| 873 |
+
# }).sort_values('ods_similaridad_cos_normalized', ascending=False).head(3)[['ods_similaridad_cos_normalized']]
|
| 874 |
+
|
| 875 |
+
# Top ODS referencia
|
| 876 |
+
ods_ref = top_ods.ODS_ID
|
| 877 |
+
|
| 878 |
+
# Top 3 METAS
|
| 879 |
+
|
| 880 |
+
top_metas = df_metas.nsmallest(4, 'ods_rank')[['rank', 'META_ID', 'score', 'frecuencia']]
|
| 881 |
+
# for i in ods_ref:
|
| 882 |
+
# top_metas_lcl = df_metas[df_metas.ODS_ID == i]
|
| 883 |
+
# top_metas_lcl = top_metas_lcl.nsmallest(2, 'meta_rank')[['META_ID','meta_rank','META','meta_similaridad_cos_normalized', 'ODS_ID']]
|
| 884 |
+
# top_metas = pd.concat([top_metas, top_metas_lcl], axis=0)
|
| 885 |
+
# top_metas['logo_id'] = top_metas['ODS_ID'].apply(lambda _: f"ods_{_}")
|
| 886 |
+
top_metas['logo_id'] = top_metas['META_ID'].apply(lambda _: f"meta_{str(_).upper()}")
|
| 887 |
+
|
| 888 |
+
recomendaciones_tblinput = Path('data/raw/ODS_169_metas_recomendaciones_detalladas.xlsx')
|
| 889 |
+
df_recomendaciones = pd.read_excel(recomendaciones_tblinput)
|
| 890 |
+
top_metas = top_metas.merge(df_recomendaciones[['Meta_ODS', 'Recomendaciones_territoriales']], left_on='META_ID', right_on='Meta_ODS', how='left')
|
| 891 |
+
# top_metas = df_metas.groupby('META_ID').agg({
|
| 892 |
+
# 'meta_similaridad_cos_normalized': 'mean'
|
| 893 |
+
# }).sort_values('meta_similaridad_cos_normalized', ascending=False).head(5)[['META_ID','META','meta_similaridad_cos_normalized']]
|
| 894 |
+
|
| 895 |
+
# Top 5 indicadores
|
| 896 |
+
# top_indicador = df_metas.nsmallest(4, 'ods_rank')[['rank', 'INDICADOR_ID', 'score', 'frecuencia']]
|
| 897 |
+
# top_indicador['ODS_ID'] = top_indicador['INDICADOR_ID'].apply(lambda x: str(x).split('.')[0] if pd.notna(x) else None)
|
| 898 |
+
# top_indicador['logo_id'] = top_indicador['ODS_ID'].apply(lambda _: f"ods_{str(_)}")
|
| 899 |
+
|
| 900 |
+
|
| 901 |
+
html = f"""
|
| 902 |
+
<div style="font-family: Arial, sans-serif; padding: 20px;">
|
| 903 |
+
<h1 style="color: #2E5090; text-align: center;">
|
| 904 |
+
📊 Tu texto en clave de ODS
|
| 905 |
+
</h1>
|
| 906 |
+
<h2 style="color: #4472C4; text-align: center;">
|
| 907 |
+
El análisis
|
| 908 |
+
identifica que tu texto se relaciona principalmente
|
| 909 |
+
con estos Objetivos de Desarrollo Sostenible ODS
|
| 910 |
+
</h2>
|
| 911 |
+
|
| 912 |
+
|
| 913 |
+
|
| 914 |
+
|
| 915 |
+
<div class="important-box" style="background-color: #009EDB; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 5px solid #E6F7E6;">
|
| 916 |
+
<h3 style="color: #E6F7E6;">🏆 Top 4 ODS Más Relevantes</h3>
|
| 917 |
+
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: space-around; align-items: flex-start;">
|
| 918 |
+
{''.join([f'''
|
| 919 |
+
<div style="display: flex; flex-direction: column; align-items: center; text-align: center; flex: 1; min-width: 150px;">
|
| 920 |
+
<img src="{dict_logos[row['logo_id']]}"
|
| 921 |
+
alt="ODS {row['ODS_ID']}"
|
| 922 |
+
width="{int(400*(row['score']**2))}"
|
| 923 |
+
style="margin: 0 auto; display: block;" />
|
| 924 |
+
<!-- <p style="margin: 10px 0; color: #333; font-weight: bold;">{row['OBJETIVO']}</p> -->
|
| 925 |
+
</div>''' for _, row in top_ods.iterrows()])}
|
| 926 |
+
</div>
|
| 927 |
+
</div>
|
| 928 |
+
|
| 929 |
+
<div class="important-box" style="background-color: #F0F0F0; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 5px solid #FFD700;">
|
| 930 |
+
<h3 style="color: #009EDB;">🎯 Metas Más Relevantes Por ODS Top</h3>
|
| 931 |
+
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: space-around; align-items: flex-start;">
|
| 932 |
+
{''.join([f'''
|
| 933 |
+
<div style="display: flex; flex-direction: column; align-items: center; text-align: center; flex: 1; min-width: 150px;">
|
| 934 |
+
<img src="{dict_logos[row['logo_id']]}"
|
| 935 |
+
alt="ODS {row['ODS_ID']}"
|
| 936 |
+
width="{int(200*(row['score']**2))}"
|
| 937 |
+
style="margin: 0 auto; display: block;" />
|
| 938 |
+
<p style="margin: 10px 0 5px 0; color: #333; font-size: 12px;"><strong style="color: #333;">Meta:</strong> {row['META_ID']}</p>
|
| 939 |
+
<!-- <p style="margin: 0; color: #666; font-size: 12px;">{row['META']}</p> -->
|
| 940 |
+
<!-- <p style="margin: 5px 0 0 0; color: #999; font-size: 11px;">Sim: {row['score']:.3f}</p> -->
|
| 941 |
+
<!-- <p style="margin: 5px 0 0 0; color: #333; font-size: 11px;">Rank: {row['meta_rank']}</p> -->
|
| 942 |
+
</div>''' for _, row in top_metas.iterrows()])}
|
| 943 |
+
</div>
|
| 944 |
+
</div>
|
| 945 |
+
|
| 946 |
+
<div class="important-box" style="background-color: #F0F0F0; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 5px solid #FFD700;">
|
| 947 |
+
<h3 style="color: #FF8C00;">🎯 Indicadores Más Relevantes Por ODS Top</h3>
|
| 948 |
+
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: space-around; align-items: flex-start;">
|
| 949 |
+
{''.join([f'''
|
| 950 |
+
<div style="display: flex; flex-direction: column; align-items: center; text-align: center; flex: 1; min-width: 150px;">
|
| 951 |
+
<img src="{dict_logos[row['logo_id']]}"
|
| 952 |
+
alt="ODS {row['ODS_ID']}"
|
| 953 |
+
width="{int(200*(row['score']**2))}"
|
| 954 |
+
style="margin: 0 auto; display: block;" />
|
| 955 |
+
<p style="margin: 10px 0 5px 0; color: #333; font-size: 12px;"><strong style="color: #333;">Ind:</strong> {row['INDICADOR_ID']}</p>
|
| 956 |
+
<!-- <p style="margin: 0; color: #666; font-size: 12px;">{row['INDICADOR']}</p> -->
|
| 957 |
+
<!-- <p style="margin: 5px 0 0 0; color: #333; font-size: 11px;">Sim: {row['score']:.3f}</p> -->
|
| 958 |
+
<p style="margin: 5px 0 0 0; color: #333; font-size: 11px;">Rank: {row['indicador_rank']}</p>
|
| 959 |
+
</div>''' for _, row in top_metas.iterrows()])}
|
| 960 |
+
</div>
|
| 961 |
+
</div>
|
| 962 |
+
|
| 963 |
+
<div class="important-box" style="background-color: #E8F4F8; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 5px solid #4472C4;">
|
| 964 |
+
<h3 style="color: #2E5090;">📋 Recomendaciones Territoriales por Meta</h3>
|
| 965 |
+
<table style="width: 100%; border-collapse: collapse; background-color: white;">
|
| 966 |
+
<thead>
|
| 967 |
+
<tr style="background-color: #2E5090; color: white;">
|
| 968 |
+
<th style="padding: 12px; text-align: left; border-bottom: 2px solid #2E5090;">ODS</th>
|
| 969 |
+
<th style="padding: 12px; text-align: left; border-bottom: 2px solid #2E5090;">Meta ID</th>
|
| 970 |
+
<th style="padding: 12px; text-align: left; border-bottom: 2px solid #2E5090;">Recomendaciones Territoriales</th>
|
| 971 |
+
</tr>
|
| 972 |
+
</thead>
|
| 973 |
+
<tbody>
|
| 974 |
+
{''.join([f'''
|
| 975 |
+
<tr style="border-bottom: 1px solid #ddd;">
|
| 976 |
+
<td style="padding: 12px; text-align: center;">
|
| 977 |
+
<img src="{dict_logos[f'ods_{row['ODS_ID']}']}"
|
| 978 |
+
alt="ODS {row['ODS_ID']}"
|
| 979 |
+
width="50"
|
| 980 |
+
style="vertical-align: middle;" />
|
| 981 |
+
</td>
|
| 982 |
+
<td style="padding: 12px; font-weight: bold; color: #2E5090;">{row['META_ID']}</td>
|
| 983 |
+
<td style="padding: 12px; color: #333;">{row.get('Recomendaciones_territoriales', 'N/A')}</td>
|
| 984 |
+
</tr>''' for _, row in df_metas.iterrows() if not pd.isna(row.get('Recomendaciones_territoriales'))])}
|
| 985 |
+
</tbody>
|
| 986 |
+
</table>
|
| 987 |
+
</div>
|
| 988 |
+
|
| 989 |
+
<!--
|
| 990 |
+
<div style="background-color: #F0F0F0; padding: 20px; border-radius: 10px; margin: 20px 0;">
|
| 991 |
+
<h3 style="color: #2E5090;">📚 Cómo usar esta aplicación</h3>
|
| 992 |
+
<ol style="line-height: 1.8;">
|
| 993 |
+
<li><strong>Explora las pestañas:</strong> Cada pestaña contiene una visualización diferente</li>
|
| 994 |
+
<li><strong>Lee las explicaciones:</strong> Cada gráfica incluye una guía de interpretación</li>
|
| 995 |
+
<li><strong>Interactúa:</strong> Las visualizaciones HTML permiten zoom, hover y exploración</li>
|
| 996 |
+
<li><strong>Descarga:</strong> Puedes descargar las imágenes desde las pestañas</li>
|
| 997 |
+
</ol>
|
| 998 |
+
</div>
|
| 999 |
+
|
| 1000 |
+
<div style="text-align: center; margin-top: 30px; padding: 20px; background-color: #E8F4F8; border-radius: 10px;">
|
| 1001 |
+
<p style="font-size: 18px; color: #2E5090;">
|
| 1002 |
+
<strong>¡Comienza explorando las visualizaciones en las pestañas superiores!</strong>
|
| 1003 |
+
</p>
|
| 1004 |
+
<p style="color: #666;">
|
| 1005 |
+
Recomendación: Empieza con el "Dashboard Integrado" para una vista general
|
| 1006 |
+
</p>
|
| 1007 |
+
</div>
|
| 1008 |
+
-->
|
| 1009 |
+
</div>
|
| 1010 |
+
"""
|
| 1011 |
+
return html
|
| 1012 |
+
|
| 1013 |
def tab_inicio_mass(df_ods=None, df_metas=None, df_indicador=None):
|
| 1014 |
# def tab_inicio():
|
| 1015 |
"""Pestaña de inicio con resumen general"""
|
|
|
|
| 2037 |
return True
|
| 2038 |
|
| 2039 |
# PESTAÑA: CONSULTA
|
| 2040 |
+
with gr.Tab("CONSULTA INDIVIDUAL PROMPT"):
|
| 2041 |
+
|
| 2042 |
+
# txt_ods = gr.Textbox(value="ods", visible=False)
|
| 2043 |
+
# txt_meta = gr.Textbox(value="meta", visible=False)
|
| 2044 |
+
# txt_indicador = gr.Textbox(value="indicador", visible=False)
|
| 2045 |
+
|
| 2046 |
+
with gr.Column():
|
| 2047 |
+
gr.Markdown(f"""
|
| 2048 |
+
|
| 2049 |
+
### Cuéntanos una iniciativa, problema o propuesta de tu territorio.
|
| 2050 |
+
|
| 2051 |
+
*La herramienta analizará el texto y mostrará con qué
|
| 2052 |
+
Objetivos de Desarrollo Sostenible (ODS) se
|
| 2053 |
+
relaciona.*
|
| 2054 |
+
""")
|
| 2055 |
+
query_in_prt = gr.Textbox(lines=5, placeholder="Escribe aquí tu consulta...", label="Iniciativa a analizar")
|
| 2056 |
+
lst_query_in_prt = gr.State() #gr.Textbox(value="[]", visible=False)
|
| 2057 |
+
def add_query_list(query):
|
| 2058 |
+
return gr.update(value=[query])
|
| 2059 |
+
query_in_prt.change(
|
| 2060 |
+
fn = add_query_list,
|
| 2061 |
+
inputs = query_in_prt,
|
| 2062 |
+
outputs = lst_query_in_prt)
|
| 2063 |
+
query_out_prt = gr.Textbox(lines=5, label="Texto ajustado para lenguaje natural", visible=False)
|
| 2064 |
+
|
| 2065 |
+
btn_prt = gr.Button(value="Analizar mi iniciativa")
|
| 2066 |
+
msj_procesamiento_prt = gr.Textbox(value="... preparando análisis de iniciativa.", visible=True)
|
| 2067 |
+
|
| 2068 |
+
with gr.Tab("🔍 Resultado"):
|
| 2069 |
+
|
| 2070 |
+
|
| 2071 |
+
with gr.Row():
|
| 2072 |
+
ods_prt = gr.Dataframe( label="ODS", visible=False)#, buttons=["fullscreen"])
|
| 2073 |
+
meta_prt = gr.Dataframe( label="METAS", visible=False)#, buttons=["fullscreen"])
|
| 2074 |
+
indicador_prt = gr.Dataframe( label="INDICADORES", visible=False)#, buttons=["fullscreen"])
|
| 2075 |
+
|
| 2076 |
+
|
| 2077 |
+
html_inicio_ods_prt = gr.HTML() #tab_inicio(ods.value)
|
| 2078 |
+
|
| 2079 |
+
#### Actualizando resultados iniciales
|
| 2080 |
+
ods_prt.change(
|
| 2081 |
+
fn=tab_inicio_prompt,
|
| 2082 |
+
inputs=[ods_prt,meta_prt,indicador_prt],
|
| 2083 |
+
outputs=[html_inicio_ods_prt]
|
| 2084 |
+
)
|
| 2085 |
+
meta_prt.change(
|
| 2086 |
+
fn=tab_inicio_prompt,
|
| 2087 |
+
inputs=[ods_prt,meta_prt,indicador_prt],
|
| 2088 |
+
outputs=[html_inicio_ods_prt]
|
| 2089 |
+
)
|
| 2090 |
+
indicador_prt.change(
|
| 2091 |
+
fn=tab_inicio_prompt,
|
| 2092 |
+
inputs=[ods_prt,meta_prt,indicador_prt],
|
| 2093 |
+
outputs=[html_inicio_ods_prt]
|
| 2094 |
+
)
|
| 2095 |
+
|
| 2096 |
+
|
| 2097 |
+
|
| 2098 |
+
|
| 2099 |
+
btn_prt.click(procesar_lote, query_in_prt, [ods_prt,meta_prt,indicador_prt], show_progress=True)
|
| 2100 |
+
|
| 2101 |
+
|
| 2102 |
with gr.Tab("CONSULTA INDIVIDUAL"):
|
| 2103 |
|
| 2104 |
txt_ods = gr.Textbox(value="ods", visible=False)
|