From 06d52d56db4eb9ddbb6ba4a27d5bf5705d45c552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Wed, 25 Mar 2026 16:53:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=A4=E7=85=A7=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppUser/AppUserService.cs | 42 +++++++- YD_Event.Application/YD_Event.Application.xml | 7 ++ ...crResult.cs => IdCardRecognitionResult.cs} | 8 +- .../Infrastructure/Aliyun/Ocr/OcrService.cs | 90 ++++++++++++++++-- .../Aliyun/Ocr/PassportRecognitionResult.cs | 73 ++++++++++++++ YD_Event.Core/YD_Event.Core.xml | 95 +++++++++++++++++-- 6 files changed, 293 insertions(+), 22 deletions(-) rename YD_Event.Core/Infrastructure/Aliyun/Ocr/{OcrResult.cs => IdCardRecognitionResult.cs} (88%) create mode 100644 YD_Event.Core/Infrastructure/Aliyun/Ocr/PassportRecognitionResult.cs diff --git a/YD_Event.Application/AppUser/AppUserService.cs b/YD_Event.Application/AppUser/AppUserService.cs index 06413ef..b73c615 100644 --- a/YD_Event.Application/AppUser/AppUserService.cs +++ b/YD_Event.Application/AppUser/AppUserService.cs @@ -318,12 +318,48 @@ public class AppUserService : BaseService, ITransient /// /// /// - [HttpPost("member/ocr")] + [HttpPost("member/recognize/idcard")] [DisplayName("OCR识别身份证")] - public async Task RecognizeIdCard([FromBody] AthleteOcrInput input) - { + public async Task RecognizeIdCard([FromBody] AthleteOcrInput input) + { + // 输入验证 + if (string.IsNullOrWhiteSpace(input.ImageUrl)) + { + throw Oops.Bah("护照图片URL不能为空"); + } + + // URL格式验证(简单的格式检查) + if (!input.ImageUrl.StartsWith("http://") && !input.ImageUrl.StartsWith("https://")) + { + throw Oops.Bah("请输入有效的图片URL地址"); + } + return await _ocrService.RecognizeIdCardAsync(input.ImageUrl); } + /// + /// 识别护照信息 + /// + /// 护照图片URL输入 + /// 护照识别结果 + [HttpPost("member/recognize/passport")] + [DisplayName("OCR识别护照")] + public async Task RecognizePassport([FromBody] AthleteOcrInput input) + { + // 输入验证 + if (string.IsNullOrWhiteSpace(input.ImageUrl)) + { + throw Oops.Bah("护照图片URL不能为空"); + } + + // URL格式验证(简单的格式检查) + if (!input.ImageUrl.StartsWith("http://") && !input.ImageUrl.StartsWith("https://")) + { + throw Oops.Bah("请输入有效的图片URL地址"); + } + + return await _ocrService.RecognizePassportAsync(input.ImageUrl); + } + #endregion } diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index 766fc98..aafe6dc 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -114,6 +114,13 @@ + + + 识别护照信息 + + 护照图片URL输入 + 护照识别结果 + 普通用户分页查询输入 diff --git a/YD_Event.Core/Infrastructure/Aliyun/Ocr/OcrResult.cs b/YD_Event.Core/Infrastructure/Aliyun/Ocr/IdCardRecognitionResult.cs similarity index 88% rename from YD_Event.Core/Infrastructure/Aliyun/Ocr/OcrResult.cs rename to YD_Event.Core/Infrastructure/Aliyun/Ocr/IdCardRecognitionResult.cs index 739a1dd..da76140 100644 --- a/YD_Event.Core/Infrastructure/Aliyun/Ocr/OcrResult.cs +++ b/YD_Event.Core/Infrastructure/Aliyun/Ocr/IdCardRecognitionResult.cs @@ -2,9 +2,9 @@ namespace YD_Event.Core.Infrastructure.Aliyun.Ocr; /// -/// OCR识别结果 +/// 身份证识别结果 /// -public class OcrResult +public class IdCardRecognitionResult { /// /// 是否成功 @@ -32,7 +32,7 @@ public class OcrResult public string? IdCardNumber { get; set; } /// - /// 出生日期 (可选) + /// 出生日期 /// public string? BirthDate { get; set; } -} +} \ No newline at end of file diff --git a/YD_Event.Core/Infrastructure/Aliyun/Ocr/OcrService.cs b/YD_Event.Core/Infrastructure/Aliyun/Ocr/OcrService.cs index e9a5b1f..12193fc 100644 --- a/YD_Event.Core/Infrastructure/Aliyun/Ocr/OcrService.cs +++ b/YD_Event.Core/Infrastructure/Aliyun/Ocr/OcrService.cs @@ -28,11 +28,11 @@ public class OcrService : ITransient /// /// 图片URL /// - public async Task RecognizeIdCardAsync(string imageUrl) + public async Task RecognizeIdCardAsync(string imageUrl) { if (string.IsNullOrWhiteSpace(imageUrl)) { - return new OcrResult { Success = false, Message = "图片URL不能为空" }; + return new IdCardRecognitionResult { Success = false, Message = "图片URL不能为空" }; } try @@ -67,23 +67,101 @@ public class OcrService : ITransient if (!string.IsNullOrEmpty(idNumber)) { - return new OcrResult + return new IdCardRecognitionResult { Success = true, Name = name, Gender = sex, IdCardNumber = idNumber, BirthDate = birthDate, - Message = "识别成功" + Message = "身份证识别成功" }; } } - return new OcrResult { Success = false, Message = "未识别到有效身份证信息" }; + return new IdCardRecognitionResult { Success = false, Message = "未识别到有效身份证信息" }; } catch (Exception ex) { - return new OcrResult { Success = false, Message = $"OCR识别异常: {ex.Message}" }; + return new IdCardRecognitionResult { Success = false, Message = $"身份证OCR识别异常: {ex.Message}" }; + } + } + + /// + /// 识别护照信息 + /// + /// 护照图片URL + /// + public async Task RecognizePassportAsync(string imageUrl) + { + if (string.IsNullOrWhiteSpace(imageUrl)) + { + return new PassportRecognitionResult { Success = false, Message = "图片URL不能为空" }; + } + + try + { + var config = new AlibabaCloud.OpenApiClient.Models.Config + { + AccessKeyId = _options.AccessKeyId, + AccessKeySecret = _options.AccessKeySecret, + Endpoint = _options.Endpoint + }; + + var client = new Client(config); + var request = new RecognizePassportRequest + { + Url = imageUrl + }; + + var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions(); + var response = await client.RecognizePassportWithOptionsAsync(request, runtime); + + if (response.Body != null && !string.IsNullOrEmpty(response.Body.Data)) + { + // Data是一个JSON字符串,包含识别结果 + var json = JObject.Parse(response.Body.Data); + + // 解析护照信息字段 + var name = (string?)json.SelectToken("..data.name") ?? (string?)json.SelectToken("..name"); + var passportNumber = (string?)json.SelectToken("..data.passportNumber") ?? (string?)json.SelectToken("..passportNumber"); + var nationality = (string?)json.SelectToken("..data.nationality") ?? (string?)json.SelectToken("..nationality"); + var gender = (string?)json.SelectToken("..data.sex") ?? (string?)json.SelectToken("..gender") ?? (string?)json.SelectToken("..sex"); + var birthDate = (string?)json.SelectToken("..data.birthDate") ?? (string?)json.SelectToken("..birthDate"); + var issuingAuthority = (string?)json.SelectToken("..data.issuingAuthority") ?? (string?)json.SelectToken("..issuingAuthority"); + var issueDate = (string?)json.SelectToken("..data.issueDate") ?? (string?)json.SelectToken("..issueDate"); + var expiryDate = (string?)json.SelectToken("..data.expiryDate") ?? (string?)json.SelectToken("..expiryDate"); + // 新增字段 + var validToDate = (string?)json.SelectToken("..data.validToDate") ?? (string?)json.SelectToken("..validToDate"); + var birthDateYmd = (string?)json.SelectToken("..data.birthDateYmd") ?? (string?)json.SelectToken("..birthDateYmd"); + var issueDateYmd = (string?)json.SelectToken("..data.issueDateYmd") ?? (string?)json.SelectToken("..issueDateYmd"); + + if (!string.IsNullOrEmpty(passportNumber)) + { + return new PassportRecognitionResult + { + Success = true, + Name = name, + Gender = gender, + PassportNumber = passportNumber, + Nationality = nationality, + BirthDate = birthDate, + IssuingAuthority = issuingAuthority, + IssueDate = issueDate, + ExpiryDate = expiryDate, + ValidToDate = validToDate, + BirthDateYmd = birthDateYmd, + IssueDateYmd = issueDateYmd, + Message = "护照识别成功" + }; + } + } + + return new PassportRecognitionResult { Success = false, Message = "未识别到有效护照信息" }; + } + catch (Exception ex) + { + return new PassportRecognitionResult { Success = false, Message = $"护照OCR识别异常: {ex.Message}" }; } } } diff --git a/YD_Event.Core/Infrastructure/Aliyun/Ocr/PassportRecognitionResult.cs b/YD_Event.Core/Infrastructure/Aliyun/Ocr/PassportRecognitionResult.cs new file mode 100644 index 0000000..d355691 --- /dev/null +++ b/YD_Event.Core/Infrastructure/Aliyun/Ocr/PassportRecognitionResult.cs @@ -0,0 +1,73 @@ +#nullable enable +namespace YD_Event.Core.Infrastructure.Aliyun.Ocr; + +/// +/// 护照识别结果 +/// +public class PassportRecognitionResult +{ + /// + /// 是否成功 + /// + public bool Success { get; set; } + + /// + /// 错误信息 + /// + public string? Message { get; set; } + + /// + /// 姓名 + /// + public string? Name { get; set; } + + /// + /// 性别 + /// + public string? Gender { get; set; } + + /// + /// 护照号码 + /// + public string? PassportNumber { get; set; } + + /// + /// 国籍 + /// + public string? Nationality { get; set; } + + /// + /// 签发地点 + /// + public string? IssuingAuthority { get; set; } + + /// + /// 签发日期 + /// + public string? IssueDate { get; set; } + + /// + /// 有效期至 + /// + public string? ExpiryDate { get; set; } + + /// + /// 出生日期 + /// + public string? BirthDate { get; set; } + + /// + /// 有效期至(格式化显示) + /// + public string? ValidToDate { get; set; } + + /// + /// 出生日期(纯数字格式) + /// + public string? BirthDateYmd { get; set; } + + /// + /// 签发日期(格式化显示) + /// + public string? IssueDateYmd { get; set; } +} \ No newline at end of file diff --git a/YD_Event.Core/YD_Event.Core.xml b/YD_Event.Core/YD_Event.Core.xml index 56f3478..082ec9f 100644 --- a/YD_Event.Core/YD_Event.Core.xml +++ b/YD_Event.Core/YD_Event.Core.xml @@ -4332,39 +4332,39 @@ 赞助单位 - + - OCR识别结果 + 身份证识别结果 - + 是否成功 - + 错误信息 - + 姓名 - + 性别 - + 身份证号 - + - 出生日期 (可选) + 出生日期 @@ -4379,6 +4379,83 @@ 图片URL + + + 识别护照信息 + + 护照图片URL + + + + + 护照识别结果 + + + + + 是否成功 + + + + + 错误信息 + + + + + 姓名 + + + + + 性别 + + + + + 护照号码 + + + + + 国籍 + + + + + 签发地点 + + + + + 签发日期 + + + + + 有效期至 + + + + + 出生日期 + + + + + 有效期至(格式化显示) + + + + + 出生日期(纯数字格式) + + + + + 签发日期(格式化显示) + + 获取完整的URL