This commit is contained in:
Mrx
2026-04-18 16:41:06 +08:00
parent 5f6cca5369
commit c3b16c0ffe
2 changed files with 183 additions and 22 deletions

View File

@@ -1052,7 +1052,7 @@ type IVYZFIC1Req struct {
IDCard string `json:"id_card" validate:"required,validIDCard"` IDCard string `json:"id_card" validate:"required,validIDCard"`
Name string `json:"name" validate:"required,min=1,validName"` Name string `json:"name" validate:"required,min=1,validName"`
PhotoData string `json:"photo_data" validate:"omitempty,validBase64Image"` PhotoData string `json:"photo_data" validate:"omitempty,validBase64Image"`
ImageUrl string `json:"image_url" validate:"omitempty,url"` ImageUrl string `json:"+" validate:"omitempty,url"`
} }
type IVYZC4R9Req struct { type IVYZC4R9Req struct {

View File

@@ -4,10 +4,15 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"math"
"strconv"
"strings"
"time"
"tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors" "tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/xingwei" "tyapi-server/internal/infrastructure/external/shumai"
) )
// ProcessIVYZZQT3Request IVYZZQT3 人脸比对V3API处理方法 // ProcessIVYZZQT3Request IVYZZQT3 人脸比对V3API处理方法
@@ -21,31 +26,187 @@ func ProcessIVYZZQT3Request(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err) return nil, errors.Join(processors.ErrInvalidParam, err)
} }
// 构建请求数据使用xingwei服务的正确字段名 // 使用数脉接口进行人脸身份证比对
reqData := map[string]interface{}{ reqFormData := map[string]interface{}{
"name": paramsDto.Name, "idcard": paramsDto.IDCard,
"idCardNum": paramsDto.IDCard, "name": paramsDto.Name,
"image": paramsDto.PhotoData, "image": paramsDto.PhotoData,
} }
// 调用行为数据API使用指定的project_id apiPath := "/v4/face_id_card/compare"
projectID := "CDJ-1104321430396268544"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData) // 先尝试政务接口,再回退实时接口
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, true)
if err != nil { if err != nil {
if errors.Is(err, xingwei.ErrNotFound) { respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
// 查空情况,返回特定的查空错误 if err != nil {
return nil, errors.Join(processors.ErrNotFound, err) if errors.Is(err, shumai.ErrNotFound) {
} else if errors.Is(err, xingwei.ErrDatasource) { return nil, errors.Join(processors.ErrNotFound, err)
// 数据源错误 } else if errors.Is(err, shumai.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err) return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, xingwei.ErrSystem) { } else if errors.Is(err, shumai.ErrSystem) {
// 系统错误 return nil, errors.Join(processors.ErrSystem, err)
return nil, errors.Join(processors.ErrSystem, err) }
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err) return nil, errors.Join(processors.ErrSystem, err)
} }
} }
return respBytes, nil outBytes, err := mapShumaiFaceCompareToIVYZZQT3(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return outBytes, nil
}
type shumaiFaceCompareResp struct {
OrderNo string `json:"order_no"`
Score interface{} `json:"score"`
Msg string `json:"msg"`
Incorrect interface{} `json:"incorrect"`
}
type ivyzzqt3Out struct {
HandleTime string `json:"handleTime"`
ResultData ivyzzqt3OutResultData `json:"resultData"`
OrderNo string `json:"orderNo"`
}
type ivyzzqt3OutResultData struct {
VerificationCode string `json:"verification_code"`
VerificationResult string `json:"verification_result"`
VerificationMessage string `json:"verification_message"`
Similarity string `json:"similarity"`
}
func mapShumaiFaceCompareToIVYZZQT3(respBytes []byte) ([]byte, error) {
var r shumaiFaceCompareResp
if err := json.Unmarshal(respBytes, &r); err != nil {
return nil, err
}
score := parseScoreToFloat64(r.Score)
similarity := strconv.Itoa(int(math.Round(mapScoreToSimilarity(score))))
verificationResult := mapScoreToVerificationResult(score)
verificationMessage := strings.TrimSpace(r.Msg)
if verificationMessage == "" {
verificationMessage = mapScoreToVerificationMessage(score)
}
out := ivyzzqt3Out{
HandleTime: time.Now().Format("2006-01-02 15:04:05"),
OrderNo: strings.TrimSpace(r.OrderNo),
ResultData: ivyzzqt3OutResultData{
VerificationCode: mapVerificationCode(verificationResult, r.Incorrect),
VerificationResult: verificationResult,
VerificationMessage: verificationMessage,
Similarity: similarity,
},
}
return json.Marshal(out)
}
func mapScoreToVerificationResult(score float64) string {
if score >= 0.45 {
return "valid"
}
// 旧结构仅支持 valid/invalid不能确定场景按 invalid 返回
return "invalid"
}
func mapScoreToVerificationMessage(score float64) string {
if score < 0.40 {
return "系统判断为不同人"
}
if score < 0.45 {
return "不能确定是否为同一人"
}
return "系统判断为同一人"
}
func mapScoreToSimilarity(score float64) float64 {
// 将 score(0~1) 分段映射到 similarity(0~1000),并对齐业务阈值:
// 0.40 -> 6000.45 -> 700
if score <= 0 {
return 0
}
if score >= 1 {
return 1000
}
if score < 0.40 {
// [0, 0.40) -> [0, 600)
return (score / 0.40) * 600
}
if score < 0.45 {
// [0.40, 0.45) -> [600, 700)
return 600 + ((score-0.40)/0.05)*100
}
// [0.45, 1] -> [700, 1000]
return 700 + ((score-0.45)/0.55)*300
}
func parseScoreToFloat64(v interface{}) float64 {
switch t := v.(type) {
case float64:
return t
case float32:
return float64(t)
case int:
return float64(t)
case int32:
return float64(t)
case int64:
return float64(t)
case json.Number:
if f, err := t.Float64(); err == nil {
return f
}
case string:
s := strings.TrimSpace(t)
if s == "" {
return 0
}
if f, err := strconv.ParseFloat(s, 64); err == nil {
return f
}
}
return 0
}
func valueToString(v interface{}) string {
switch t := v.(type) {
case string:
return strings.TrimSpace(t)
case json.Number:
return t.String()
case float64:
return strconv.FormatFloat(t, 'f', -1, 64)
case float32:
return strconv.FormatFloat(float64(t), 'f', -1, 64)
case int:
return strconv.Itoa(t)
case int32:
return strconv.FormatInt(int64(t), 10)
case int64:
return strconv.FormatInt(t, 10)
default:
if v == nil {
return ""
}
return strings.TrimSpace(fmt.Sprint(v))
}
}
func mapVerificationCode(verificationResult string, upstreamIncorrect interface{}) string {
if verificationResult == "valid" {
return "1000"
}
if verificationResult == "invalid" {
return "2006"
}
// 兜底:若后续扩展出其它结果,保持可追溯
if s := valueToString(upstreamIncorrect); s != "" {
return s
}
return "2006"
} }