Riconoscimento vocale con intelligenza artificiale in Unity

'Riconoscimento vocale AI in Unity'

Introduzione

Questo tutorial ti guiderà nel processo di implementazione del riconoscimento vocale all’avanguardia nel tuo gioco Unity utilizzando l’API Unity di Hugging Face. Questa funzionalità può essere utilizzata per impartire comandi, parlare con un NPC, migliorare l’accessibilità o qualsiasi altra funzionalità in cui la conversione delle parole pronunciate in testo può essere utile.

Per provare il riconoscimento vocale in Unity, dai un’occhiata alla demo live su itch.io .

Prerequisiti

Questo tutorial presuppone una conoscenza di base di Unity. È inoltre necessario avere installato l’API Unity di Hugging Face . Per istruzioni su come configurare l’API, consulta il nostro post di blog precedente .

Passaggi

1. Prepara la Scena

In questo tutorial, prepareremo una scena molto semplice in cui il giocatore può avviare e interrompere una registrazione e il risultato verrà convertito in testo.

Inizia creando un progetto Unity, quindi crea un Canvas con quattro elementi UI:

  1. Pulsante di Avvio : Questo avvierà la registrazione.
  2. Pulsante di Interruzione : Questo interromperà la registrazione.
  3. Testo (TextMeshPro) : Qui verrà visualizzato il risultato del riconoscimento vocale.

2. Prepara lo Script

Crea uno script chiamato SpeechRecognitionTest e allegalo a un GameObject vuoto.

Nello script, definisci i riferimenti ai tuoi componenti UI:

[SerializeField] private Button startButton;
[SerializeField] private Button stopButton;
[SerializeField] private TextMeshProUGUI text;

Assegnali nell’inspector.

Quindi, utilizza il metodo Start() per impostare gli ascoltatori per i pulsanti di avvio e interruzione:

private void Start() {
    startButton.onClick.AddListener(StartRecording);
    stopButton.onClick.AddListener(StopRecording);
}

A questo punto, il tuo script dovrebbe assomigliare a questo:

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class SpeechRecognitionTest : MonoBehaviour {
    [SerializeField] private Button startButton;
    [SerializeField] private Button stopButton;
    [SerializeField] private TextMeshProUGUI text;

    private void Start() {
        startButton.onClick.AddListener(StartRecording);
        stopButton.onClick.AddListener(StopRecording);
    }

    private void StartRecording() {

    }

    private void StopRecording() {

    }
}

3. Registra l’Input del Microfono

Ora registriamo l’input del microfono e lo codifichiamo nel formato WAV. Inizia definendo le variabili di istanza:

private AudioClip clip;
private byte[] bytes;
private bool recording;

Quindi, in StartRecording() , utilizza il metodo Microphone.Start() per avviare la registrazione:

private void StartRecording() {
    clip = Microphone.Start(null, false, 10, 44100);
    recording = true;
}

Questo registrerà fino a 10 secondi di audio a 44100 Hz.

In caso la registrazione raggiunga la sua lunghezza massima di 10 secondi, vorremo interrompere automaticamente la registrazione. Per farlo, scrivi quanto segue nel metodo Update():

private void Update() {
    if (recording && Microphone.GetPosition(null) >= clip.samples) {
        StopRecording();
    }
}

Quindi, in StopRecording() , tronca la registrazione e la codifica nel formato WAV:

private void StopRecording() {
    var position = Microphone.GetPosition(null);
    Microphone.End(null);
    var samples = new float[position * clip.channels];
    clip.GetData(samples, 0);
    bytes = EncodeAsWAV(samples, clip.frequency, clip.channels);
    recording = false;
}

Infine, dovremo implementare il metodo EncodeAsWAV(), per preparare i dati audio per l’API di Hugging Face:

private byte[] EncodeAsWAV(float[] samples, int frequency, int channels) {
    using (var memoryStream = new MemoryStream(44 + samples.Length * 2)) {
        using (var writer = new BinaryWriter(memoryStream)) {
            writer.Write("RIFF".ToCharArray());
            writer.Write(36 + samples.Length * 2);
            writer.Write("WAVE".ToCharArray());
            writer.Write("fmt ".ToCharArray());
            writer.Write(16);
            writer.Write((ushort)1);
            writer.Write((ushort)channels);
            writer.Write(frequency);
            writer.Write(frequency * channels * 2);
            writer.Write((ushort)(channels * 2));
            writer.Write((ushort)16);
            writer.Write("data".ToCharArray());
            writer.Write(samples.Length * 2);

            foreach (var sample in samples) {
                writer.Write((short)(sample * short.MaxValue));
            }
        }
        return memoryStream.ToArray();
    }
}

Lo script completo dovrebbe ora apparire più o meno così:

