1. 程式人生 > >Azure AI 服務之文字翻譯

Azure AI 服務之文字翻譯

當下人工智慧可謂是風頭正勁,幾乎所有的大廠都有相關的技術棧。微軟在 AI 領域自然也是投入了重注,並且以 Azure 認知服務的方式投入了市場:

也就是說作為開發者我們不需要學習太多 AI 的理論知識,直接使用 Azure 提供的認知服務 API 就可以在程式中實現 AI 的功能了!

本文作為介紹 Azure AI 服務系列的第一篇,將通過 demo 介紹 Azure 認識服務中 Language 分類中的文字翻譯服務(Translator Text API )。

Microsoft 文字翻譯 API 是一種基於雲的機器翻譯服務, 支援多種語言。使用者可用於構建應用程式、網站、工具或任何需要多語言支援的解決方案。該服務是通過 REST API 提供的,所以我們可以以任何語言來呼叫它們。本文筆者使用 C# 通過構建一個 WPF 程式來演示如何通過簡單的幾步就能建立一個像模像樣的翻譯程式:

本文的完整 demo 請從這裡下載

建立 Azure 服務

要使用 Azure 的翻譯服務需要先在 Azure 上建立對應的例項,比如我們需要先建立一個 "Translator Text API" 服務例項:

在本文的 demo 程式中我們還會用到拼寫檢查的服務,所以還需要建立一個 "Bing Spell Check v7 API" 服務的例項:

說明:對於學習和練習來說,你可以建立免費的 Azure 賬號並建立免費版的上述例項,詳細資訊請參考 Azure 官網。

建立 WPF 應用程式

先在 VS 中建立 WPF 程式並簡單的佈局。

既然是 REST API,那麼我們肯定是以 url 的方式訪問服務,下面分別是訪問文字翻譯服務和拼寫檢查服務的 url:

const string TEXT_TRANSLATION_API_ENDPOINT = "https://api.microsofttranslator.com/v2/Http.svc/";
const string BING_SPELL_CHECK_API_ENDPOINT = "https://api.cognitive.microsoft.com/bing/v7.0/spellcheck/";

在訪問相應的服務時,我們用這兩個常量再拼接上合適的引數就可以了。

需要注意的是,Azure 提供的認知服務 API 都是需要認證資訊的。具體的方式就是把我們建立的服務的 key 隨 API 傳送的伺服器端進行認證,比如把 key 新增到 http 請求的 header 中:

WebRequest.Headers.Add("Ocp-Apim-Subscription-Key", "your key");

你可以在建立的服務例項的詳情介面獲得對應的 key,我們在程式中通過定義的常量來儲存它們:

const string TEXT_TRANSLATION_API_SUBSCRIPTION_KEY = "your translator key";
const string BING_SPELL_CHECK_API_SUBSCRIPTION_KEY = "your spell check key";

由於 demo 的程式碼比較長,為了能集中精力介紹 Azure AI 相關的內容,本文中只貼出相關的程式碼。完整的 demo 程式碼在這裡

獲取支援的語言列表

在進行任何的文字翻譯之前,我們需要搞清楚 Azure 提供的翻譯服務究竟支援哪些語言!下面的請求能夠返回翻譯服務支援的語言列表:

string uri = TEXT_TRANSLATION_API_ENDPOINT + "GetLanguagesForTranslate?scope=text";

我們把程式碼封裝到下面的函式中:

複製程式碼
private string[] languageCodes;
private void GetLanguagesForTranslate()
{
    // 獲得翻譯服務支援的語言
    string uri = TEXT_TRANSLATION_API_ENDPOINT + "GetLanguagesForTranslate?scope=text";
    WebRequest WebRequest = WebRequest.Create(uri);
    // 在 http 請求中新增認證資訊
    WebRequest.Headers.Add("Ocp-Apim-Subscription-Key", TEXT_TRANSLATION_API_SUBSCRIPTION_KEY);
    WebResponse response = null;

    // 把返回的 xml 資訊抽取到陣列中
    response = WebRequest.GetResponse();
    using (Stream stream = response.GetResponseStream())
    {
        DataContractSerializer dcs = new DataContractSerializer(typeof(List<string>));
        List<string> languagesForTranslate = (List<string>)dcs.ReadObject(stream);
        languageCodes = languagesForTranslate.ToArray();
    }
}
複製程式碼

執行這個函式後,languageCodes 中的內容如下圖所示:

雖然取到了可以翻譯的語言列表,但是像圖中的內容是無法顯示給使用者的,還需要把它們轉換成對使用者友好的名稱,因此我們定義 GetLanguageNames 函式完成這個功能:

