250 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package user
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"crypto/rand"
 | |
| 	"encoding/base64"
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"github.com/qiniu/go-sdk/v7/storagev2/credentials"
 | |
| 	"github.com/qiniu/go-sdk/v7/storagev2/http_client"
 | |
| 	"github.com/qiniu/go-sdk/v7/storagev2/uploader"
 | |
| 	"tianyuan-api/apps/gateway/internal/svc"
 | |
| 	"tianyuan-api/apps/gateway/internal/types"
 | |
| 	"io"
 | |
| 	"math/big"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/zeromicro/go-zero/core/logx"
 | |
| )
 | |
| 
 | |
| type UploadBusinessLicenseLogic struct {
 | |
| 	logx.Logger
 | |
| 	ctx    context.Context
 | |
| 	svcCtx *svc.ServiceContext
 | |
| }
 | |
| 
 | |
| func NewUploadBusinessLicenseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadBusinessLicenseLogic {
 | |
| 	return &UploadBusinessLicenseLogic{
 | |
| 		Logger: logx.WithContext(ctx),
 | |
| 		ctx:    ctx,
 | |
| 		svcCtx: svcCtx,
 | |
| 	}
 | |
| }
 | |
| func (l *UploadBusinessLicenseLogic) UploadBusinessLicense(r *http.Request) (resp *types.UploadBusinessLicenseResp, err error) {
 | |
| 	// 1. 解析文件上传表单,限制文件大小
 | |
| 	err = r.ParseMultipartForm(4 << 20) // 限制最大文件大小为4MB
 | |
| 	if err != nil {
 | |
| 		return nil, errors.New("图片不能超过4MB")
 | |
| 	}
 | |
| 
 | |
| 	// 2. 获取上传的文件
 | |
| 	file, handler, err := r.FormFile("file")
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer file.Close()
 | |
| 
 | |
| 	// 3. 创建临时文件保存上传的内容
 | |
| 	tempFile, err := os.CreateTemp("", "upload-*.jpg")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("创建临时文件失败: %v", err)
 | |
| 	}
 | |
| 	defer tempFile.Close()
 | |
| 
 | |
| 	// 4. 将文件内容保存到临时文件
 | |
