Eventos

[Cognitive Services] Speech Services & Text Analytics con los #CNMAudios

Hoy 7 de Agosto del 2018 es un día especial para la Justicia y el Perú, y esto es porque hoy se cumple exactamente 1 mes, desde que IDL Reporteros empezó a difundir los primeros audios que revelarían presuntas manipulaciones de sentencias, favorcitos, negociaciones de ascensos de funcionarios, entre otros delitos de corrupción que involucrarían a jueces, miembros del Consejo Nacional de la Magistratura y a la Señora K.

Probablemente existan más de 20 mil audios y si vemos la cantidad de vídeos publicados hasta el momento en el canal de IDL pues parece que aún queda mucho trabajo por hacer. No me imagino lo tedioso que debe ser escuchar cada uno de los 20 mil audios, transcribirlos, clasificarlos y relacionarlos con otros audios, sería excelente que existiera una aplicación donde solo tengas que seleccionar el archivo de audio para que la computadora lo vaya leyendo por ti, lo cual es completamente factible gracias a la Inteligencia Artificial, y mientras vas seleccionando otros audios y preparándote algo de comer, la computadora pueda ir encontrando las palabras relevantes dentro de cada una de las conversaciones y mostrártelas para que en primera instancia puedas clasificar y relacionar los audios a la velocidad de la luz.


Plataforma de desarrollo y Azure

En caso no existan, si estas ejecutando Windows de 64 bits, tienes que crear una nueva configuración de plataforma llamada x64 y si estas ejecutando Windows de 32 bits, tienes que crear una nueva configuración de plataforma llamada x86.


Y en nuestra suscripción de Azure debemos crear un servicio Speech (preview) y Text Analytics respectivamente para poder continuar.


Seleccionando nuestros archivos de audio

En nuestra primera tarea, lo que tenemos que hacer es definir una clase, con sus respectivas propiedades, que nos permita administrar los datos en relación a un audio y también la lógica necesaria para seleccionar un archivo.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ES.SpeechToText.CNMAudios.Classes
{
public class CNMAudioItem : INotifyPropertyChanged
{
public string Code { get; set; }
public string Filename { get; set; }
public string OriginalFilename { get; set; }
public string RecognizedText { get; private set; }
public List<string> _keyPhrases;
public List<string> KeyPhrases { get { return _keyPhrases; } set { _keyPhrases = value; RaisePropertyChanged(); } }
private bool _isBusy;
public bool IsBusy { get { return _isBusy; } set { _isBusy = value; RaisePropertyChanged(); } }
public void AppendTextLine(string line)
{
RecognizedText = string.Concat(RecognizedText, Environment.NewLine, line);
RaisePropertyChanged("RecognizedText");
}
public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
view raw CNMAudioItem.cs hosted with ❤ by GitHub

Así como definir el código necesario para leer archivos de audio y empezar su procesamiento usando programación paralela.

using CSCore;
using CSCore.Codecs;
using ES.SpeechToText.CNMAudios.Classes;
using Microsoft.CognitiveServices.Speech;
using Microsoft.ProjectOxford.Text.KeyPhrase;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
namespace ES.SpeechToText.CNMAudios
{
public partial class MainWindow : Window
{
#region View Variables
public ObservableCollection<CNMAudioItem> _cnmAudios = new ObservableCollection<CNMAudioItem>();
public DateTime? _lastAudioSent = null;
#endregion View Variables
//...
public MainWindow()
{
InitializeComponent();
CNMAudiosListBox.ItemsSource = _cnmAudios;
}
private void Add_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var ofd = new OpenFileDialog();
ofd.Filter = "wav files (*.wav)|*.wav";
if (ofd.ShowDialog() == true)
{
var cnmAudioItem = new CNMAudioItem();
cnmAudioItem.IsBusy = true;
cnmAudioItem.Code = Guid.NewGuid().ToString();
cnmAudioItem.Filename = string.Format("{0}.wav", cnmAudioItem.Code);
cnmAudioItem.OriginalFilename = ofd.FileName;
_cnmAudios.Add(cnmAudioItem);
Task.Factory.StartNew(() => StartProcessWithNewAudio(cnmAudioItem));
_lastAudioSent = DateTime.Now;
}
}
//...
}
}
view raw MainWindow_1.cs hosted with ❤ by GitHub

Reconociendo la voz

Primero ordenemos los pasos que daremos para procesar un audio.

using CSCore;
using CSCore.Codecs;
using ES.SpeechToText.CNMAudios.Classes;
using Microsoft.CognitiveServices.Speech;
using Microsoft.ProjectOxford.Text.KeyPhrase;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
namespace ES.SpeechToText.CNMAudios
{
public partial class MainWindow : Window
{
//...
private async void StartProcessWithNewAudio(CNMAudioItem cnmAudioItem)
{
if (_lastAudioSent != null && (DateTime.Now - _lastAudioSent.Value).TotalMilliseconds < 12000)
await Task.Delay(12000 - (int)(DateTime.Now - _lastAudioSent.Value).TotalMilliseconds);
ResampleAudio(cnmAudioItem.OriginalFilename, cnmAudioItem.Filename);
await RecognizeSpeechAsync(cnmAudioItem);
DetectKeyPhrases(cnmAudioItem);
}
//...
}
}
view raw MainWindow_2.cs hosted with ❤ by GitHub

Ahora, según la documentación sobre el Speech Service de Microsoft Azure, solo podemos trabajar con audios que tengan el formato "single-channel (mono) WAV / PCM with a sampling rate of 16 kHz". Por eso lo primero que tenemos que hacer es corregir el formato de los archivos seleccionados con ayuda de CSCore.

using CSCore;
using CSCore.Codecs;
//...
namespace ES.SpeechToText.CNMAudios
{
public partial class MainWindow : Window
{
//...
private void ResampleAudio(string originFilename, string destinyFilename)
{
using (var source = CodecFactory.Instance.GetCodec(originFilename)
.ToSampleSource()
.ChangeSampleRate(16000)
.ToMono()
.ToWaveSource(16))
{
source.WriteToFile(destinyFilename);
}
}
//...
}
}
view raw MainWindow_3.cs hosted with ❤ by GitHub

Y una vez con el audio listo ya podemos consumir el servicios a través del Speech SDK.


De la siguiente forma:

using Microsoft.CognitiveServices.Speech;
//...
namespace ES.SpeechToText.CNMAudios
{
public partial class MainWindow : Window
{
//...
#region Cognitive Services Variables
private SpeechFactory _speechFactory = null;
private KeyPhraseClient _keyPhraseClient = null;
#endregion Cognitive Services Variables
//...
public async Task RecognizeSpeechAsync(CNMAudioItem cnmAudioItem)
{
var stopRecognition = new TaskCompletionSource<int>();
var factory = _speechFactory ?? SpeechFactory.FromSubscription("77623f52633c426890a6d2bb11116c8b", "westus");
using (var recognizer = factory.CreateSpeechRecognizerWithFileInput(cnmAudioItem.Filename, "es-ES"))
{
recognizer.FinalResultReceived += (s, e) =>
{
if (e.Result.RecognitionStatus == RecognitionStatus.Recognized)
cnmAudioItem.AppendTextLine(e.Result.Text);
};
recognizer.OnSessionEvent += (s, e) =>
{
if (e.EventType == SessionEventType.SessionStoppedEvent)
{
cnmAudioItem.IsBusy = false;
stopRecognition.TrySetResult(0);
}
};
recognizer.RecognitionErrorRaised += (s, e) =>
{
Console.WriteLine(e.FailureReason);
};
await recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);
await stopRecognition.Task.ConfigureAwait(false);
await recognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
}
}
//...
}
}
view raw MainWindow_4.cs hosted with ❤ by GitHub

