243 lines
8.5 KiB
Go
243 lines
8.5 KiB
Go
package check
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
audiocallback "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/audio/callback/v4/response"
|
|
videocallback "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/video/callback/v4/response"
|
|
callbackresponse "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution/callback/v2/response"
|
|
queryrequest "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution/query/v2/request"
|
|
vsrequest "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution/submit/v2/request"
|
|
)
|
|
|
|
// VideoDetectionService 视频检测服务
|
|
type VideoDetectionService struct{}
|
|
|
|
var VideoDetection = new(VideoDetectionService)
|
|
|
|
var (
|
|
ErrVideoStillProcessing = errors.New("视频仍在检测中,请稍后重试")
|
|
ErrVideoResultNotFound = errors.New("未找到视频检测结果")
|
|
)
|
|
|
|
// VideoSubmitResult 视频检测提交结果
|
|
type VideoSubmitResult struct {
|
|
TaskID string `json:"taskId"`
|
|
DataID string `json:"dataId"`
|
|
DealingCount int64 `json:"dealingCount"`
|
|
}
|
|
|
|
// DetectVideo 提交视频检测任务
|
|
func (s *VideoDetectionService) DetectVideo(ctx context.Context, videoURL, dataID string, callbackURL string) (*VideoSubmitResult, error) {
|
|
if DefaultClients == nil || DefaultClients.VideoClient == nil {
|
|
return nil, fmt.Errorf("易盾视频检测客户端未初始化")
|
|
}
|
|
if videoURL == "" {
|
|
return nil, fmt.Errorf("视频URL不能为空")
|
|
}
|
|
|
|
g.Log().Infof(ctx, "视频检测任务提交, url: %s, dataID: %s", videoURL, dataID)
|
|
|
|
req := vsrequest.NewVideoSolutionSubmitV2Req()
|
|
req.SetURL(videoURL)
|
|
req.SetDataID(dataID)
|
|
req.SetUniqueKey(dataID)
|
|
if callbackURL != "" {
|
|
req.SetCallbackURL(callbackURL)
|
|
}
|
|
req.SetSubProduct("videoStream")
|
|
|
|
response, err := DefaultClients.VideoClient.Submit(req)
|
|
if err != nil {
|
|
g.Log().Errorf(ctx, "视频检测提交HTTP错误: %v", err)
|
|
return nil, fmt.Errorf("视频检测提交HTTP错误: %w", err)
|
|
}
|
|
if response.GetCode() != 200 {
|
|
g.Log().Errorf(ctx, "视频检测API错误: code=%d, msg=%s", response.GetCode(), response.GetMsg())
|
|
errMsg := fmt.Sprintf("视频检测API错误: code=%d, msg=%s", response.GetCode(), response.GetMsg())
|
|
switch response.GetCode() {
|
|
case 417:
|
|
errMsg += " (可能原因: 视频URL无法访问或业务配置问题)"
|
|
case 400:
|
|
errMsg += " (可能原因: 请求参数错误)"
|
|
case 403:
|
|
errMsg += " (可能原因: 鉴权失败,检查secretId和secretKey)"
|
|
}
|
|
return nil, fmt.Errorf("%s", errMsg)
|
|
}
|
|
|
|
result := &VideoSubmitResult{}
|
|
if response.Result != nil {
|
|
if response.Result.TaskID != nil {
|
|
result.TaskID = *response.Result.TaskID
|
|
}
|
|
if response.Result.DataID != nil {
|
|
result.DataID = *response.Result.DataID
|
|
}
|
|
if response.Result.DealingCount != nil {
|
|
result.DealingCount = *response.Result.DealingCount
|
|
}
|
|
}
|
|
g.Log().Infof(ctx, "视频检测任务提交成功, taskID: %s, dealingCount: %d", result.TaskID, result.DealingCount)
|
|
return result, nil
|
|
}
|
|
|
|
// VideoResult 视频检测完整结果
|
|
type VideoResult struct {
|
|
TaskID string `json:"taskId"`
|
|
Status int `json:"status"` // 0=未开始, 1=检测中, 2=检测成功, 3=检测失败
|
|
Suggestion int `json:"suggestion"` // 0=通过, 1=嫌疑, 2=不通过
|
|
Label int `json:"label"` // 违规类别
|
|
ResultType int `json:"resultType"` // 1=机器结果, 2=人审结果
|
|
DataID string `json:"dataId"`
|
|
CensorTime int64 `json:"censorTime"`
|
|
Duration int64 `json:"duration"`
|
|
|
|
// 完整证据信息
|
|
Antispam *callbackresponse.VideoSolutionAntispamCallbackV2Response `json:"antispam,omitempty"`
|
|
Language *audiocallback.AudioLanguageCallbackV4Response `json:"language,omitempty"`
|
|
Voice *audiocallback.AudioVoiceCallbackV4Response `json:"voice,omitempty"`
|
|
Asr *audiocallback.AudioAsrCallbackV4Response `json:"asr,omitempty"`
|
|
Ocr *videocallback.VideoCallbackOcrV4Response `json:"ocr,omitempty"`
|
|
Discern *videocallback.VideoCallbackDiscernV4Response `json:"discern,omitempty"`
|
|
Logo *videocallback.VideoCallbackLogoV4Response `json:"logo,omitempty"`
|
|
Face *videocallback.VideoCallbackFaceV4Response `json:"face,omitempty"`
|
|
Aigc *videocallback.VideoCallbackAigcV4Response `json:"aigc,omitempty"`
|
|
Quality *callbackresponse.VideoSolutionQualityCallbackV2Response `json:"quality,omitempty"`
|
|
}
|
|
|
|
// queryCheckStatusToStatus 将易盾 checkStatus 映射为内部 Status
|
|
func queryCheckStatusToStatus(checkStatus int) int {
|
|
switch checkStatus {
|
|
case 0:
|
|
return 1 // Processing
|
|
case 1:
|
|
return 2 // Success
|
|
case 2:
|
|
return 3 // Failed
|
|
default:
|
|
return 0 // NotStart
|
|
}
|
|
}
|
|
|
|
// queryResultToSuggestion 将易盾 result 映射为内部 suggestion
|
|
// result: 1=正常, 2=异常, 3=疑似 → suggestion: 0=通过, 1=嫌疑, 2=不通过
|
|
func queryResultToSuggestion(result int) int {
|
|
switch result {
|
|
case 1:
|
|
return 0 // 通过
|
|
case 2:
|
|
return 2 // 不通过
|
|
case 3:
|
|
return 1 // 嫌疑
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// GetVideoResult 获取视频检测结果(轮询模式)
|
|
func (s *VideoDetectionService) GetVideoResult(ctx context.Context, taskID string) (*VideoResult, error) {
|
|
if DefaultClients == nil || DefaultClients.VideoClient == nil {
|
|
return nil, fmt.Errorf("易盾视频检测客户端未初始化")
|
|
}
|
|
|
|
g.Log().Infof(ctx, "查询视频检测结果, taskID: %s", taskID)
|
|
|
|
req := queryrequest.NewVideoSolutionQueryTaskV2Request()
|
|
req.SetTaskIds([]string{taskID})
|
|
|
|
response, err := DefaultClients.VideoClient.QueryTaskV2(req)
|
|
if err != nil {
|
|
g.Log().Errorf(ctx, "查询视频检测结果失败: %v", err)
|
|
return nil, fmt.Errorf("查询视频检测结果失败: %w", err)
|
|
}
|
|
if response.GetCode() != 200 {
|
|
g.Log().Errorf(ctx, "查询视频检测结果API错误: code=%d, msg=%s", response.GetCode(), response.GetMsg())
|
|
return nil, fmt.Errorf("查询视频检测结果API错误: code=%d, msg=%s", response.GetCode(), response.GetMsg())
|
|
}
|
|
if response.Result == nil || len(*response.Result) == 0 {
|
|
g.Log().Warningf(ctx, "未找到视频检测结果, taskID: %s", taskID)
|
|
return nil, ErrVideoResultNotFound
|
|
}
|
|
|
|
for _, item := range *response.Result {
|
|
if item.TaskID != nil && *item.TaskID == taskID {
|
|
// status: 0=检测完成/失败, 20=非7天内, 30=不存在, 40=检测中
|
|
if item.Status != nil {
|
|
if *item.Status == 30 {
|
|
g.Log().Warningf(ctx, "视频检测结果不存在, taskID: %s", taskID)
|
|
return nil, ErrVideoResultNotFound
|
|
}
|
|
if *item.Status == 40 {
|
|
g.Log().Infof(ctx, "视频仍在检测中, taskID: %s", taskID)
|
|
return nil, ErrVideoStillProcessing
|
|
}
|
|
}
|
|
|
|
result := &VideoResult{TaskID: taskID}
|
|
if item.DataID != nil {
|
|
result.DataID = *item.DataID
|
|
}
|
|
if item.TaskID != nil {
|
|
result.TaskID = *item.TaskID
|
|
}
|
|
if item.Antispam.Status != nil {
|
|
result.Status = *item.Antispam.Status
|
|
}
|
|
if item.Antispam.Suggestion != nil {
|
|
result.Suggestion = *item.Antispam.Suggestion
|
|
}
|
|
if item.Antispam.Label != nil {
|
|
result.Label = *item.Antispam.Label
|
|
}
|
|
if item.Antispam.ResultType != nil {
|
|
result.ResultType = *item.Antispam.ResultType
|
|
}
|
|
if item.Antispam.DataID != nil {
|
|
result.DataID = *item.Antispam.DataID
|
|
}
|
|
if item.Antispam.CensorTime != nil {
|
|
result.CensorTime = *item.Antispam.CensorTime
|
|
}
|
|
if item.Antispam.Duration != nil {
|
|
result.Duration = *item.Antispam.Duration
|
|
}
|
|
|
|
// 完整证据信息
|
|
result.Antispam = &item.Antispam
|
|
|
|
g.Log().Infof(ctx, "视频检测结果查询成功, taskID: %s, suggestion=%d, label=%d",
|
|
taskID, result.Suggestion, result.Label)
|
|
return result, nil
|
|
}
|
|
}
|
|
|
|
g.Log().Warningf(ctx, "未找到指定的taskID: %s", taskID)
|
|
return nil, ErrVideoResultNotFound
|
|
}
|
|
|
|
// VideoCallbackData 推送模式回调数据
|
|
type VideoCallbackData struct {
|
|
Antispam *VideoCallbackAntispam `json:"antispam"`
|
|
}
|
|
|
|
// VideoCallbackAntispam 视频回调反垃圾结果
|
|
type VideoCallbackAntispam struct {
|
|
TaskID string `json:"taskId"`
|
|
DataID string `json:"dataId"`
|
|
Suggestion int `json:"suggestion"`
|
|
Status int `json:"status"`
|
|
ResultType int `json:"resultType"`
|
|
Label int `json:"label"`
|
|
SecondLabel string `json:"secondLabel"`
|
|
ThirdLabel string `json:"thirdLabel"`
|
|
RiskDescription string `json:"riskDescription"`
|
|
CensorSource int `json:"censorSource"`
|
|
CensorTime int64 `json:"censorTime"`
|
|
CheckTime int64 `json:"checkTime"`
|
|
Duration int64 `json:"duration"`
|
|
}
|