contentSecurity/internal/api/video_scanner.go
2025-10-15 14:52:37 +08:00

201 lines
5.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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("---")
}
}
}