package api import ( "encoding/json" "fmt" "time" "contentSecurityDemo/conf" "contentSecurityDemo/internal/model" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" "github.com/aliyun/alibaba-cloud-sdk-go/services/green" ) // VideoScanner 视频内容安全扫描器 type VideoScanner struct { Client *green.Client Config *conf.Config } // NewVideoScanner 创建视频扫描器 func NewVideoScanner(config *conf.Config) (*VideoScanner, error) { client, err := green.NewClientWithAccessKey(config.Region, config.AccessKeyID, config.AccessKeySecret) if err != nil { return nil, fmt.Errorf("创建客户端失败: %v", err) } return &VideoScanner{ Client: client, Config: config, }, nil } // ScanVideoAsync 异步扫描视频 func (s *VideoScanner) ScanVideoAsync(videoURL string, dataID string) (*model.VideoScanResponse, error) { request := requests.NewCommonRequest() request.Method = "POST" request.Scheme = "https" request.Domain = s.Config.Endpoint request.Version = "2018-05-09" request.ApiName = "VideoAsyncScan" request.QueryParams["RegionId"] = s.Config.Region scanRequest := model.VideoScanRequest{ Tasks: []model.VideoTask{ { DataID: dataID, URL: videoURL, Interval: 1, // 每秒截取一帧 MaxFrames: 100, // 最多截取100帧 }, }, Scenes: []string{"porn", "terrorism", "ad", "live"}, } requestBody, err := json.Marshal(scanRequest) if err != nil { return nil, fmt.Errorf("序列化请求失败: %v", err) } request.Content = requestBody response, err := s.Client.ProcessCommonRequest(request) if err != nil { return nil, fmt.Errorf("请求失败: %v", err) } var scanResponse model.VideoScanResponse if err := json.Unmarshal(response.GetHttpContentBytes(), &scanResponse); err != nil { return nil, fmt.Errorf("解析响应失败: %v", err) } return &scanResponse, nil } // GetVideoResult 获取视频审核结果 func (s *VideoScanner) GetVideoResult(taskID string) (*model.VideoResultResponse, error) { request := requests.NewCommonRequest() request.Method = "POST" request.Scheme = "https" request.Domain = s.Config.Endpoint request.Version = "2018-05-09" request.ApiName = "VideoAsyncScanResults" request.QueryParams["RegionId"] = s.Config.Region requestBody := fmt.Sprintf(`{"taskId": "%s"}`, taskID) request.Content = []byte(requestBody) response, err := s.Client.ProcessCommonRequest(request) if err != nil { return nil, fmt.Errorf("请求失败: %v", err) } var resultResponse model.VideoResultResponse if err := json.Unmarshal(response.GetHttpContentBytes(), &resultResponse); err != nil { return nil, fmt.Errorf("解析响应失败: %v", err) } return &resultResponse, nil } // ScanVideoAndWait 扫描视频并等待结果 func (s *VideoScanner) ScanVideoAndWait(videoURL string, dataID string, maxWaitTime time.Duration) (*model.VideoResultResponse, error) { // 提交扫描任务 scanResponse, err := s.ScanVideoAsync(videoURL, dataID) if err != nil { return nil, fmt.Errorf("提交扫描任务失败: %v", err) } if len(scanResponse.Data) == 0 { return nil, fmt.Errorf("未获取到任务ID") } taskID := scanResponse.Data[0].TaskID fmt.Printf("视频扫描任务已提交,任务ID: %s\n", taskID) // 轮询获取结果 startTime := time.Now() for time.Since(startTime) < maxWaitTime { result, err := s.GetVideoResult(taskID) if err != nil { return nil, fmt.Errorf("获取结果失败: %v", err) } if len(result.Data) > 0 { status := result.Data[0].Status fmt.Printf("当前状态: %s\n", status) switch status { case "success": return result, nil case "failure": return nil, fmt.Errorf("视频审核失败: %s", result.Data[0].Message) case "running", "pending": // 继续等待 time.Sleep(5 * time.Second) default: return nil, fmt.Errorf("未知状态: %s", status) } } else { time.Sleep(5 * time.Second) } } return nil, fmt.Errorf("等待超时,请稍后手动查询结果,任务ID: %s", taskID) } // PrintScanResult 打印扫描提交结果 func (s *VideoScanner) PrintScanResult(response *model.VideoScanResponse) { fmt.Println("=== 视频扫描任务提交结果 ===") fmt.Printf("状态码: %d\n", response.Code) fmt.Printf("消息: %s\n", response.Message) for _, data := range response.Data { fmt.Printf("数据ID: %s\n", data.DataID) fmt.Printf("任务ID: %s\n", data.TaskID) fmt.Printf("处理状态: %d - %s\n", data.Code, data.Message) fmt.Printf("视频URL: %s\n", data.URL) } } // PrintResult 打印审核结果 func (s *VideoScanner) PrintResult(response *model.VideoResultResponse) { 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("任务ID: %s\n", data.TaskID) fmt.Printf("处理状态: %d - %s\n", data.Code, data.Message) fmt.Printf("审核状态: %s\n", data.Status) if len(data.Results) == 0 { fmt.Println("✅ 未检测到违规内容") continue } for _, result := range data.Results { fmt.Printf("场景: %s\n", result.Scene) fmt.Printf("标签: %s\n", result.Label) fmt.Printf("建议: %s\n", result.Suggestion) fmt.Printf("置信度: %.2f\n", result.Rate) // 打印帧级别的结果 if len(result.Frames) > 0 { fmt.Println("违规帧详情:") for _, frame := range result.Frames { fmt.Printf(" 时间偏移: %d秒\n", frame.Offset) fmt.Printf(" 帧URL: %s\n", frame.URL) for _, frameResult := range frame.Results { fmt.Printf(" 场景: %s, 标签: %s, 建议: %s, 置信度: %.2f\n", frameResult.Scene, frameResult.Label, frameResult.Suggestion, frameResult.Rate) } } } fmt.Println("---") } } }