// Package gateway 提供付款凭证识别能力,仅用于交易流水号表单预填。 // 识别结果不是资金事实,也不代表系统已完成任何资金动作。 package gateway import ( "context" "reflect" "strings" "github.com/bytedance/sonic" "go.uber.org/zap" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // paymentVoucherRecognitionPath 是付款凭证识别接口路径。 const paymentVoucherRecognitionPath = "/ai/ocr/extract-payment" // PaymentVoucherExtractionRequest 是付款凭证识别请求,只传图片内容。 type PaymentVoucherExtractionRequest struct { // ImageBase64 是付款凭证图片的 base64 编码内容。 ImageBase64 string `json:"image_base64"` } // paymentVoucherExtraction 只解码本系统消费的支付单号。 // 识别响应还含 amount(数值)、payee、payment_method、payment_time 与 remark, // 这些字段刻意不声明、不解码:既不进入响应、不预填、不落库,也不被本进程持有, // 同时避免上游字段类型漂移(实测 amount 为 JSON 数值)导致整条响应解析失败。 type paymentVoucherExtraction struct { OrderNumber string `json:"order_number"` } // ExtractPaymentVoucherOrderNumber 识别付款凭证图片并只返回识别出的支付单号。 // 该能力刻意不使用记录完整请求体与响应体的泛型入口,日志只含路径、耗时与结果摘要; // 返回空字符串表示识别服务未给出支付单号,由调用方决定失败口径。 func (c *Client) ExtractPaymentVoucherOrderNumber(ctx context.Context, imageBase64 string) (string, error) { if strings.TrimSpace(imageBase64) == "" { return "", errors.New(errors.CodeInvalidParam, "付款凭证图片内容不能为空") } data, err := c.doRequestWithoutPayloadLog(ctx, paymentVoucherRecognitionPath, PaymentVoucherExtractionRequest{ ImageBase64: imageBase64, }) if err != nil { return "", err } var extraction paymentVoucherExtraction if err := sonic.Unmarshal(data, &extraction); err != nil { // 刻意不记录 err.Error():sonic 的类型错误消息会内嵌响应 JSON 原文片段, // 一旦进入日志或错误上下文就等于记录识别原始结果(金额、单号等)。 // 只记录可诊断且非敏感的摘要:路径、响应字节数与错误类型名, // 足以区分语法错、类型错与空响应,又不携带任何载荷内容。 c.logger.Warn("付款凭证识别响应解析失败", zap.String("path", paymentVoucherRecognitionPath), zap.Int("result_bytes", len(data)), zap.String("err_kind", reflect.TypeOf(err).String()), ) return "", errors.New(errors.CodeGatewayInvalidResp, "解析付款凭证识别结果失败") } return strings.TrimSpace(extraction.OrderNumber), nil }