| 	_, err = io.Copy(tempFile, file)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("保存文件失败: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// 5. 调用百度智能云进行营业执照识别
 | |
| 	tempFilePath := tempFile.Name()
 | |
| 	fileBytes, err := os.ReadFile(tempFilePath)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("读取临时文件失败: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	licenseInfo, err := l.RecognizeBusinessLicense(fileBytes)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("营业执照识别失败: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// 6. 生成新的文件名
 | |
| 	newFileName := l.GenerateFileName("business_license_", handler.Filename)
 | |
| 
 | |
| 	// 7. 确认是营业执照后,将图片上传到七牛云
 | |
| 	imageUrl, err := l.UploadToQiniu(tempFilePath, newFileName)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("上传图片到七牛云失败: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// 8. 返回百度智能云的识别信息和图片URL给前端
 | |
| 	return &types.UploadBusinessLicenseResp{
 | |
| 		Url:            imageUrl,
 | |
| 		EnterpriseName: licenseInfo["company_name"],
 | |
| 		CreditCode:     licenseInfo["credit_code"],
 | |
| 		LegalPerson:    licenseInfo["legal_person"],
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // 百度智能云营业执照识别
 | |
| func (l *UploadBusinessLicenseLogic) RecognizeBusinessLicense(fileBytes []byte) (map[string]string, error) {
 | |
| 	// 获取百度智能云Access Token
 | |
| 	accessToken := l.GetAccessToken()
 | |
| 	if accessToken == "" {
 | |
| 		return nil, errors.New("获取百度智能云Access Token失败")
 | |
| 	}
 | |
| 
 | |
| 	// 调用百度智能云营业执照识别接口
 | |
| 	baiduUrl := "https://aip.baidubce.com/rest/2.0/ocr/v1/business_license?access_token=" + accessToken
 | |
| 
 | |
| 	// 将图片文件进行Base64编码
 | |
| 	fileBase64 := base64.StdEncoding.EncodeToString(fileBytes)
 | |
| 	fileBase64UrlEncoded := url.QueryEscape(fileBase64)
 | |
| 	// 准备POST请求的Payload
 | |
| 	payload := strings.NewReader(fmt.Sprintf("image=%s", fileBase64UrlEncoded))
 | |
| 
 | |
| 	req, err := http.NewRequest("POST", baiduUrl, payload)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
 | |
| 	client := &http.Client{}
 | |
| 	res, err := client.Do(req)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer res.Body.Close()
 | |
| 
 | |
| 	body, err := io.ReadAll(res.Body)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// 解析响应体
 | |
| 	var result map[string]interface{}
 | |
| 	if err := json.Unmarshal(body, &result); err != nil {
 | |
| 		return nil, fmt.Errorf("解析响应失败: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// 检查是否有错误码
 | |
| 	if _, exists := result["error_code"]; exists {
 | |
| 		return nil, fmt.Errorf("图片解析失败,请上传清晰正确的图片")
 | |
| 	}
 | |
| 
 | |
| 	// 成功,提取所需的字段
 | |
| 	wordsResult := result["words_result"].(map[string]interface{})
 | |
| 	companyName := wordsResult["单位名称"].(map[string]interface{})["words"].(string)
 | |
| 	socialCreditCode := wordsResult["社会信用代码"].(map[string]interface{})["words"].(string)
 | |
| 	legalPerson := wordsResult["法人"].(map[string]interface{})["words"].(string)
 | |
| 
 | |
| 	// 返回提取的信息
 | |
| 	return map[string]string{
 | |
| 		"company_name": companyName,
 | |
| 		"credit_code":  socialCreditCode,
 | |
| 		"legal_person": legalPerson,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // 获取百度智能云Access Token
 | |
| func (l *UploadBusinessLicenseLogic) GetAccessToken() string {
 | |
| 	apiKey := l.svcCtx.Config.Baidu.ApiKey
 | |
| 	secretKey := l.svcCtx.Config.Baidu.SecretKey
 | |
| 
 | |
| 	baiduUrl := "https://aip.baidubce.com/oauth/2.0/token"
 | |
| 	postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", apiKey, secretKey)
 | |
| 	resp, err := http.Post(baiduUrl, "application/x-www-form-urlencoded", strings.NewReader(postData))
 | |
| 	if err != nil {
 | |
| 		return ""
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	body, err := io.ReadAll(resp.Body)
 | |
| 	if err != nil {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	accessTokenObj := map[string]interface{}{}
 | |
| 	_ = json.Unmarshal(body, &accessTokenObj)
 | |
| 	return accessTokenObj["access_token"].(string)
 | |
| }
 | |
| 
 | |
| // 七牛云上传图片
 | |
| func (l *UploadBusinessLicenseLogic) UploadToQiniu(localFilePath string, fileName string) (string, error) {
 | |
| 	// 从配置中获取七牛云的AccessKey和SecretKey
 | |
| 	accessKey := l.svcCtx.Config.Qiniu.AccessKey
 | |
| 	secretKey := l.svcCtx.Config.Qiniu.SecretKey
 | |
| 	bucket := l.svcCtx.Config.Qiniu.Bucket
 | |
| 	domain := l.svcCtx.Config.Qiniu.Domain
 | |
| 
 | |
| 	// 1. 构建上传凭证
 | |
| 	mac := credentials.NewCredentials(accessKey, secretKey)
 | |
| 
 | |
| 	// 2. 构建上传管理器
 | |
| 	options := uploader.UploadManagerOptions{
 | |
| 		Options: http_client.Options{
 | |
| 			Credentials: mac, // 这里传入认证信息
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	uploadManager := uploader.NewUploadManager(&options)
 | |
| 
 | |
| 	objectOptions := &uploader.ObjectOptions{
 | |
| 		BucketName: bucket,
 | |
| 		ObjectName: &fileName,
 | |
| 		FileName:   fileName,
 | |
| 	}
 | |
| 
 | |
| 	// 3. 执行文件上传
 | |
| 	err := uploadManager.UploadFile(context.Background(), localFilePath, objectOptions, nil)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	// 返回文件的URL地址
 | |
| 	fileUrl := fmt.Sprintf("%s/%s", domain, fileName)
 | |
| 	return fileUrl, nil
 | |
| }
 | |
| 
 | |
| // 生成新的文件名,包含前缀、时间戳和随机数
 | |
| func (l *UploadBusinessLicenseLogic) GenerateFileName(prefix, originalFileName string) string {
 | |
| 	timestamp := time.Now().Format("20060102150405")      // 生成时间戳
 | |
| 	randomNumber := l.GenerateRandomNumber(4)             // 生成4位随机数
 | |
| 	fileExtension := l.GetFileExtension(originalFileName) // 获取原文件扩展名
 | |
| 
 | |
| 	// 返回生成的文件名
 | |
| 	return fmt.Sprintf("%s%s_%s%s", prefix, timestamp, randomNumber, fileExtension)
 | |
| }
 | |
| 
 | |
| // 生成指定长度的随机数
 | |
| func (l *UploadBusinessLicenseLogic) GenerateRandomNumber(length int) string {
 | |
| 	var digits = "0123456789"
 | |
| 	result := make([]byte, length)
 | |
| 	for i := range result {
 | |
| 		n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(digits))))
 | |
| 		result[i] = digits[n.Int64()]
 | |
| 	}
 | |
| 	return string(result)
 | |
| }
 | |
| 
 | |
| // 获取文件扩展名
 | |
| func (l *UploadBusinessLicenseLogic) GetFileExtension(fileName string) string {
 | |
| 	if len(fileName) > 0 {
 | |
| 		for i := len(fileName) - 1; i >= 0 && fileName[i] != '.'; i-- {
 | |
| 			if i == 0 {
 | |
| 				return "" // 无扩展名
 | |
| 			}
 | |
| 		}
 | |
| 		return fileName[strings.LastIndex(fileName, "."):]
 | |
| 	}
 | |
| 	return ""
 | |
| }
 |