You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
IoT-For-Beginners/translations/he/6-consumer/lessons/1-speech-recognition/wio-terminal-speech-to-text.md

24 KiB

דיבור לטקסט - Wio Terminal

בחלק זה של השיעור, תכתבו קוד להמרת דיבור באודיו שנלכד לטקסט באמצעות שירות הדיבור.

שליחת האודיו לשירות הדיבור

ניתן לשלוח את האודיו לשירות הדיבור באמצעות ה-REST API. כדי להשתמש בשירות הדיבור, תחילה יש לבקש אסימון גישה, ולאחר מכן להשתמש באסימון זה כדי לגשת ל-REST API. אסימוני גישה אלו פגים לאחר 10 דקות, ולכן הקוד שלכם צריך לבקש אותם באופן קבוע כדי להבטיח שהם תמיד מעודכנים.

משימה - קבלת אסימון גישה

  1. פתחו את פרויקט smart-timer אם הוא עדיין לא פתוח.

  2. הוסיפו את התלויות הבאות לקובץ platformio.ini כדי לגשת ל-WiFi ולטפל ב-JSON:

    seeed-studio/Seeed Arduino rpcWiFi @ 1.0.5
    seeed-studio/Seeed Arduino rpcUnified @ 2.1.3
    seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1
    seeed-studio/Seeed Arduino RTC @ 2.0.0
    bblanchon/ArduinoJson @ 6.17.3
    
  3. הוסיפו את הקוד הבא לקובץ הכותרת config.h:

    const char *SSID = "<SSID>";
    const char *PASSWORD = "<PASSWORD>";
    
    const char *SPEECH_API_KEY = "<API_KEY>";
    const char *SPEECH_LOCATION = "<LOCATION>";
    const char *LANGUAGE = "<LANGUAGE>";
    
    const char *TOKEN_URL = "https://%s.api.cognitive.microsoft.com/sts/v1.0/issuetoken";
    

    החליפו <SSID> ו-<PASSWORD> בערכים הרלוונטיים עבור ה-WiFi שלכם.

    החליפו <API_KEY> במפתח ה-API של משאב שירות הדיבור שלכם. החליפו <LOCATION> במיקום שבו יצרתם את משאב שירות הדיבור.

    החליפו <LANGUAGE> בשם האזורי של השפה שבה תדברו, לדוגמה en-GB עבור אנגלית, או zn-HK עבור קנטונזית. ניתן למצוא רשימה של השפות הנתמכות ושמות האזורים שלהן בתיעוד Language and voice support במיקרוסופט.

    הקבוע TOKEN_URL הוא ה-URL של מנפיק האסימונים ללא המיקום. זה ישולב עם המיקום מאוחר יותר כדי לקבל את ה-URL המלא.

  4. כמו בחיבור ל-Custom Vision, תצטרכו להשתמש בחיבור HTTPS כדי להתחבר לשירות מנפיק האסימונים. הוסיפו את הקוד הבא לסוף config.h:

    const char *TOKEN_CERTIFICATE =
        "-----BEGIN CERTIFICATE-----\r\n"
        "MIIF8zCCBNugAwIBAgIQAueRcfuAIek/4tmDg0xQwDANBgkqhkiG9w0BAQwFADBh\r\n"
        "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n"
        "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\r\n"
        "MjAeFw0yMDA3MjkxMjMwMDBaFw0yNDA2MjcyMzU5NTlaMFkxCzAJBgNVBAYTAlVT\r\n"
        "MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKjAoBgNVBAMTIU1pY3Jv\r\n"
        "c29mdCBBenVyZSBUTFMgSXNzdWluZyBDQSAwNjCCAiIwDQYJKoZIhvcNAQEBBQAD\r\n"
        "ggIPADCCAgoCggIBALVGARl56bx3KBUSGuPc4H5uoNFkFH4e7pvTCxRi4j/+z+Xb\r\n"
        "wjEz+5CipDOqjx9/jWjskL5dk7PaQkzItidsAAnDCW1leZBOIi68Lff1bjTeZgMY\r\n"
        "iwdRd3Y39b/lcGpiuP2d23W95YHkMMT8IlWosYIX0f4kYb62rphyfnAjYb/4Od99\r\n"
        "ThnhlAxGtfvSbXcBVIKCYfZgqRvV+5lReUnd1aNjRYVzPOoifgSx2fRyy1+pO1Uz\r\n"
        "aMMNnIOE71bVYW0A1hr19w7kOb0KkJXoALTDDj1ukUEDqQuBfBxReL5mXiu1O7WG\r\n"
        "0vltg0VZ/SZzctBsdBlx1BkmWYBW261KZgBivrql5ELTKKd8qgtHcLQA5fl6JB0Q\r\n"
        "gs5XDaWehN86Gps5JW8ArjGtjcWAIP+X8CQaWfaCnuRm6Bk/03PQWhgdi84qwA0s\r\n"
        "sRfFJwHUPTNSnE8EiGVk2frt0u8PG1pwSQsFuNJfcYIHEv1vOzP7uEOuDydsmCjh\r\n"
        "lxuoK2n5/2aVR3BMTu+p4+gl8alXoBycyLmj3J/PUgqD8SL5fTCUegGsdia/Sa60\r\n"
        "N2oV7vQ17wjMN+LXa2rjj/b4ZlZgXVojDmAjDwIRdDUujQu0RVsJqFLMzSIHpp2C\r\n"
        "Zp7mIoLrySay2YYBu7SiNwL95X6He2kS8eefBBHjzwW/9FxGqry57i71c2cDAgMB\r\n"
        "AAGjggGtMIIBqTAdBgNVHQ4EFgQU1cFnOsKjnfR3UltZEjgp5lVou6UwHwYDVR0j\r\n"
        "BBgwFoAUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1Ud\r\n"
        "JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMHYG\r\n"
        "CCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu\r\n"
        "Y29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln\r\n"
        "aUNlcnRHbG9iYWxSb290RzIuY3J0MHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9j\r\n"
        "cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOG\r\n"
        "MWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5j\r\n"
        "cmwwHQYDVR0gBBYwFDAIBgZngQwBAgEwCAYGZ4EMAQICMBAGCSsGAQQBgjcVAQQD\r\n"
        "AgEAMA0GCSqGSIb3DQEBDAUAA4IBAQB2oWc93fB8esci/8esixj++N22meiGDjgF\r\n"
        "+rA2LUK5IOQOgcUSTGKSqF9lYfAxPjrqPjDCUPHCURv+26ad5P/BYtXtbmtxJWu+\r\n"
        "cS5BhMDPPeG3oPZwXRHBJFAkY4O4AF7RIAAUW6EzDflUoDHKv83zOiPfYGcpHc9s\r\n"
        "kxAInCedk7QSgXvMARjjOqdakor21DTmNIUotxo8kHv5hwRlGhBJwps6fEVi1Bt0\r\n"
        "trpM/3wYxlr473WSPUFZPgP1j519kLpWOJ8z09wxay+Br29irPcBYv0GMXlHqThy\r\n"
        "8y4m/HyTQeI2IMvMrQnwqPpY+rLIXyviI2vLoI+4xKE4Rn38ZZ8m\r\n"
        "-----END CERTIFICATE-----\r\n";
    

    זהו אותו אישור שהשתמשתם בו כאשר התחברתם ל-Custom Vision.

  5. הוסיפו include עבור קובץ הכותרת של WiFi וקובץ הכותרת של config לראש קובץ main.cpp:

    #include <rpcWiFi.h>
    
    #include "config.h"
    
  6. הוסיפו קוד להתחברות ל-WiFi ב-main.cpp מעל הפונקציה setup:

    void connectWiFi()
    {
        while (WiFi.status() != WL_CONNECTED)
        {
            Serial.println("Connecting to WiFi..");
            WiFi.begin(SSID, PASSWORD);
            delay(500);
        }
    
        Serial.println("Connected!");
    }
    
  7. קראו לפונקציה זו מתוך הפונקציה setup לאחר שהחיבור הסדרתי הוקם:

    connectWiFi();
    
  8. צרו קובץ כותרת חדש בתיקיית src בשם speech_to_text.h. בקובץ כותרת זה, הוסיפו את הקוד הבא:

    #pragma once
    
    #include <Arduino.h>
    #include <ArduinoJson.h>
    #include <HTTPClient.h>
    #include <WiFiClientSecure.h>
    
    #include "config.h"
    #include "mic.h"
    
    class SpeechToText
    {
    public:
    
    private:
    
    };
    
    SpeechToText speechToText;
    

    זה כולל כמה קבצי כותרת נחוצים לחיבור HTTP, קונפיגורציה וקובץ הכותרת mic.h, ומגדיר מחלקה בשם SpeechToText, לפני הכרזה על מופע של מחלקה זו שניתן להשתמש בו מאוחר יותר.

  9. הוסיפו את שני השדות הבאים לחלק ה-private של מחלקה זו:

    WiFiClientSecure _token_client;
    String _access_token;
    

    _token_client הוא WiFi Client שמשתמש ב-HTTPS וישמש לקבלת אסימון הגישה. אסימון זה יישמר לאחר מכן ב-_access_token.

  10. הוסיפו את השיטה הבאה לחלק ה-private:

    String getAccessToken()
    {
        char url[128];
        sprintf(url, TOKEN_URL, SPEECH_LOCATION);
    
        HTTPClient httpClient;
        httpClient.begin(_token_client, url);
    
        httpClient.addHeader("Ocp-Apim-Subscription-Key", SPEECH_API_KEY);
        int httpResultCode = httpClient.POST("{}");
    
        if (httpResultCode != 200)
        {
            Serial.println("Error getting access token, trying again...");
            delay(10000);
            return getAccessToken();
        }
    
        Serial.println("Got access token.");
        String result = httpClient.getString();
    
        httpClient.end();
    
        return result;
    }
    

    קוד זה בונה את ה-URL עבור ה-API של מנפיק האסימונים באמצעות המיקום של משאב הדיבור. לאחר מכן הוא יוצר HTTPClient לביצוע הבקשה, ומגדיר אותו להשתמש ב-WiFi client שהוגדר עם האישור של מנפיק האסימונים. הוא מגדיר את מפתח ה-API ככותרת לבקשה. לאחר מכן הוא מבצע בקשת POST לקבלת האישור, ומנסה שוב אם יש שגיאות. לבסוף, אסימון הגישה מוחזר.

  11. לחלק ה-public, הוסיפו שיטה לקבלת אסימון הגישה. זה יידרש בשיעורים הבאים להמרת טקסט לדיבור.

    String AccessToken()
    {
        return _access_token;
    }
    
  12. לחלק ה-public, הוסיפו שיטת init שמגדירה את ה-token client:

    void init()
    {
        _token_client.setCACert(TOKEN_CERTIFICATE);
        _access_token = getAccessToken();
    }
    

    זה מגדיר את האישור על ה-WiFi client, ואז מקבל את אסימון הגישה.

  13. ב-main.cpp, הוסיפו את קובץ הכותרת החדש הזה להוראות ה-include:

    #include "speech_to_text.h"
    
  14. אתחלו את מחלקת SpeechToText בסוף הפונקציה setup, לאחר הקריאה ל-mic.init אך לפני שכותבים Ready למוניטור הסדרתי:

    speechToText.init();
    

