addon
This commit is contained in:
507
docs/FEATURE_INTELLIGENT_CLASSIFICATION.md
Executable file
507
docs/FEATURE_INTELLIGENT_CLASSIFICATION.md
Executable file
@@ -0,0 +1,507 @@
|
||||
# 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}")
|
||||
```
|
||||
Reference in New Issue
Block a user