using System.IO;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class SpeechRecognitionTest : MonoBehaviour {
    [SerializeField] private Button startButton;
    [SerializeField] private Button stopButton;
    [SerializeField] private TextMeshProUGUI text;

    private AudioClip clip;
    private byte[] bytes;
    private bool recording;

    private void Start() {
        startButton.onClick.AddListener(StartRecording);
        stopButton.onClick.AddListener(StopRecording);
    }

    private void Update() {
        if (recording && Microphone.GetPosition(null) >= clip.samples) {
            StopRecording();
        }
    }

    private void StartRecording() {
        clip = Microphone.Start(null, false, 10, 44100);
        recording = true;
    }

    private void StopRecording() {
        var position = Microphone.GetPosition(null);
        Microphone.End(null);
        var samples = new float[position * clip.channels];
        clip.GetData(samples, 0);
        bytes = EncodeAsWAV(samples, clip.frequency, clip.channels);
        recording = false;
    }

    private byte[] EncodeAsWAV(float[] samples, int frequency, int channels) {
        using (var memoryStream = new MemoryStream(44 + samples.Length * 2)) {
            using (var writer = new BinaryWriter(memoryStream)) {
                writer.Write("RIFF".ToCharArray());
                writer.Write(36 + samples.Length * 2);
                writer.Write("WAVE".ToCharArray());
                writer.Write("fmt ".ToCharArray());
                writer.Write(16);
                writer.Write((ushort)1);
                writer.Write((ushort)channels);
                writer.Write(frequency);
                writer.Write(frequency * channels * 2);
                writer.Write((ushort)(channels * 2));
                writer.Write((ushort)16);
                writer.Write("data".ToCharArray());
                writer.Write(samples.Length * 2);

                foreach (var sample in samples) {
                    writer.Write((short)(sample * short.MaxValue));
                }
            }
            return memoryStream.ToArray();
        }
    }
}

Per testare se questo codice funziona correttamente, puoi aggiungere la seguente riga alla fine del metodo StopRecording():

File.WriteAllBytes(Application.dataPath + "/test.wav", bytes);

Adesso, se clicchi il pulsante Start, parli nel microfono e clicchi Stop, verrà salvato un file test.wav nella cartella Unity Assets con l’audio registrato.

4. Riconoscimento Vocale

Successivamente, vorremo utilizzare l’API Unity di Hugging Face per eseguire il riconoscimento vocale sul nostro audio codificato. Per farlo, creeremo un metodo SendRecording():

using HuggingFace.API;

private void SendRecording() {
    HuggingFaceAPI.AutomaticSpeechRecognition(bytes, response => {
        text.color = Color.white;
        text.text = response;
    }, error => {
        text.color = Color.red;
        text.text = error;
    });
}

Ciò invierà l’audio codificato all’API, visualizzando la risposta in bianco se avviene con successo, altrimenti il messaggio di errore in rosso.

Non dimenticare di chiamare SendRecording() alla fine del metodo StopRecording():

private void StopRecording() {
    /* altro codice */
    SendRecording();
}

5. Tocchi Finali

Infine, miglioreremo un po’ l’esperienza utente di questa demo utilizzando l’interattività dei pulsanti e i messaggi di stato.

I pulsanti Start e Stop dovrebbero essere interagibili solo quando appropriato, ovvero quando una registrazione è pronta per essere avviata/fermata.

Quindi, imposta il testo della risposta a un semplice messaggio di stato durante la registrazione o l’attesa dell’API.

Lo script completo dovrebbe essere simile a questo:

using System.IO;
using HuggingFace.API;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class SpeechRecognitionTest : MonoBehaviour {
    [SerializeField] private Button startButton;
    [SerializeField] private Button stopButton;
    [SerializeField] private TextMeshProUGUI text;

    private AudioClip clip;
    private byte[] bytes;
    private bool recording;

    private void Start() {
        startButton.onClick.AddListener(StartRecording);
        stopButton.onClick.AddListener(StopRecording);
        stopButton.interactable = false;
    }

    private void Update() {
        if (recording && Microphone.GetPosition(null) >= clip.samples) {
            StopRecording();
        }
    }

    private void StartRecording() {
        text.color = Color.white;
        text.text = "Registrazione...";
        startButton.interactable = false;
        stopButton.interactable = true;
        clip = Microphone.Start(null, false, 10, 44100);
        recording = true;
    }

    private void StopRecording() {
        var position = Microphone.GetPosition(null);
        Microphone.End(null);
        var samples = new float[position * clip.channels];
        clip.GetData(samples, 0);
        bytes = EncodeAsWAV(samples, clip.frequency, clip.channels);
        recording = false;
        SendRecording();
    }

    private void SendRecording() {
        text.color = Color.yellow;
        text.text = "Invio...";
        stopButton.interactable = false;
        HuggingFaceAPI.AutomaticSpeechRecognition(bytes, response => {
            text.color = Color.white;
            text.text = response;
            startButton.interactable = true;
        }, error => {
            text.color = Color.red;
            text.text = error;
            startButton.interactable = true;
        });
    }

    private byte[] EncodeAsWAV(float[] samples, int frequency, int channels) {
        using (var memoryStream = new MemoryStream(44 + samples.Length * 2)) {
            using (var writer = new BinaryWriter(memoryStream)) {
                writer.Write("RIFF".ToCharArray());
                writer.Write(36 + samples.Length * 2);
                writer.Write("WAVE".ToCharArray());
                writer.Write("fmt ".ToCharArray());
                writer.Write(16);
                writer.Write((ushort)1);
                writer.Write((ushort)channels);
                writer.Write(frequency);
                writer.Write(frequency * channels * 2);
                writer.Write((ushort)(channels * 2));
                writer.Write((ushort)16);
                writer.Write("data".ToCharArray());
                writer.Write(samples.Length * 2);

                foreach (var sample in samples) {
                    writer.Write((short)(sample * short.MaxValue));
                }
            }
            return memoryStream.ToArray();
        }
    }
}

Congratulazioni, ora puoi utilizzare il riconoscimento vocale all’avanguardia in Unity!

Se hai domande o desideri essere più coinvolto nell’utilizzo di Hugging Face per i giochi, unisciti al Discord di Hugging Face!