複製程式碼
private SortedDictionary<string, string> languageCodesAndTitles =
            new SortedDictionary<string, string>(Comparer<string>.Create((a, b) => string.Compare(a, b, true)));
private void GetLanguageNames()
{
    // 獲得簡體中文的語言名稱
    string uri = TEXT_TRANSLATION_API_ENDPOINT + "GetLanguageNames?locale=zh-CHS";
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.Headers.Add("Ocp-Apim-Subscription-Key", TEXT_TRANSLATION_API_SUBSCRIPTION_KEY);
    request.ContentType = "text/xml";
    request.Method = "POST";
    DataContractSerializer dcs = new DataContractSerializer(Type.GetType("System.String[]"));
    using (Stream stream = request.GetRequestStream())
    {
        dcs.WriteObject(stream, languageCodes);
    }
        
    // 把返回的 xml 資訊抽取到陣列中
    var response = request.GetResponse();
    string[] languageNames;
    using (Stream stream = response.GetResponseStream())
    {
        languageNames = (string[])dcs.ReadObject(stream);
    }
        
    // 把支援的語言列表及其友好名稱儲存到字典資料結構中,
    // 隨後會把它們繫結給 combo box 控制元件進行顯示
    for (int i = 0; i < languageNames.Length; i++)
    {
        languageCodesAndTitles.Add(languageNames[i], languageCodes[i]);
    }
}
複製程式碼

這次我們拿到了用中文顯示的語言名稱:

初始化源和目標語言列表

當獲得了支援翻譯的語言列表後,就可以通過 UI 控制元件把它們顯示出來:

複製程式碼
private void PopulateLanguageMenus()
{
    int count = languageCodesAndTitles.Count;
    foreach (string menuItem in languageCodesAndTitles.Keys)
    {
        FromLanguageComboBox.Items.Add(menuItem);
        ToLanguageComboBox.Items.Add(menuItem);
    }

    // 設定預設的源語言和目標語言
    FromLanguageComboBox.SelectedItem = "英語";
    ToLanguageComboBox.SelectedItem = "簡體中文";
}
複製程式碼

在我們的使用場景中,把預設的翻譯文字設定為 "英語",翻譯的目標語言為 "簡體中文":

翻譯文字

接下來介紹文字翻譯的 API,其核心是下面的 url 請求:

TEXT_TRANSLATION_API_ENDPOINT + "Translate?text=" + 待翻譯文字 + "&from=" + 源語言 + "&to=" + 目標語言

同樣,我們把它封裝成一個具有完整功能的函式:

複製程式碼
private void TranslateButton_Click(object sender, EventArgs e)
{
    string textToTranslate = TextToTranslate.Text.Trim();
    string fromLanguage = FromLanguageComboBox.SelectedValue.ToString();
    string fromLanguageCode = languageCodesAndTitles[fromLanguage];
    string toLanguageCode = languageCodesAndTitles[ToLanguageComboBox.SelectedValue.ToString()];

    // 如果要翻譯的文字是英語,還可以進行拼寫檢查
    if (fromLanguageCode == "en")
    {
        textToTranslate = CorrectSpelling(textToTranslate);
        // 把更新後的文字儲存到 UI 控制元件上
        TextToTranslate.Text = textToTranslate;     
    }

    // 處理文字為空和不需要翻譯的情況
    if (textToTranslate == "" || fromLanguageCode == toLanguageCode)
    {
        TranslatedText.Text = textToTranslate;
        return;
    }

    // 通過 http 請求執行翻譯任務
    string uri = string.Format(TEXT_TRANSLATION_API_ENDPOINT + "Translate?text=" +
        System.Web.HttpUtility.UrlEncode(textToTranslate) + "&from={0}&to={1}", fromLanguageCode, toLanguageCode);
    var translationWebRequest = HttpWebRequest.Create(uri);
    translationWebRequest.Headers.Add("Ocp-Apim-Subscription-Key", TEXT_TRANSLATION_API_SUBSCRIPTION_KEY);
    WebResponse response = null;
    response = translationWebRequest.GetResponse();

    // 把返回的翻譯結果抽取到 UI 控制元件中
    Stream stream = response.GetResponseStream();
    StreamReader translatedStream = new StreamReader(stream, Encoding.GetEncoding("utf-8"));
    System.Xml.XmlDocument xmlResponse = new System.Xml.XmlDocument();
    xmlResponse.LoadXml(translatedStream.ReadToEnd());
    TranslatedText.Text = xmlResponse.InnerText;
}
複製程式碼

