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

13 KiB
Executable File
Raw Permalink Blame History

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

# 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 :

@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 :

from app.utils.device_classifier import DeviceClassifier

Ligne 737-746 - USB CLI extraction avec détection intelligente :

# 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 :

# 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 :

"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 :

// 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

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

bluetooth
bcm20702      # Broadcom BT chips
bt\s+adapter

Storage - Clé USB

flash\s+drive
usb\s+stick
cruzer           # SanDisk Cruzer series
datatraveler     # Kingston DataTraveler
usb.*flash
clé\s+usb
pendrive

Storage - Disque dur externe

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

card\s+reader
lecteur.*carte
sd.*reader
microsd.*reader
multi.*card
cf.*reader

Hub

usb\s+hub
hub\s+controller
multi[-]?port

ZigBee

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)

fingerprint
fingprint             # Common typo
empreinte
biometric
biométrique
validity.*sensor      # Validity sensors
synaptics.*fingerprint
goodix.*fingerprint
elan.*fingerprint

Clavier

keyboard
clavier
hid.*keyboard

Souris

mouse
souris
hid.*mouse
optical\s+mouse

Webcam

webcam
camera
video\s+capture
uvc           # USB Video Class

Ethernet

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
- id: usb_nouveau_type
  nom: Nouveau Type USB
  type_principal: USB
  sous_type: Mon Nouveau Type
  icone: icon-name
  1. Ajouter les patterns dans device_classifier.py
TYPE_KEYWORDS = {
    # ...
    ("USB", "Mon Nouveau Type"): [
        r"pattern1",
        r"pattern2",
        r"mot[-]?clé",
    ],
}
  1. 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

# 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

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

# 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() :

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}")