經過上一篇簡單說明與設定 Cognitive Service - 文字翻譯服務,在這一篇我們要開始實作英文翻譯機器人。這邊提供一個範例,您可以透過這個範例進行延伸,增加文字語言偵測或多語言翻譯功能,讓這個機器人功能更加完善與嚴謹。
註:若您尚未設定 Azure Translate Text API,請回到上一篇
如同上一篇說明的,我們的流程如下圖,會有兩個程式區塊:取得 Access Token 與使用翻譯服務。
Step 1. 首先我們新增一個類別,命名為 AzureAuthToken.cs。
Step 2. 增加一個方法GetAccessTokenAsync用來進行驗證並且取得 Access Token,內容如下(參考範本):
public class AzureAuthToken
{
private static readonly Uri ServiceUrl = new Uri("https://api.cognitive.microsoft.com/sts/v1.0/issueToken");
private const string OcpApimSubscriptionKeyHeader = "Ocp-Apim-Subscription-Key";
private static readonly TimeSpan TokenCacheDuration = new TimeSpan(0, 5, 0);
private string _storedTokenValue = string.Empty;
private DateTime _storedTokenTime = DateTime.MinValue;
public string SubscriptionKey { get; }
public HttpStatusCode RequestStatusCode { get; private set; }
public AzureAuthToken(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException(nameof(key), "A subscription key is required");
}
this.SubscriptionKey = key;
this.RequestStatusCode = HttpStatusCode.InternalServerError;
}
public async Task<string> GetAccessTokenAsync()
{
if (string.IsNullOrWhiteSpace(this.SubscriptionKey))
{
return string.Empty;
}
// Re-use the cached token if there is one.
if ((DateTime.Now - _storedTokenTime) < TokenCacheDuration)
{
return _storedTokenValue;
}
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = ServiceUrl;
request.Content = new StringContent(string.Empty);
request.Headers.TryAddWithoutValidation(OcpApimSubscriptionKeyHeader, this.SubscriptionKey);
client.Timeout = TimeSpan.FromSeconds(2);
var response = await client.SendAsync(request);
this.RequestStatusCode = response.StatusCode;
response.EnsureSuccessStatusCode();
var token = await response.Content.ReadAsStringAsync();
_storedTokenTime = DateTime.Now;
_storedTokenValue = "Bearer " + token;
return _storedTokenValue;
}
}
public string GetAccessToken()
{
// Re-use the cached token if there is one.
if ((DateTime.Now - _storedTokenTime) < TokenCacheDuration)
{
return _storedTokenValue;
}
string accessToken = null;
var task = Task.Run(async () =>
{
accessToken = await this.GetAccessTokenAsync();
});
while (!task.IsCompleted)
{
System.Threading.Thread.Yield();
}
if (task.IsFaulted)
{
throw task.Exception;
}
if (task.IsCanceled)
{
throw new Exception("Timeout obtaining access token.");
}
return accessToken;
}
}
Step 3. 開啟 Bot Template 範本新專案,開啟 RootDialog.cs,先增加一個私有方法 AuthoizeService
private async Task<string> AuthoizeService(string key)
{
var authTokenSource = new AzureAuthToken(key.Trim());
string authToken;
try
{
authToken = await authTokenSource.GetAccessTokenAsync();
}
catch (HttpRequestException)
{
if (authTokenSource.RequestStatusCode == HttpStatusCode.Unauthorized)
{
return "Request to token service is not authorized (401). Check that the Azure subscription key is valid.";
}
if (authTokenSource.RequestStatusCode == HttpStatusCode.Forbidden)
{
return "Request to token service is not authorized (403). For accounts in the free-tier, check that the account quota is not exceeded.";
}
throw;
}
return authToken;
}
Step 4. 新增一個私有方法 TranslateString,用於呼叫翻譯
註:因為是簡單講解如何介接服務,XML剖析部分,實作時請用更好的方法處理
private async Task<string> TranslateString(string authToken, string text)
{
string from = "en";
string to = "zh";
string uri = "/v2/Http.svc/Translate?text=" + HttpUtility.UrlEncode(text) + "&from=" + from + "&to=" + to;
string result = string.Empty;
var client = new RestClient("https://api.microsofttranslator.com");
var request = new RestRequest(uri, Method.GET);
request.AddHeader("Authorization", authToken);
var response = await client.ExecuteTaskAsync(request);
return response.Content.Replace("<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">", "").Replace("</string>", "");
}
Step 5. 增加 Key
private string APIPassword = "83xxxxxxxxxxxxxxx";
Step 6. 修改程式如下:
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
string response = string.Empty;
if (activity.Text.StartsWith("tran") || activity.Text.StartsWith("翻譯"))
{
string authToken = string.Empty;
authToken = await AuthoizeService(APIPassword);
response = await TranslateString(authToken, activity.Text.Replace("tran", "").Replace("翻譯",""));
}
// return our reply to the user
await context.PostAsync($"{response}");
context.Wait(MessageReceivedAsync);
}
Step 7.啟動專案
Step 8.透過模擬器測試,成功!!
https://github.com/matsurigoto/TranslatorBotExample.git
其實做多功能機器人好像沒有很難...? (被毆)