From 4d0d446686b5e98e747b1237807cbfb40ff9c219 Mon Sep 17 00:00:00 2001 From: Yinyin Liu Date: Wed, 18 Feb 2026 16:55:03 +0100 Subject: [PATCH] add alarm AI diagnosis demo panel --- .../src/content/dashboards/Log/Log.tsx | 180 +++++++++++++++++- typescript/frontend-marios2/src/lang/de.json | 14 +- typescript/frontend-marios2/src/lang/en.json | 14 +- typescript/frontend-marios2/src/lang/fr.json | 14 +- typescript/frontend-marios2/src/lang/it.json | 14 +- 5 files changed, 230 insertions(+), 6 deletions(-) diff --git a/typescript/frontend-marios2/src/content/dashboards/Log/Log.tsx b/typescript/frontend-marios2/src/content/dashboards/Log/Log.tsx index 3f545dc60..80587ffa7 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Log/Log.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Log/Log.tsx @@ -3,18 +3,23 @@ import { Alert, Box, Card, + Chip, CircularProgress, Container, Divider, Grid, IconButton, + ListSubheader, + MenuItem, + Select, + TextField, useTheme } from '@mui/material'; import Typography from '@mui/material/Typography'; -import { FormattedMessage } from 'react-intl'; +import { FormattedMessage, useIntl } from 'react-intl'; import ErrorIcon from '@mui/icons-material/Error'; import WarningIcon from '@mui/icons-material/Warning'; -import axiosConfig from '../../../Resources/axiosConfig'; +import axiosConfig, { axiosConfigWithoutToken } from '../../../Resources/axiosConfig'; import { AxiosError, AxiosResponse } from 'axios/index'; import routes from '../../../Resources/routes.json'; import { useNavigate } from 'react-router-dom'; @@ -24,6 +29,15 @@ import Button from '@mui/material/Button'; import FormControlLabel from '@mui/material/FormControlLabel'; import Checkbox from '@mui/material/Checkbox'; +interface TestDiagnoseResult { + source: string; + alarm: string; + explanation?: string; + causes?: string[]; + nextSteps?: string[]; + message?: string; +} + interface LogProps { errorLoadingS3Data: boolean; id: number; @@ -47,11 +61,19 @@ function Log(props: LogProps) { const navigate = useNavigate(); const tokencontext = useContext(TokenContext); const { removeToken } = tokencontext; + const intl = useIntl(); const [diagnoses, setDiagnoses] = useState<{ description: string; lastSeen: string; response: DiagnosticResponse }[]>([]); const [diagnosisLoading, setDiagnosisLoading] = useState(false); const [expandedDiagnoses, setExpandedDiagnoses] = useState>(new Set()); + // demo panel state + const [demoPanelOpen, setDemoPanelOpen] = useState(false); + const [demoAlarm, setDemoAlarm] = useState('AbnormalGridVoltage'); + const [demoCustom, setDemoCustom] = useState(''); + const [demoLoading, setDemoLoading] = useState(false); + const [demoResult, setDemoResult] = useState(null); + useEffect(() => { axiosConfig .get(`/GetAllErrorsForInstallation?id=${props.id}`) @@ -174,6 +196,63 @@ function Log(props: LogProps) { }); }; + const DEMO_ALARMS = { + sinexcel: [ + 'AbnormalGridVoltage', + 'GridVoltagePhaseLoss', + 'Battery1NotConnected', + 'Battery1Overvoltage', + 'LithiumBattery1DischargeForbidden', + 'InsulationFault', + 'FanFault', + 'InverterPowerTubeFault', + 'Pv1Overvoltage', + 'IslandProtection', + 'SystemDerating', + 'DcBusOvervoltage', + ], + growatt: [ + 'StringFault', + 'PvShortCircuited', + 'DcFuseBlown', + 'DcInputVoltageTooHigh', + 'NoUtilityGrid', + 'GridVoltageOutOfRange', + 'FanFailure', + 'BatteryDisconnected', + 'BmsFault', + 'BatteryCommunicationFailure', + 'BatteryVoltageTooHigh', + 'OverTemperatureAlarm', + ], + }; + + const runDemo = () => { + const alarm = demoAlarm === '__custom__' ? demoCustom.trim() : demoAlarm; + if (!alarm) return; + setDemoLoading(true); + setDemoResult(null); + axiosConfigWithoutToken + .get(`/TestDiagnoseError?errorDescription=${encodeURIComponent(alarm)}`) + .then((res: AxiosResponse) => { + setDemoResult(res.data); + }) + .catch(() => { + setDemoResult({ source: 'Error', alarm, message: 'Request failed.' }); + }) + .finally(() => setDemoLoading(false)); + }; + + const sourceChip = (source: string) => { + if (source === 'KnowledgeBase') + return ; + if (source === 'MistralAI') + return ; + if (source === 'MistralFailed') + return ; + return ; + }; + const warningDescriptionMap: { [key: string]: string } = { // BMS warnings "TaM1": "TaM1: BMS temperature high", @@ -469,6 +548,103 @@ function Log(props: LogProps) { + {/* ── AI Diagnosis Demo Panel ── */} + + + + + + {demoPanelOpen && ( + + + + + + + + + {demoAlarm === '__custom__' && ( + { setDemoCustom(e.target.value); setDemoResult(null); }} + sx={{ minWidth: 220 }} + /> + )} + + + + + {demoResult && ( + + + + {demoResult.alarm} + + {sourceChip(demoResult.source)} + + + {demoResult.message ? ( + {demoResult.message} + ) : ( + <> + {demoResult.explanation} + + +
    + {(demoResult.causes ?? []).map((c, i) => ( +
  • {c}
  • + ))} +
+ +
    + {(demoResult.nextSteps ?? []).map((s, i) => ( +
  1. {s}
  2. + ))} +
+
+ + )} +
+ )} +
+ )} +
+ {/* AI Diagnosis banner — shown when loading or diagnoses are available */} {diagnosisLoading && ( diff --git a/typescript/frontend-marios2/src/lang/de.json b/typescript/frontend-marios2/src/lang/de.json index cfbeb1878..bb930fd35 100644 --- a/typescript/frontend-marios2/src/lang/de.json +++ b/typescript/frontend-marios2/src/lang/de.json @@ -130,5 +130,17 @@ "downloadingBatteryLog": "Das Batterieprotokoll wird heruntergeladen. Es wird im Downloads-Ordner gespeichert. Bitte warten...", "confirmBatteryLogDownload": "Möchten Sie das Batterieprotokoll wirklich herunterladen?", "downloadBatteryLogFailed": "Herunterladen des Batterieprotokolls fehlgeschlagen, bitte versuchen Sie es erneut.", - "noReportData": "Keine Berichtsdaten gefunden." + "noReportData": "Keine Berichtsdaten gefunden.", + "ai_analyzing": "KI analysiert...", + "ai_show_details": "Details anzeigen", + "ai_show_less": "Weniger anzeigen", + "ai_likely_causes": "Wahrscheinliche Ursachen:", + "ai_next_steps": "Empfohlene nächste Schritte:", + "demo_test_button": "KI-Diagnose testen", + "demo_hide_button": "KI-Diagnose Demo ausblenden", + "demo_panel_title": "KI-Diagnose Demo", + "demo_custom_group": "Benutzerdefiniert (kann Mistral KI verwenden)", + "demo_custom_option": "Benutzerdefinierten Alarm eingeben…", + "demo_custom_placeholder": "z.B. UnknownBatteryFault", + "demo_diagnose_button": "Diagnostizieren" } \ No newline at end of file diff --git a/typescript/frontend-marios2/src/lang/en.json b/typescript/frontend-marios2/src/lang/en.json index a659b6aea..c265a4bc7 100644 --- a/typescript/frontend-marios2/src/lang/en.json +++ b/typescript/frontend-marios2/src/lang/en.json @@ -112,5 +112,17 @@ "downloadingBatteryLog": "The battery log is getting downloaded. It will be saved in the Downloads folder. Please wait...", "confirmBatteryLogDownload": "Do you really want to download battery log?", "downloadBatteryLogFailed": "Download battery log failed, please try again.", - "noReportData": "No report data found." + "noReportData": "No report data found.", + "ai_analyzing": "AI is analyzing...", + "ai_show_details": "Show details", + "ai_show_less": "Show less", + "ai_likely_causes": "Likely causes:", + "ai_next_steps": "Suggested next steps:", + "demo_test_button": "Test AI Diagnosis", + "demo_hide_button": "Hide AI Diagnosis Demo", + "demo_panel_title": "AI Diagnosis Demo", + "demo_custom_group": "Custom (may use Mistral AI)", + "demo_custom_option": "Type custom alarm below…", + "demo_custom_placeholder": "e.g. UnknownBatteryFault", + "demo_diagnose_button": "Diagnose" } diff --git a/typescript/frontend-marios2/src/lang/fr.json b/typescript/frontend-marios2/src/lang/fr.json index 16088f576..86dab1ddc 100644 --- a/typescript/frontend-marios2/src/lang/fr.json +++ b/typescript/frontend-marios2/src/lang/fr.json @@ -124,5 +124,17 @@ "downloadingBatteryLog": "Le journal de la batterie est en cours de téléchargement. Il sera enregistré dans le dossier Téléchargements. Veuillez patienter...", "confirmBatteryLogDownload": "Voulez-vous vraiment télécharger le journal de la batterie?", "downloadBatteryLogFailed": "Échec du téléchargement du journal de la batterie, veuillez réessayer.", - "noReportData": "Aucune donnée de rapport trouvée." + "noReportData": "Aucune donnée de rapport trouvée.", + "ai_analyzing": "L'IA analyse...", + "ai_show_details": "Afficher les détails", + "ai_show_less": "Afficher moins", + "ai_likely_causes": "Causes probables :", + "ai_next_steps": "Prochaines étapes suggérées :", + "demo_test_button": "Tester le diagnostic IA", + "demo_hide_button": "Masquer la démo de diagnostic IA", + "demo_panel_title": "Démo de diagnostic IA", + "demo_custom_group": "Personnalisé (peut utiliser Mistral IA)", + "demo_custom_option": "Saisir une alarme personnalisée…", + "demo_custom_placeholder": "ex. UnknownBatteryFault", + "demo_diagnose_button": "Diagnostiquer" } diff --git a/typescript/frontend-marios2/src/lang/it.json b/typescript/frontend-marios2/src/lang/it.json index c1a0c7f41..c24227d15 100644 --- a/typescript/frontend-marios2/src/lang/it.json +++ b/typescript/frontend-marios2/src/lang/it.json @@ -135,5 +135,17 @@ "downloadingBatteryLog": "Il registro della batteria è in fase di download. Verrà salvato nella cartella Download. Attendere prego...", "confirmBatteryLogDownload": "Vuoi davvero scaricare il registro della batteria?", "downloadBatteryLogFailed": "Download del registro della batteria fallito, riprovare.", - "noReportData": "Nessun dato del rapporto trovato." + "noReportData": "Nessun dato del rapporto trovato.", + "ai_analyzing": "L'IA sta analizzando...", + "ai_show_details": "Mostra dettagli", + "ai_show_less": "Mostra meno", + "ai_likely_causes": "Cause probabili:", + "ai_next_steps": "Passi successivi suggeriti:", + "demo_test_button": "Testa diagnosi IA", + "demo_hide_button": "Nascondi demo diagnosi IA", + "demo_panel_title": "Demo diagnosi IA", + "demo_custom_group": "Personalizzato (potrebbe usare Mistral IA)", + "demo_custom_option": "Inserisci allarme personalizzato…", + "demo_custom_placeholder": "es. UnknownBatteryFault", + "demo_diagnose_button": "Diagnostica" }