ruipay/wechat/mp/api/
ocr.rs

1use std::fs::File;
2use std::io::Read;
3use std::path::Path;
4use std::vec;
5
6use serde::{Serialize, Deserialize};
7use serde_json::{Value};
8
9use crate::{session::SessionStore, request::{RequestType}, WechatCommonResponse, WechatMpClient, LabradorResult, WechatRequest, RequestBody};
10use crate::wechat::mp::constants::IMG_URL;
11use crate::wechat::mp::method::{MpOcrMethod, WechatMpMethod};
12
13/// 微信连接WI-FI接口.
14#[derive(Debug, Clone)]
15pub struct WechatMpOcr<'a, T: SessionStore> {
16    client: &'a WechatMpClient<T>,
17}
18
19#[allow(unused)]
20impl<'a, T: SessionStore> WechatMpOcr<'a, T> {
21
22    #[inline]
23    pub fn new(client: &WechatMpClient<T>) -> WechatMpOcr<T> {
24        WechatMpOcr {
25            client,
26        }
27    }
28
29    /// 身份证OCR识别接口
30    pub async fn id_card(&self, img_url: &str) -> LabradorResult<WechatOcrIdCardResponse> {
31        let img_url = urlencoding::encode(img_url).to_string();
32        let v = self.client.post(WechatMpMethod::Ocr(MpOcrMethod::IdCard), vec![(IMG_URL.to_string(), img_url)], Value::Null, RequestType::Json).await?.json::<Value>()?;
33        WechatCommonResponse::parse::<WechatOcrIdCardResponse>(v)
34    }
35
36    /// 身份证OCR识别接口
37    pub async fn id_card_file(&self, file_path: &str) -> LabradorResult<WechatOcrIdCardResponse> {
38        let path = Path::new(file_path);
39        let file_name = path.file_name().map(|v| v.to_str().unwrap_or_default()).unwrap_or_default();
40        let mut f = File::open(path)?;
41        let mut content: Vec<u8> = Vec::new();
42        let _ = f.read_to_end(&mut content)?;
43        let req = WechatMpOcrRequest {
44            ocr_type: 1,
45            filename: "".to_string(),
46            data: content
47        };
48        let v = self.client.execute::<WechatMpOcrRequest, String>(req).await?.json::<Value>()?;
49        WechatCommonResponse::parse::<WechatOcrIdCardResponse>(v)
50    }
51
52    /// 银行卡OCR识别接口
53    /// 文件大小限制:小于2M
54    pub async fn back_card(&self, img_url: &str) -> LabradorResult<WechatOcrBankCardResponse> {
55        let img_url = urlencoding::encode(img_url).to_string();
56        let v = self.client.post(WechatMpMethod::Ocr(MpOcrMethod::BankCard), vec![(IMG_URL.to_string(), img_url)], Value::Null, RequestType::Json).await?.json::<Value>()?;
57        WechatCommonResponse::parse::<WechatOcrBankCardResponse>(v)
58    }
59
60    /// 银行卡OCR识别接口
61    /// 文件大小限制:小于2M
62    pub async fn back_card_file(&self, file_path: &str) -> LabradorResult<WechatOcrBankCardResponse> {
63        let path = Path::new(file_path);
64        let file_name = path.file_name().map(|v| v.to_str().unwrap_or_default()).unwrap_or_default();
65        let mut f = File::open(path)?;
66        let mut content: Vec<u8> = Vec::new();
67        let _ = f.read_to_end(&mut content)?;
68        let req = WechatMpOcrRequest {
69            ocr_type: 2,
70            filename: "".to_string(),
71            data: content
72        };
73        let v = self.client.execute::<WechatMpOcrRequest, String>(req).await?.json::<Value>()?;
74        WechatCommonResponse::parse::<WechatOcrBankCardResponse>(v)
75    }
76
77    /// 行驶证OCR识别接口
78    /// 文件大小限制:小于2M
79    pub async fn driving(&self, img_url: &str) -> LabradorResult<WechatOcrDrivingResponse> {
80        let img_url = urlencoding::encode(img_url).to_string();
81        let v = self.client.post(WechatMpMethod::Ocr(MpOcrMethod::Driving), vec![(IMG_URL.to_string(), img_url)], Value::Null, RequestType::Json).await?.json::<Value>()?;
82        WechatCommonResponse::parse::<WechatOcrDrivingResponse>(v)
83    }
84
85    /// 行驶证OCR识别接口
86    /// 文件大小限制:小于2M
87    pub async fn driving_file(&self, file_path: &str) -> LabradorResult<WechatOcrDrivingResponse> {
88        let path = Path::new(file_path);
89        let file_name = path.file_name().map(|v| v.to_str().unwrap_or_default()).unwrap_or_default();
90        let mut f = File::open(path)?;
91        let mut content: Vec<u8> = Vec::new();
92        let _ = f.read_to_end(&mut content)?;
93        let req = WechatMpOcrRequest {
94            ocr_type: 3,
95            filename: "".to_string(),
96            data: content
97        };
98        let v = self.client.execute::<WechatMpOcrRequest, String>(req).await?.json::<Value>()?;
99        WechatCommonResponse::parse::<WechatOcrDrivingResponse>(v)
100    }
101
102    /// 驾驶证OCR识别接口
103    /// 文件大小限制:小于2M
104    pub async fn driving_license(&self, img_url: &str) -> LabradorResult<WechatOcrDrivingLicenseResponse> {
105        let img_url = urlencoding::encode(img_url).to_string();
106        let v = self.client.post(WechatMpMethod::Ocr(MpOcrMethod::DrivingLicense), vec![(IMG_URL.to_string(), img_url)], Value::Null, RequestType::Json).await?.json::<Value>()?;
107        WechatCommonResponse::parse::<WechatOcrDrivingLicenseResponse>(v)
108    }
109
110    /// 驾驶证OCR识别接口
111    /// 文件大小限制:小于2M
112    pub async fn driving_license_file(&self, file_path: &str) -> LabradorResult<WechatOcrDrivingLicenseResponse> {
113        let path = Path::new(file_path);
114        let file_name = path.file_name().map(|v| v.to_str().unwrap_or_default()).unwrap_or_default();
115        let mut f = File::open(path)?;
116        let mut content: Vec<u8> = Vec::new();
117        let _ = f.read_to_end(&mut content)?;
118        let req = WechatMpOcrRequest {
119            ocr_type: 4,
120            filename: "".to_string(),
121            data: content
122        };
123        let v = self.client.execute::<WechatMpOcrRequest, String>(req).await?.json::<Value>()?;
124        WechatCommonResponse::parse::<WechatOcrDrivingLicenseResponse>(v)
125    }
126
127    /// 营业执照OCR识别接口
128    /// 文件大小限制:小于2M
129    pub async fn biz_license(&self, img_url: &str) -> LabradorResult<WechatOcrBizLicenseResponse> {
130        let img_url = urlencoding::encode(img_url).to_string();
131        let v = self.client.post(WechatMpMethod::Ocr(MpOcrMethod::BizLicense), vec![(IMG_URL.to_string(), img_url)], Value::Null, RequestType::Json).await?.json::<Value>()?;
132        WechatCommonResponse::parse::<WechatOcrBizLicenseResponse>(v)
133    }
134
135    /// 营业执照OCR识别接口
136    /// 文件大小限制:小于2M
137    pub async fn biz_license_file(&self, file_path: &str) -> LabradorResult<WechatOcrBizLicenseResponse> {
138        let path = Path::new(file_path);
139        let file_name = path.file_name().map(|v| v.to_str().unwrap_or_default()).unwrap_or_default();
140        let mut f = File::open(path)?;
141        let mut content: Vec<u8> = Vec::new();
142        let _ = f.read_to_end(&mut content)?;
143        let req = WechatMpOcrRequest {
144            ocr_type: 5,
145            filename: "".to_string(),
146            data: content
147        };
148        let v = self.client.execute::<WechatMpOcrRequest, String>(req).await?.json::<Value>()?;
149        WechatCommonResponse::parse::<WechatOcrBizLicenseResponse>(v)
150    }
151
152    /// 通用印刷体OCR识别接口
153    /// 文件大小限制:小于2M
154    /// 适用于屏幕截图、印刷体照片等场景
155    pub async fn comm(&self, img_url: &str) -> LabradorResult<WechatOcrCommResponse> {
156        let img_url = urlencoding::encode(img_url).to_string();
157        let v = self.client.post(WechatMpMethod::Ocr(MpOcrMethod::Comm), vec![(IMG_URL.to_string(), img_url)], Value::Null, RequestType::Json).await?.json::<Value>()?;
158        WechatCommonResponse::parse::<WechatOcrCommResponse>(v)
159    }
160
161    /// 通用印刷体OCR识别接口
162    /// 文件大小限制:小于2M
163    /// 适用于屏幕截图、印刷体照片等场景
164    pub async fn comm_file(&self, file_path: &str) -> LabradorResult<WechatOcrCommResponse> {
165        let path = Path::new(file_path);
166        let file_name = path.file_name().map(|v| v.to_str().unwrap_or_default()).unwrap_or_default();
167        let mut f = File::open(path)?;
168        let mut content: Vec<u8> = Vec::new();
169        let _ = f.read_to_end(&mut content)?;
170        let req = WechatMpOcrRequest {
171            ocr_type: 6,
172            filename: "".to_string(),
173            data: content
174        };
175        let v = self.client.execute::<WechatMpOcrRequest, String>(req).await?.json::<Value>()?;
176        WechatCommonResponse::parse::<WechatOcrCommResponse>(v)
177    }
178
179}
180
181//----------------------------------------------------------------------------------------------------------------------------
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct WechatOcrIdCardResponse {
185    #[serde(rename="type")]
186    pub r#type: Option<String>,
187    pub name: Option<String>,
188    pub id: Option<String>,
189    pub valid_date: Option<String>,
190}
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct WechatOcrCommResponse {
193    pub img_size: Option<WechatOcrImgSize>,
194    pub items: Option<Vec<WechatOcrItems>>,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct WechatOcrItems {
199    pub text: Option<String>,
200    pub pos: Option<WechatOcrPos>,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct WechatOcrBankCardResponse {
205    pub number: Option<String>,
206}
207
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct WechatOcrDrivingLicenseResponse {
211    /// 证号
212    pub id_num: Option<String>,
213    /// 姓名
214    pub name: Option<String>,
215    /// 性别
216    pub sex: Option<String>,
217    /// 国籍
218    pub nationality: Option<String>,
219    /// 住址
220    pub address: Option<String>,
221    /// 出生日期
222    pub birth_date: Option<String>,
223    /// 初次领证日期
224    pub issue_date: Option<String>,
225    /// 准驾车型
226    pub car_class: Option<String>,
227    /// 有效期限起始日
228    pub valid_from: Option<String>,
229    /// 有效期限终止日
230    pub valid_to: Option<String>,
231    /// 印章文字
232    pub official_seal: Option<String>,
233}
234
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
237pub struct WechatOcrBizLicenseResponse {
238    /// 注册号
239    pub reg_num: Option<String>,
240    /// 编号
241    pub serial: Option<String>,
242    /// 法定代表人姓名
243    pub legal_representative: Option<String>,
244    /// 企业名称
245    pub enterprise_name: Option<String>,
246    /// 组成形式
247    pub type_of_organization: Option<String>,
248    /// 经营场所/企业住所
249    pub address: Option<String>,
250    /// 公司类型
251    pub type_of_enterprise: Option<String>,
252    /// 经营范围
253    pub business_scope: Option<String>,
254    /// 注册资本
255    pub registered_capital: Option<String>,
256    /// 实收资本
257    pub paid_in_capital: Option<String>,
258    /// 营业期限
259    pub valid_period: Option<String>,
260    /// 注册日期/成立日期
261    pub registered_date: Option<String>,
262    /// 营业执照位置
263    pub cert_position: Option<CertPosition>,
264    /// 图片大小
265    pub img_size: Option<WechatOcrImgSize>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct WechatOcrDrivingResponse {
270    /// 车牌号码
271    pub plate_num: Option<String>,
272    /// 车辆类型
273    pub vehicle_type: Option<String>,
274    /// 所有人
275    pub owner: Option<String>,
276    /// 住址
277    pub addr: Option<String>,
278    /// 使用性质
279    pub use_character: Option<String>,
280    /// 品牌型号
281    pub model: Option<String>,
282    /// 车辆识别代码
283    pub vin: Option<String>,
284    /// 发动机号码
285    pub engine_num: Option<String>,
286    /// 注册日期
287    pub register_date: Option<String>,
288    /// 发证日期
289    pub issue_date: Option<String>,
290    /// 车牌号码
291    pub plate_num_b: Option<String>,
292    /// 号牌
293    pub record: Option<String>,
294    /// 核定载人数
295    pub passengers_num: Option<String>,
296    /// 总质量
297    pub total_quality: Option<String>,
298    /// 整备质量
299    pub prepare_quality: Option<String>,
300    /// 外廓尺寸
301    pub overall_size: Option<String>,
302    /// 卡片正面位置(检测到卡片正面才会返回)
303    pub card_position_front: Option<CardPosition>,
304    /// 卡片反面位置(检测到卡片反面才会返回)
305    pub card_position_back: Option<CardPosition>,
306    /// 图片大小
307    pub img_size: Option<WechatOcrImgSize>,
308}
309
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct CardPosition {
313    pub pos: Option<WechatOcrPos>,
314}
315
316
317#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct CertPosition {
319    pub pos: Option<WechatOcrPos>,
320}
321
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct WechatOcrPos {
325    pub left_top: Option<Coordinate>,
326    pub right_top: Option<Coordinate>,
327    pub right_bottom: Option<Coordinate>,
328    pub left_bottom: Option<Coordinate>,
329}
330
331#[derive(Debug, Clone, Serialize, Deserialize)]
332pub struct Coordinate {
333    pub x: Option<i64>,
334    pub y: Option<i64>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct WechatOcrImgSize {
339    pub w: Option<i64>,
340    pub h: Option<i64>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
344pub struct WechatMpOcrRequest {
345    /// 1 身份证 2 银行卡 3 行驶证 4 驾驶证 5 营业执照 6 通用印刷体
346    pub ocr_type: u8,
347    pub filename: String,
348    pub data: Vec<u8>
349}
350
351impl WechatRequest for WechatMpOcrRequest {
352    fn get_api_method_name(&self) -> String {
353        match self.ocr_type {
354            1 => MpOcrMethod::IdCard.get_method(),
355            2 => MpOcrMethod::BankCard.get_method(),
356            3 => MpOcrMethod::Driving.get_method(),
357            4 => MpOcrMethod::DrivingLicense.get_method(),
358            5 => MpOcrMethod::BizLicense.get_method(),
359            6 => MpOcrMethod::Comm.get_method(),
360            _=> "".to_string()
361        }
362    }
363
364    fn get_request_body<T: Serialize>(&self) -> RequestBody<T> {
365        let form = reqwest::multipart::Form::new().part("media", reqwest::multipart::Part::stream(self.data.to_vec()).file_name(self.filename.to_string()));
366        form.into()
367    }
368}