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