Retour à l'accueil

Reconnaissance vocale C# VK Cloud avec hooks

L'article décrit l'implémentation d'une utilitaire pour reconnaissance vocale en C# utilisant l'API VK Cloud, NAudio et hooks clavier globaux. L'application enregistre l'audio sur raccourcis clavier, envoie au serveur et insère le texte via presse-papiers. Code complet avec gestion d'erreurs.

Entrée vocale en C# : hooks + VK Cloud ASR
Advertisement 728x90

Reconnaissance vocale en C# avec VK Cloud : Hooks bas niveau et NAudio

Un développeur a créé une application console en C# qui capte la parole via microphone, envoie l'audio à l'API Speech de VK Cloud, puis insère le texte reconnu dans le presse-papiers. L'activation est gérée par des hooks clavier globaux : maintenir la touche Ctrl droit démarre l'enregistrement, la relâcher déclenche le traitement. NAudio gère l'enregistrement WAV (16 kHz, 16 bits, mono), tandis qu'HttpClient gère les requêtes API avec un délai d'attente de 15 secondes.

Le code est spécifique à Windows et nécessite d'être exécuté en tant qu'administrateur en raison de SetWindowsHookEx. Le jeton VK Cloud est codé en dur comme constante — il s'agit d'une clé service issue de votre tableau de bord personnel.

Hooks globaux pour activer l'enregistrement

Le hook clavier bas niveau (WH_KEYBOARD_LL) intercepte les événements WM_KEYDOWN/WM_KEYUP. Appuyer sur la touche Ctrl droit (0xA3) démarre ou arrête l'enregistrement de manière asynchrone. Appuyer sur ESC ferme l'application.

Google AdInline article slot

Déclarations P/Invoke clés :

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

Dans HookCallback, vkCode issu de lParam est vérifié. Si !isRecording && !isProcessing, une tâche Task.Run(() => StartRecordingAsync()) est lancée.

Capture audio et traitement

WaveInEvent est configuré à 16 000 Hz. DataAvailable écrit les données dans un fichier temporaire voice_temp.wav via WaveFileWriter. Après l’arrêt, la taille du fichier est vérifiée (>1 000 octets), puis le traitement de reconnaissance suit.

Google AdInline article slot
var waveFormat = new WaveFormat(16000, 16, 1);
waveIn = new WaveInEvent { WaveFormat = waveFormat };
writer = new WaveFileWriter(OutputFileName, waveIn.WaveFormat);
waveIn.DataAvailable += (s, e) => writer?.Write(e.Buffer, 0, e.BytesRecorded);

Dans StopRecordingAndProcessAsync : les ressources sont libérées, une pause de 200 ms est effectuée, puis RecognizeSpeechAsync est appelé avec un jeton Bearer.

Intégration avec l'API Speech de VK Cloud

Requête POST vers https://voice.mcs.mail.ru/asr avec type de contenu audio/wave. La réponse est analysée via Newtonsoft.Json.Linq : result.texts[0].punctuated_text.

var request = new HttpRequestMessage(HttpMethod.Post, "https://voice.mcs.mail.ru/asr");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
request.Content = content;
var response = await httpClient.SendAsync(request);

La gestion des erreurs inclut Unauthorized (jeton expiré), timeouts et codes HTTP. Les logs s'affichent dans la console avec des emojis pour un retour visuel immédiat.

Google AdInline article slot
  • Succès : le texte est placé dans le presse-papiers, le log affiche "✅ Reconnu".
  • Fichier court : ignoré si inférieur à 1 000 octets.
  • Erreur API : sonnerie + détails affichés.

Insertion du texte via thread STA

Clipboard.SetText nécessite un contexte STA (Single-Threaded Apartment). Un thread séparé est créé avec SetApartmentState(STA), puis Join() attend la fin.

Thread staThread = new Thread(() => {
    Clipboard.SetText(text, TextDataFormat.Text);
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();

Des alternatives existent (SendKeys ou UI Automation), mais cette méthode fonctionne de façon fiable via Ctrl+V.

Points clés

  • Hooks globaux : WH_KEYBOARD_LL nécessite des privilèges administrateur et injecte dans tout processus.
  • Format audio : 16 kHz / 16 bits / mono — optimal pour ASR de VK Cloud.
  • Asynchronicité : Task.Run empêche le blocage du hook.
  • Sécurité : jeton intégré au code — destiné à une utilisation personnelle uniquement ; ne jamais commettre dans les dépôts.
  • Limites : sortie via presse-papiers au lieu d'entrée directe ; coût de stockage ~3 RUB par article.

— Editorial Team

Advertisement 728x90

Lire ensuite