一、功能介绍
使用百度AI技术《通用文字识别(高精度)》和《通用翻译API(标准版)》来实现图片/文字翻译功能,本教程仅实现中英文翻译,其他语言翻译在此基础上稍加修改就能实现。
二、应用场景
通用翻译API可广泛应用于APP、网站及客户端,提供实时优质的多语言翻译服务。
将此翻译功能部署到网站上,可实现手机拍照翻译的效果(部分手机浏览器的图片上传功能可实现直接拍照上传图片),添加多语种翻译后,基本上就是一个简单的在线拍照翻译网站了。
对于出国游玩、纸质文献翻译等场景,拍照翻译就显得很有必要了。
三、使用攻略
说明:本文采用C# 语言,开发环境为.Net Core 3.1,采用在线API接口方式实现。
(1)接口文档
(1-1)通用文字识别(高精度)
文档地址:https://ai.baidu.com/ai-doc/OCR/1k3h7y3db
接口描述:在通用文字识别的基础上,提供更高精度的识别服务,支持更多语种识别(丹麦语、荷兰语、马来语、瑞典语、印尼语、波兰语、罗马尼亚语、土耳其语、希腊语、匈牙利语),并将字库从1w+扩展到2w+,能识别所有常用字和大部分生僻字。
(1-2)通用翻译API(标准版)
文档地址:http://fanyi-api.baidu.com/doc/21
接口描述:通用翻译API通过HTTP接口对外提供多语种互译服务。您只需要通过调用通用翻译API,传入待翻译的内容,并指定要翻译的源语言(支持源语言语种自动检测)和目标语言种类,就可以得到相应的翻译结果。
具体关于输入参数、输出参数、错误码等说明,请参考开发文档,这里不再罗列。
(2)源码共享
(2-1)根据 API Key 和 Secret Key 获取 AccessToken
///
/// 获取百度access_token
///
/// API Key
/// Secret Key
///
public static string GetAccessToken(string clientId, string clientSecret)
{
string authHost = "https://aip.baidubce.com/oauth/2.0/token";
HttpClient client = new HttpClient();
List> paraList = new List>();
paraList.Add(new KeyValuePair("grant_type", "client_credentials"));
paraList.Add(new KeyValuePair("client_id", clientId));
paraList.Add(new KeyValuePair("client_secret", clientSecret));
HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
string result = response.Content.ReadAsStringAsync().Result;
JObject jo = (JObject)JsonConvert.DeserializeObject(result);
string token = jo["access_token"].ToString();
return token;
}
(2-2)调用API接口获取识别结果
(2-2-1)在Startup.cs 文件 的 Configure(IApplicationBuilder app, IHostingEnvironment env) 方法中开启虚拟目录映射功能:
string webRootPath = HostingEnvironment.WebRootPath;//wwwroot目录
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(webRootPath, "Uploads", "BaiduAIs")),
RequestPath = "/BaiduAIs"
});
(2-2-2) 建立Index.cshtml文件
(2-2-2-1)前台代码:
由于html代码无法原生显示,只能简单说明一下:
主要是一个form表单,需要设置属性enctype="multipart/form-data",否则无法上传图片;
form表单里面有几个控件:
一个input:type="file",asp-for="FileUpload" ,上传图片;
一个textarea:asp-for="Text" ,输入要翻译的内容;
一个input:type="submit",asp-page-handler="Words" ,实现文字翻译功能。
一个input:type="submit",asp-page-handler="Accurate" ,实现图片识别文字翻译功能。
一个img:src="@Model.curPath",显示需要识别的图片。
最后显示后台 msg 字符串列表信息,如果需要输出原始Html代码,则需要使用@Html.Raw()函数。
(2-2-2-2) 后台代码:
主程序代码:
[BindProperty]
public IFormFile FileUpload { get; set; }
[BindProperty]
public string ImageUrl { get; set; }
[BindProperty]
public string Text { get; set; }
public List msg = new List();
public StringBuilder sourceLanguage = new StringBuilder();
public string curPath { get; set; }
string webRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
string BaiduAI_OCRPath="Uploads//BaiduAIs//";
string BaiduAI_OCRUrl="/BaiduAIs/";
string OCR_API_KEY="你的API KEY";
string OCR_SECRET_KEY="你的SECRET KEY";
string Trans_APP_ID="你的百度翻译APP_ID";
string Trans_API_KEY="你的百度翻译SECRET_KEY";
public TransModel()
{
}
public void OnGet()
{
}
///
/// 获取翻译后的目标语言
///
/// 源语言
///
private string GetTargetLanguage(string sorceLanguage)
{
string salt = GetRandomString();
string sign = EncryptString(Trans_APP_ID + sorceLanguage + salt + Trans_API_KEY);
string targetLanguage = GetFormTransJson(sorceLanguage, salt, sign, Trans_APP_ID, Trans_API_KEY);
JObject jo = (JObject)JsonStringToObj(targetLanguage);
return jo["trans_result"].ToList()[0]["dst"].ToString();
}
public async Task OnPostWordsAsync()
{
if (string.IsNullOrEmpty(Text))
{
ModelState.AddModelError(string.Empty, "请输入翻译内容!");
}
if (!ModelState.IsValid)
{
return Page();
}
msg = new List();
sourceLanguage = new StringBuilder();
try
{
sourceLanguage.Append(Text.ToString());
DateTime startTime = DateTime.Now;
string targetLanguage = sourceLanguage.Length > 0 ? GetTargetLanguage(sourceLanguage.ToString()) : "";
DateTime endTime = DateTime.Now;
TimeSpan ts = endTime - startTime;
msg.Add("文字翻译结果(耗时" + ts.TotalSeconds + "秒):\n");
msg.Add("源语言:\n" + sourceLanguage.ToString());
msg.Add("\n目标语言:\n" + targetLanguage);
}
catch (Exception e)
{
msg.Add(e.ToString());
}
return Page();
}
public async Task OnPostAccurateAsync()
{
if (FileUpload is null)
{
ModelState.AddModelError(string.Empty, "请先选择需要识别的图片!");
}
if (!ModelState.IsValid)
{
return Page();
}
msg = new List();
sourceLanguage = new StringBuilder();
string fileDir = Path.Combine(webRootPath, BaiduAI_OCRPath);
string imgName = GetRandomName();
imgName = await UploadFile(FileUpload, fileDir);
string fileName = Path.Combine(fileDir, imgName);
string imgBase64 = GetFileBase64(fileName);
curPath = Path.Combine(BaiduAI_OCRUrl, imgName);
DateTime startTime = DateTime.Now;
string result = GetOCRJson(imgBase64, OCR_API_KEY, OCR_SECRET_KEY);
DateTime endTime = DateTime.Now;
TimeSpan ts = endTime - startTime;
JObject jo = (JObject)JsonStringToObj(result);
try
{
msg.Add("文字识别(高精度)(耗时" + ts.TotalSeconds + "秒)翻译结果:\n");
List msgList = jo["words_result"].ToList();
foreach (JToken ms in msgList)
{
sourceLanguage.Append(ms["words"].ToString());
}
startTime = DateTime.Now;
string targetLanguage = sourceLanguage.Length > 0 ? GetTargetLanguage(sourceLanguage.ToString()) : "";
endTime = DateTime.Now;
ts = endTime - startTime;
msg.Add("源语言:\n" + sourceLanguage.ToString());
msg.Add("\n目标语言(耗时" + ts.TotalSeconds + "秒):\n" + targetLanguage);
}
catch (Exception e)
{
msg.Add(result);
}
return Page();
}
其他相关函数:
///
/// 百度翻译字符串
///
/// 原文
/// 随机数
/// 签名
/// APP ID
/// 密钥
/// 源语言
/// 目标语言
///
public static string GetFormTransJson(string q, string salt, string sign, string appId, string secretKey, string from = "zh", string to = "en")
{
string url = "http://api.fanyi.baidu.com/api/trans/vip/translate?";
url += "q=" + HttpUtility.UrlEncode(q);
url += "&from=" + from;
url += "&to=" + to;
url += "&appid=" + appId;
url += "&salt=" + salt;
url += "&sign=" + sign;
Encoding encoding = Encoding.Default;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.ContentType = "text/html;charset=UTF-8";
request.UserAgent = null;
request.Timeout = 6000;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
string result = reader.ReadToEnd();
return result;
}
///
/// 文字识别Json字符串
///
/// 图片base64编码
/// API Key
/// Secret Key
///
public static string GetOCRJson( string strbaser64, string clientId, string clientSecret)
{
string token = GetAccessToken(clientId, clientSecret);
string host = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + token;
Encoding encoding = Encoding.Default;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
request.Method = "post";
request.ContentType = "application/x-www-form-urlencoded";
request.KeepAlive = true;
string str = "image=" + HttpUtility.UrlEncode(strbaser64);
byte[] buffer = encoding.GetBytes(str);
request.ContentLength = buffer.Length;
request.GetRequestStream().Write(buffer, 0, buffer.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
string result = reader.ReadToEnd();
return result;
}
///
/// 获取百度access_token
///
/// API Key
/// Secret Key
///
public static string GetAccessToken(string clientId, string clientSecret)
{
string authHost = "https://aip.baidubce.com/oauth/2.0/token";
HttpClient client = new HttpClient();
List> paraList = new List>();
paraList.Add(new KeyValuePair("grant_type", "client_credentials"));
paraList.Add(new KeyValuePair("client_id", clientId));
paraList.Add(new KeyValuePair("client_secret", clientSecret));
HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result;
string result = response.Content.ReadAsStringAsync().Result;
JObject jo = (JObject)JsonConvert.DeserializeObject(result);
string token = jo["access_token"].ToString();
return token;
}
///
/// 计算MD5值
///
/// 文本
///
public static string EncryptString(string str)
{
MD5 md5 = MD5.Create();
// 将字符串转换成字节数组
byte[] byteOld = Encoding.UTF8.GetBytes(str);
// 调用加密方法
byte[] byteNew = md5.ComputeHash(byteOld);
// 将加密结果转换为字符串
StringBuilder sb = new StringBuilder();
foreach (byte b in byteNew)
{
// 将字节转换成16进制表示的字符串,
sb.Append(b.ToString("x2"));
}
// 返回加密的字符串
return sb.ToString();
}
///
/// 获取一个随机数
///
///
public static string GetRandomString()
{
Random rd = new Random();
string salt = rd.Next(100000).ToString();
return salt;
}
///
/// 生成一个随机唯一文件名(Guid)
///
///
public static string GetRandomName()
{
return Guid.NewGuid().ToString("N");
}
///
/// 返回图片的base64编码
///
/// 文件绝对路径名称
///
public static String GetFileBase64(string fileName)
{
FileStream filestream = new FileStream(fileName, FileMode.Open);
byte[] arr = new byte[filestream.Length];
filestream.Read(arr, 0, (int)filestream.Length);
string baser64 = Convert.ToBase64String(arr);
filestream.Close();
return baser64;
}
///
/// json转为对象
///
/// Json字符串
///
public static Object JsonStringToObj(string jsonString)
{
Object s = JsonConvert.DeserializeObject(jsonString);
return s;
}
///
/// 上传文件,返回文件名
///
/// 文件上传控件
/// 文件绝对路径
///
public static async Task UploadFile(IFormFile formFile, string fileDir)
{
if (!DirectoryExists(directory))
{
Directory.CreateDirectory(directory);
}
string extension = Path.GetExtension(formFile.FileName);
string imgName = Guid.NewGuid().ToString("N") + extension;
var filePath = Path.Combine(fileDir, imgName);
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
await formFile.CopyToAsync(fileStream);
}
return imgName;
}
四、效果测试
1、页面:
2、识别结果:
2.1
2.2
2.3
2.4
2.5
五、测试结果及建议
从测试结果来看,文字翻译结果在简单的语句上是比较准的,速度也是比较快的,0.3秒左右,但是当语句比较复杂且没有分隔符的时候(图2.3,图2.4)翻译结果就比较差了,当然这个情况也比较少见,不过也是一个需要优化的地方:实现智能断句,正确翻译。
其实图片拍照翻译这个用处还是比较大的,随手一拍,直接显示翻译结果,简单方便,特别是出国旅游/纸质文献翻译等场景下,基本上算得上刚需了。
百度也有专门的拍照翻译SDK/API一体化,大家也可以去试试看。
看到了,,原来机器翻译也有啊
这个是不是偏题了呀