当前位置 博文首页 > time-flies:C#调百度通用翻译API翻译HALCON的示例描述

    time-flies:C#调百度通用翻译API翻译HALCON的示例描述

    作者:time-flies 时间:2021-06-26 18:27

    通用翻译API的HTTPS 地址为https://fanyi-api.baidu.com/api/trans/vip/translate,使用方法参考通用翻译API接入文档 。 请求方式可使用 GET 或 POST 方式(Content-Type 请指定为:application/x-www-form-urlencoded),字符编码统一采用 UTF-8 编码格式,单次请求长度控制在 6000 bytes以内(汉字约为输入参数 2000 个)。 API返回的结果是json格式,需要反序列为对象实例后再进行处理。为了减少第三方库的依赖,反序列化使用.NET自带的DataContractJsonSerializer。

    目录
    • 准备工作
    • 参数简介
      • 输入参数
      • 输出参数
    • 使用HttpClient
    • 翻译工具类
    • 应用:翻译HALCON的示例描述

    准备工作

    HALCON示例程序的描述部分一直是英文的,看起来很不方便。我决定汉化一下HALCON示例程序的描述,准备工作如下:

    • 拿到HALCON的例程描述文件index_examples_en_US.xml,我的在C:\Program Files\MVTec\HALCON-18.11-Progress\help,其它版本类似。
    • 在百度翻译开放平台注册拿到自己的ID和密钥,开通通用翻译API服务。

    注:百度官方有提供通用翻译API的使用DEMO,不过比较简单,C# DEMO下载

    参数简介

    通用翻译API的HTTPS 地址为https://fanyi-api.baidu.com/api/trans/vip/translate,使用方法参考通用翻译API接入文档 。

    输入参数

    请求方式可使用 GETPOST 方式(Content-Type 请指定为:application/x-www-form-urlencoded),字符编码统一采用 UTF-8 编码格式,单次请求长度控制在 6000 bytes以内(汉字约为输入参数 2000 个)。
    将API需要的输入参数封装为一个类(ID和密钥换成自己的),代码如下:

    /// <summary>
    /// 输入产数
    /// </summary>
    class InputQuery
    {
        /// <summary>
        /// APP ID
        /// </summary>
        private static string appId = "2021xxxxxxx0626";
        /// <summary>
        /// 密钥
        /// </summary>
        private static string passWord = "cnblongsxtimefiles";
    
    
        /// <summary>
        /// 请求翻译query UTF-8编码
        /// </summary>
        public string Content { get; set; }
        /// <summary>
        /// 翻译源语言 可设置为auto
        /// </summary>
        public string From { get; set; }
        /// <summary>
        /// 翻译目标语言 不可设置为auto
        /// </summary>
        public string To { get; set; }
        /// <summary>
        /// APP ID
        /// </summary>
        public string AppId { get; set; }
        /// <summary>
        /// 随机数 可为字母或数字的字符串
        /// </summary>
        public string Salt { get; set; }
        /// <summary>
        /// 签名 appid+q+salt+密钥的MD5值
        /// </summary>
        public string Sign { get; set; }
    
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="content">翻译内容</param>
        /// <param name="fromStr">源语言</param>
        /// <param name="toStr">目标语言</param>
        public InputQuery(string content, string fromStr, string toStr)
        {
            Content = content;
            From = fromStr;
            To = toStr;
            AppId = appId;
    
            string randomNum = new Random().Next().ToString();
            string md5Sign = GetMD5(appId + content + randomNum + passWord).ToLower();
            Salt = randomNum;
            Sign = md5Sign;
        }
    
        /// <summary>
        /// 计算字符串的MD5值
        /// </summary>
        static string GetMD5(string source)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] data = Encoding.UTF8.GetBytes(source);
            byte[] md5Data = md5.ComputeHash(data, 0, data.Length);
            md5.Clear();
    
            string destString = string.Empty;
            for (int i = 0; i < md5Data.Length; i++)
            {
                destString += Convert.ToString(md5Data[i], 16).PadLeft(2, '0');
            }
            destString = destString.PadLeft(32, '0');
            return destString;
        }
    }
    

    输出参数

    API返回的结果是json格式,需要反序列为对象实例后再进行处理。为了减少第三方库的依赖,反序列化使用.NET自带的DataContractJsonSerializer
    封装的输出参数类代码如下:

    /// <summary>
    /// 输出参数
    /// </summary>
    [DataContract]
    class OutputResult
    {
        
        /// <summary>
        /// 错误码 仅当出现错误时显示
        /// </summary>
        [DataMember(Name = "error_code")]
        public string Error_code { set; get; }
    
        /// <summary>
        /// 错误信息
        /// </summary>
        [DataMember(Name = "error_msg")]
        public string Error_msg { set; get; }
    
        /// <summary>
        /// 源语言 返回用户指定的语言,或者自动检测出的语种(源语言设为 auto 时)
        /// </summary>
        [DataMember(Name = "from")]
        public string From { set; get; }
    
        /// <summary>
        /// 目标语言 返回用户指定的目标语言
        /// </summary>
        [DataMember(Name = "to")]
        public string To { set; get; }
    
        /// <summary>
        /// 翻译结果 返回翻译结果,包括 src 和 dst 字段
        /// </summary>
        [DataMember(Name = "trans_result")]
        public TranslateContent[] Trans_result { set; get; }
    }
    /// <summary>
    /// 翻译结果
    /// </summary>
    [DataContract]
    class TranslateContent
    {
        /// <summary>
        /// 原文
        /// </summary>
        [DataMember(Name = "src")]
        public string Src { set; get; }
    
        /// <summary>
        /// 译文
        /// </summary>
        [DataMember(Name = "dst")]
        public string Dst { set; get; }
    }
    

    使用HttpClient

    调用API需要一个类发送 HTTP 请求以及接收HTTP响应,推荐使用HttpClient类(微软不建议使用WebClient、HttpWebRequest类)。
    需要注意的是:HttpClient 用于在应用程序的整个生存期内实例化一次并重复使用,也就是说一个应用程序只需要一个HttpClient单例即可,代码如下:

    public class GoodController
    {
        public static readonly HttpClient HttpClient;
    
        static GoodController()
        {
            HttpClient = new HttpClient();
        }
    }
    

    翻译工具类

    将API的调用方法封装成一个Translate类,目前只提供一个英翻中的方法,其它翻译需求可以参考 常见语种列表 自己扩展。
    Translate类代码如下(注意添加System.Web依赖项):

    /// <summary>
    /// 百度通用翻译API工具类
    /// </summary>
    class Translate
    {
        /*
         * 代码链接:https://www.cnblogs.com/timefiles/p/BaiduTranslateAPI.html
         * 创建时间:2021/06/26
         * 主页链接:https://www.cnblogs.com/timefiles/
         * 
         * 常用的语种代码:
         * 自动检测	auto	
         * 中文	zh	
         * 英语	en
         * 日语	jp
         */
    
        /// <summary>
        /// 英文翻译为中文
        /// </summary>
        /// <param name="content">翻译内容</param>
        /// <returns></returns>
        public static string EnToZh(string content)
        {
            string languageFrom = "en", languageTo = "zh";
            return GetTranslateResult(content, languageFrom, languageTo);
        }
    
        /// <summary>
        /// 获取翻译结果
        /// </summary>
        /// <param name="content">翻译内容</param>
        /// <param name="fromStr">源语言</param>
        /// <param name="toStr">目标语言</param>
        /// <returns></returns>
        static string GetTranslateResult(string content, string fromStr, string toStr)
        {
            InputQuery input = new InputQuery(content, fromStr, toStr);
            Uri uri = GetUri(input);
            var task = GetOutputResultAsync(uri);
            //个人认证后API的每秒请求量最高为10,异步意义不大,直接使用同步的方式
            OutputResult output = task.Result;
            if (output.Error_code == null)
            {
                return output.Trans_result[0].Dst;
            }
            else
            {
                throw new Exception("翻译异常,错误代码:" + output.Error_msg);
            }
        }
    
        /// <summary>
        /// 获取请求Uri
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        static Uri GetUri(InputQuery input)
        {
            var query = HttpUtility.ParseQueryString(string.Empty);
            query["q"] = input.Content;
            query["from"] = input.From;
            query["to"] = input.To;
            query["appid"] = input.AppId;
            query["salt"] = input.Salt;
            query["sign"] = input.Sign;
    
            //构造Uri,不建议直接拼字符串
            UriBuilder uriBur = new UriBuilder("http://api.fanyi.baidu.com/api/trans/vip/translate");
            uriBur.Query = query.ToString();
            //Uri会自动进行转义
            return uriBur.Uri;
        }
    
        /// <summary>
        /// 获取API返回的结果
        /// </summary>
        /// <param name="uri">请求的uri</param>
        /// <returns></returns>
        static async Task<OutputResult> GetOutputResultAsync(Uri uri)
        {
            OutputResult result = null;
            var response = await GoodController.HttpClient.GetStringAsync(uri);
            var ser = new DataContractJsonSerializer(typeof(OutputResult));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(response)))
            {
                result = (OutputResult)ser.ReadObject(ms);
            }
            return result;
        }
    }
    

    个人认证后API的每秒请求量最高为10,此处使用同步方式获取翻译结果,有异步需求的可以自己更改。

    应用:翻译HALCON的示例描述

    static void Main(string[] args)
    {
        XmlDocument xd = new XmlDocument();
        xd.Load("index_examples_en_US.xml");
        //查找固定名称 节点名要从根节点开始写
        XmlNodeList nodelist = xd.DocumentElement.SelectNodes("/examples/example/desc");
        for (int i = 0; i < nodelist.Count; i++)
        {
            string desc = nodelist[i].InnerText;
            //百度翻译有时不太准确,建议保留原文
            nodelist[i].InnerText = Translate.EnToZh(desc)+"("+ nodelist[i].InnerText+")";               
            Console.WriteLine("翻译结果"+i+":" + nodelist[i].InnerText);
            Console.WriteLine();
        }
    
        StreamWriter sw = new StreamWriter("index_examples_en_US_翻译.xml", false, new UTF8Encoding(false));
        //为了和原文件保存一致,原文件是使用的是"\n"换行
        sw.NewLine = "\n";
        xd.Save(sw);
        sw.Close();                  
        Console.WriteLine("完成");
        Console.Read();
    }
    

    注:大概有1000多条需要翻译,需要等待10几分钟。考虑过使用特定字符组合成几个大字符串翻译后再拆分,但特定字符在翻译过程中有丢失导致拆分失败,只能使用这种方式。

    将原HALCON的xml文件重命名作为备份,将翻译后的文件复制到HALCON程序目录下命名为index_examples_en_US.xml,效果如下:

    bk