CoolFace
Apppublic

fmatituy/selectospromanager

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
estudio_sara.py147 linesDownload Raw Back to sst
1from nicegui import ui2from services.auth import require_auth, get_current_user3from modules.layout import SelectosLayout4from .services_sst_ext import get_sara_analytics5from modules.sst_industrial import sst_top_navigation, CORP_BLUE, CORP_ORANGE, CORP_RED, CORP_GRAY, CORP_BG, CORP_GREEN6 7@ui.page('/sst/sara-estudio')8@require_auth9def sara_estudio_page():10    user = get_current_user()11    from services.navigation import MANAGER_ROLES12    if user.get('rol') not in MANAGER_ROLES:13        return ui.navigate.to('/')14 15    data = get_sara_analytics()16 17    with SelectosLayout('SARA Studio - Inteligencia SST'):18        ui.query('body').style(f'background-color: {CORP_BG}')19        sst_top_navigation('/sst/sara-estudio')20        21        with ui.column().classes('w-full max-w-7xl mx-auto p-4 md:p-8 gap-8'):22            23            # --- HEADER PREMIUM ---24            with ui.row().classes('w-full justify-between items-center bg-white p-8 rounded-xl shadow-sm border-b-4').style('border-color: #6366F1'):25                with ui.column().classes('gap-1'):26                    with ui.row().classes('items-center gap-2'):27                        ui.icon('psychology', color='indigo-500', size='sm')28                        ui.label('AI PREDICTIVE CORE').classes('text-[10px] font-black tracking-[0.3em] text-indigo-500 uppercase')29                    ui.label('SARA: Estudio Automático').classes(f'text-4xl font-bold text-[{CORP_GRAY}] tracking-tight')30                    ui.label('Análisis inteligente de riesgos, tendencias y predicción de incidentes.').classes('text-sm text-slate-400 font-medium')31                32                with ui.column().classes('items-end gap-2'):33                    ui.button('GENERAR REPORTE GLOBAL', icon='auto_awesome', on_click=lambda: ui.notify('Generando Reporte Ejecutivo IA...', type='ongoing')) \34                        .props('unelevated rounded-lg').style('background-color: #6366F1').classes('px-6 py-3 font-bold text-white text-[10px]')35                    ui.label('Kernel v2.4.0 Activo').classes('text-[8px] font-black text-slate-300 tracking-widest')36 37            # --- SMART ALERT BANNER (Conditional) ---38            score = data.get('risk_prediction_score', 0)39            if score > 50:40                with ui.row().classes('w-full p-4 bg-rose-50 border-l-4 border-rose-500 rounded-r-xl items-center gap-4'):41                    ui.icon('report_problem', color='rose-600', size='md').classes('animate-pulse')42                    with ui.column().classes('gap-0'):43                        ui.label('ALERTA DE SEGURIDAD PROACTIVA').classes('text-[10px] font-black text-rose-600 tracking-widest')44                        ui.label(f'Nivel de riesgo predictivo elevado ({score}%). SARA detecta patrones de recurrencia en actos inseguros.').classes('text-sm text-rose-900 font-bold')45                    ui.space()46                    ui.button('MITIGAR AHORA', icon='shield').props('unelevated color=rose-600 size=sm').classes('px-4 py-2 font-bold text-[9px]')47 48            # --- KPI DE PREDICCIÓN DE RIESGO ---49            with ui.row().classes('w-full grid grid-cols-1 md:grid-cols-3 gap-8'):50                51                # Gauge de Predicción52                with ui.card().classes('p-8 rounded-xl bg-white border border-slate-200 shadow-sm flex flex-col items-center justify-center'):53                    ui.label('SCORE DE RIESGO PREDICTIVO').classes('text-[9px] font-black text-slate-400 tracking-widest uppercase mb-4')54                    score = data.get('risk_prediction_score', 0)55                    color = '#10B981' if score < 30 else ('#F59E0B' if score < 70 else '#EF4444')56                    57                    ui.echart({58                        'series': [{59                            'type': 'gauge', 'startAngle': 180, 'endAngle': 0, 'center': ['50%', '75%'], 'radius': '100%',60                            'progress': {'show': True, 'width': 12},61                            'axisLine': {'lineStyle': {'width': 12}},62                            'axisTick': {'show': False}, 'splitLine': {'show': False}, 'axisLabel': {'show': False},63                            'pointer': {'show': False},64                            'detail': {'valueAnimation': True, 'distance': -10, 'formatter': '{value}', 'fontSize': 32, 'fontWeight': 'bold'},65                            'data': [{'value': score}],66                            'itemStyle': {'color': color}67                        }]68                    }).classes('h-48 w-full')69                    ui.label('PRÓXIMAS 72 HORAS').classes('text-[8px] font-black text-slate-300 uppercase mt-[-10px]')70 71                # Recomendaciones de SARA72                with ui.card().classes('md:col-span-2 p-8 rounded-xl bg-indigo-50 border border-indigo-100 shadow-sm'):73                    with ui.row().classes('items-center gap-2 mb-4'):74                        ui.icon('lightbulb', color='indigo-500', size='18px')75                        ui.label('INSIGHTS Y RECOMENDACIONES DE SARA').classes('text-[10px] font-black text-indigo-500 tracking-widest uppercase')76                    77                    with ui.column().classes('gap-3'):78                        for insight in data.get('ai_insights', ["No hay recomendaciones críticas en este momento."]):79                            with ui.row().classes('w-full bg-white/60 p-4 rounded-lg border border-white items-start gap-3'):80                                ui.icon('auto_awesome', size='xs', color='indigo-400')81                                ui.label(insight).classes('text-xs text-indigo-900 font-medium leading-relaxed')82 83            # --- ANÁLISIS DE TENDENCIAS Y PATRONES ---84            with ui.row().classes('w-full grid grid-cols-1 lg:grid-cols-2 gap-8'):85                86                # Tendencia de Incidentes87                with ui.card().classes('p-8 rounded-xl bg-white border border-slate-200 shadow-sm'):88                    ui.label('TENDENCIA DE INCIDENTABILIDAD (FORECAST)').classes('text-[10px] font-black text-slate-400 tracking-widest uppercase mb-6')89                    import datetime90                    hoy = datetime.datetime.now()91                    labels = [(hoy - datetime.timedelta(days=30*i)).strftime('%b') for i in range(5, -1, -1)]92                    93                    # Simulación de predicción basada en tendencia real94                    last_val = data['tendencia_incidentes'][-1] if data['tendencia_incidentes'] else 095                    prediccion = [None]*5 + [last_val, last_val + 1, last_val - 1]96 97                    ui.echart({98                        'tooltip': {'trigger': 'axis'},99                        'xAxis': {'type': 'category', 'data': labels + ['Prox', 'Fut']},100                        'yAxis': {'type': 'value'},101                        'series': [102                            {'name': 'Histórico', 'type': 'line', 'smooth': True, 'data': data['tendencia_incidentes'], 'lineStyle': {'width': 3}, 'itemStyle': {'color': '#6366F1'}},103                            {'name': 'Predicción', 'type': 'line', 'smooth': True, 'data': prediccion, 'lineStyle': {'type': 'dashed', 'width': 2}, 'itemStyle': {'color': '#A5B4FC'}}104                        ]105                    }).classes('h-64 w-full')106 107                # Áreas con Riesgo Recurrente108                with ui.card().classes('p-8 rounded-xl bg-white border border-slate-200 shadow-sm'):109                    ui.label('ZONAS CON CONCENTRACIÓN DE HALLAZGOS').classes('text-[10px] font-black text-slate-400 tracking-widest uppercase mb-6')110                    areas = [row['area'] for row in data['hallazgos_por_area']]111                    values = [row['qty'] for row in data['hallazgos_por_area']]112                    113                    if not areas:114                        ui.label('Sin hallazgos registrados para mapeo de calor.').classes('text-xs text-slate-300 italic py-10 text-center')115                    else:116                        ui.echart({117                            'tooltip': {'trigger': 'item'},118                            'series': [{119                                'type': 'pie', 'radius': ['40%', '70%'], 'avoidLabelOverlap': False,120                                'itemStyle': {'borderRadius': 10, 'borderColor': '#fff', 'borderWidth': 2},121                                'label': {'show': False}, 'emphasis': {'label': {'show': True, 'fontSize': '12', 'fontWeight': 'bold'}},122                                'data': [{'value': v, 'name': a} for a, v in zip(areas, values)]123                            }]124                        }).classes('h-64 w-full')125 126            # --- REPORTES AUTOMÁTICOS ---127            ui.label('REPORTES DE INTELIGENCIA DISPONIBLES').classes('text-[10px] font-black text-slate-400 tracking-widest uppercase mb-[-20px]')128            with ui.row().classes('w-full grid grid-cols-1 md:grid-cols-3 gap-6'):129                reports = [130                    ('Estudio de Fatiga Operativa', 'Análisis de HH vs Incidentes', 'timer', 'blue'),131                    ('Correlación IPVR-Campo', 'Brecha entre matriz y realidad', 'compare_arrows', 'emerald'),132                    ('Análisis de Cumplimiento Normativo', 'Proyección auditoría 1072', 'gavel', 'indigo')133                ]134                for title, desc, icon, color in reports:135                    with ui.card().classes('p-6 rounded-xl bg-white border border-slate-200 hover:shadow-md transition-all cursor-pointer group'):136                        with ui.row().classes('w-full justify-between items-center mb-4'):137                            ui.icon(icon, color=f'{color}-500', size='sm').classes('group-hover:scale-110 transition-transform')138                            ui.badge('AUTO-GEN').props(f'unelevated color={color}-50').classes(f'text-[8px] font-black text-{color}-600 px-2')139                        ui.label(title).classes('text-lg font-bold text-slate-800 leading-tight')140                        ui.label(desc).classes('text-xs text-slate-400 mt-1')141                        ui.button('DESCARGAR ESTUDIO', icon='download', on_click=lambda t=title: ui.notify(f'Compilando {t}...', type='info')) \142                            .props('flat color=primary size=xs').classes('w-full mt-6 font-black text-[9px] tracking-widest')143 144            # --- FOOTER ---145            with ui.row().classes('w-full justify-center opacity-30 mt-10'):146                ui.label('SARA ENGINE • NEURAL RISK PROTECTION • 2026').classes('text-[8px] font-black tracking-[0.4em] text-slate-500')147