當下人工智能可謂是風頭正勁,幾乎所有的大廠都有相關的技術棧。微軟在 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 的一段旅程。
參考:
Microsoft Translator WPF application in C#
轉載自:https://www.cnblogs.com/sparkdev/p/8847494.html