Add GitHub Actions workflow for Panel app deployment to Hugging Face Spaces with path-based triggers, VS Code project color customization, and comprehensive KPI health check drill-down documentation including group-based filtering, SLA benchmarking, timeline visualization, and complaint sites roadmap
Browse files- .github/workflows/kpi_analysis.yml +55 -0
- .github/workflows/main.yml +16 -0
- .vscode/settings.json +51 -0
- documentations/kpi_health_check_drilldown_graphs_plan.md +247 -0
- documentations/kpi_health_check_improvement_roadmap.md +301 -0
- documentations/kpi_health_check_map_v2_plan.md +120 -0
- hf_spaces/kpi_analysis/Dockerfile +28 -0
- hf_spaces/kpi_analysis/README.md +11 -0
- hf_spaces/kpi_analysis/requirements.txt +6 -0
.github/workflows/kpi_analysis.yml
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Sync Panel (kpi_analysis) to Hugging Face
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches: [main]
|
| 6 |
+
paths:
|
| 7 |
+
- "panel_app/**"
|
| 8 |
+
- "process_kpi/**"
|
| 9 |
+
- "utils/**"
|
| 10 |
+
- "data/**"
|
| 11 |
+
- "physical_db/**"
|
| 12 |
+
- "hf_spaces/kpi_analysis/**"
|
| 13 |
+
- ".github/workflows/kpi_analysis.yml"
|
| 14 |
+
|
| 15 |
+
workflow_dispatch:
|
| 16 |
+
|
| 17 |
+
jobs:
|
| 18 |
+
sync-panel-to-hub:
|
| 19 |
+
runs-on: ubuntu-latest
|
| 20 |
+
steps:
|
| 21 |
+
- uses: actions/checkout@v4
|
| 22 |
+
with:
|
| 23 |
+
fetch-depth: 0
|
| 24 |
+
lfs: false
|
| 25 |
+
|
| 26 |
+
- name: Build Space bundle
|
| 27 |
+
run: |
|
| 28 |
+
rm -rf hf_space
|
| 29 |
+
mkdir -p hf_space
|
| 30 |
+
|
| 31 |
+
# Space root files
|
| 32 |
+
cp -r hf_spaces/kpi_analysis/* hf_space/
|
| 33 |
+
|
| 34 |
+
# App code + shared modules
|
| 35 |
+
cp -r panel_app hf_space/
|
| 36 |
+
cp -r process_kpi hf_space/
|
| 37 |
+
cp -r utils hf_space/
|
| 38 |
+
|
| 39 |
+
# Data files needed by the app
|
| 40 |
+
cp -r data hf_space/
|
| 41 |
+
cp -r physical_db hf_space/
|
| 42 |
+
|
| 43 |
+
- name: Push bundle to Hugging Face Space
|
| 44 |
+
env:
|
| 45 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 46 |
+
run: |
|
| 47 |
+
cd hf_space
|
| 48 |
+
git init
|
| 49 |
+
git config user.name "github-actions"
|
| 50 |
+
git config user.email "[email protected]"
|
| 51 |
+
git add -A
|
| 52 |
+
git commit -m "Deploy Panel Space" || true
|
| 53 |
+
git branch -M main
|
| 54 |
+
git remote add hf https://DavMelchi:[email protected]/spaces/DavMelchi/kpi_analysis
|
| 55 |
+
git push --force hf main
|
.github/workflows/main.yml
CHANGED
|
@@ -2,6 +2,22 @@ name: Sync 2 to Hugging Face hub
|
|
| 2 |
on:
|
| 3 |
push:
|
| 4 |
branches: [main]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
# to run this workflow manually from the Actions tab
|
| 7 |
workflow_dispatch:
|
|
|
|
| 2 |
on:
|
| 3 |
push:
|
| 4 |
branches: [main]
|
| 5 |
+
paths:
|
| 6 |
+
- "app.py"
|
| 7 |
+
- "apps/**"
|
| 8 |
+
- "assets/**"
|
| 9 |
+
- "queries/**"
|
| 10 |
+
- "utils/**"
|
| 11 |
+
- "process_kpi/**"
|
| 12 |
+
- "data/**"
|
| 13 |
+
- "physical_db/**"
|
| 14 |
+
- ".streamlit/**"
|
| 15 |
+
- "requirements.txt"
|
| 16 |
+
- "README.md"
|
| 17 |
+
- "!.github/workflows/kpi_analysis.yml"
|
| 18 |
+
- "!hf_spaces/**"
|
| 19 |
+
- "!panel_app/**"
|
| 20 |
+
- "!process_kpi/kpi_health_check/**"
|
| 21 |
|
| 22 |
# to run this workflow manually from the Actions tab
|
| 23 |
workflow_dispatch:
|
.vscode/settings.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"projectColors.mainColor": "#1e22fa",
|
| 3 |
+
"window.title": "${rootName}${separator}${profileName}${separator}${appName}${separator}${activeEditorShort}${dirty}",
|
| 4 |
+
"workbench.colorCustomizations": {
|
| 5 |
+
"statusBarItem.warningBackground": "#1e22fa",
|
| 6 |
+
"statusBarItem.warningForeground": "#ffffff",
|
| 7 |
+
"statusBarItem.warningHoverBackground": "#1e22fa",
|
| 8 |
+
"statusBarItem.warningHoverForeground": "#ffffff90",
|
| 9 |
+
"statusBarItem.remoteBackground": "#1e22fa",
|
| 10 |
+
"statusBarItem.remoteForeground": "#ffffff",
|
| 11 |
+
"statusBarItem.remoteHoverBackground": "#1e22fa",
|
| 12 |
+
"statusBarItem.remoteHoverForeground": "#ffffff90",
|
| 13 |
+
"statusBar.background": "#1e22fa",
|
| 14 |
+
"statusBar.foreground": "#ffffff",
|
| 15 |
+
"statusBar.border": "#1e22fa",
|
| 16 |
+
"statusBar.debuggingBackground": "#1e22fa",
|
| 17 |
+
"statusBar.debuggingForeground": "#ffffff",
|
| 18 |
+
"statusBar.debuggingBorder": "#1e22fa",
|
| 19 |
+
"statusBar.noFolderBackground": "#1e22fa",
|
| 20 |
+
"statusBar.noFolderForeground": "#ffffff",
|
| 21 |
+
"statusBar.noFolderBorder": "#1e22fa",
|
| 22 |
+
"statusBar.prominentBackground": "#1e22fa",
|
| 23 |
+
"statusBar.prominentForeground": "#ffffff",
|
| 24 |
+
"statusBar.prominentHoverBackground": "#1e22fa",
|
| 25 |
+
"statusBar.prominentHoverForeground": "#ffffff90",
|
| 26 |
+
"focusBorder": "#1e22fa99",
|
| 27 |
+
"progressBar.background": "#1e22fa",
|
| 28 |
+
"textLink.foreground": "#5e62ff",
|
| 29 |
+
"textLink.activeForeground": "#6b6fff",
|
| 30 |
+
"selection.background": "#1115ed",
|
| 31 |
+
"list.highlightForeground": "#1e22fa",
|
| 32 |
+
"list.focusAndSelectionOutline": "#1e22fa99",
|
| 33 |
+
"button.background": "#1e22fa",
|
| 34 |
+
"button.foreground": "#ffffff",
|
| 35 |
+
"button.hoverBackground": "#2b2fff",
|
| 36 |
+
"tab.activeBorderTop": "#2b2fff",
|
| 37 |
+
"pickerGroup.foreground": "#2b2fff",
|
| 38 |
+
"list.activeSelectionBackground": "#1e22fa4d",
|
| 39 |
+
"panelTitle.activeBorder": "#2b2fff",
|
| 40 |
+
"activityBar.activeBorder": "#1e22fa",
|
| 41 |
+
"activityBarBadge.foreground": "#ffffff",
|
| 42 |
+
"activityBarBadge.background": "#1e22fa"
|
| 43 |
+
},
|
| 44 |
+
"projectColors.isActivityBarColored": false,
|
| 45 |
+
"projectColors.isProjectNameColored": false,
|
| 46 |
+
"projectColors.isStatusBarColored": false,
|
| 47 |
+
"projectColors.isTitleBarColored": false,
|
| 48 |
+
"projectColors.setWindowTitle": false,
|
| 49 |
+
"projectColors.name": "OML_DB",
|
| 50 |
+
"projectColors.isActiveItemsColored": true
|
| 51 |
+
}
|
documentations/kpi_health_check_drilldown_graphs_plan.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# KPI Health Check – Plan final UX Drill-down (Graphes / Groupes KPI / SLA) – V2
|
| 2 |
+
|
| 3 |
+
## Objectifs
|
| 4 |
+
|
| 5 |
+
- Rendre le drill-down **plus lisible** pour analyser rapidement un site.
|
| 6 |
+
- Permettre une vue “site” où les KPI sont **regroupés par nature** (success rate, fails, throughput, traffic, availability, etc.).
|
| 7 |
+
- Garder une interaction **Plotly native**: légende cliquable pour masquer/afficher des KPI individuellement.
|
| 8 |
+
- Ajouter un **benchmark** basé sur les SLA/règles (quand c’est pertinent) sans mélanger des KPI hétérogènes.
|
| 9 |
+
|
| 10 |
+
## Non-objectifs (scope control)
|
| 11 |
+
|
| 12 |
+
- Pas de clustering/ML automatique des KPI.
|
| 13 |
+
- Pas de refonte globale de l’UI (on reste dans la section drill-down existante).
|
| 14 |
+
- Pas de comparaison multi-sites sur cette itération (site unique, plus lisible).
|
| 15 |
+
|
| 16 |
+
## Contraintes / invariants
|
| 17 |
+
|
| 18 |
+
- Ne pas casser les fonctionnalités existantes:
|
| 19 |
+
- sélection KPI (`kpi_select`), comparaison multi-KPI (`kpi_compare_select`), normalisation, export drill-down.
|
| 20 |
+
- cache des figures et guard anti-récursion déjà en place.
|
| 21 |
+
- Les KPI n’ont pas tous la même unité: éviter les graphes qui mélangent des échelles incompatibles.
|
| 22 |
+
- Modularité: éviter d’alourdir `panel_app/kpi_health_check_panel.py`. La logique “métier” de drill-down (groupes, sélection KPI, benchmark, figures) doit être extraite en modules.
|
| 23 |
+
|
| 24 |
+
## Modularité / architecture (production)
|
| 25 |
+
|
| 26 |
+
Objectif: garder `panel_app/kpi_health_check_panel.py` comme couche d’orchestration (widgets + callbacks) et déplacer la logique testable dans des modules dédiés.
|
| 27 |
+
|
| 28 |
+
Découpage proposé:
|
| 29 |
+
|
| 30 |
+
- `process_kpi/kpi_health_check/kpi_groups.py`
|
| 31 |
+
- classification KPI -> groupe
|
| 32 |
+
- résolution collisions + règles de priorité
|
| 33 |
+
- sélection top-N (perfs)
|
| 34 |
+
|
| 35 |
+
- `process_kpi/kpi_health_check/benchmarks.py`
|
| 36 |
+
- calcul des métriques SLA (median_recent, %BAD recent)
|
| 37 |
+
- calcul quantiles population (si bonus)
|
| 38 |
+
|
| 39 |
+
- `panel_app/kpi_health_check_drilldown_plots.py`
|
| 40 |
+
- construction des figures Plotly (trend annoté, timeline BAD)
|
| 41 |
+
- conventions `legendgroup` + styles
|
| 42 |
+
|
| 43 |
+
Note: le découpage exact peut être ajusté selon ce qui est le plus simple à tester, mais la contrainte “pas un gros fichier” est un invariant.
|
| 44 |
+
|
| 45 |
+
## Définitions
|
| 46 |
+
|
| 47 |
+
- **KPI “tracé”**: KPI qui apparaît comme une trace Plotly (ligne/markers).
|
| 48 |
+
- **Groupe KPI**: catégorie sémantique (success rate / fails / traffic / etc.) utilisée pour filtrer/organiser.
|
| 49 |
+
- **Benchmark SLA**: comparaison au seuil `sla` des rules, alignée avec la logique `is_bad()`.
|
| 50 |
+
|
| 51 |
+
## 1) Groupes KPI “par nature” (meilleure option)
|
| 52 |
+
|
| 53 |
+
### Proposition retenue
|
| 54 |
+
|
| 55 |
+
- Ajouter un widget: **`kpi_group_select`** (Select / Autocomplete / Radio) avec:
|
| 56 |
+
- `All (selected KPIs)`
|
| 57 |
+
- `Success rate (>= SLA / proche 100%)`
|
| 58 |
+
- `Fails / Drop / Block (<= SLA / proche 0)`
|
| 59 |
+
- `Throughput / Debit`
|
| 60 |
+
- `Traffic / Volume`
|
| 61 |
+
- `Availability / Dispo`
|
| 62 |
+
- `Latency / Delay`
|
| 63 |
+
- `Other`
|
| 64 |
+
|
| 65 |
+
- Ajouter un widget: **`kpi_group_mode`** (Select):
|
| 66 |
+
- `Filter KPI list only (recommended)`
|
| 67 |
+
- `Add top-N KPIs from group to compare`
|
| 68 |
+
|
| 69 |
+
### Comment on conserve la sélection individuelle via Plotly
|
| 70 |
+
|
| 71 |
+
- Le graphe “Trend (site)” affichera plusieurs traces (1 trace = 1 KPI).
|
| 72 |
+
- Les traces seront **groupées** dans la légende via `legendgroup`.
|
| 73 |
+
- La légende Plotly permet:
|
| 74 |
+
- click: hide/show trace
|
| 75 |
+
- double-click: isolate trace
|
| 76 |
+
|
| 77 |
+
=> L’utilisateur peut afficher un groupe complet puis isoler un KPI d’un click.
|
| 78 |
+
|
| 79 |
+
### Méthode de classification (règles)
|
| 80 |
+
|
| 81 |
+
#### Source of truth + résolution des collisions (production-grade)
|
| 82 |
+
|
| 83 |
+
- **Priorité 1 (future-proof)**: overrides explicites (si on ajoute plus tard un mapping KPI->groupe dans un fichier/profil).
|
| 84 |
+
- **Priorité 2**: indices issus des rules (direction + présence SLA) quand disponibles.
|
| 85 |
+
- **Priorité 3**: heuristiques sur le nom du KPI (regex).
|
| 86 |
+
|
| 87 |
+
Règle: **un KPI appartient à 0..1 groupe**. Si plusieurs regex matchent, on prend le premier match selon l’ordre de priorité défini ci-dessous.
|
| 88 |
+
|
| 89 |
+
Patterns initiaux (ajustables):
|
| 90 |
+
|
| 91 |
+
- Success rate: `cssr|success|attach|setup|erab|rrc|\basr\b|\bsr\b`
|
| 92 |
+
- Fails/Drop/Block: `drop|fail|block|reject|deny|accessibility.*fail|retention.*fail`
|
| 93 |
+
- Throughput/debit: `throughput|thp|debit|dl.*rate|ul.*rate|bitrate`
|
| 94 |
+
- Traffic: `traffic|volume|erl|payload|gbytes|gb`
|
| 95 |
+
- Availability: `availability|avail|unavailability|unavail|dispo|disponibil|uptime`
|
| 96 |
+
- Latency: `latency|delay|\brt\b|rtt`
|
| 97 |
+
|
| 98 |
+
Note: on évite de matcher `sr` trop largement (trop de faux positifs). `sr` est uniquement accepté sous forme de mot (`\bsr\b`).
|
| 99 |
+
|
| 100 |
+
## 1.1) Garde-fous performance (obligatoire en prod)
|
| 101 |
+
|
| 102 |
+
- Ajouter un paramètre interne `max_kpis_in_plot` (recommandé: 12).
|
| 103 |
+
- Si la liste de KPI à tracer dépasse `max_kpis_in_plot`:
|
| 104 |
+
- on réduit à top-N selon `% BAD days (recent)` calculé via `is_bad()`.
|
| 105 |
+
- si égalité, tri secondaire: variance recent ou `anomaly_score` si disponible.
|
| 106 |
+
|
| 107 |
+
## 2) Trend “annoté” (lisibilité)
|
| 108 |
+
|
| 109 |
+
### Ajouts sur le graphe trend
|
| 110 |
+
|
| 111 |
+
Pour le KPI sélectionné (ou pour chaque KPI tracé quand affichage en groupe):
|
| 112 |
+
|
| 113 |
+
- **Baseline médiane** (ligne horizontale)
|
| 114 |
+
- **Bande de seuil relatif** (baseline ± `rel_threshold_pct`)
|
| 115 |
+
- **SLA** si présent (ligne horizontale)
|
| 116 |
+
- **Points colorés** par jour:
|
| 117 |
+
- OK vs BAD selon `is_bad()`
|
| 118 |
+
- **Shading des fenêtres**:
|
| 119 |
+
- baseline window
|
| 120 |
+
- recent window
|
| 121 |
+
|
| 122 |
+
Règle: le status OK/BAD doit être **strictement cohérent** avec l’engine (utiliser `is_bad()` et les mêmes paramètres `rel_threshold_pct`, `sla`, `direction`).
|
| 123 |
+
|
| 124 |
+
### Mode groupe
|
| 125 |
+
|
| 126 |
+
- Si le groupe contient plusieurs KPI:
|
| 127 |
+
- par défaut (recommended): le groupe **filtre** la liste de KPI proposée à l’utilisateur; le graphe trace `kpi_select` + `kpi_compare_select`.
|
| 128 |
+
- option alternative: `Add top-N KPIs from group to compare` ajoute automatiquement top-N KPI au `kpi_compare_select` (avec limite `max_kpis_in_plot`).
|
| 129 |
+
|
| 130 |
+
## 3) Timeline “BAD days / streak”
|
| 131 |
+
|
| 132 |
+
- Ajouter un sous-graphe (subplot) ou un second panneau:
|
| 133 |
+
- une barre par jour: 0/1 BAD
|
| 134 |
+
- annotations: longueur de streak et seuil `min_consecutive_days`
|
| 135 |
+
|
| 136 |
+
Objectif: expliquer rapidement le passage DEGRADED -> PERSISTENT.
|
| 137 |
+
|
| 138 |
+
## 4) Benchmark basé sur SLA (et option population)
|
| 139 |
+
|
| 140 |
+
### Benchmark SLA (demandé)
|
| 141 |
+
|
| 142 |
+
- Pour chaque KPI tracé:
|
| 143 |
+
- afficher la **ligne SLA** si `sla` est un nombre.
|
| 144 |
+
- afficher une métrique synthèse (annotation ou mini-table):
|
| 145 |
+
- `% BAD days (recent)` basé sur `is_bad()`.
|
| 146 |
+
- `median_recent` vs `sla`.
|
| 147 |
+
|
| 148 |
+
Cas direction:
|
| 149 |
+
|
| 150 |
+
- `higher_is_better`: BAD si (valeur trop basse vs baseline et/ou < SLA selon la règle `is_bad`).
|
| 151 |
+
- `lower_is_better`: BAD si (valeur trop haute vs baseline et/ou > SLA selon la règle `is_bad`).
|
| 152 |
+
|
| 153 |
+
### Option “population benchmark” (bonus)
|
| 154 |
+
|
| 155 |
+
- Afficher `p50` et `p90` (ou p10/p90 selon direction) sur l’ensemble des sites (ou sur la même City)
|
| 156 |
+
- Important:
|
| 157 |
+
- uniquement pour un KPI à la fois (ou normalisation obligatoire)
|
| 158 |
+
|
| 159 |
+
## 5) UX / Layout proposé
|
| 160 |
+
|
| 161 |
+
Dans la section Drill-down:
|
| 162 |
+
|
| 163 |
+
- Ligne 1: `site_select`, `rat_select`
|
| 164 |
+
- Ligne 2: `kpi_select`, `kpi_compare_select`, `kpi_compare_norm`
|
| 165 |
+
- Ligne 3 (nouveau): `kpi_group_select`, `kpi_group_mode`, (option) `benchmark_mode`
|
| 166 |
+
- Plots:
|
| 167 |
+
- Trend annoté (grand)
|
| 168 |
+
- Timeline BAD (petit, dessous)
|
| 169 |
+
- Heatmap / Histogram (déjà existants)
|
| 170 |
+
|
| 171 |
+
## 6) Impact code (zones à modifier)
|
| 172 |
+
|
| 173 |
+
- `panel_app/kpi_health_check_panel.py`
|
| 174 |
+
- Ajout widgets (group + benchmark options)
|
| 175 |
+
- Orchestration `_update_site_view`:
|
| 176 |
+
- récupérer les dataframes filtrées
|
| 177 |
+
- appeler les fonctions des modules (group selection / benchmark / plot building)
|
| 178 |
+
- pousser les figures dans les panes
|
| 179 |
+
- Cache: intégrer les nouveaux paramètres dans `_drilldown_cache_key`.
|
| 180 |
+
|
| 181 |
+
- `process_kpi/kpi_health_check/kpi_groups.py`
|
| 182 |
+
- nouvelle logique de groupe KPI + top-N
|
| 183 |
+
|
| 184 |
+
- `process_kpi/kpi_health_check/benchmarks.py`
|
| 185 |
+
- nouveaux calculs benchmark SLA (+ population optionnel)
|
| 186 |
+
|
| 187 |
+
- `panel_app/kpi_health_check_drilldown_plots.py`
|
| 188 |
+
- builders Plotly (trend annoté + timeline BAD)
|
| 189 |
+
|
| 190 |
+
Paramètres à ajouter dans la cache key:
|
| 191 |
+
|
| 192 |
+
- `kpi_group_select.value`
|
| 193 |
+
- `kpi_group_mode.value`
|
| 194 |
+
- `benchmark_mode.value`
|
| 195 |
+
- `max_kpis_in_plot`
|
| 196 |
+
|
| 197 |
+
Persistance profil (si on valide):
|
| 198 |
+
|
| 199 |
+
- `kpi_group_selected`
|
| 200 |
+
- `kpi_group_mode`
|
| 201 |
+
- `benchmark_mode`
|
| 202 |
+
- `max_kpis_in_plot` (si exposé)
|
| 203 |
+
|
| 204 |
+
- Optionnel (si on veut isoler la logique):
|
| 205 |
+
- nouveau module utilitaire `process_kpi/kpi_health_check/kpi_groups.py` (mais on peut rester inline pour v1).
|
| 206 |
+
|
| 207 |
+
## 7) Critères d’acceptation
|
| 208 |
+
|
| 209 |
+
- Quand je sélectionne un site/RAT:
|
| 210 |
+
- je vois un trend lisible avec baseline/seuil/SLA
|
| 211 |
+
- je peux masquer/afficher des KPI dans la légende
|
| 212 |
+
- Quand je choisis un groupe:
|
| 213 |
+
- le graphe affiche les KPI du groupe (selon mode)
|
| 214 |
+
- la légende permet d’isoler un KPI
|
| 215 |
+
- Le benchmark SLA apparaît seulement si SLA existe.
|
| 216 |
+
- Aucun effet de bord sur export / cache / callbacks.
|
| 217 |
+
|
| 218 |
+
## 7.1) Risques & mitigations
|
| 219 |
+
|
| 220 |
+
- Noms KPI hétérogènes (vendors) => fallback `Other` + regex ajustables.
|
| 221 |
+
- Trop de KPI à tracer => `max_kpis_in_plot` + top-N.
|
| 222 |
+
- SLA incohérents (NaN/texte) => ignorer SLA et afficher seulement baseline/seuil.
|
| 223 |
+
|
| 224 |
+
## 8) Ordre de livraison (recommandé)
|
| 225 |
+
|
| 226 |
+
1. Ajouter widgets groupes + logique de sélection KPI (garde-fous perf)
|
| 227 |
+
2. Trend annoté (baseline + seuil + SLA)
|
| 228 |
+
3. Timeline BAD/streak
|
| 229 |
+
4. Population benchmark (optionnel)
|
| 230 |
+
|
| 231 |
+
## Definition of Done (DoD)
|
| 232 |
+
|
| 233 |
+
- Démo: 1 site 2G + 1 site 3G + 1 site LTE.
|
| 234 |
+
- Vérifier que:
|
| 235 |
+
- double-clic tables => drill-down OK.
|
| 236 |
+
- cache drill-down fonctionne (pas de lag, pas de rerender inutile).
|
| 237 |
+
- export drill-down OK.
|
| 238 |
+
|
| 239 |
+
## Questions à valider
|
| 240 |
+
|
| 241 |
+
- Quels groupes minimum tu veux (liste finale) ?
|
| 242 |
+
- En mode groupe, tu veux:
|
| 243 |
+
- tracer tous les KPI du groupe ? ou
|
| 244 |
+
- limiter à ceux cochés dans `Compare KPIs` ? (recommandé)
|
| 245 |
+
- Pour le benchmark:
|
| 246 |
+
- SLA uniquement (demandé)
|
| 247 |
+
- +option population (bonus) ?
|
documentations/kpi_health_check_improvement_roadmap.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# KPI Health Check (Panel) — Plan d’amélioration (Roadmap)
|
| 2 |
+
|
| 3 |
+
## 0) Objectif
|
| 4 |
+
|
| 5 |
+
Consolider l’app **KPI Health Check** pour une utilisation “NPO / exploitation” plus fluide et plus actionnable.
|
| 6 |
+
|
| 7 |
+
Axes demandés:
|
| 8 |
+
|
| 9 |
+
- **[A] Exploitation / priorisation** (alert pack, ops queue, snapshot/delta, RCA hints)
|
| 10 |
+
- **[B] Visualisation** (map des sites, corrélation KPI)
|
| 11 |
+
|
| 12 |
+
Décision prise:
|
| 13 |
+
|
| 14 |
+
- **“Complaint sites only” = UI + export Excel (les deux)**
|
| 15 |
+
|
| 16 |
+
Non-scope:
|
| 17 |
+
|
| 18 |
+
- Génération PDF / evidence pack (optionnel, non prioritaire).
|
| 19 |
+
|
| 20 |
+
## 0.1) Principes (invariants)
|
| 21 |
+
|
| 22 |
+
- **Compatibilité**: ne pas casser l’existant (tables, drill-down, export principal).
|
| 23 |
+
- **Performance**: éviter les recalculs inutiles (réutiliser caches/versions déjà en place dans l’UI).
|
| 24 |
+
- **Robustesse données**: gérer proprement `NO_DATA`, colonnes manquantes, coordonnées absentes.
|
| 25 |
+
- **Export Excel**: garder des noms d’onglets **stables** (important pour les utilisateurs qui automatisent).
|
| 26 |
+
|
| 27 |
+
---
|
| 28 |
+
|
| 29 |
+
## 1) État actuel (déjà en place)
|
| 30 |
+
|
| 31 |
+
### 1.1 Flux de l’app
|
| 32 |
+
|
| 33 |
+
- Upload KPI **2G/3G/LTE** (CSV/ZIP)
|
| 34 |
+
- Normalisation `date_only`, `site_code`, enrichissement éventuel `City/Lat/Lon`
|
| 35 |
+
- Construction + édition des **rules** (`direction`, `sla`)
|
| 36 |
+
- Health-check: `OK / DEGRADED / PERSISTENT_DEGRADED / RESOLVED / NO_DATA`
|
| 37 |
+
- Synthèses:
|
| 38 |
+
- `Site_Summary`
|
| 39 |
+
- `MultiRAT_Summary` (score criticité)
|
| 40 |
+
- `Top_Anomalies` (score anomaly)
|
| 41 |
+
- Drill-down: trend + heatmap + histogram
|
| 42 |
+
- Export Excel (Datasets / KPI Rules / Summary / Status / MultiRAT / Top)
|
| 43 |
+
- Gestion: presets + profiles
|
| 44 |
+
- Filtre existant: checkbox **Only complaint sites** (filtre les tables multi-rat / top anomalies)
|
| 45 |
+
|
| 46 |
+
### 1.2 Fichiers “source of truth”
|
| 47 |
+
|
| 48 |
+
- UI:
|
| 49 |
+
- `panel_app/kpi_health_check_panel.py`
|
| 50 |
+
- Export:
|
| 51 |
+
- `process_kpi/kpi_health_check/export.py`
|
| 52 |
+
- Calculs:
|
| 53 |
+
- `process_kpi/kpi_health_check/engine.py`
|
| 54 |
+
- `process_kpi/kpi_health_check/multi_rat.py`
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
+
|
| 58 |
+
## 2) Roadmap (ordre recommandé)
|
| 59 |
+
|
| 60 |
+
### Phase 1 — Complaint sites only (UI + Export) (priorité haute)
|
| 61 |
+
|
| 62 |
+
#### 2.1 UI: onglet dédié “Complaint sites only”
|
| 63 |
+
|
| 64 |
+
But: ne plus dépendre d’un filtre à cocher; fournir un écran prêt à l’emploi.
|
| 65 |
+
|
| 66 |
+
Contenu onglet:
|
| 67 |
+
|
| 68 |
+
- `MultiRAT Summary (Complaint)`
|
| 69 |
+
- `Top Anomalies (Complaint)`
|
| 70 |
+
- Optionnel: un petit “mini résumé” (counts)
|
| 71 |
+
|
| 72 |
+
Spécifications:
|
| 73 |
+
|
| 74 |
+
- Les tables doivent être **toujours** filtrées sur `is_complaint_site == True`.
|
| 75 |
+
- Les interactions existantes restent:
|
| 76 |
+
- double-click (ou click) pour appliquer le drill-down (`_handle_double_click` + `_apply_drilldown_selection`).
|
| 77 |
+
|
| 78 |
+
Implémentation (point d’intégration):
|
| 79 |
+
|
| 80 |
+
- Créer 2 nouveaux `Tabulator` dans `kpi_health_check_panel.py`, alimentés par une fonction de refresh dédiée.
|
| 81 |
+
- Réutiliser la logique existante de flag `is_complaint_site` déjà posée dans `_apply_complaint_flags()`.
|
| 82 |
+
|
| 83 |
+
Critères d’acceptation:
|
| 84 |
+
|
| 85 |
+
- Après `Run health check`, l’onglet affiche uniquement les complaint sites.
|
| 86 |
+
- Les filtres “city / min score / top RAT / status” ne doivent pas casser l’onglet.
|
| 87 |
+
- Si la liste plaintes est vide/non trouvée, l’onglet reste vide (ou affiche un message) **sans erreur**.
|
| 88 |
+
|
| 89 |
+
#### 2.2 Export Excel: feuilles “Complaint sites only”
|
| 90 |
+
|
| 91 |
+
But: avoir un export directement partageable “ops / plaintes”.
|
| 92 |
+
|
| 93 |
+
Feuilles proposées:
|
| 94 |
+
|
| 95 |
+
- `Complaint_MultiRAT`
|
| 96 |
+
- `Complaint_Top_Anomalies`
|
| 97 |
+
|
| 98 |
+
Option bonus (si utile):
|
| 99 |
+
|
| 100 |
+
- `Complaint_Ops_Queue` (par site) = tri par criticité pondérée trafic si dispo.
|
| 101 |
+
|
| 102 |
+
Implémentation (point d’intégration):
|
| 103 |
+
|
| 104 |
+
- Étendre `process_kpi/kpi_health_check/export.py`:
|
| 105 |
+
- soit en ajoutant de nouveaux paramètres optionnels,
|
| 106 |
+
- soit en ajoutant des dfs supplémentaires en fin de liste (compatibilité).
|
| 107 |
+
- Dans `kpi_health_check_panel.py`, construire les df “complaint only” à partir de `current_multirat_df` / `current_top_anomalies_df` ou des raw (selon besoin) et les fournir à l’export.
|
| 108 |
+
|
| 109 |
+
Critères d’acceptation:
|
| 110 |
+
|
| 111 |
+
- L’export contient les 2 feuilles complaint.
|
| 112 |
+
- Les feuilles complaint restent vides si aucune liste plaintes n’est chargée et aucun fichier `data/complaint_sites.*` n’est trouvé.
|
| 113 |
+
- Les noms d’onglets restent < 31 caractères et sans caractères invalides (contrainte Excel).
|
| 114 |
+
|
| 115 |
+
---
|
| 116 |
+
|
| 117 |
+
### Phase 2 — Ops Queue + Alert Pack (priorité haute)
|
| 118 |
+
|
| 119 |
+
#### 2.3 “Ops Queue” (table unique priorisée)
|
| 120 |
+
|
| 121 |
+
But: une table de travail qui regroupe le besoin exploitation:
|
| 122 |
+
|
| 123 |
+
- 1 ligne par site
|
| 124 |
+
- priorité = criticité (pondérée trafic si dispo)
|
| 125 |
+
- infos clés: `impacted_rats`, `persistent_kpis_total`, `degraded_kpis_total`, `resolved_kpis_total`, `is_complaint_site`, trafic
|
| 126 |
+
|
| 127 |
+
Implémentation:
|
| 128 |
+
|
| 129 |
+
- Construire `ops_queue_df` à partir de `current_multirat_raw` (qui contient déjà scores + flags).
|
| 130 |
+
- Ajouter un onglet UI “Ops Queue” + une feuille Excel.
|
| 131 |
+
|
| 132 |
+
#### 2.4 “Alert Pack” export court
|
| 133 |
+
|
| 134 |
+
But: un export “prêt à envoyer” (résumé + ops queue + top anomalies) sans l’exhaustivité.
|
| 135 |
+
|
| 136 |
+
- Nouveau bouton export, ou une option dans l’export existant.
|
| 137 |
+
|
| 138 |
+
---
|
| 139 |
+
|
| 140 |
+
### Phase 3 — Snapshot + Delta (priorité haute)
|
| 141 |
+
|
| 142 |
+
#### 2.5 Snapshot de run
|
| 143 |
+
|
| 144 |
+
But: figer un run (résultats + paramètres + rules) pour audit et comparaison.
|
| 145 |
+
|
| 146 |
+
Format recommandé:
|
| 147 |
+
|
| 148 |
+
- `json` (simple) ou `parquet` (plus robuste pour gros volumes). Pour MVP: JSON.
|
| 149 |
+
|
| 150 |
+
Contenu snapshot (proposition):
|
| 151 |
+
|
| 152 |
+
- `snapshot_version`: int
|
| 153 |
+
- `created_at`: ISO datetime
|
| 154 |
+
- `profile_config`: dict (baseline/recent/thr/min streak + filtres)
|
| 155 |
+
- `rules_df`: list[dict] (records)
|
| 156 |
+
- `multirat_df`: list[dict]
|
| 157 |
+
- `top_anomalies_df`: list[dict]
|
| 158 |
+
|
| 159 |
+
UI:
|
| 160 |
+
|
| 161 |
+
- `FileDownload` “Save snapshot”
|
| 162 |
+
- `FileInput` “Load snapshot”
|
| 163 |
+
|
| 164 |
+
#### 2.6 Delta entre runs
|
| 165 |
+
|
| 166 |
+
But: sortir les variations entre snapshot chargé et run courant:
|
| 167 |
+
|
| 168 |
+
- `New degraded`
|
| 169 |
+
- `Still degraded`
|
| 170 |
+
- `Resolved`
|
| 171 |
+
- `Severity up / down`
|
| 172 |
+
|
| 173 |
+
Sorties:
|
| 174 |
+
|
| 175 |
+
- onglet UI “Delta”
|
| 176 |
+
- feuille Excel “Delta”
|
| 177 |
+
|
| 178 |
+
---
|
| 179 |
+
|
| 180 |
+
### Phase 4 — Visualisation (Map + Corrélation) (priorité moyenne)
|
| 181 |
+
|
| 182 |
+
#### 2.7 Map des sites dégradés
|
| 183 |
+
|
| 184 |
+
But: voir des clusters (zone / ville) et naviguer vers le drill-down.
|
| 185 |
+
|
| 186 |
+
Pré-requis:
|
| 187 |
+
|
| 188 |
+
- `Latitude` / `Longitude` disponibles (normalisation ou physical db).
|
| 189 |
+
|
| 190 |
+
Affichage:
|
| 191 |
+
|
| 192 |
+
- Plotly `scatter_mapbox` (style `open-street-map`) ou `scatter_geo`
|
| 193 |
+
- Couleur = status (ou degraded/persistent)
|
| 194 |
+
- Taille = criticité (weighted si dispo)
|
| 195 |
+
|
| 196 |
+
Interaction:
|
| 197 |
+
|
| 198 |
+
- click point => sélection site dans drill-down
|
| 199 |
+
|
| 200 |
+
#### 2.8 KPI Correlation Explorer
|
| 201 |
+
|
| 202 |
+
But: RCA rapide sur un site/RAT.
|
| 203 |
+
|
| 204 |
+
- Matrice corrélation des KPI sélectionnés (Pearson/Spearman)
|
| 205 |
+
- fenêtre: `recent` / `baseline` / `full filtered range`
|
| 206 |
+
- sortie: heatmap Plotly (`px.imshow`)
|
| 207 |
+
|
| 208 |
+
---
|
| 209 |
+
|
| 210 |
+
## 3) RCA Hints (bonus mais très utile)
|
| 211 |
+
|
| 212 |
+
Objectif: rendre `Top_Anomalies` plus actionnable.
|
| 213 |
+
|
| 214 |
+
Ajouts colonnes:
|
| 215 |
+
|
| 216 |
+
- `delta_pct`
|
| 217 |
+
- `sla_breached`
|
| 218 |
+
- `reason` (texte)
|
| 219 |
+
- `data_quality_flag`
|
| 220 |
+
|
| 221 |
+
Ces colonnes peuvent être calculées:
|
| 222 |
+
|
| 223 |
+
- lors de la génération de `Top_Anomalies` (dans `multi_rat.py`),
|
| 224 |
+
- ou côté Panel lors du refresh (plus rapide à itérer).
|
| 225 |
+
|
| 226 |
+
---
|
| 227 |
+
|
| 228 |
+
## 4) Découpage technique (recommandé)
|
| 229 |
+
|
| 230 |
+
Pour éviter d’alourdir `kpi_health_check_panel.py`:
|
| 231 |
+
|
| 232 |
+
- `process_kpi/kpi_health_check/snapshot.py`
|
| 233 |
+
- save/load snapshot + validation version
|
| 234 |
+
- compute delta
|
| 235 |
+
|
| 236 |
+
- `process_kpi/kpi_health_check/ops_queue.py`
|
| 237 |
+
- build ops queue df
|
| 238 |
+
|
| 239 |
+
- `panel_app/kpi_health_check_maps.py`
|
| 240 |
+
- build map figure
|
| 241 |
+
|
| 242 |
+
- `process_kpi/kpi_health_check/correlation.py`
|
| 243 |
+
- build correlation matrix
|
| 244 |
+
|
| 245 |
+
---
|
| 246 |
+
|
| 247 |
+
## 4.1) Qualité des données & garde-fous (à intégrer dès Sprint 1)
|
| 248 |
+
|
| 249 |
+
- **Validation d’inputs**:
|
| 250 |
+
- dataset vide / pas de `date_only` / pas de `site_code`
|
| 251 |
+
- aucun point dans la `analysis_range`
|
| 252 |
+
- **Validation complaint list**:
|
| 253 |
+
- parsing robuste (csv/txt/xlsx déjà prévu)
|
| 254 |
+
- normalisation des codes site (cast int + extraction regex si besoin)
|
| 255 |
+
- **Fail-safe**: si `is_complaint_site` n’existe pas, ne pas crasher (considérer `False`).
|
| 256 |
+
|
| 257 |
+
## 4.2) Performance / mémoire (à surveiller)
|
| 258 |
+
|
| 259 |
+
- Limiter le volume affiché dans les tables (ex: top N) quand nécessaire.
|
| 260 |
+
- Éviter les copies inutiles de DataFrames lors des refresh.
|
| 261 |
+
- Garder les calculs lourds dans `process_kpi/*` et l’UI comme orchestration.
|
| 262 |
+
|
| 263 |
+
## 4.3) Tests rapides (smoke tests) / DoD
|
| 264 |
+
|
| 265 |
+
Minimum avant de considérer une phase “done”:
|
| 266 |
+
|
| 267 |
+
- Charger un petit sample 2G/3G/LTE et exécuter `Load` + `Run` sans erreur.
|
| 268 |
+
- Vérifier:
|
| 269 |
+
- export Excel principal
|
| 270 |
+
- export complaint
|
| 271 |
+
- double-click tables => drill-down
|
| 272 |
+
- aucun crash si complaint list absente
|
| 273 |
+
|
| 274 |
+
---
|
| 275 |
+
|
| 276 |
+
## 5) Critères de réussite globaux
|
| 277 |
+
|
| 278 |
+
- **Exploitation**: obtenir une liste priorisée + top anomalies complaint en < 1 minute.
|
| 279 |
+
- **Partage**: export Excel avec onglets complaint + delta.
|
| 280 |
+
- **Visualisation**: map cliquable et corrélation sur drill-down.
|
| 281 |
+
|
| 282 |
+
---
|
| 283 |
+
|
| 284 |
+
## 6) Plan de livraison (sprints)
|
| 285 |
+
|
| 286 |
+
- Sprint 1: Complaint UI tab + Export complaint sheets
|
| 287 |
+
- Sprint 2: Ops Queue + Alert Pack
|
| 288 |
+
- Sprint 3: Snapshot + Delta
|
| 289 |
+
- Sprint 4: Map + Correlation explorer
|
| 290 |
+
- Sprint 5 (option): RCA hints (reason/tags)
|
| 291 |
+
|
| 292 |
+
---
|
| 293 |
+
|
| 294 |
+
## 7) Risques & mitigations
|
| 295 |
+
|
| 296 |
+
- **Volumes importants** (beaucoup de sites/KPI/jours):
|
| 297 |
+
- mitigation: top-N dans certaines vues + pagination Tabulator + éviter les figures avec trop de traces.
|
| 298 |
+
- **Coordonnées manquantes** (pas de Lat/Lon):
|
| 299 |
+
- mitigation: la map doit être optionnelle et afficher un message clair si données insuffisantes.
|
| 300 |
+
- **Excel / automatisation utilisateur** (noms d’onglets attendus):
|
| 301 |
+
- mitigation: ajouter les nouveaux onglets sans renommer les existants.
|
documentations/kpi_health_check_map_v2_plan.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# KPI Health Check – Map v2 (Mode exploitation + recherche)
|
| 2 |
+
|
| 3 |
+
## Objectif
|
| 4 |
+
|
| 5 |
+
Améliorer l’onglet **Map** pour l’exploitation quotidienne (≈ 0–3000 sites) avec:
|
| 6 |
+
|
| 7 |
+
- Vue géographique lisible immédiatement (zoom/centrage automatique)
|
| 8 |
+
- Encodage visuel orienté actions (status + criticité)
|
| 9 |
+
- Recherche rapide (site_code / City) + navigation vers le drill-down
|
| 10 |
+
- Performance stable (pas de lag, pas de sur-affichage de labels)
|
| 11 |
+
|
| 12 |
+
## Non-objectifs
|
| 13 |
+
|
| 14 |
+
- RCA hints / tags automatiques (Sprint 5)
|
| 15 |
+
- Clustering avancé “maison” (geohash/grid) si non indispensable
|
| 16 |
+
- Historique temporel sur la map
|
| 17 |
+
|
| 18 |
+
## UX / Fonctionnel
|
| 19 |
+
|
| 20 |
+
### A. Encodage visuel
|
| 21 |
+
|
| 22 |
+
- **Taille**: criticité (déjà en place)
|
| 23 |
+
- **Couleur**: status dominant du site (ex: `PERSISTENT_DEGRADED`, `DEGRADED`, `RESOLVED`, `NO_DATA`)
|
| 24 |
+
- **Label**: `site_code` (déjà en place) limité à un Top-N configurable
|
| 25 |
+
|
| 26 |
+
### B. Fit bounds (centrage auto)
|
| 27 |
+
|
| 28 |
+
- Bouton (ou comportement automatique) “Fit to points”
|
| 29 |
+
- À chaque refresh map, centrer/zoomer sur l’ensemble des points affichés (après filtres)
|
| 30 |
+
|
| 31 |
+
### C. Filtres Map (mode exploitation)
|
| 32 |
+
|
| 33 |
+
Widgets simples dans l’onglet Map:
|
| 34 |
+
- **Top N sites** (par score) + option “All”
|
| 35 |
+
- **Only complaint sites** (reprend le bool déjà existant dans le sidebar)
|
| 36 |
+
- **RAT impacted** (2G/3G/LTE/Any) basé sur `impacted_rats`
|
| 37 |
+
- Option: “Only persistent” (status)
|
| 38 |
+
|
| 39 |
+
### D. Recherche (rapide)
|
| 40 |
+
|
| 41 |
+
- Champ `Search` (texte):
|
| 42 |
+
- accepte `site_code` (entier) ou `City` (substring)
|
| 43 |
+
- résultat:
|
| 44 |
+
- si `site_code` trouvé: centre la map sur le site + sélectionne le site (drill-down)
|
| 45 |
+
- si `City`: filtre/centre sur les sites de la ville + propose une petite liste (Top 20) cliquable
|
| 46 |
+
|
| 47 |
+
### E. Interaction
|
| 48 |
+
|
| 49 |
+
- Click point => drill-down (déjà en place)
|
| 50 |
+
- Option: bouton “Open Drill-down” à côté des infos (si on ajoute un mini panneau résumé)
|
| 51 |
+
|
| 52 |
+
## Données / Hypothèses
|
| 53 |
+
|
| 54 |
+
- Les coords sont présentes via `Latitude/Longitude` (venant du `physical_db`)
|
| 55 |
+
- `current_multirat_raw` contient:
|
| 56 |
+
- `site_code`
|
| 57 |
+
- scores (`criticality_score_weighted` ou `criticality_score`)
|
| 58 |
+
- `impacted_rats`
|
| 59 |
+
- compteurs persistent/degraded/resolved
|
| 60 |
+
- Les status par RAT existent dans `current_status_df` (par `site_code`, `RAT`, `status`)
|
| 61 |
+
|
| 62 |
+
## Plan d’implémentation (Map v2)
|
| 63 |
+
|
| 64 |
+
### 1) Calcul du status dominant
|
| 65 |
+
|
| 66 |
+
- À partir de `current_status_df`, agréger par `site_code`:
|
| 67 |
+
- règle: `PERSISTENT_DEGRADED` > `DEGRADED` > `RESOLVED` > `OK` > `NO_DATA`
|
| 68 |
+
- produire une colonne `dominant_status`
|
| 69 |
+
- Merge dans le DF map
|
| 70 |
+
|
| 71 |
+
### 2) Color mapping
|
| 72 |
+
|
| 73 |
+
- Définir une palette stable:
|
| 74 |
+
- `PERSISTENT_DEGRADED` -> rouge foncé
|
| 75 |
+
- `DEGRADED` -> rouge/orange
|
| 76 |
+
- `RESOLVED` -> vert
|
| 77 |
+
- `OK` -> bleu
|
| 78 |
+
- `NO_DATA` -> gris
|
| 79 |
+
- Appliquer via `px.scatter_mapbox(..., color='dominant_status')` + `category_orders`
|
| 80 |
+
|
| 81 |
+
### 3) Fit bounds
|
| 82 |
+
|
| 83 |
+
- Calculer `lat_min/max`, `lon_min/max` sur les points affichés
|
| 84 |
+
- Utiliser `fig.update_layout(mapbox=dict(bounds=...))` ou `center/zoom` estimé
|
| 85 |
+
- Ajouter un bouton “Fit to points” si on veut éviter un recentrage automatique trop agressif
|
| 86 |
+
|
| 87 |
+
### 4) Recherche
|
| 88 |
+
|
| 89 |
+
- Widget `AutocompleteInput` ou `TextInput` + bouton `Go`
|
| 90 |
+
- Si nombre:
|
| 91 |
+
- set `site_select` + centre map
|
| 92 |
+
- Si texte:
|
| 93 |
+
- filtrer sur `City` et afficher une liste cliquable (Tabulator ou Select)
|
| 94 |
+
|
| 95 |
+
### 5) Filtres Map
|
| 96 |
+
|
| 97 |
+
- Implémenter filtres (TopN / complaint / RAT impacted / status) avant rendu
|
| 98 |
+
- Ajouter widgets correspondants dans l’onglet Map
|
| 99 |
+
|
| 100 |
+
### 6) Tests / Critères de réussite
|
| 101 |
+
|
| 102 |
+
- 3000 sites: refresh map < 2s (hors 1er chargement)
|
| 103 |
+
- Search par `site_code`: centre + drill-down correct
|
| 104 |
+
- Search par `City`: restreint l’affichage et fit bounds
|
| 105 |
+
- Les labels restent limités (Top-N)
|
| 106 |
+
|
| 107 |
+
## Risques / Points d’attention
|
| 108 |
+
|
| 109 |
+
- Trop de texte (labels) => perf (mitigation: Top-N déjà fait)
|
| 110 |
+
- Fit bounds automatique peut “bouger” la map trop souvent (mitigation: bouton / toggle)
|
| 111 |
+
- `dominant_status` doit être robuste même si `current_status_df` vide
|
| 112 |
+
|
| 113 |
+
## Estimation
|
| 114 |
+
|
| 115 |
+
- Status dominant + colors: 45–90 min
|
| 116 |
+
- Fit bounds: 20–40 min
|
| 117 |
+
- Recherche: 1–2 h
|
| 118 |
+
- Filtres map: 1–2 h
|
| 119 |
+
|
| 120 |
+
Total: ~3–6 h selon niveau de polish.
|
hf_spaces/kpi_analysis/Dockerfile
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.11-slim
|
| 2 |
+
|
| 3 |
+
RUN useradd -m -u 1000 user
|
| 4 |
+
WORKDIR /app
|
| 5 |
+
|
| 6 |
+
COPY --chown=user:user requirements.txt /app/requirements.txt
|
| 7 |
+
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
| 8 |
+
|
| 9 |
+
COPY --chown=user:user . /app
|
| 10 |
+
|
| 11 |
+
USER user
|
| 12 |
+
EXPOSE 7860
|
| 13 |
+
|
| 14 |
+
CMD [
|
| 15 |
+
"panel",
|
| 16 |
+
"serve",
|
| 17 |
+
"panel_app/panel_portal.py",
|
| 18 |
+
"--address",
|
| 19 |
+
"0.0.0.0",
|
| 20 |
+
"--port",
|
| 21 |
+
"7860",
|
| 22 |
+
"--allow-websocket-origin",
|
| 23 |
+
"*",
|
| 24 |
+
"--num-procs",
|
| 25 |
+
"1",
|
| 26 |
+
"--log-level",
|
| 27 |
+
"info"
|
| 28 |
+
]
|
hf_spaces/kpi_analysis/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: KPI Analysis (Panel)
|
| 3 |
+
emoji: "📊"
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: red
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
pinned: false
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
This Space runs the Panel portal located at `panel_app/panel_portal.py`.
|
hf_spaces/kpi_analysis/requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
panel>=1.4
|
| 2 |
+
bokeh>=3.4
|
| 3 |
+
pandas>=2.0
|
| 4 |
+
numpy>=1.23
|
| 5 |
+
plotly>=5.0
|
| 6 |
+
xlsxwriter>=3.0
|