משימה - קריאת אודיו מזיכרון הפלאש

  1. בחלק מוקדם יותר של השיעור, האודיו הוקלט לזיכרון הפלאש. אודיו זה יצטרך להישלח ל-REST API של שירות הדיבור, ולכן יש לקרוא אותו מזיכרון הפלאש. לא ניתן לטעון אותו למאגר בזיכרון מכיוון שהוא יהיה גדול מדי. מחלקת HTTPClient שמבצעת קריאות REST יכולה להזרים נתונים באמצעות Arduino Stream - מחלקה שיכולה לטעון נתונים בחתיכות קטנות, ולשלוח את החתיכות אחת בכל פעם כחלק מהבקשה. בכל פעם שקוראים ל-read על stream, הוא מחזיר את הבלוק הבא של הנתונים. ניתן ליצור Arduino stream שיכול לקרוא מזיכרון הפלאש. צרו קובץ חדש בשם flash_stream.h בתיקיית src, והוסיפו אליו את הקוד הבא:

    #pragma once
    
    #include <Arduino.h>
    #include <HTTPClient.h>
    #include <sfud.h>
    
    #include "config.h"
    
    class FlashStream : public Stream
    {
    public:
        virtual size_t write(uint8_t val)
        {    
        }
    
        virtual int available()
        {
        }
    
        virtual int read()
        {
        }
    
        virtual int peek()
        {
        }
    private:
    
    };
    

    זה מצהיר על מחלקת FlashStream, שיורשת ממחלקת Stream של Arduino. זו מחלקה מופשטת - מחלקות יורשות צריכות לממש כמה שיטות לפני שניתן יהיה ליצור מופע של המחלקה, ושיטות אלו מוגדרות במחלקה זו.

    קראו עוד על Arduino Streams בתיעוד Arduino Stream

  2. הוסיפו את השדות הבאים לחלק ה-private:

    size_t _pos;
    size_t _flash_address;
    const sfud_flash *_flash;
    
    byte _buffer[HTTP_TCP_BUFFER_SIZE];
    

    זה מגדיר מאגר זמני לאחסון נתונים שנקראו מזיכרון הפלאש, יחד עם שדות לאחסון המיקום הנוכחי בעת קריאה מהמאגר, הכתובת הנוכחית לקריאה מזיכרון הפלאש, ומכשיר זיכרון הפלאש.

  3. בחלק ה-private, הוסיפו את השיטה הבאה:

    void populateBuffer()
    {
        sfud_read(_flash, _flash_address, HTTP_TCP_BUFFER_SIZE, _buffer);
        _flash_address += HTTP_TCP_BUFFER_SIZE;
        _pos = 0;
    }
    

    קוד זה קורא מזיכרון הפלאש בכתובת הנוכחית ושומר את הנתונים במאגר. לאחר מכן הוא מגדיל את הכתובת, כך שהקריאה הבאה תקרא את הבלוק הבא של הזיכרון. המאגר מוגדר בגודל המבוסס על החתיכה הגדולה ביותר ש-HTTPClient ישלח ל-REST API בכל פעם.

    💁 מחיקת זיכרון פלאש חייבת להיעשות באמצעות גודל גרעין, קריאה לעומת זאת לא.

  4. בחלק ה-public של מחלקה זו, הוסיפו בנאי:

    FlashStream()
    {
        _pos = 0;
        _flash_address = 0;
        _flash = sfud_get_device_table() + 0;
    
        populateBuffer();
    }
    

    בנאי זה מגדיר את כל השדות להתחיל קריאה מתחילת בלוק זיכרון הפלאש, וטוען את החתיכה הראשונה של הנתונים למאגר.

  5. מימוש שיטת write. stream זה יקרא נתונים בלבד, ולכן ניתן להשאיר פונקציה זו ריקה ולהחזיר 0:

    virtual size_t write(uint8_t val)
    {
        return 0;
    }
    
  6. מימוש שיטת peek. שיטה זו מחזירה את הנתונים במיקום הנוכחי מבלי להזיז את ה-stream קדימה. קריאה ל-peek מספר פעמים תחזיר תמיד את אותם נתונים כל עוד לא נקראו נתונים מה-stream.

    virtual int peek()
    {
        return _buffer[_pos];
    }
    
  7. מימוש פונקציית available. פונקציה זו מחזירה כמה בתים ניתן לקרוא מה-stream, או -1 אם ה-stream הושלם. עבור מחלקה זו, המקסימום הזמין לא יהיה יותר מגודל החתיכה של HTTPClient. כאשר stream זה משמש ב-HTTP client, הוא קורא לפונקציה זו כדי לראות כמה נתונים זמינים, ואז מבקש כמות זו לשליחה ל-REST API. אנחנו לא רוצים שכל חתיכה תהיה יותר מגודל החתיכה של HTTP client, ולכן אם יותר מזה זמין, גודל החתיכה מוחזר. אם פחות, אז מה שזמין מוחזר. ברגע שכל הנתונים הוזרמו, מוחזר -1.

    virtual int available()
    {
        int remaining = BUFFER_SIZE - ((_flash_address - HTTP_TCP_BUFFER_SIZE) + _pos);
        int bytes_available = min(HTTP_TCP_BUFFER_SIZE, remaining);
    
        if (bytes_available == 0)
        {
            bytes_available = -1;
        }
    
        return bytes_available;
    }
    
  8. מימוש שיטת read להחזרת הבת הבא מהמאגר, תוך הגדלת המיקום. אם המיקום חורג מגודל המאגר, הוא מאכלס את המאגר עם הבלוק הבא מזיכרון הפלאש ומאפס את המיקום.

    virtual int read()
    {
        int retVal = _buffer[_pos++];
    
        if (_pos == HTTP_TCP_BUFFER_SIZE)
        {
            populateBuffer();
        }
    
        return retVal;
    }
    
  9. בקובץ הכותרת speech_to_text.h, הוסיפו הוראת include עבור קובץ הכותרת החדש הזה:

    #include "flash_stream.h"
    

