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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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;
}
}
Así como definir el código necesario para leer archivos de audio y empezar su procesamiento usando programación paralela.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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;
}
}
//...
}
}
Reconociendo la voz
Primero ordenemos los pasos que daremos para procesar un audio.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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);
}
//...
}
}
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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);
}
}
//...
}
}
Y una vez con el audio listo ya podemos consumir el servicios a través del Speech SDK.
De la siguiente forma:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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);
}
}
//...
}
}
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:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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();
}
}
}
}
Y eso es todo amiguitos ;)!
No hay comentarios.:
Publicar un comentario