Files
serv_benchmark/docs/FEATURE_INTELLIGENT_CLASSIFICATION.md
Gilles Soulier c67befc549 addon
2026-01-05 16:08:01 +01:00

508 lines
13 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Feature: Classification intelligente des périphériques
## Vue d'ensemble
Détection automatique du `type_principal` et `sous_type` des périphériques basée sur l'analyse du contenu CLI et des fichiers markdown.
Le système analyse intelligemment :
- Le contenu de la sortie `lsusb -v`
- Les fichiers markdown importés
- Les vendor/product IDs
- Les classes USB
- Les chaînes de caractères (manufacturer, product)
## Fonctionnement
### Stratégies de détection (par ordre de priorité)
1. **USB Device Class** - Basé sur `bDeviceClass`
- `08` → Clé USB (Mass Storage)
- `03` → HID (Clavier/Souris, affiné par mots-clés)
- `0e` → Webcam (Video)
- `09` → Hub
- `e0` → Bluetooth (Wireless Controller)
2. **Vendor/Product Info** - Analyse des IDs et chaînes
- Recherche de mots-clés dans manufacturer/product strings
- Matching sur vendor_id/product_id connus
3. **Analyse du contenu CLI** - Mots-clés dans `lsusb -v`
- WiFi : `wifi`, `wireless`, `802.11`, `wlan`, `rtl81xx`, `mt76xx`
- Bluetooth : `bluetooth`, `bcm20702`
- Storage : `mass storage`, `flash drive`, `sandisk`
- Hub : `usb hub`, `multi-port`
- Keyboard : `keyboard`, `clavier`, `hid.*keyboard`
- Mouse : `mouse`, `souris`
- Webcam : `webcam`, `camera`, `uvc`
- Ethernet : `ethernet`, `gigabit`, `rtl81xx.*ethernet`
4. **Analyse du markdown** - Mots-clés dans le fichier .md
- Même système de patterns que pour le CLI
- Utilisé lors de l'import de fichiers markdown
### Système de scoring
- Chaque mot-clé trouvé augmente le score d'un type
- Le type avec le meilleur score est sélectionné
- Si aucun match : fallback sur `("USB", "Autre")`
## Exemples de détection
### Exemple 1 : Adaptateur WiFi
**Input CLI :**
```
Bus 002 Device 005: ID 0bda:8176 Realtek RTL8188CUS
bDeviceClass 0
iManufacturer 1 Realtek
iProduct 2 802.11n WLAN Adapter
```
**Détection :**
- Mots-clés trouvés : `realtek`, `rtl8176`, `802.11n`, `wlan`
- **Résultat : `type_principal = "USB"`, `sous_type = "Adaptateur WiFi"`**
### Exemple 2 : Clé USB
**Input CLI :**
```
Bus 002 Device 003: ID 0781:55ab SanDisk Corp.
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
iManufacturer 1 USB
iProduct 2 SanDisk 3.2Gen1
Interface Class: 08 — Mass Storage
```
**Détection :**
- Device Class 08 trouvé → Mass Storage
- Mots-clés : `sandisk`, `mass storage`
- **Résultat : `type_principal = "USB"`, `sous_type = "Clé USB"`**
### Exemple 3 : Bluetooth
**Input CLI :**
```
Bus 001 Device 004: ID 0b05:17cb ASUSTek
bDeviceClass 224 Wireless
iManufacturer 1 Broadcom Corp
iProduct 2 BCM20702A0
```
**Détection :**
- Device Class e0 (Wireless Controller)
- Mots-clés : `bluetooth`, `bcm20702`
- **Résultat : `type_principal = "Bluetooth"`, `sous_type = "Autre"`**
### Exemple 4 : Import markdown
**Fichier : `ID_0bda_8176.md`**
```markdown
# USB Device ID 0bda_8176
## Description
Realtek RTL8188CUS WiFi USB
```
**Détection :**
- Analyse du contenu markdown
- Mots-clés : `wi-fi`, `usb`, `realtek`
- IDs extraits du nom de fichier : `vendor_id=0x0bda`, `product_id=0x8176`
- **Résultat : `type_principal = "USB"`, `sous_type = "Adaptateur WiFi"`**
## Fichiers modifiés
### Backend
#### 1. Nouveau classificateur
**`backend/app/utils/device_classifier.py`** (NOUVEAU)
Classe `DeviceClassifier` avec méthodes :
```python
@staticmethod
def classify_device(cli_content: Optional[str] = None,
synthese_content: Optional[str] = None,
device_info: Optional[Dict] = None) -> Tuple[str, str]:
"""
Classify a device using all available information
Returns: (type_principal, sous_type)
"""
```
Dictionnaire `TYPE_KEYWORDS` - Mapping (type, sous_type) → liste de patterns regex
Dictionnaire `USB_CLASS_MAPPING` - Mapping USB class code → (type, sous_type)
#### 2. Endpoints modifiés
**`backend/app/api/endpoints/peripherals.py`**
**Ligne 28** - Import du classificateur :
```python
from app.utils.device_classifier import DeviceClassifier
```
**Ligne 737-746** - USB CLI extraction avec détection intelligente :
```python
# Intelligent classification of device type
type_principal, sous_type = DeviceClassifier.classify_device(
cli_content=device_section,
synthese_content=None,
device_info=device_info
)
# Refine Bluetooth subtype if needed
if type_principal == "Bluetooth" and sous_type == "Autre":
sous_type = DeviceClassifier.refine_bluetooth_subtype(device_section)
```
**Ligne 589-614** - Import markdown avec détection intelligente :
```python
# Intelligent classification of device type from markdown content
type_principal = parsed_data.get("type_principal")
sous_type = parsed_data.get("sous_type")
if not type_principal or not sous_type:
device_info = {
"vendor_id": parsed_data.get("caracteristiques_specifiques", {}).get("vendor_id"),
"product_id": parsed_data.get("caracteristiques_specifiques", {}).get("product_id"),
"manufacturer": parsed_data.get("marque"),
"product": parsed_data.get("modele"),
"device_class": parsed_data.get("caracteristiques_specifiques", {}).get("device_class"),
}
detected_type_principal, detected_sous_type = DeviceClassifier.classify_device(
cli_content=None,
synthese_content=md_content,
device_info=device_info
)
if not type_principal:
type_principal = detected_type_principal
if not sous_type:
sous_type = detected_sous_type
```
**Ligne 625** - Stockage de la synthèse markdown :
```python
"synthese": md_content, # Store the full markdown content in synthese field
```
### Frontend
**`frontend/js/peripherals.js`** - Ligne 452-477
Amélioration du pré-remplissage avec logique robuste :
```javascript
// Set type_principal and wait for subtypes to load before setting sous_type
if (suggested.type_principal) {
document.getElementById('type_principal').value = suggested.type_principal;
// Trigger the change event to load subtypes
const typePrincipalSelect = document.getElementById('type_principal');
const changeEvent = new Event('change');
typePrincipalSelect.dispatchEvent(changeEvent);
// Wait for subtypes to load, then set sous_type
if (suggested.sous_type) {
// Use a Promise-based approach with retry logic
const setSousType = async () => {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
const sousTypeSelect = document.getElementById('sous_type');
if (sousTypeSelect && sousTypeSelect.options.length > 1) {
// Options are loaded
sousTypeSelect.value = suggested.sous_type;
break;
}
}
};
setSousType();
}
}
```
**Amélioration** : Retry logic avec vérification du chargement des options au lieu d'un simple timeout
## Flows utilisateur
### Flow 1 : Import USB avec CLI
1. Utilisateur clique **"Importer USB"**
2. Popup : colle la sortie de `lsusb -v`
3. Click **"Importer"**
4. Backend détecte les périphériques
5. Popup 2 : liste avec radio buttons
6. Utilisateur sélectionne un périphérique
7. Click **"Finaliser"**
8. **Backend analyse le CLI et détecte automatiquement le type**
9. Formulaire s'ouvre avec :
- `type_principal` = **"USB"** (pré-sélectionné)
- `sous_type` = **"Adaptateur WiFi"** (pré-sélectionné automatiquement)
- `nom`, `marque`, `modele`, `numero_serie` pré-remplis
- `cli` contient le markdown formaté
### Flow 2 : Import fichier markdown
1. Utilisateur clique **"Importer Markdown"**
2. Sélectionne un fichier `.md`
3. **Backend lit et analyse le contenu**
4. **Détecte le type automatiquement depuis le markdown**
5. Formulaire s'ouvre avec :
- `type_principal` et `sous_type` pré-sélectionnés
- `synthese` contient le contenu markdown complet
- Autres champs extraits du markdown
## Patterns de détection supportés
### WiFi/Wireless
```regex
wi[-]?fi
wireless
802\.11[a-z]
rtl81\d+ # Realtek WiFi chips
mt76\d+ # MediaTek WiFi chips
atheros
qualcomm.*wireless
broadcom.*wireless
wlan
wireless\s+adapter
```
### Bluetooth
```regex
bluetooth
bcm20702 # Broadcom BT chips
bt\s+adapter
```
### Storage - Clé USB
```regex
flash\s+drive
usb\s+stick
cruzer # SanDisk Cruzer series
datatraveler # Kingston DataTraveler
usb.*flash
clé\s+usb
pendrive
```
### Storage - Disque dur externe
```regex
external\s+hdd
external\s+ssd
portable\s+ssd
portable\s+drive
disk\s+drive
disque\s+dur\s+externe
my\s+passport # WD My Passport
expansion # Seagate Expansion
backup\s+plus # Seagate Backup Plus
elements # WD Elements
touro # Hitachi Touro
adata.*hd\d+ # ADATA external drives
```
### Storage - Lecteur de carte
```regex
card\s+reader
lecteur.*carte
sd.*reader
microsd.*reader
multi.*card
cf.*reader
```
### Hub
```regex
usb\s+hub
hub\s+controller
multi[-]?port
```
### ZigBee
```regex
zigbee
conbee # Dresden Elektronik ConBee
cc2531 # Texas Instruments ZigBee chip
cc2652 # TI newer ZigBee chip
dresden\s+elektronik
zigbee.*gateway
zigbee.*coordinator
thread.*border
```
### Lecteur biométrique (Fingerprint)
```regex
fingerprint
fingprint # Common typo
empreinte
biometric
biométrique
validity.*sensor # Validity sensors
synaptics.*fingerprint
goodix.*fingerprint
elan.*fingerprint
```
### Clavier
```regex
keyboard
clavier
hid.*keyboard
```
### Souris
```regex
mouse
souris
hid.*mouse
optical\s+mouse
```
### Webcam
```regex
webcam
camera
video\s+capture
uvc # USB Video Class
```
### Ethernet
```regex
ethernet
gigabit
network\s+adapter
lan\s+adapter
rtl81\d+.*ethernet
```
## Extensibilité
Pour ajouter un nouveau type de périphérique :
1. **Ajouter le type dans `config/peripheral_types.yaml`**
```yaml
- id: usb_nouveau_type
nom: Nouveau Type USB
type_principal: USB
sous_type: Mon Nouveau Type
icone: icon-name
```
2. **Ajouter les patterns dans `device_classifier.py`**
```python
TYPE_KEYWORDS = {
# ...
("USB", "Mon Nouveau Type"): [
r"pattern1",
r"pattern2",
r"mot[-]?clé",
],
}
```
3. **Redémarrer le backend**
Le nouveau type sera automatiquement :
- Détectable lors des imports
- Disponible dans les dropdowns
- Pré-sélectionné si les patterns matchent
## Avantages
**Gain de temps** - Plus besoin de sélectionner manuellement le type
**Précision** - Détection basée sur plusieurs sources d'information
**Extensible** - Facile d'ajouter de nouveaux types et patterns
**Robuste** - Fallback sur "USB / Autre" si détection impossible
**Multilingue** - Supporte patterns français et anglais
**Flexible** - Fonctionne avec CLI et markdown
## Limitations actuelles
⚠️ **Périphériques hybrides** - Un Unifying Receiver est détecté comme "USB / Autre" car il peut être clavier OU souris
⚠️ **Périphériques rares** - Types exotiques non couverts par les patterns
⚠️ **Patterns manquants** - Certains fabricants utilisent des termes non standards
## Améliorations futures
1. **Machine Learning** - Entraîner un modèle sur les périphériques existants
2. **Base de données USB ID** - Intégration avec `usb.ids` pour reconnaissance par vendor/product
3. **Détection multi-fonction** - Support des périphériques combinés (ex: hub + ethernet)
4. **Historique** - Apprendre des corrections manuelles utilisateur
5. **API externe** - Interroger des APIs publiques (USB ID Repository)
## Tests
### Test 1 : WiFi Realtek
```bash
# Préparer un fichier test
cat > /tmp/test_wifi.txt << 'EOF'
Bus 002 Device 005: ID 0bda:8176 Realtek Semiconductor Corp.
bDeviceClass 0
iManufacturer 1 Realtek
iProduct 2 802.11n WLAN Adapter
EOF
# Dans l'interface :
# 1. Importer USB
# 2. Coller le contenu
# 3. Sélectionner le périphérique
# 4. Vérifier : type_principal = "USB", sous_type = "Adaptateur WiFi"
```
**Résultat attendu** : ✅ Détection automatique comme "Adaptateur WiFi"
### Test 2 : Clé USB SanDisk
```bash
cat > /tmp/test_storage.txt << 'EOF'
Bus 002 Device 003: ID 0781:55ab SanDisk Corp.
bDeviceClass 0
iProduct 2 SanDisk 3.2Gen1
bInterfaceClass 8 Mass Storage
EOF
# Même procédure
```
**Résultat attendu** : ✅ Détection comme "Clé USB"
### Test 3 : Import markdown WiFi
```bash
# Utiliser le fichier existant
# fichier_usb/ID_0bda_8176.md
```
**Résultat attendu** : ✅ Détection automatique depuis le markdown
## Logs de détection
Pour débugger la détection, ajouter des logs dans `DeviceClassifier.classify_device()` :
```python
logger.info(f"Classification attempt - CLI: {bool(cli_content)}, Synthese: {bool(synthese_content)}")
logger.info(f"Device info: {device_info}")
logger.info(f"Detected: type_principal={type_principal}, sous_type={sous_type}")
```