משימה - המרת הדיבור לטקסט

  1. ניתן להמיר את הדיבור לטקסט על ידי שליחת האודיו לשירות הדיבור דרך REST API. ל-REST API זה יש אישור שונה ממנפיק האסימונים, ולכן הוסיפו את הקוד הבא לקובץ הכותרת config.h כדי להגדיר אישור זה:

    const char *SPEECH_CERTIFICATE =
        "-----BEGIN CERTIFICATE-----\r\n"
        "MIIF8zCCBNugAwIBAgIQCq+mxcpjxFFB6jvh98dTFzANBgkqhkiG9w0BAQwFADBh\r\n"
        "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n"
        "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\r\n"
        "MjAeFw0yMDA3MjkxMjMwMDBaFw0yNDA2MjcyMzU5NTlaMFkxCzAJBgNVBAYTAlVT\r\n"
        "MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKjAoBgNVBAMTIU1pY3Jv\r\n"
        "c29mdCBBenVyZSBUTFMgSXNzdWluZyBDQSAwMTCCAiIwDQYJKoZIhvcNAQEBBQAD\r\n"
        "ggIPADCCAgoCggIBAMedcDrkXufP7pxVm1FHLDNA9IjwHaMoaY8arqqZ4Gff4xyr\r\n"
        "RygnavXL7g12MPAx8Q6Dd9hfBzrfWxkF0Br2wIvlvkzW01naNVSkHp+OS3hL3W6n\r\n"
        "l/jYvZnVeJXjtsKYcXIf/6WtspcF5awlQ9LZJcjwaH7KoZuK+THpXCMtzD8XNVdm\r\n"
        "GW/JI0C/7U/E7evXn9XDio8SYkGSM63aLO5BtLCv092+1d4GGBSQYolRq+7Pd1kR\r\n"
        "EkWBPm0ywZ2Vb8GIS5DLrjelEkBnKCyy3B0yQud9dpVsiUeE7F5sY8Me96WVxQcb\r\n"
        "OyYdEY/j/9UpDlOG+vA+YgOvBhkKEjiqygVpP8EZoMMijephzg43b5Qi9r5UrvYo\r\n"
        "o19oR/8pf4HJNDPF0/FJwFVMW8PmCBLGstin3NE1+NeWTkGt0TzpHjgKyfaDP2tO\r\n"
        "4bCk1G7pP2kDFT7SYfc8xbgCkFQ2UCEXsaH/f5YmpLn4YPiNFCeeIida7xnfTvc4\r\n"
        "7IxyVccHHq1FzGygOqemrxEETKh8hvDR6eBdrBwmCHVgZrnAqnn93JtGyPLi6+cj\r\n"
        "WGVGtMZHwzVvX1HvSFG771sskcEjJxiQNQDQRWHEh3NxvNb7kFlAXnVdRkkvhjpR\r\n"
        "GchFhTAzqmwltdWhWDEyCMKC2x/mSZvZtlZGY+g37Y72qHzidwtyW7rBetZJAgMB\r\n"
        "AAGjggGtMIIBqTAdBgNVHQ4EFgQUDyBd16FXlduSzyvQx8J3BM5ygHYwHwYDVR0j\r\n"
        "BBgwFoAUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1Ud\r\n"
        "JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMHYG\r\n"
        "CCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu\r\n"
        "Y29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln\r\n"
        "aUNlcnRHbG9iYWxSb290RzIuY3J0MHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9j\r\n"
        "cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOG\r\n"
        "MWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5j\r\n"
        "cmwwHQYDVR0gBBYwFDAIBgZngQwBAgEwCAYGZ4EMAQICMBAGCSsGAQQBgjcVAQQD\r\n"
        "AgEAMA0GCSqGSIb3DQEBDAUAA4IBAQAlFvNh7QgXVLAZSsNR2XRmIn9iS8OHFCBA\r\n"
        "WxKJoi8YYQafpMTkMqeuzoL3HWb1pYEipsDkhiMnrpfeYZEA7Lz7yqEEtfgHcEBs\r\n"
        "K9KcStQGGZRfmWU07hPXHnFz+5gTXqzCE2PBMlRgVUYJiA25mJPXfB00gDvGhtYa\r\n"
        "+mENwM9Bq1B9YYLyLjRtUz8cyGsdyTIG/bBM/Q9jcV8JGqMU/UjAdh1pFyTnnHEl\r\n"
        "Y59Npi7F87ZqYYJEHJM2LGD+le8VsHjgeWX2CJQko7klXvcizuZvUEDTjHaQcs2J\r\n"
        "+kPgfyMIOY1DMJ21NxOJ2xPRC/wAh/hzSBRVtoAnyuxtkZ4VjIOh\r\n"
        "-----END CERTIFICATE-----\r\n";
    
  2. הוסיפו קבוע לקובץ זה עבור ה-URL של הדיבור ללא המיקום. זה ישולב עם המיקום והשפה מאוחר יותר כדי לקבל את ה-URL המלא.

    const char *SPEECH_URL = "https://%s.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=%s";
    
  3. בקובץ הכותרת speech_to_text.h, בחלק ה-private של מחלקת SpeechToText, הגדירו שדה עבור WiFi Client שמשתמש באישור הדיבור:

    WiFiClientSecure _speech_client;
    
  4. בשיטת init, הגדירו את האישור על WiFi Client זה:

    _speech_client.setCACert(SPEECH_CERTIFICATE);
    
  5. הוסיפו את הקוד הבא לחלק ה-public של מחלקת SpeechToText כדי להגדיר שיטה להמרת דיבור לטקסט:

    String convertSpeechToText()
    {
    
    }
    
  6. הוסיפו את הקוד הבא לשיטה זו כדי ליצור HTTP client באמצעות ה-WiFi client שהוגדר עם אישור הדיבור, ובשימוש ב-URL של הדיבור שהוגדר עם המיקום והשפה:

    char url[128];
    sprintf(url, SPEECH_URL, SPEECH_LOCATION, LANGUAGE);
    
    HTTPClient httpClient;
    httpClient.begin(_speech_client, url);
    
  7. יש להגדיר כמה כותרות על החיבור:

    httpClient.addHeader("Authorization", String("Bearer ") + _access_token);
    httpClient.addHeader("Content-Type", String("audio/wav; codecs=audio/pcm; samplerate=") + String(RATE));
    httpClient.addHeader("Accept", "application/json;text/xml");
    

    זה מגדיר כותרות עבור האימות באמצעות אסימון הגישה, פורמט האודיו באמצעות קצב הדגימה, ומגדיר שהלקוח מצפה לתוצאה כ-JSON.

  8. לאחר מכן, הוסיפו את הקוד הבא לביצוע קריאת REST API:

    Serial.println("Sending speech...");
    
    FlashStream stream;
    int httpResponseCode = httpClient.sendRequest("POST", &stream, BUFFER_SIZE);
    
    Serial.println("Speech sent!");
    

    זה יוצר FlashStream ומשתמש בו להזרים נתונים ל-REST API.

  9. מתחת לזה, הוסיפו את הקוד הבא:

    String text = "";
    
    if (httpResponseCode == 200)
    {
        String result = httpClient.getString();
        Serial.println(result);
    
        DynamicJsonDocument doc(1024);
        deserializeJson(doc, result.c_str());
    
        JsonObject obj = doc.as<JsonObject>();
        text = obj["DisplayText"].as<String>();
    }
    else if (httpResponseCode == 401)
    {
        Serial.println("Access token expired, trying again with a new token");
        _access_token = getAccessToken();
        return convertSpeechToText();
    }
    else
    {
        Serial.print("Failed to convert text to speech - error ");
        Serial.println(httpResponseCode);
    }
    

    קוד זה בודק את קוד התגובה.

    אם הוא 200, הקוד להצלחה, אז התוצאה נשלפת, מפוענחת מ-JSON, ותכונת DisplayText מוגדרת במשתנה text. זו התכונה שבה מוחזר הטקסט של הדיבור.

    אם קוד התגובה הוא 401, אז אסימון הגישה פג תוקף (אסימונים אלו תקפים רק ל-10 דקות). אסימון גישה חדש מתבקש, והקריאה מתבצעת שוב.

    אחרת, שגיאה נשלחת למוניטור הסדרתי, ו-text נשאר ריק.

  10. הוסיפו את הקוד הבא לסוף שיטה זו כדי לסגור את HTTP client ולהחזיר את הטקסט:

    httpClient.end();
    
    return text;
    
  11. ב-main.cpp קראו לשיטה החדשה convertSpeechToText בפונקציה processAudio, ואז רשמו את הדיבור למוניטור הסדרתי:

    String text = speechToText.convertSpeechToText();
    Serial.println(text);
    
  12. בנו את הקוד הזה, העלו אותו ל-Wio Terminal שלכם ובדקו אותו דרך המוניטור הסדרתי. ברגע שתראו Ready במוניטור הסדרתי, לחצו על כפתור C (הכפתור בצד השמאלי, הקרוב ביותר למתג ההפעלה), ודברו. 4 שניות של אודיו יוקלטו, ואז יומרו לטקסט.

    --- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
    --- More details at http://bit.ly/pio-monitor-filters
    --- Miniterm on /dev/cu.usbmodem1101  9600,8,N,1 ---
    --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
    Connecting to WiFi..
    Connected!
    Got access token.
    Ready.
    Starting recording...
    Finished recording
    Sending speech...
    Speech sent!
    {"RecognitionStatus":"Success","DisplayText":"Set a 2 minute and 27 second timer.","Offset":4700000,"Duration":35300000}
    Set a 2 minute and 27 second timer.
    

💁 ניתן למצוא את הקוד הזה בתיקייה code-speech-to-text/wio-terminal.

😀 התוכנית להמרת דיבור לטקסט הצליחה!


כתב ויתור:
מסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית Co-op Translator. למרות שאנו שואפים לדיוק, יש לקחת בחשבון שתרגומים אוטומטיים עשויים להכיל שגיאות או אי דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור סמכותי. עבור מידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי אדם. איננו נושאים באחריות לאי הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה.