WebApiClientCore簡約呼叫百度AI介面

jiulang發表於2020-07-23

WebApiClientCore

WebApiClient.JIT/AOT的netcore版本,集高效能高可擴充套件性於一體的宣告式http客戶端庫,特別適用於微服務的restful資源請求,也適用於各種畸形http介面請求。

百度AI

百度AI目前相當開放(至少在使用上),如果不是高併發請求場景,一般免費使用即可。鑑於其提供的.net sdk比較先進(laji),使用Dictionary型別替代模型引數,以及使用萬能的JObject型別做為返回值型別的設計,正常人都無法體會其中精髓。試看以下的api原型,想必大家都想找找沒有文件說明吧?我覺得這sdk更像是一個httpUtil,只提供了一個 object Send( object )方法。

public JObject Detect(string image, string imageType, Dictionary<string, object> options = null);

小牛試刀

今天我們拋開官方SDK,使用WebApiClientCore請求我們感興趣的人臉檢測介面,雖然只有一個介面,但我會盡量按高規格的設計質量來呼叫這個介面,讓朋友們瞭解WebApiClientCore的魅力之處。首先,我們先閱讀官方文件:Api文件.人臉檢測,根據文件內容,大概有以下知識塊:

  • access_token獲取與使用
  • access_token的過期與重新整理
  • 請求引數模型
  • 正確的響應結果模型
  • 人臉識別錯誤碼

模型設計

請求引數模型

為了使用方便,我們將圖片型別、人臉型別設計為列舉型別,注意實際請求時,傳輸的是列舉的鍵名,而不是值。

/// <summary>
/// 表示待人臉檢測的圖片
/// </summary>
public class DetectImage
{
    /// <summary>
    /// 圖片資訊
    /// </summary>
    public string Image { get; set; }

    /// <summary>
    /// 圖片資訊
    /// </summary>
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public ImageType Image_type { get; set; }

    /// <summary>
    /// 最多處理人臉的數目
    /// </summary>
    [Range(1, 10)]
    public int? Max_face_num { get; set; } = 1;

    /// <summary>
    /// 人臉的型別
    /// </summary>
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public FaceType Face_type { get; set; }


    /// <summary>
    /// 影像型別
    /// </summary>
    public enum ImageType
    {
        /// <summary>
        /// 圖片的base64值
        /// </summary>
        BASE64,
        /// <summary>
        /// 圖片的 URL地址
        /// </summary>
        URL,
        /// <summary>
        /// 人臉圖片的唯一標識
        /// </summary>
        FACE_TOKEN
    }

    /// <summary>
    /// 人臉的型別
    /// </summary>
    public enum FaceType
    {
        /// <summary>
        /// 生活照
        /// </summary>
        LIVE,
        /// <summary>
        /// 身份證晶片照
        /// </summary>
        IDCARD,
        /// <summary>
        /// 帶水印證件照
        /// </summary>
        WATERMARK,
        /// <summary>
        /// 證件照片
        /// </summary>
        CERT
    }
}

響應模型

通過PostMan預請求,我們發現官方文件裡提到的響應內容,實際上只是完整響應內容的裡面的Result值而已(官方文件有點不靠譜) 。

/// <summary>
/// 響應內容
/// </summary>
/// <typeparam name="T"></typeparam>
public class Response<T>
{
    /// <summary>
    /// 錯誤碼
    /// </summary>
    public int Error_code { get; set; }

    /// <summary>
    /// 錯誤資訊
    /// </summary>
    public string Error_msg { get; set; }

    /// <summary>
    /// 結果值
    /// </summary>
    public T Result { get; set; }
}

/// <summary>
/// 表示檢測結果
/// </summary>
public class DetectResult
{
    /// <summary>
    /// 人臉數量
    /// </summary>
    public int Face_num { get; set; }

    /// <summary>
    /// 人臉列表
    /// </summary>
    public FaceItem[] Face_list { get; set; }

    /// <summary>
    /// 人臉
    /// </summary>
    public class FaceItem
    {
        public string Face_token { get; set; }

        public FaceLocation Location { get; set; }

        public int Face_probability { get; set; }

        public FaceAngle Angle { get; set; }

        /// <summary>
        /// 位置
        /// </summary>
        public class FaceLocation
        {
            public double Left { get; set; }
            public double Top { get; set; }
            public int Width { get; set; }
            public int Height { get; set; }
            public int Rotation { get; set; }
        }

        /// <summary>
        /// 角度
        /// </summary>
        public class FaceAngle
        {
            public double Yaw { get; set; }
            public double Pitch { get; set; }
            public double Roll { get; set; }
        }
    }
}

介面宣告

應用請求與響應模型

