yidun检测、查询
This commit is contained in:
389
service/yidun/image_detection_service.go
Normal file
389
service/yidun/image_detection_service.go
Normal file
@@ -0,0 +1,389 @@
|
||||
package yidun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/yidun/yidun-golang-sdk/yidun/service/antispam/image/v5/callback"
|
||||
"github.com/yidun/yidun-golang-sdk/yidun/service/antispam/image/v5/check"
|
||||
"github.com/yidun/yidun-golang-sdk/yidun/service/antispam/image/v5/check/async"
|
||||
imagesync "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/image/v5/check/sync"
|
||||
)
|
||||
|
||||
// ImageDetectionService 图片检测服务
|
||||
type ImageDetectionService struct{}
|
||||
|
||||
var ImageDetection = new(ImageDetectionService)
|
||||
|
||||
var (
|
||||
ErrImageStillProcessing = errors.New("图片仍在检测中,请稍后重试")
|
||||
ErrImageResultNotFound = errors.New("未找到图片检测结果")
|
||||
)
|
||||
|
||||
// ImageSubmitResult 图片检测提交结果
|
||||
type ImageSubmitResult struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
Name string `json:"name"` // 图片唯一标识
|
||||
DataID string `json:"dataId"` // 客户图片唯一标识
|
||||
DealingCount int64 `json:"dealingCount"` // 缓冲池排队待处理数据量
|
||||
}
|
||||
|
||||
// DetectImage 提交图片异步检测任务,返回完整响应
|
||||
func (s *ImageDetectionService) DetectImage(ctx context.Context, imageURL, dataID string, callbackURL string) (*ImageSubmitResult, error) {
|
||||
if DefaultClients == nil || DefaultClients.ImageClient == nil {
|
||||
return nil, fmt.Errorf("易盾图片检测客户端未初始化")
|
||||
}
|
||||
|
||||
if imageURL == "" {
|
||||
return nil, fmt.Errorf("图片URL不能为空")
|
||||
}
|
||||
|
||||
businessId := g.Cfg().MustGet(ctx, "yidun.image.business_id").String()
|
||||
g.Log().Infof(ctx, "图片检测任务提交, url: %s, business_id: %s", imageURL, businessId)
|
||||
|
||||
// 创建请求
|
||||
request := async.NewImageV5AsyncCheckRequest(businessId)
|
||||
imageBean := check.NewImageBeanRequest()
|
||||
imageBean.SetData(imageURL)
|
||||
imageBean.SetName(dataID)
|
||||
imageBean.SetType(1) // 1: 图片URL
|
||||
if callbackURL != "" {
|
||||
imageBean.SetCallbackUrl(callbackURL)
|
||||
}
|
||||
request.SetImages([]check.ImageBeanRequest{*imageBean})
|
||||
|
||||
// 调用API
|
||||
response, err := DefaultClients.ImageClient.ImageAsyncCheck(request)
|
||||
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())
|
||||
}
|
||||
|
||||
result := &ImageSubmitResult{
|
||||
DealingCount: 0,
|
||||
}
|
||||
if response.Result != nil {
|
||||
if response.Result.DealingCount != nil {
|
||||
result.DealingCount = *response.Result.DealingCount
|
||||
}
|
||||
if response.Result.CheckImages != nil && len(*response.Result.CheckImages) > 0 {
|
||||
detail := (*response.Result.CheckImages)[0]
|
||||
if detail.TaskId != nil {
|
||||
result.TaskID = *detail.TaskId
|
||||
}
|
||||
if detail.Name != nil {
|
||||
result.Name = *detail.Name
|
||||
}
|
||||
if detail.DataId != nil {
|
||||
result.DataID = *detail.DataId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "图片检测任务提交成功, taskID: %s, dealingCount: %d", result.TaskID, result.DealingCount)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ImageResult 图片检测完整结果
|
||||
type ImageResult struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
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"` // 数据ID
|
||||
Name string `json:"name"` // 图片标识
|
||||
CensorTime int64 `json:"censorTime"` // 审核完成时间(毫秒)
|
||||
Url string `json:"url"` // 图片URL
|
||||
|
||||
// 完整证据信息
|
||||
Antispam *imagesync.ImageV5AntispamResp `json:"antispam,omitempty"` // 反垃圾检测结果
|
||||
Ocr *imagesync.ImageV5OcrResp `json:"ocr,omitempty"` // OCR文字识别结果
|
||||
Face *imagesync.ImageV5FaceResp `json:"face,omitempty"` // 人脸检测结果
|
||||
Quality *imagesync.ImageV5QualityResp `json:"quality,omitempty"` // 图片质量结果
|
||||
Logo *imagesync.ImageV5LogoResp `json:"logo,omitempty"` // Logo识别结果
|
||||
Discern *imagesync.ImageV5DiscernResp `json:"discern,omitempty"` // 图片识别结果
|
||||
Ad *imagesync.ImageV5AdResp `json:"ad,omitempty"` // 广告识别结果
|
||||
UserRisk *imagesync.ImageV5UserRiskResp `json:"userRisk,omitempty"` // 用户画像结果
|
||||
Anticheat *imagesync.ImageAnticheatV5Resp `json:"anticheat,omitempty"` // 反作弊结果
|
||||
RiskControl *imagesync.ImageRiskControlV5Resp `json:"riskControl,omitempty"` // 智能风控结果
|
||||
Aigc *imagesync.ImageV5AigcResp `json:"aigc,omitempty"` // AIGC识别结果
|
||||
LlmCheckInfo *[]imagesync.LlmCheckInfo `json:"llmCheckInfo,omitempty"` // 大模型检测结果
|
||||
}
|
||||
|
||||
// GetImageResult 获取图片检测结果(轮询模式)
|
||||
func (s *ImageDetectionService) GetImageResult(ctx context.Context, taskID string) (*ImageResult, error) {
|
||||
if DefaultClients == nil || DefaultClients.ImageClient == nil {
|
||||
return nil, fmt.Errorf("易盾图片检测客户端未初始化")
|
||||
}
|
||||
|
||||
businessId := g.Cfg().MustGet(ctx, "yidun.image.business_id").String()
|
||||
g.Log().Infof(ctx, "查询图片检测结果, taskID: %s", taskID)
|
||||
|
||||
req := callback.NewImageCallbackRequest(businessId)
|
||||
req.SetYidunRequestId(taskID)
|
||||
|
||||
response, err := DefaultClients.ImageClient.ImageCallback(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, ErrImageStillProcessing
|
||||
}
|
||||
|
||||
// 查找指定taskID的结果
|
||||
for _, item := range *response.Result {
|
||||
if item.Antispam != nil && item.Antispam.TaskId != nil && *item.Antispam.TaskId == taskID {
|
||||
result := &ImageResult{
|
||||
Antispam: item.Antispam,
|
||||
Ocr: item.Ocr,
|
||||
Face: item.Face,
|
||||
Quality: item.Quality,
|
||||
Logo: item.Logo,
|
||||
Discern: item.Discern,
|
||||
Ad: item.Ad,
|
||||
UserRisk: item.UserRisk,
|
||||
Anticheat: item.Anticheat,
|
||||
RiskControl: item.RiskControl,
|
||||
Aigc: item.Aigc,
|
||||
LlmCheckInfo: item.LlmCheckInfo,
|
||||
}
|
||||
|
||||
result.TaskID = 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.Name != nil {
|
||||
result.Name = *item.Antispam.Name
|
||||
}
|
||||
if item.Antispam.CensorTime != nil {
|
||||
result.CensorTime = *item.Antispam.CensorTime
|
||||
}
|
||||
if item.Antispam.Url != nil {
|
||||
result.Url = *item.Antispam.Url
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
g.Log().Warningf(ctx, "未找到指定的taskID: %s", taskID)
|
||||
return nil, ErrImageResultNotFound
|
||||
}
|
||||
|
||||
// ImageCallbackData 推送模式回调数据完整结构
|
||||
type ImageCallbackData struct {
|
||||
Antispam *ImageCallbackAntispam `json:"antispam"` // 反垃圾检测结果
|
||||
}
|
||||
|
||||
type ImageCallbackAntispam struct {
|
||||
TaskId string `json:"taskId"` // 任务ID
|
||||
Name string `json:"name"` // 图片名称
|
||||
DataId string `json:"dataId"` // 客户数据ID
|
||||
Suggestion int `json:"suggestion"` // 处置建议:0=通过,1=嫌疑,2=不通过
|
||||
Label int `json:"label"` // 一级分类
|
||||
SecondLabel string `json:"secondLabel"` // 二级分类
|
||||
ThirdLabel string `json:"thirdLabel"` // 三级分类
|
||||
RiskDescription string `json:"riskDescription"` // 风险描述
|
||||
Status int `json:"status"` // 检测状态:0=未开始,1=检测中,2=检测成功,3=检测失败
|
||||
ResultType int `json:"resultType"` // 结果类型:1=机器结果,2=人审结果
|
||||
CensorTime int64 `json:"censorTime"` // 审核完成时间
|
||||
CensorSource int `json:"censorSource"` // 审核来源
|
||||
CensorRound int `json:"censorRound"` // 审核轮数
|
||||
CensorLabels []*CensorLabel `json:"censorLabels"` // 审核标签
|
||||
Remark string `json:"remark"` // 审核备注
|
||||
OverAllMarkDesc string `json:"overAllMarkDesc"` // 整体审核备注
|
||||
DetailMarks []*DetailMarkInfo `json:"detailMarks"` // 细节标注
|
||||
Labels []*ImageLabelInfo `json:"labels"` // 分类标签详情
|
||||
Url string `json:"url"` // 图片URL
|
||||
ImgMd5 string `json:"imgMd5"` // 图片MD5
|
||||
FrameSize int `json:"frameSize"` // 分帧数
|
||||
CustomLabels []*CustomLabelInfo `json:"customLabels"` // 客户自定义标签
|
||||
CensorExtension *CensorExtensionInfo `json:"censorExtension"` // 人审拓展字段
|
||||
StrategyVersions []*StrategyVersionInfo `json:"strategyVersions"` // 策略版本
|
||||
HitType int `json:"hitType"` // 命中策略类型
|
||||
StrategyType int `json:"strategyType"` // 策略类型:1=公有策略,2=私有策略
|
||||
HitResult string `json:"hitResult"` // 命中结果
|
||||
HitSource int `json:"hitSource"` // 特征添加来源
|
||||
Hidden bool `json:"hidden"` // 是否有隐藏文件
|
||||
HiddenFormat string `json:"hiddenFormat"` // 隐藏文件格式
|
||||
PublicOpinionInfo string `json:"publicOpinionInfo"` // 舆情信息
|
||||
}
|
||||
|
||||
// CensorLabel 审核标签信息
|
||||
type CensorLabel struct {
|
||||
Code string `json:"code"` // 审核标签编码
|
||||
CustomCode string `json:"customCode"` // 自定义标签编码
|
||||
Name string `json:"name"` // 审核标签名称
|
||||
Desc string `json:"desc"` // 审核标签描述
|
||||
ParentLabelId string `json:"parentLabelId"` // 父标签ID
|
||||
Depth int `json:"depth"` // 标签深度
|
||||
}
|
||||
|
||||
// ImageLabelInfo 分类标签详情
|
||||
type ImageLabelInfo struct {
|
||||
Label int `json:"label"` // 标签类型
|
||||
Level int `json:"level"` // 判断结果:0=正常,1=不确定,2=确定
|
||||
Rate float32 `json:"rate"` // 置信度
|
||||
SubLabels []*SubLabelDetailInfo `json:"subLabels"` // 二级分类详情
|
||||
Explain string `json:"explain"` // LLM解释说明
|
||||
IsLlmCheck bool `json:"isLlmCheck"` // 是否LLM检测命中
|
||||
}
|
||||
|
||||
// SubLabelDetailInfo 二级分类详情
|
||||
type SubLabelDetailInfo struct {
|
||||
SubLabel string `json:"subLabel"` // 二级分类标签
|
||||
Level int `json:"level"` // 级别
|
||||
SubLabelDepth int `json:"subLabelDepth"` // 细分类层级
|
||||
SecondLabel string `json:"secondLabel"` // 二级分类
|
||||
ThirdLabel string `json:"thirdLabel"` // 三级分类
|
||||
RiskDescription string `json:"riskDescription"` // 风险描述
|
||||
HitStrategy int `json:"hitStrategy"` // 命中标识
|
||||
Rate float32 `json:"rate"` // 置信度
|
||||
Explain string `json:"explain"` // 解释说明
|
||||
IsLlmCheck bool `json:"isLlmCheck"` // 是否LLM命中
|
||||
Details *SubLabelHitDetails `json:"details"` // 命中详情
|
||||
}
|
||||
|
||||
// SubLabelHitDetails 二级分类命中详情
|
||||
type SubLabelHitDetails struct {
|
||||
Keywords []*HitKeywordInfo `json:"keywords"` // 敏感词命中
|
||||
LibInfos []*HitLibInfo `json:"libInfos"` // 图片名单命中
|
||||
HitInfos []*HitInfo `json:"hitInfos"` // 其他命中信息
|
||||
Anticheat *AnticheatHitInfo `json:"anticheat"` // 反作弊命中
|
||||
Llm *LlmKeywordInfo `json:"llm"` // 大模型关键词
|
||||
}
|
||||
|
||||
// HitKeywordInfo 敏感词命中信息
|
||||
type HitKeywordInfo struct {
|
||||
Type int `json:"type"` // 命中类型
|
||||
Word string `json:"word"` // 敏感词
|
||||
Entity string `json:"entity"` // 图片名单URL
|
||||
HitCount int `json:"hitCount"` // 命中次数
|
||||
Value string `json:"value"` // 值
|
||||
Group string `json:"group"` // 分组
|
||||
X1 float32 `json:"x1"` // 坐标
|
||||
Y1 float32 `json:"y1"` // 坐标
|
||||
X2 float32 `json:"x2"` // 坐标
|
||||
Y2 float32 `json:"y2"` // 坐标
|
||||
ReleaseTime int64 `json:"releaseTime"` // 释放时间
|
||||
StrategyGroupName string `json:"strategyGroupName"` // 策略组名称
|
||||
StrategyGroupId int64 `json:"strategyGroupId"` // 策略组ID
|
||||
}
|
||||
|
||||
// HitLibInfo 图片名单命中信息
|
||||
type HitLibInfo struct {
|
||||
Type int `json:"type"` // 命中类型
|
||||
Entity string `json:"entity"` // 图片名单URL
|
||||
HitCount int `json:"hitCount"` // 命中次数
|
||||
ReleaseTime int64 `json:"releaseTime"` // 释放时间
|
||||
StrategyGroupName string `json:"strategyGroupName"` // 策略组名称
|
||||
StrategyGroupId int64 `json:"strategyGroupId"` // 策略组ID
|
||||
}
|
||||
|
||||
// HitInfo 其他命中信息
|
||||
type HitInfo struct {
|
||||
Type int `json:"type"` // 命中类型
|
||||
Value string `json:"value"` // 值
|
||||
Group string `json:"group"` // 分组
|
||||
X1 float32 `json:"x1"` // 坐标
|
||||
Y1 float32 `json:"y1"` // 坐标
|
||||
X2 float32 `json:"x2"` // 坐标
|
||||
Y2 float32 `json:"y2"` // 坐标
|
||||
}
|
||||
|
||||
// AnticheatHitInfo 反作弊命中信息
|
||||
type AnticheatHitInfo struct {
|
||||
HitType int `json:"hitType"` // 命中类型
|
||||
}
|
||||
|
||||
// LlmKeywordInfo 大模型关键词信息
|
||||
type LlmKeywordInfo struct {
|
||||
Keyword string `json:"keyword"` // 关键词
|
||||
}
|
||||
|
||||
// DetailMarkInfo 细节标注信息
|
||||
type DetailMarkInfo struct {
|
||||
Position []*MarkPointInfo `json:"position"` // 标注位置
|
||||
CensorLabels []*CensorLabel `json:"censorLabels"` // 标注标签
|
||||
Desc string `json:"desc"` // 标注备注
|
||||
}
|
||||
|
||||
// MarkPointInfo 标注点坐标
|
||||
type MarkPointInfo struct {
|
||||
X float32 `json:"x"` // X坐标
|
||||
Y float32 `json:"y"` // Y坐标
|
||||
}
|
||||
|
||||
// CustomLabelInfo 客户自定义标签
|
||||
type CustomLabelInfo struct {
|
||||
Name string `json:"name"` // 名称
|
||||
Code string `json:"code"` // 编码
|
||||
Depth int `json:"depth"` // 深度
|
||||
}
|
||||
|
||||
// CensorExtensionInfo 人审拓展字段
|
||||
type CensorExtensionInfo struct {
|
||||
QualityInspectionTaskId string `json:"qualityInspectionTaskId"` // 质检任务ID
|
||||
InspTaskCreateTime float64 `json:"inspTaskCreateTime"` // 质检任务创建时间
|
||||
QualityInspectionType float64 `json:"qualityInspectionType"` // 质检类型
|
||||
}
|
||||
|
||||
// StrategyVersionInfo 策略版本信息
|
||||
type StrategyVersionInfo struct {
|
||||
Label int `json:"label"` // 垃圾类别
|
||||
Version string `json:"version"` // 版本号
|
||||
}
|
||||
|
||||
// ProcessImageCallback 处理图片检测回调(推送模式)
|
||||
func (s *ImageDetectionService) ProcessImageCallback(ctx context.Context, callbackData string) error {
|
||||
if callbackData == "" {
|
||||
return fmt.Errorf("回调数据不能为空")
|
||||
}
|
||||
|
||||
var data ImageCallbackData
|
||||
if err := json.Unmarshal([]byte(callbackData), &data); err != nil {
|
||||
g.Log().Errorf(ctx, "解析回调数据失败: %v", err)
|
||||
return fmt.Errorf("解析回调数据失败: %w", err)
|
||||
}
|
||||
|
||||
if data.Antispam == nil {
|
||||
return fmt.Errorf("回调数据格式错误:缺少antispam字段")
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "处理图片检测结果 - taskId: %s, suggestion: %d, resultType: %d",
|
||||
data.Antispam.TaskId, data.Antispam.Suggestion, data.Antispam.ResultType)
|
||||
|
||||
// TODO: 业务逻辑,如保存数据库、触发后续流程等
|
||||
// 可使用完整字段:data.Antispam.Labels, data.Antispam.CensorLabels, data.Antispam.Remark 等
|
||||
|
||||
return nil
|
||||
}
|
||||
51
service/yidun/text_detection_service.go
Normal file
51
service/yidun/text_detection_service.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package yidun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/yidun/yidun-golang-sdk/yidun/service/antispam/text/v5/check/async/single"
|
||||
)
|
||||
|
||||
// TextDetectionService 文本检测服务
|
||||
type TextDetectionService struct{}
|
||||
|
||||
var TextDetection = new(TextDetectionService)
|
||||
|
||||
// DetectText 提交文本异步检测任务
|
||||
func (s *TextDetectionService) DetectText(ctx context.Context, req *single.TextAsyncCheckRequest) (string, error) {
|
||||
if DefaultClients == nil || DefaultClients.TextClient == nil {
|
||||
return "", fmt.Errorf("易盾文本检测客户端未初始化")
|
||||
}
|
||||
|
||||
response, err := DefaultClients.TextClient.AsyncCheckText(req)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "文本检测提交失败: %v", err)
|
||||
return "", fmt.Errorf("文本检测提交失败: %w", err)
|
||||
}
|
||||
|
||||
if response.GetCode() != 200 {
|
||||
g.Log().Errorf(ctx, "文本检测API错误: code=%d, msg=%s", response.GetCode(), response.GetMsg())
|
||||
return "", fmt.Errorf("文本检测API错误: code=%d, msg=%s", response.GetCode(), response.GetMsg())
|
||||
}
|
||||
|
||||
var taskID string
|
||||
if response.Result != nil && len(response.Result.CheckTexts) > 0 {
|
||||
taskID = *response.Result.CheckTexts[0].TaskID
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "文本检测任务提交成功, taskID: %s", taskID)
|
||||
return taskID, nil
|
||||
}
|
||||
|
||||
// GetTextResult 获取文本检测结果
|
||||
func (s *TextDetectionService) GetTextResult(ctx context.Context, taskID string) (interface{}, error) {
|
||||
if DefaultClients == nil || DefaultClients.TextClient == nil {
|
||||
return nil, fmt.Errorf("易盾文本检测客户端未初始化")
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "查询文本检测结果, taskID: %s", taskID)
|
||||
// TODO: 根据实际业务需求实现查询逻辑
|
||||
return nil, nil
|
||||
}
|
||||
714
service/yidun/video_detection_service.go
Normal file
714
service/yidun/video_detection_service.go
Normal file
@@ -0,0 +1,714 @@
|
||||
package yidun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
callbackrequest "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution/callback/v2/request"
|
||||
callbackresponse "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution/callback/v2/response"
|
||||
vsrequest "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution/submit/v2/request"
|
||||
submitresponse "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution/submit/v2/response"
|
||||
)
|
||||
|
||||
// VideoDetectionService 视频检测服务
|
||||
type VideoDetectionService struct{}
|
||||
|
||||
var VideoDetection = new(VideoDetectionService)
|
||||
|
||||
var (
|
||||
ErrVideoStillProcessing = errors.New("视频仍在检测中,请稍后重试")
|
||||
ErrVideoResultNotFound = errors.New("未找到视频检测结果")
|
||||
)
|
||||
|
||||
// VideoSubmitResult 视频检测提交结果
|
||||
type VideoSubmitResult struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
DataID string `json:"dataId"` // 数据ID
|
||||
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", videoURL)
|
||||
|
||||
// 创建请求
|
||||
req := vsrequest.NewVideoSolutionSubmitV2Req()
|
||||
req.SetURL(videoURL)
|
||||
req.SetDataID(dataID)
|
||||
req.SetUniqueKey(dataID)
|
||||
if callbackURL != "" {
|
||||
req.SetCallbackURL(callbackURL)
|
||||
}
|
||||
|
||||
// 调用API
|
||||
response, err := DefaultClients.VideoClient.Submit(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())
|
||||
}
|
||||
|
||||
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 视频检测完整结果
|
||||
// 包含易盾返回的完整检测信息:文本、图片、音频、ASR等
|
||||
type VideoResult struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
Status int `json:"status"` // 检测状态:0=未开始,1=检测中,2=检测完成
|
||||
Suggestion int `json:"suggestion"` // 处置建议:0=通过,1=嫌疑,2=不通过
|
||||
Label int `json:"label"` // 垃圾类型
|
||||
ResultType int `json:"resultType"` // 结果类型:1=机器结果,2=人审结果
|
||||
DataID string `json:"dataId"` // 数据ID
|
||||
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"` // ASR语音转文字结果
|
||||
Ocr *videocallback.VideoCallbackOcrV4Response `json:"ocr,omitempty"` // OCR文字识别结果
|
||||
Discern *videocallback.VideoCallbackDiscernV4Response `json:"discern,omitempty"` // 画面识别结果
|
||||
Logo *videocallback.VideoCallbackLogoV4Response `json:"logo,omitempty"` // Logo识别结果
|
||||
Face *videocallback.VideoCallbackFaceV4Response `json:"face,omitempty"` // 人脸识别结果
|
||||
Aigc *videocallback.VideoCallbackAigcV4Response `json:"aigc,omitempty"` // AIGC识别结果
|
||||
Quality *callbackresponse.VideoSolutionQualityCallbackV2Response `json:"quality,omitempty"` // 音视频质量检测结果
|
||||
}
|
||||
|
||||
// GetVideoResult 获取视频检测结果(轮询模式)
|
||||
// 返回完整的检测详情,包括文本、图片、音频、ASR等
|
||||
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 := callbackrequest.NewVideoSolutionCallbackV2Request()
|
||||
req.SetYidunRequestId(taskID)
|
||||
response, err := DefaultClients.VideoClient.Callback(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, ErrVideoStillProcessing
|
||||
}
|
||||
|
||||
// 查找指定taskID的结果
|
||||
for _, item := range *response.Result {
|
||||
if item.Antispam != nil && item.Antispam.TaskID != nil && *item.Antispam.TaskID == taskID {
|
||||
result := &VideoResult{
|
||||
Antispam: item.Antispam,
|
||||
Language: item.Language,
|
||||
Voice: item.Voice,
|
||||
Asr: item.Asr,
|
||||
Ocr: item.Ocr,
|
||||
Discern: item.Discern,
|
||||
Logo: item.Logo,
|
||||
Face: item.Face,
|
||||
Aigc: item.Aigc,
|
||||
Quality: item.Quality,
|
||||
}
|
||||
|
||||
result.TaskID = 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
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
g.Log().Warningf(ctx, "未找到指定的taskID: %s", taskID)
|
||||
return nil, ErrVideoResultNotFound
|
||||
}
|
||||
|
||||
// PollVideoResult 轮询获取视频检测结果
|
||||
func (s *VideoDetectionService) PollVideoResult(ctx context.Context, taskID string, interval, maxWait time.Duration) (*VideoResult, error) {
|
||||
if interval <= 0 {
|
||||
interval = 1 * time.Second
|
||||
}
|
||||
if maxWait <= 0 {
|
||||
maxWait = 5 * time.Minute
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
g.Log().Infof(ctx, "开始轮询视频检测结果, taskID: %s, interval: %v, maxWait: %v", taskID, interval, maxWait)
|
||||
|
||||
for time.Since(startTime) < maxWait {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("轮询取消: %w", ctx.Err())
|
||||
default:
|
||||
}
|
||||
|
||||
result, err := s.GetVideoResult(ctx, taskID)
|
||||
if err == nil {
|
||||
g.Log().Infof(ctx, "轮询成功, taskID: %s, elapsed: %v", taskID, time.Since(startTime))
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if errors.Is(err, ErrVideoResultNotFound) {
|
||||
g.Log().Infof(ctx, "视频仍在检测中,继续轮询, taskID: %s, elapsed: %v", taskID, time.Since(startTime))
|
||||
} else {
|
||||
g.Log().Warningf(ctx, "查询出错,继续重试, taskID: %s, error: %v", taskID, err)
|
||||
}
|
||||
|
||||
time.Sleep(interval)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("轮询超时,已等待 %v", time.Since(startTime))
|
||||
}
|
||||
|
||||
// GetSDKSubmitResponse 获取SDK原始提交响应(包含完整易盾返回信息)
|
||||
func (s *VideoDetectionService) GetSDKSubmitResponse(ctx context.Context, videoURL, dataID string, callbackURL string) (*submitresponse.VideoSolutionSubmitV2Response, error) {
|
||||
if DefaultClients == nil || DefaultClients.VideoClient == nil {
|
||||
return nil, fmt.Errorf("易盾视频检测客户端未初始化")
|
||||
}
|
||||
|
||||
req := vsrequest.NewVideoSolutionSubmitV2Req()
|
||||
req.SetURL(videoURL)
|
||||
req.SetDataID(dataID)
|
||||
req.SetUniqueKey(dataID)
|
||||
if callbackURL != "" {
|
||||
req.SetCallbackURL(callbackURL)
|
||||
}
|
||||
|
||||
response, err := DefaultClients.VideoClient.Submit(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetSDKCallbackResponse 获取SDK原始回调响应(包含完整易盾返回信息)
|
||||
func (s *VideoDetectionService) GetSDKCallbackResponse(ctx context.Context, taskID string) (*callbackresponse.VideoSolutionCallbackV2Response, error) {
|
||||
if DefaultClients == nil || DefaultClients.VideoClient == nil {
|
||||
return nil, fmt.Errorf("易盾视频检测客户端未初始化")
|
||||
}
|
||||
|
||||
req := callbackrequest.NewVideoSolutionCallbackV2Request()
|
||||
req.SetYidunRequestId(taskID)
|
||||
|
||||
response, err := DefaultClients.VideoClient.Callback(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 视频检测结果推送模式(易盾主动回调)
|
||||
// =============================================================================
|
||||
|
||||
// VideoCallbackData 推送模式回调数据完整结构
|
||||
type VideoCallbackData struct {
|
||||
Antispam *VideoCallbackAntispam `json:"antispam"` // 反垃圾检测结果
|
||||
}
|
||||
|
||||
type VideoCallbackAntispam struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
DataID string `json:"dataId"` // 客户数据ID
|
||||
Callback string `json:"callback"` // 回调参数
|
||||
Suggestion int `json:"suggestion"` // 处置建议:0=通过,1=嫌疑,2=不通过
|
||||
Status int `json:"status"` // 检测状态:0=未开始,1=检测中,2=检测成功,3=检测失败
|
||||
ResultType int `json:"resultType"` // 结果类型:1=机器结果,2=人审结果
|
||||
CensorRound int `json:"censorRound"` // 人审轮次
|
||||
Censor string `json:"censor"` // 人审操作人
|
||||
CensorSource int `json:"censorSource"` // 审核来源:0=易盾人审,1=客户人审,2=易盾机审
|
||||
CheckTime int64 `json:"checkTime"` // 机器检测结束时间
|
||||
CensorTime int64 `json:"censorTime"` // 人工审核完成时间
|
||||
Duration int64 `json:"duration"` // 音视频时长(毫秒)
|
||||
DurationMs int64 `json:"durationMs"` // 音频时长(毫秒)
|
||||
Label int `json:"label"` // 一级垃圾类型
|
||||
SecondLabel string `json:"secondLabel"` // 二级垃圾类型
|
||||
ThirdLabel string `json:"thirdLabel"` // 三级垃圾类型
|
||||
RiskDescription string `json:"riskDescription"` // 风险描述
|
||||
PicCount int64 `json:"picCount"` // 截图数量
|
||||
CensorLabels []*VideoCensorLabel `json:"censorLabels"` // 审核标签
|
||||
CensorExtension *VideoCensorExtension `json:"censorExtension"` // 质检扩展结果
|
||||
Evidences *VideoCallbackEvidence `json:"evidences"` // 机器检测证据信息
|
||||
SolutionExtra *VideoSolutionExtra `json:"solutionExtra"` // 额外信息
|
||||
ReviewEvidences *VideoReviewEvidence `json:"reviewEvidences"` // 人审证据信息
|
||||
}
|
||||
|
||||
// VideoCensorLabel 审核标签
|
||||
type VideoCensorLabel struct {
|
||||
Code string `json:"code"` // 审核标签编码
|
||||
Desc string `json:"desc"` // 审核标签描述
|
||||
Name string `json:"name"` // 审核标签名称
|
||||
CustomCode string `json:"customCode"` // 自定义标签编码
|
||||
ParentLabelId string `json:"parentLabelId"` // 父标签ID
|
||||
Depth int `json:"depth"` // 标签深度
|
||||
}
|
||||
|
||||
// VideoCensorExtension 质检扩展结果
|
||||
type VideoCensorExtension struct {
|
||||
QualityInspectionTaskId string `json:"qualityInspectionTaskId"` // 质检任务ID
|
||||
QualityInspectionType int `json:"qualityInspectionType"` // 质检类型
|
||||
InspTaskCreateTime int64 `json:"inspTaskCreateTime"` // 质检任务创建时间
|
||||
}
|
||||
|
||||
// VideoCallbackEvidence 机器检测证据信息
|
||||
type VideoCallbackEvidence struct {
|
||||
Text *VideoTextEvidence `json:"text,omitempty"` // 文本证据
|
||||
Images *[]VideoImageEvidence `json:"images,omitempty"` // 图片证据
|
||||
Audio *VideoAudioEvidence `json:"audio,omitempty"` // 音频证据
|
||||
Video *VideoVideoEvidence `json:"video,omitempty"` // 视频证据
|
||||
}
|
||||
|
||||
// VideoTextEvidence 文本证据
|
||||
type VideoTextEvidence struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
DataID string `json:"dataId"` // 数据ID
|
||||
Suggestion int `json:"suggestion"` // 处置建议
|
||||
ResultType int `json:"resultType"` // 结果类型
|
||||
CensorType int `json:"censorType"` // 审核类型
|
||||
IsRelatedHit bool `json:"isRelatedHit"` // 是否关联命中
|
||||
Labels []*VideoTextLabel `json:"labels"` // 分类标签
|
||||
}
|
||||
|
||||
// VideoTextLabel 文本分类标签
|
||||
type VideoTextLabel struct {
|
||||
Label int `json:"label"` // 标签类型
|
||||
Level int `json:"level"` // 级别
|
||||
SubLabels []*VideoTextSubLabel `json:"subLabels"` // 二级分类
|
||||
}
|
||||
|
||||
// VideoTextSubLabel 文本二级分类
|
||||
type VideoTextSubLabel struct {
|
||||
SubLabel string `json:"subLabel"` // 二级分类
|
||||
SubLabelDepth int `json:"subLabelDepth"` // 细分类层级
|
||||
SecondLabel string `json:"secondLabel"` // 二级分类
|
||||
ThirdLabel string `json:"thirdLabel"` // 三级分类
|
||||
Details *VideoTextSubLabelDetail `json:"details"` // 命中详情
|
||||
}
|
||||
|
||||
// VideoTextSubLabelDetail 文本二级分类命中详情
|
||||
type VideoTextSubLabelDetail struct {
|
||||
Keywords *[]VideoTextKeyword `json:"keywords,omitempty"` // 敏感词
|
||||
LibInfos *[]VideoTextLibInfo `json:"libInfos,omitempty"` // 名单信息
|
||||
Anticheat *VideoTextAnticheat `json:"anticheat,omitempty"` // 反作弊
|
||||
HitInfos *[]VideoTextHitInfo `json:"hitInfos,omitempty"` // 其他命中
|
||||
}
|
||||
|
||||
// VideoTextKeyword 敏感词信息
|
||||
type VideoTextKeyword struct {
|
||||
Word string `json:"word"` // 敏感词
|
||||
StrategyGroupId int64 `json:"strategyGroupId"` // 策略组ID
|
||||
StrategyGroupName string `json:"strategyGroupName"` // 策略组名称
|
||||
}
|
||||
|
||||
// VideoTextLibInfo 名单信息
|
||||
type VideoTextLibInfo struct {
|
||||
Type int `json:"type"` // 名单类型
|
||||
Entity string `json:"entity"` // 名单内容
|
||||
ReleaseTime int64 `json:"releaseTime"` // 释放时间
|
||||
}
|
||||
|
||||
// VideoTextAnticheat 反作弊信息
|
||||
type VideoTextAnticheat struct {
|
||||
HitType int `json:"hitType"` // 命中类型
|
||||
}
|
||||
|
||||
// VideoTextHitInfo 其他命中信息
|
||||
type VideoTextHitInfo struct {
|
||||
Value string `json:"value"` // 命中值
|
||||
Positions *[]VideoTextHitPosition `json:"positions"` // 命中位置
|
||||
}
|
||||
|
||||
// VideoTextHitPosition 命中位置
|
||||
type VideoTextHitPosition struct {
|
||||
FieldName string `json:"fieldName"` // 字段名
|
||||
StartPos int `json:"startPos"` // 开始位置
|
||||
EndPos int `json:"endPos"` // 结束位置
|
||||
}
|
||||
|
||||
// VideoImageEvidence 图片证据
|
||||
type VideoImageEvidence struct {
|
||||
Name string `json:"name"` // 图片名称
|
||||
DataID string `json:"dataId"` // 数据ID
|
||||
Suggestion int `json:"suggestion"` // 处置建议
|
||||
ResultType int `json:"resultType"` // 结果类型
|
||||
Status int `json:"status"` // 状态
|
||||
CensorType int `json:"censorType"` // 审核类型
|
||||
Labels []*VideoImageLabel `json:"labels"` // 分类标签
|
||||
TaskId string `json:"taskId"` // 任务ID
|
||||
}
|
||||
|
||||
// VideoImageLabel 图片分类标签
|
||||
type VideoImageLabel struct {
|
||||
Label int `json:"label"` // 标签类型
|
||||
Level int `json:"level"` // 级别
|
||||
Rate float32 `json:"rate"` // 置信度
|
||||
SubLabels []*VideoImageSubLabel `json:"subLabels"` // 二级分类
|
||||
}
|
||||
|
||||
// VideoImageSubLabel 图片二级分类
|
||||
type VideoImageSubLabel struct {
|
||||
SubLabel interface{} `json:"subLabel"` // 二级分类标签
|
||||
SubLabelDepth int `json:"subLabelDepth"` // 细分类层级
|
||||
SecondLabel string `json:"secondLabel"` // 二级分类
|
||||
ThirdLabel string `json:"thirdLabel"` // 三级分类
|
||||
HitStrategy int `json:"hitStrategy"` // 命中策略
|
||||
Rate float32 `json:"rate"` // 置信度
|
||||
Details *VideoImageSubDetail `json:"details"` // 命中详情
|
||||
Explain string `json:"explain"` // 解释
|
||||
IsLlmCheck bool `json:"isLlmCheck"` // 是否LLM命中
|
||||
}
|
||||
|
||||
// VideoImageSubDetail 图片二级分类命中详情
|
||||
type VideoImageSubDetail struct {
|
||||
Keywords *[]VideoImageHitInfo `json:"keywords,omitempty"` // 敏感词
|
||||
LibInfos *[]VideoImageLibInfo `json:"libInfos,omitempty"` // 名单信息
|
||||
HitInfos *[]VideoImageHitInfo `json:"hitInfos,omitempty"` // 其他命中
|
||||
Anticheat *VideoImageAnticheat `json:"anticheat,omitempty"` // 反作弊
|
||||
Llm *VideoImageLlm `json:"llm,omitempty"` // 大模型
|
||||
}
|
||||
|
||||
// VideoImageHitInfo 图片命中信息
|
||||
type VideoImageHitInfo struct {
|
||||
Type int `json:"type"` // 命中类型
|
||||
Word string `json:"word"` // 敏感词
|
||||
Entity string `json:"entity"` // 名单URL
|
||||
HitCount int `json:"hitCount"` // 命中次数
|
||||
Value string `json:"value"` // 值
|
||||
Group string `json:"group"` // 分组
|
||||
X1 float32 `json:"x1"` // 坐标
|
||||
Y1 float32 `json:"y1"` // 坐标
|
||||
X2 float32 `json:"x2"` // 坐标
|
||||
Y2 float32 `json:"y2"` // 坐标
|
||||
StrategyGroupName string `json:"strategyGroupName"` // 策略组名称
|
||||
StrategyGroupId int64 `json:"strategyGroupId"` // 策略组ID
|
||||
}
|
||||
|
||||
// VideoImageLibInfo 图片名单信息
|
||||
type VideoImageLibInfo struct {
|
||||
Type int `json:"type"` // 名单类型
|
||||
Entity string `json:"entity"` // 名单URL
|
||||
HitCount int `json:"hitCount"` // 命中次数
|
||||
ReleaseTime int64 `json:"releaseTime"` // 释放时间
|
||||
StrategyGroupName string `json:"strategyGroupName"` // 策略组名称
|
||||
StrategyGroupId int64 `json:"strategyGroupId"` // 策略组ID
|
||||
}
|
||||
|
||||
// VideoImageAnticheat 反作弊信息
|
||||
type VideoImageAnticheat struct {
|
||||
HitType int `json:"hitType"` // 命中类型
|
||||
}
|
||||
|
||||
// VideoImageLlm 大模型信息
|
||||
type VideoImageLlm struct {
|
||||
Keyword string `json:"keyword"` // 关键词
|
||||
}
|
||||
|
||||
// VideoAudioEvidence 音频证据
|
||||
type VideoAudioEvidence struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
DataID string `json:"dataId"` // 数据ID
|
||||
Status int `json:"status"` // 状态
|
||||
Suggestion int `json:"suggestion"` // 处置建议
|
||||
Label int `json:"label"` // 标签
|
||||
ResultType int `json:"resultType"` // 结果类型
|
||||
Callback string `json:"callback"` // 回调参数
|
||||
CensorSource int `json:"censorSource"` // 审核来源
|
||||
CensorTime int64 `json:"censorTime"` // 审核时间
|
||||
Duration int64 `json:"duration"` // 音频时长
|
||||
Segments []*VideoAudioSegment `json:"segments"` // 音频片段
|
||||
}
|
||||
|
||||
// VideoAudioSegment 音频片段
|
||||
type VideoAudioSegment struct {
|
||||
StartTime int `json:"startTime"` // 开始时间(秒)
|
||||
EndTime int `json:"endTime"` // 结束时间(秒)
|
||||
StartTimeMillis int64 `json:"startTimeMillis"` // 开始时间(毫秒)
|
||||
EndTimeMillis int64 `json:"endTimeMillis"` // 结束时间(毫秒)
|
||||
Content string `json:"content"` // 语音识别原文
|
||||
Type int `json:"type"` // 片段类型:0=语音识别,1=声纹检测
|
||||
LeaderName string `json:"leaderName"` // 声纹检测人名
|
||||
Labels []*VideoAudioLabel `json:"labels"` // 分类标签
|
||||
Url string `json:"url"` // 音频URL
|
||||
}
|
||||
|
||||
// VideoAudioLabel 音频分类标签
|
||||
type VideoAudioLabel struct {
|
||||
Label int `json:"label"` // 标签类型
|
||||
Level int `json:"level"` // 级别
|
||||
SubLabels []*VideoAudioSubLabel `json:"subLabels"` // 二级分类
|
||||
}
|
||||
|
||||
// VideoAudioSubLabel 音频二级分类
|
||||
type VideoAudioSubLabel struct {
|
||||
SubLabel string `json:"subLabel"` // 细分类
|
||||
SubLabelDepth int `json:"subLabelDepth"` // 细分类层级
|
||||
SecondLabel string `json:"secondLabel"` // 二级分类
|
||||
ThirdLabel string `json:"thirdLabel"` // 三级分类
|
||||
SuggestionRiskLevel int `json:"suggestionRiskLevel"` // 嫌疑级别
|
||||
Rate float64 `json:"rate"` // 置信度
|
||||
RiskDescription string `json:"riskDescription"` // 风险描述
|
||||
Details *VideoAudioSubLabelDetail `json:"details"` // 命中详情
|
||||
}
|
||||
|
||||
// VideoAudioSubLabelDetail 音频二级分类命中详情
|
||||
type VideoAudioSubLabelDetail struct {
|
||||
HitInfos *[]VideoAudioHitInfo `json:"hitInfos,omitempty"` // 命中内容
|
||||
Keywords *[]VideoAudioKeyword `json:"keywords,omitempty"` // 自定义敏感词
|
||||
LibInfos *[]VideoAudioLibInfo `json:"libInfos,omitempty"` // 自定义名单
|
||||
}
|
||||
|
||||
// VideoAudioHitInfo 音频命中内容
|
||||
type VideoAudioHitInfo struct {
|
||||
Value string `json:"value"` // 命中敏感词或声纹检测分值
|
||||
StartTime int `json:"startTime"` // 开始时间
|
||||
EndTime int `json:"endTime"` // 结束时间
|
||||
}
|
||||
|
||||
// VideoAudioKeyword 自定义敏感词
|
||||
type VideoAudioKeyword struct {
|
||||
Word string `json:"word"` // 敏感词
|
||||
StrategyGroupName string `json:"strategyGroupName"` // 策略组名称
|
||||
StrategyGroupId int64 `json:"strategyGroupId"` // 策略组ID
|
||||
}
|
||||
|
||||
// VideoAudioLibInfo 自定义名单
|
||||
type VideoAudioLibInfo struct {
|
||||
ListType int `json:"listType"` // 名单类型
|
||||
Entity string `json:"entity"` // 名单内容
|
||||
}
|
||||
|
||||
// VideoVideoEvidence 视频证据
|
||||
type VideoVideoEvidence struct {
|
||||
TaskID string `json:"taskId"` // 任务ID
|
||||
DataID string `json:"dataId"` // 数据ID
|
||||
Status int `json:"status"` // 状态
|
||||
Suggestion int `json:"suggestion"` // 处置建议
|
||||
ResultType int `json:"resultType"` // 结果类型
|
||||
CensorSource int `json:"censorSource"` // 审核来源
|
||||
CensorTime int64 `json:"censorTime"` // 审核时间
|
||||
Pictures []*VideoPicture `json:"pictures"` // 截图列表
|
||||
}
|
||||
|
||||
// VideoPicture 截图信息
|
||||
type VideoPicture struct {
|
||||
Type int `json:"type"` // 类型
|
||||
URL string `json:"url"` // 图片URL
|
||||
StartTime int64 `json:"startTime"` // 开始时间
|
||||
EndTime int64 `json:"endTime"` // 结束时间
|
||||
Labels []*VideoPictureLabel `json:"labels"` // 分类标签
|
||||
CensorSource int `json:"censorSource"` // 审核来源
|
||||
FrontPics []*VideoRelatedPic `json:"frontPics"` // 关联前帧
|
||||
BackPics []*VideoRelatedPic `json:"backPics"` // 关联后帧
|
||||
PictureID string `json:"pictureId"` // 图片ID
|
||||
}
|
||||
|
||||
// VideoPictureLabel 截图分类标签
|
||||
type VideoPictureLabel struct {
|
||||
Label int `json:"label"` // 标签类型
|
||||
Level int `json:"level"` // 级别
|
||||
Rate float32 `json:"rate"` // 置信度
|
||||
SubLabels []*VideoPictureSubLabel `json:"subLabels"` // 二级分类
|
||||
}
|
||||
|
||||
// VideoPictureSubLabel 截图二级分类
|
||||
type VideoPictureSubLabel struct {
|
||||
SubLabel interface{} `json:"subLabel"` // 二级分类标签
|
||||
SubLabelDepth int `json:"subLabelDepth"` // 细分类层级
|
||||
SecondLabel string `json:"secondLabel"` // 二级分类
|
||||
ThirdLabel string `json:"thirdLabel"` // 三级分类
|
||||
HitStrategy int `json:"hitStrategy"` // 命中策略
|
||||
Rate float32 `json:"rate"` // 置信度
|
||||
Details *VideoPictureSubDetail `json:"details"` // 命中详情
|
||||
Explain string `json:"explain"` // 解释
|
||||
IsLlmCheck bool `json:"isLlmCheck"` // 是否LLM命中
|
||||
}
|
||||
|
||||
// VideoPictureSubDetail 截图二级分类命中详情
|
||||
type VideoPictureSubDetail struct {
|
||||
Keywords *[]VideoPictureHitInfo `json:"keywords,omitempty"` // 敏感词
|
||||
LibInfos *[]VideoPictureLibInfo `json:"libInfos,omitempty"` // 名单信息
|
||||
HitInfos *[]VideoPictureHitInfo `json:"hitInfos,omitempty"` // 其他命中
|
||||
Anticheat *VideoPictureAnticheat `json:"anticheat,omitempty"` // 反作弊
|
||||
Llm *VideoPictureLlm `json:"llm,omitempty"` // 大模型
|
||||
}
|
||||
|
||||
// VideoPictureHitInfo 截图命中信息
|
||||
type VideoPictureHitInfo struct {
|
||||
Value string `json:"value"` // 命中值
|
||||
Group string `json:"group"` // 分组
|
||||
Type int `json:"type"` // 类型
|
||||
X1 float32 `json:"x1"` // 坐标
|
||||
Y1 float32 `json:"y1"` // 坐标
|
||||
X2 float32 `json:"x2"` // 坐标
|
||||
Y2 float32 `json:"y2"` // 坐标
|
||||
}
|
||||
|
||||
// VideoPictureLibInfo 截图名单信息
|
||||
type VideoPictureLibInfo struct {
|
||||
Type int `json:"type"` // 名单类型
|
||||
Entity string `json:"entity"` // 名单URL
|
||||
HitCount int `json:"hitCount"` // 命中次数
|
||||
ReleaseTime int64 `json:"releaseTime"` // 释放时间
|
||||
StrategyGroupName string `json:"strategyGroupName"` // 策略组名称
|
||||
StrategyGroupId int64 `json:"strategyGroupId"` // 策略组ID
|
||||
}
|
||||
|
||||
// VideoPictureAnticheat 反作弊信息
|
||||
type VideoPictureAnticheat struct {
|
||||
HitType int `json:"hitType"` // 命中类型
|
||||
}
|
||||
|
||||
// VideoPictureLlm 大模型信息
|
||||
type VideoPictureLlm struct {
|
||||
Keyword string `json:"keyword"` // 关键词
|
||||
}
|
||||
|
||||
// VideoRelatedPic 关联截图
|
||||
type VideoRelatedPic struct {
|
||||
URL string `json:"url"` // 图片URL
|
||||
}
|
||||
|
||||
// VideoSolutionExtra 额外信息
|
||||
type VideoSolutionExtra struct {
|
||||
FailUnit *VideoFailUnit `json:"failUnit,omitempty"` // 失败单元
|
||||
}
|
||||
|
||||
// VideoFailUnit 失败单元
|
||||
type VideoFailUnit struct {
|
||||
Images *[]VideoImageFailUnit `json:"images,omitempty"` // 图片失败单元
|
||||
Audio *VideoTargetFailUnit `json:"audio,omitempty"` // 音频失败单元
|
||||
Video *VideoTargetFailUnit `json:"video,omitempty"` // 视频失败单元
|
||||
}
|
||||
|
||||
// VideoImageFailUnit 图片失败单元
|
||||
type VideoImageFailUnit struct {
|
||||
FailureReason int `json:"failureReason"` // 失败原因
|
||||
Name string `json:"name"` // 名称
|
||||
}
|
||||
|
||||
// VideoTargetFailUnit 目标失败单元
|
||||
type VideoTargetFailUnit struct {
|
||||
FailureReason int `json:"failureReason"` // 失败原因
|
||||
}
|
||||
|
||||
// VideoReviewEvidence 人审证据信息
|
||||
type VideoReviewEvidence struct {
|
||||
Description string `json:"description"` // 描述
|
||||
Detail string `json:"detail"` // 详情
|
||||
Texts *[]VideoReviewText `json:"texts"` // 文本证据
|
||||
Images *[]VideoReviewImage `json:"images"` // 图片证据
|
||||
Audios *[]VideoReviewAudio `json:"audios"` // 音频证据
|
||||
Videos *[]VideoReviewVideo `json:"videos"` // 视频证据
|
||||
}
|
||||
|
||||
// VideoReviewText 人审文本证据
|
||||
type VideoReviewText struct {
|
||||
Snippet string `json:"snippet"` // 片段
|
||||
Description string `json:"description"` // 描述
|
||||
}
|
||||
|
||||
// VideoReviewImage 人审图片证据
|
||||
type VideoReviewImage struct {
|
||||
URL string `json:"url"` // 图片URL
|
||||
Description string `json:"description"` // 描述
|
||||
}
|
||||
|
||||
// VideoReviewAudio 人审音频证据
|
||||
type VideoReviewAudio struct {
|
||||
StartTime int64 `json:"startTime"` // 开始时间
|
||||
EndTime int64 `json:"endTime"` // 结束时间
|
||||
Description string `json:"description"` // 描述
|
||||
}
|
||||
|
||||
// VideoReviewVideo 人审视频证据
|
||||
type VideoReviewVideo struct {
|
||||
StartTime int64 `json:"startTime"` // 开始时间
|
||||
EndTime int64 `json:"endTime"` // 结束时间
|
||||
URL string `json:"url"` // 视频URL
|
||||
Description string `json:"description"` // 描述
|
||||
}
|
||||
|
||||
// ProcessVideoCallback 处理视频检测回调(推送模式)
|
||||
func (s *VideoDetectionService) ProcessVideoCallback(ctx context.Context, callbackData string) error {
|
||||
if callbackData == "" {
|
||||
return fmt.Errorf("回调数据不能为空")
|
||||
}
|
||||
|
||||
var data VideoCallbackData
|
||||
if err := json.Unmarshal([]byte(callbackData), &data); err != nil {
|
||||
g.Log().Errorf(ctx, "解析视频回调数据失败: %v", err)
|
||||
return fmt.Errorf("解析视频回调数据失败: %w", err)
|
||||
}
|
||||
|
||||
if data.Antispam == nil {
|
||||
return fmt.Errorf("视频回调数据格式错误:缺少antispam字段")
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "处理视频检测结果 - taskId: %s, suggestion: %d, resultType: %d, status: %d",
|
||||
data.Antispam.TaskID, data.Antispam.Suggestion, data.Antispam.ResultType, data.Antispam.Status)
|
||||
|
||||
// TODO: 业务逻辑,如保存数据库、触发后续流程等
|
||||
// 可使用完整字段:data.Antispam.Evidences, data.Antispam.CensorLabels, data.Antispam.Duration 等
|
||||
|
||||
return nil
|
||||
}
|
||||
53
service/yidun/yidun_client.go
Normal file
53
service/yidun/yidun_client.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package yidun
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/yidun/yidun-golang-sdk/yidun/service/antispam/image/v5"
|
||||
text "github.com/yidun/yidun-golang-sdk/yidun/service/antispam/text"
|
||||
"github.com/yidun/yidun-golang-sdk/yidun/service/antispam/videosolution"
|
||||
)
|
||||
|
||||
// YidunClients 易盾客户端集合(直接使用SDK客户端)
|
||||
type YidunClients struct {
|
||||
TextClient *text.TextClient
|
||||
ImageClient *image.ImageClient
|
||||
VideoClient *videosolution.VideoSolutionClient
|
||||
}
|
||||
|
||||
var DefaultClients *YidunClients
|
||||
|
||||
// InitYidunClients 初始化所有易盾客户端
|
||||
func InitYidunClients(ctx context.Context) error {
|
||||
clients := &YidunClients{}
|
||||
|
||||
// 文本检测
|
||||
secretId := g.Cfg().MustGet(ctx, "yidun.text.secret_id").String()
|
||||
secretKey := g.Cfg().MustGet(ctx, "yidun.text.secret_key").String()
|
||||
if secretId != "" && secretKey != "" {
|
||||
clients.TextClient = text.NewTextClientWithAccessKey(secretId, secretKey)
|
||||
g.Log().Info(ctx, "文本检测客户端初始化成功")
|
||||
}
|
||||
|
||||
// 图片检测
|
||||
secretId = g.Cfg().MustGet(ctx, "yidun.image.secret_id").String()
|
||||
secretKey = g.Cfg().MustGet(ctx, "yidun.image.secret_key").String()
|
||||
businessId := g.Cfg().MustGet(ctx, "yidun.image.business_id").String()
|
||||
if secretId != "" && secretKey != "" {
|
||||
clients.ImageClient = image.NewImageClientWithAccessKey(secretId, secretKey)
|
||||
g.Log().Infof(ctx, "图片检测客户端初始化成功, business_id: %s", businessId)
|
||||
}
|
||||
|
||||
// 视频检测
|
||||
secretId = g.Cfg().MustGet(ctx, "yidun.video.secret_id").String()
|
||||
secretKey = g.Cfg().MustGet(ctx, "yidun.video.secret_key").String()
|
||||
businessId = g.Cfg().MustGet(ctx, "yidun.video.business_id").String()
|
||||
if secretId != "" && secretKey != "" {
|
||||
clients.VideoClient = videosolution.NewVideoSolutionClientWithAccessKey(secretId, secretKey)
|
||||
g.Log().Infof(ctx, "视频检测客户端初始化成功, business_id: %s", businessId)
|
||||
}
|
||||
|
||||
DefaultClients = clients
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user