package api import ( "fmt" "io" "os" "path/filepath" "strings" "contentSecurityDemo/conf" "contentSecurityDemo/internal/model" openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" green20220302 "github.com/alibabacloud-go/green-20220302/v2/client" util "github.com/alibabacloud-go/tea-utils/v2/service" "github.com/alibabacloud-go/tea/tea" ) // ImageScanner 图片内容安全扫描器2.0 type ImageScanner struct { Client *green20220302.Client Config *conf.Config } // ImageServiceType 图片审核服务类型 type ImageServiceType string const ( // BaselineCheckGlobal 通用基线检测 BaselineCheckGlobal ImageServiceType = "baselineCheck_global" // PostImageCheckByVLGlobal 大小模型融合图片审核服务(专业版) PostImageCheckByVLGlobal ImageServiceType = "postImageCheckByVL_global" // AigcDetectorGlobal AI生成图片鉴别 AigcDetectorGlobal ImageServiceType = "aigcDetector_global" ) // NewImageScanner 创建图片扫描器 func NewImageScanner(config *conf.Config) (*ImageScanner, error) { // 获取有效的访问凭证 accessKeyID, accessKeySecret, securityToken := config.GetEffectiveCredentials() // 创建配置 clientConfig := &openapi.Config{ AccessKeyId: tea.String(accessKeyID), AccessKeySecret: tea.String(accessKeySecret), SecurityToken: tea.String(securityToken), RegionId: tea.String(config.Region), Endpoint: tea.String(config.Endpoint), } // 创建客户端 client, err := green20220302.NewClient(clientConfig) if err != nil { return nil, fmt.Errorf("创建客户端失败: %v", err) } return &ImageScanner{ Client: client, Config: config, }, nil } // ScanImageByURL 通过URL扫描图片 func (s *ImageScanner) ScanImageByURL(imageURL string, dataID string, serviceType ImageServiceType) (*model.ImageScanResponse, error) { // 创建运行时配置 runtime := &util.RuntimeOptions{} runtime.ReadTimeout = tea.Int(10000) runtime.ConnectTimeout = tea.Int(10000) // 构建请求参数 imageScanRequest := &green20220302.ImageModerationRequest{ Service: tea.String(string(serviceType)), ServiceParameters: tea.String(fmt.Sprintf(`{"imageUrl":"%s","dataId":"%s"}`, imageURL, dataID)), } // 调用API response, err := s.Client.ImageModerationWithOptions(imageScanRequest, runtime) if err != nil { return nil, fmt.Errorf("请求失败: %v", err) } // 转换响应格式 scanResponse := &model.ImageScanResponse{ Code: tea.Int32Value(response.Body.Code), Message: tea.StringValue(response.Body.Msg), Data: make([]model.ImageScanData, 0), } // 创建单个数据项 scanData := model.ImageScanData{ DataID: *response.Body.Data.DataId, Code: tea.Int32Value(response.Body.Code), Message: "success", Results: make([]*green20220302.ImageModerationResponseBodyDataResult, 0), } // 如果有结果数据,进行转换 if response.Body.Data != nil { data := response.Body.Data scanData.Results = append(scanData.Results, data.Result...) } scanResponse.Data = append(scanResponse.Data, scanData) return scanResponse, nil } // ScanImageByFile 通过文件扫描图片 func (s *ImageScanner) ScanImageByFile(filePath string, dataID string, serviceType ImageServiceType) (*model.ImageScanResponse, error) { // 读取文件 file, err := os.Open(filePath) if err != nil { return nil, fmt.Errorf("打开文件失败: %v", err) } defer file.Close() // 检查文件大小(限制为9MB) fileInfo, err := file.Stat() if err != nil { return nil, fmt.Errorf("获取文件信息失败: %v", err) } if fileInfo.Size() > 9*1024*1024 { return nil, fmt.Errorf("文件大小超过9MB限制") } // 读取文件内容并转换为base64 fileContent, err := io.ReadAll(file) if err != nil { return nil, fmt.Errorf("读取文件失败: %v", err) } // 检查文件类型 - 2.0版本支持更多格式 ext := strings.ToLower(filepath.Ext(filePath)) supportedExts := []string{".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp", ".tiff", ".svg", ".ico", ".heic"} isSupported := false for _, supportedExt := range supportedExts { if ext == supportedExt { isSupported = true break } } if !isSupported { return nil, fmt.Errorf("不支持的文件格式: %s", ext) } // 将文件内容转换为base64 base64Content := fmt.Sprintf("data:image/%s;base64,%s", ext[1:], strings.ReplaceAll(string(fileContent), "\n", "")) // 创建运行时配置 runtime := &util.RuntimeOptions{} runtime.ReadTimeout = tea.Int(10000) runtime.ConnectTimeout = tea.Int(10000) // 构建请求参数 imageScanRequest := &green20220302.ImageModerationRequest{ Service: tea.String(string(serviceType)), ServiceParameters: tea.String(fmt.Sprintf(`{"content":"%s"}`, base64Content)), } // 调用API response, err := s.Client.ImageModerationWithOptions(imageScanRequest, runtime) if err != nil { return nil, fmt.Errorf("请求失败: %v", err) } // 转换响应格式 scanResponse := &model.ImageScanResponse{ Code: tea.Int32Value(response.Body.Code), Message: tea.StringValue(response.Body.Msg), Data: make([]model.ImageScanData, 0), } // 创建单个数据项 scanData := model.ImageScanData{ DataID: dataID, Code: tea.Int32Value(response.Body.Code), Message: "success", Results: make([]*green20220302.ImageModerationResponseBodyDataResult, 0), } // 如果有结果数据,进行转换 if response.Body.Data != nil { // 这里需要根据实际的响应结构进行调整 // 暂时创建一个基本的结果结构 data := response.Body.Data scanData.Results = append(scanData.Results, data.Result...) } scanResponse.Data = append(scanResponse.Data, scanData) return scanResponse, nil } // PrintResult 打印扫描结果 func (s *ImageScanner) PrintResult(response *model.ImageScanResponse) { fmt.Println("=== 图片内容安全审核结果===") fmt.Printf("状态码: %d\n", response.Code) fmt.Printf("消息: %s\n", response.Message) for _, data := range response.Data { fmt.Printf("\n数据ID: %s\n", data.DataID) fmt.Printf("处理状态: %d - %s\n", data.Code, data.Message) for _, result := range data.Results { if result.Confidence != nil { fmt.Printf("置信度: %f\n", *result.Confidence) } if result.Description != nil { fmt.Printf("描述: %s\n", *result.Description) } if result.Label != nil { fmt.Printf("标签: %s\n", *result.Label) } if result.RiskLevel != nil { fmt.Printf("风险等级: %s\n", *result.RiskLevel) } fmt.Println("---") } } }