/// <summary>
/// 百度人臉相關介面
/// </summary>
public interface IBaiduFaceApi
{
    /// <summary>
    /// 影像的人臉檢測
    /// </summary>
    /// <param name="detectImage">待檢測影像</param>
    /// <returns></returns>
    [HttpPost("rest/2.0/face/v3/detect")]
    ITask<Response<DetectResult>> DetectAsync([JsonContent] DetectImage detectImage);
}

應用請求日誌

為了方便除錯,我們需要將實際請求內容輸出到日誌元件,這裡為介面應用[LoggingFilter]。

/// <summary>
/// 百度人臉相關介面
/// </summary>
[LoggingFilter]
public interface IBaiduFaceApi
{
    /// <summary>
    /// 影像的人臉檢測
    /// </summary>
    /// <param name="detectImage">待檢測影像</param>
    /// <returns></returns>
    [HttpPost("rest/2.0/face/v3/detect")]
    ITask<Response<DetectResult>> DetectAsync([JsonContent] DetectImage detectImage);
}

應用access_token

access_token我們可以做為一個切面處理,WebApiClientCore.Extensions.OAuths擴充套件包專門處理這個切面,由於百度的access_token不是標準的放到Authorization請求頭,而是放到access_token的query引數,所以我們需要繼承ClientCredentialsTokenAttribute來實現自定義token應用特性。

/// <summary>
/// token應用特性
/// </summary>
class AccessTokenAttribute : ClientCredentialsTokenAttribute
{
    protected override void UseTokenResult(ApiRequestContext context, TokenResult tokenResult)
    {
        context.HttpContext.RequestMessage.AddUrlQuery("access_token", tokenResult.Access_token);
    }
}


/// <summary>
/// 百度人臉相關介面
/// </summary>
[AccessToken]
[LoggingFilter]
public interface IBaiduFaceApi
{
    /// <summary>
    /// 影像的人臉檢測
    /// </summary>
    /// <param name="detectImage">待檢測影像</param>
    /// <returns></returns>
    [HttpPost("rest/2.0/face/v3/detect")]
    ITask<Response<DetectResult>> DetectAsync([JsonContent] DetectImage detectImage);
}

介面註冊與配置

介面註冊

services.AddHttpApi<IBaiduFaceApi>(c =>
{
    c.HttpHost = new Uri("https://aip.baidubce.com/");
});

token提供者配置

百度返回的token有refreshToken值,但文件裡沒有提到怎麼重新整理token,嘗試使用token請求地址去重新整理token會失敗,所以這裡直接配置禁用使用refreshToken的功能,強迫時間到期之後,重新去申請一次token。

services.AddClientCredentialsTokenProvider<IBaiduFaceApi>(c =>
{
    c.Endpoint = new Uri("https://aip.baidubce.com/oauth/2.0/token");
    c.UseRefreshToken = false;
    c.Credentials.Client_id = "API Key";
    c.Credentials.Client_secret = "Secret Key";
});

介面呼叫

將IBaiduFaceApi注入到我們的服務,即可呼叫

public class FaceService
{
    private readonly IBaiduFaceApi baiduFaceApi;

    public FaceService(IBaiduFaceApi baiduFaceApi)
    {
        this.baiduFaceApi = baiduFaceApi;
    }

    public async Task DetectAsync()
    {
        var img = new DetectImage
        {
            Face_type = DetectImage.FaceType.IDCARD,
            Image = "http://xxx.jpg",
            Image_type = DetectImage.ImageType.URL
        };
        var result = await baiduFaceApi.DetectAsync(img);
    }
}

現在,我們已經拿到正常的結果,順便檢視請求日誌確認請求是否正確。

POST /rest/2.0/face/v3/detect?access_token=省略值 HTTP/1.1
Host: aip.baidubce.com
User-Agent: WebApiClientCore/1.0.6.0
Accept: application/json; q=0.01, application/xml; q=0.01
Content-Type: application/json; charset=utf-8

{"image":"http://xxx.jpg","image_type":"URL","max_face_num":1,"face_type":"IDCARD"}
HTTP/1.1 200 OK
Connection: keep-alive
Date: Thu, 23 Jul 2020 02:05:58 GMT
Content-Type: application/json
Content-Length: 328

{"error_code":0,"error_msg":"SUCCESS","log_id":2599254579794,"timestamp":1595469958,"cached":0,"result":{"face_num":1,"face_list":[{"face_token":"97071a7f306483fea94d0766cfeb120c","location":{"left":34.54,"top":74.23,"width":101,"height":101,"rotation":0},"face_probability":1,"angle":{"yaw":-0.92,"pitch":6.68,"roll":-3.72}}]}}

結束語

以上為WebApiClientCore在百度Ai請求的一個小例子,當然WebApiClientCore還有好多功能,點選專案連結,帶你GET到N種使用技能,不求star,只求提供良好建議。

https://github.com/dotnetcore/WebApiClient

相關文章