在呼叫翻譯文字的 API 前,需要先從 UI 控制元件中取得使用者設定的源語言和目標語言,並且還要對放在 url 中傳輸的文字內容進行編碼:

string uri = string.Format(TEXT_TRANSLATION_API_ENDPOINT + "Translate?text=" +
    System.Web.HttpUtility.UrlEncode(textToTranslate) + "&from={0}&to={1}", fromLanguageCode, toLanguageCode);

拼寫檢查

對於英語,我們可以通過 Bing Spell Check 服務進行翻譯前的拼寫檢查。比如 TranslateButton_Click 函式中的:

複製程式碼
// 如果要翻譯的文字是英語,還可以進行拼寫檢查
if (fromLanguageCode == "en")
{
    textToTranslate = CorrectSpelling(textToTranslate);
    // 把更新後的文字儲存到 UI 控制元件上
    TextToTranslate.Text = textToTranslate;     
}
複製程式碼

主要的拼寫檢查邏輯被封裝在了 CorrectSpelling 函式中:

複製程式碼
private string CorrectSpelling(string text)
{
    string uri = BING_SPELL_CHECK_API_ENDPOINT + "?mode=spell&mkt=en-US";
    // 建立拼寫檢查的請求
    HttpWebRequest spellCheckWebRequest = (HttpWebRequest)WebRequest.Create(uri);
    spellCheckWebRequest.Headers.Add("Ocp-Apim-Subscription-Key", BING_SPELL_CHECK_API_SUBSCRIPTION_KEY);
    spellCheckWebRequest.Method = "POST";
    spellCheckWebRequest.ContentType = "application/x-www-form-urlencoded"; // 這個設定是必須的!

    // 把文字內容放在請求的 body 中
    string body = "text=" + System.Web.HttpUtility.UrlEncode(text);
    byte[] data = Encoding.UTF8.GetBytes(body);
    spellCheckWebRequest.ContentLength = data.Length;
    using (var requestStream = spellCheckWebRequest.GetRequestStream())
        requestStream.Write(data, 0, data.Length);
    HttpWebResponse response = (HttpWebResponse)spellCheckWebRequest.GetResponse();

    // 從返回中取出 json 格式的拼寫檢查結果
    var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    var responseStream = response.GetResponseStream();
    var jsonString = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")).ReadToEnd();
    dynamic jsonResponse = serializer.DeserializeObject(jsonString);
    var flaggedTokens = jsonResponse["flaggedTokens"];

    // 我們定義一個規則來應用拼寫檢查的結果,
    // 比如:當拼寫檢查的權值大於 0.7 時就用建議的值替換掉文字中的值。
    var corrections = new SortedDictionary<int, string[]>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
    for (int i = 0; i < flaggedTokens.Length; i++)
    {
        var correction = flaggedTokens[i];
        var suggestion = correction["suggestions"][0];
        if (suggestion["score"] > (decimal)0.7)         
            corrections[(int)correction["offset"]] = new string[]   
                { correction["token"], suggestion["suggestion"] };
    }

    foreach (int i in corrections.Keys)
    {
        var oldtext = corrections[i][0];
        var newtext = corrections[i][1];
        if (text.Substring(i, oldtext.Length).All(char.IsUpper)) newtext = newtext.ToUpper();
        else if (char.IsUpper(text[i])) newtext = newtext[0].ToString().ToUpper() + newtext.Substring(1);
        text = text.Substring(0, i) + newtext + text.Substring(i + oldtext.Length);
    }
    return text;
}
複製程式碼

從上面的程式碼可以看出,拼寫檢查只是給出一些建議,具體怎麼做還是由使用者決定的。比如上面的程式碼中當拼寫檢查的權值大於 0.7 時就用建議的值替換掉文字中的值。下面我們來測試一下拼寫檢查的邏輯,執行程式,並輸入 "helo world!" 進行翻譯:

執行翻譯操作,程式碼邏輯在檢測到待翻譯的語言為英語時,會先進行程式碼的拼寫檢查:

上圖顯示拼寫檢查函式 CorrectSpelling 糾正了我們的拼寫錯誤,下面是翻譯的結果:

有了程式碼的拼寫檢查,是不是感覺這個程式有點 "智慧" 的味道啦!

總結

就像 azure 提供的其它服務一樣,入門和上手非常的容易。我們簡單的搞了幾下就能夠執行一個簡單的文字翻譯程式了。
當然這只是一個開始,希望大家和筆者一道通過本文開啟 Azure AI 的一段旅程。

參考:

轉載自:https://www.cnblogs.com/sparkdev/p/8847494.html