Detectando las palabras clave

Este caso es muy similar al anterior, solo necesitamos el paquete adecuado


Y hacer los request como corresponden según el siguiente ejemplo:

using Microsoft.ProjectOxford.Text.KeyPhrase;
//...
namespace ES.SpeechToText.CNMAudios
{
public partial class MainWindow : Window
{
//...
#region Cognitive Services Variables
private SpeechFactory _speechFactory = null;
private KeyPhraseClient _keyPhraseClient = null;
#endregion Cognitive Services Variables
//...
public async void DetectKeyPhrases(CNMAudioItem cnmAudioItem)
{
if (string.IsNullOrWhiteSpace(cnmAudioItem.RecognizedText))
return;
var keyPhraseClient = _keyPhraseClient ?? new KeyPhraseClient("4f2c3df7714f4bbfbc742547624a6f2b");
var keyPhraseRequest = new KeyPhraseRequest();
keyPhraseRequest.Documents.Add(new KeyPhraseDocument { Id = Guid.NewGuid().ToString(), Text = cnmAudioItem.RecognizedText, Language = "es" });
var keyPhraseResult = await keyPhraseClient.GetKeyPhrasesAsync(keyPhraseRequest);
if (keyPhraseResult.Errors.Count == 0)
{
var doc = keyPhraseResult.Documents[0];
Dispatcher.BeginInvoke(new Action(() =>
{
cnmAudioItem.KeyPhrases = doc.KeyPhrases;
}), null).Wait();
}
}
}
}
view raw MainWindow_5.cs hosted with ❤ by GitHub

Y eso es todo amiguitos ;)!


No hay comentarios.:

Publicar un comentario

Epicalsoft — Superheroic Software Development Blog Designed by Templateism Copyright © 2014

Con tecnología de Blogger.