# 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 – Wi‑Fi 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}") ```