yidun送检功能

This commit is contained in:
2026-05-15 10:28:17 +08:00
parent 51d26aeee7
commit c8cc19e8e7
29 changed files with 5133 additions and 121 deletions

View File

@@ -0,0 +1,509 @@
package dataengine
import (
consts "cid/consts/dataengine"
dao "cid/dao/dataengine"
entity "cid/model/entity/dataengine"
serviceDataengine "cid/service/dataengine"
"context"
"fmt"
"time"
"github.com/gogf/gf/v2/frame/g"
)
// MaterialVerifyController 素材校验控制器
type MaterialVerifyController struct{}
// MaterialVerify 控制器单例
var MaterialVerify = new(MaterialVerifyController)
// =============================================================================
// 请求/响应结构体
// =============================================================================
// ImageListReq 图片列表请求
type ImageListReq struct {
Status string `json:"status"`
AccountID int64 `json:"accountId"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
}
// ImageListRes 图片列表响应
type ImageListRes struct {
List interface{} `json:"list"`
Total int `json:"total"`
}
// StatsRes 统计响应
type StatsRes struct {
Pending int `json:"pending"`
Verified int `json:"verified"`
Rejected int `json:"rejected"`
}
// VideoListReq 视频列表请求
type VideoListReq struct {
Status string `json:"status"`
AccountID int64 `json:"accountId"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
}
// VideoListRes 视频列表响应
type VideoListRes struct {
List interface{} `json:"list"`
Total int `json:"total"`
}
// LogListReq 日志列表请求
type LogListReq struct {
MaterialType string `json:"materialType"`
MaterialID string `json:"materialId"`
VerifyStatus string `json:"verifyStatus"`
AccountID int64 `json:"accountId"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
}
// ManualVerifyReq 手动校验请求
type ManualVerifyReq struct {
MaterialID string `json:"materialId" v:"required#素材ID不能为空"`
}
// TaskIDReq 任务ID请求
type TaskIDReq struct {
TaskID string `json:"taskId" v:"required#任务ID不能为空"`
}
// ImageCallbackReq 图片回调请求
type ImageCallbackReq struct {
CallbackData string `json:"callbackData"`
}
// VideoCallbackReq 视频回调请求
type VideoCallbackReq struct {
CallbackData string `json:"callbackData"`
}
// BatchVerifyReq 批量校验请求
type BatchVerifyReq struct {
Limit int `json:"limit"`
}
// =============================================================================
// 图片素材接口
// =============================================================================
// ListImage 图片素材列表
func (c *MaterialVerifyController) ListImage(ctx context.Context, req *ImageListReq) (res *ImageListRes, err error) {
if req.Page == 0 {
req.Page = 1
}
if req.PageSize == 0 {
req.PageSize = 20
}
condition := make(map[string]interface{})
if req.Status != "" {
condition[entity.TencentImageCols.VerifyStatus] = req.Status
}
if req.AccountID > 0 {
condition[entity.TencentImageCols.AccountID] = req.AccountID
}
data, total, err := dao.TencentImage.GetByCondition(ctx, condition, req.Page, req.PageSize)
if err != nil {
return nil, err
}
return &ImageListRes{
List: data,
Total: total,
}, nil
}
// StatsImage 图片素材统计
func (c *MaterialVerifyController) StatsImage(ctx context.Context, req *ImageListReq) (res *StatsRes, err error) {
// 使用实体中定义的正确状态值PENDING=待校验, VERIFIED=校验通过, REJECTED=校验不通过
pending, _ := dao.TencentImage.CountByStatus(ctx, entity.VerifyStatusPending)
verified, _ := dao.TencentImage.CountByStatus(ctx, entity.VerifyStatusVerified)
rejected, _ := dao.TencentImage.CountByStatus(ctx, entity.VerifyStatusRejected)
return &StatsRes{
Pending: pending,
Verified: verified,
Rejected: rejected,
}, nil
}
// =============================================================================
// 视频素材接口
// =============================================================================
// ListVideo 视频素材列表
func (c *MaterialVerifyController) ListVideo(ctx context.Context, req *VideoListReq) (res *VideoListRes, err error) {
if req.Page == 0 {
req.Page = 1
}
if req.PageSize == 0 {
req.PageSize = 20
}
condition := make(map[string]interface{})
if req.Status != "" {
condition[entity.TencentVideoCols.VerifyStatus] = req.Status
}
if req.AccountID > 0 {
condition[entity.TencentVideoCols.AccountID] = req.AccountID
}
data, total, err := dao.TencentVideo.GetByCondition(ctx, condition, req.Page, req.PageSize)
if err != nil {
return nil, err
}
return &VideoListRes{
List: data,
Total: total,
}, nil
}
// StatsVideo 视频素材统计
func (c *MaterialVerifyController) StatsVideo(ctx context.Context, req *VideoListReq) (res *StatsRes, err error) {
// 使用实体中定义的正确状态值PENDING=待校验, VERIFIED=校验通过, REJECTED=校验不通过
pending, _ := dao.TencentVideo.CountByStatus(ctx, entity.VerifyStatusPending)
verified, _ := dao.TencentVideo.CountByStatus(ctx, entity.VerifyStatusVerified)
rejected, _ := dao.TencentVideo.CountByStatus(ctx, entity.VerifyStatusRejected)
return &StatsRes{
Pending: pending,
Verified: verified,
Rejected: rejected,
}, nil
}
// =============================================================================
// 校验日志接口
// =============================================================================
// ListLogRes 日志列表响应
type ListLogRes struct {
List interface{} `json:"list"`
Total int `json:"total"`
}
// ListLog 日志列表
func (c *MaterialVerifyController) ListLog(ctx context.Context, req *LogListReq) (res *ListLogRes, err error) {
if req.Page == 0 {
req.Page = 1
}
if req.PageSize == 0 {
req.PageSize = 20
}
condition := make(map[string]interface{})
if req.MaterialType != "" {
condition[entity.MaterialVerifyLogCols.MaterialType] = req.MaterialType
}
if req.MaterialID != "" {
condition[entity.MaterialVerifyLogCols.MaterialID] = req.MaterialID
}
if req.VerifyStatus != "" {
condition[entity.MaterialVerifyLogCols.VerifyStatus] = req.VerifyStatus
}
if req.AccountID > 0 {
condition[entity.MaterialVerifyLogCols.AccountID] = req.AccountID
}
data, total, err := serviceDataengine.MaterialVerify.GetLogsByCondition(ctx, condition, req.Page, req.PageSize)
if err != nil {
return nil, err
}
return &ListLogRes{
List: data,
Total: total,
}, nil
}
// LogDetailRes 日志详情响应
type LogDetailRes struct {
*entity.MaterialVerifyLog
PreviewURL string `json:"previewURL"`
}
// GetLogDetailReq 日志详情请求
type GetLogDetailReq struct {
Id int64 `json:"id" v:"required#日志ID不能为空"`
}
// GetLogDetail 日志详情
func (c *MaterialVerifyController) GetLogDetail(ctx context.Context, req *GetLogDetailReq) (res *LogDetailRes, err error) {
log, err := serviceDataengine.MaterialVerify.GetLogByID(ctx, req.Id)
if err != nil {
return nil, err
}
if log == nil {
return nil, fmt.Errorf("日志不存在")
}
// 获取来源数据预览
res = &LogDetailRes{
MaterialVerifyLog: log,
}
if log.SourceTable == consts.SourceTableTencentImage {
image, _ := dao.TencentImage.GetByID(ctx, log.SourceID)
if image != nil {
res.PreviewURL = image.PreviewURL
}
} else if log.SourceTable == consts.SourceTableTencentVideo {
video, _ := dao.TencentVideo.GetByID(ctx, log.SourceID)
if video != nil {
res.PreviewURL = video.PreviewURL
}
}
return
}
// StatsLogRes 日志统计响应
type StatsLogRes struct {
Total int `json:"total"`
Pending int `json:"pending"`
Verified int `json:"verified"`
Rejected int `json:"rejected"`
}
// StatsLog 日志统计
func (c *MaterialVerifyController) StatsLog(ctx context.Context, req *LogListReq) (res *StatsLogRes, err error) {
stats, err := serviceDataengine.MaterialVerify.GetStats(ctx)
if err != nil {
return nil, err
}
return &StatsLogRes{
Total: stats["total"],
Pending: stats["pending"],
Verified: stats["verified"],
Rejected: stats["rejected"],
}, nil
}
// =============================================================================
// 手动校验接口
// =============================================================================
// ManualVerifyImageRes 手动校验响应
type ManualVerifyImageRes struct {
Id int64 `json:"id"`
TaskID string `json:"taskId"`
SourceID string `json:"sourceId"`
}
// ManualVerifyImage 手动校验图片
func (c *MaterialVerifyController) ManualVerifyImage(ctx context.Context, req *ManualVerifyReq) (res *ManualVerifyImageRes, err error) {
log, err := serviceDataengine.MaterialVerify.VerifyImageByID(ctx, req.MaterialID)
if err != nil {
return nil, err
}
return &ManualVerifyImageRes{
Id: log.Id,
TaskID: log.TaskID,
SourceID: fmt.Sprintf("%d", log.SourceID),
}, nil
}
// ManualVerifyVideo 手动校验视频
func (c *MaterialVerifyController) ManualVerifyVideo(ctx context.Context, req *ManualVerifyReq) (res *ManualVerifyImageRes, err error) {
log, err := serviceDataengine.MaterialVerify.VerifyVideoByID(ctx, req.MaterialID)
if err != nil {
return nil, err
}
return &ManualVerifyImageRes{
Id: log.Id,
TaskID: log.TaskID,
SourceID: fmt.Sprintf("%d", log.SourceID),
}, nil
}
// =============================================================================
// 批量校验接口
// =============================================================================
// BatchVerifyRes 批量校验响应
type BatchVerifyRes struct {
Success int `json:"success"`
Fail int `json:"fail"`
Total int `json:"total"`
Message string `json:"message"`
}
// BatchVerifyImage 批量校验图片
func (c *MaterialVerifyController) BatchVerifyImage(ctx context.Context, req *BatchVerifyReq) (res *BatchVerifyRes, err error) {
if req.Limit <= 0 {
req.Limit = 100
}
images, err := dao.TencentImage.GetPendingList(ctx, req.Limit)
if err != nil {
return nil, err
}
successCount := 0
failCount := 0
for _, image := range images {
log, err := serviceDataengine.MaterialVerify.VerifyImageByID(ctx, image.ImageID)
if err != nil {
failCount++
g.Log().Errorf(ctx, "图片校验失败: %s, error: %v", image.ImageID, err)
} else {
successCount++
g.Log().Infof(ctx, "图片校验已提交: %s, logId: %d", image.ImageID, log.Id)
}
time.Sleep(100 * time.Millisecond)
}
// 等待易盾处理,然后自动查询结果
msg := fmt.Sprintf("批量校验完成,成功: %d失败: %d", successCount, failCount)
if successCount > 0 {
g.Log().Infof(ctx, "提交完成等待2秒后自动查询结果...")
time.Sleep(2 * time.Second)
pollSuccess, pollFail, _ := serviceDataengine.MaterialVerify.PollPendingResults(ctx)
msg = fmt.Sprintf("批量校验完成,提交成功: %d提交失败: %d自动查询成功: %d未就绪: %d",
successCount, failCount, pollSuccess, pollFail)
}
return &BatchVerifyRes{
Success: successCount,
Fail: failCount,
Total: len(images),
Message: msg,
}, nil
}
// BatchVerifyVideo 批量校验视频
func (c *MaterialVerifyController) BatchVerifyVideo(ctx context.Context, req *BatchVerifyReq) (res *BatchVerifyRes, err error) {
if req.Limit <= 0 {
req.Limit = 100
}
videos, err := dao.TencentVideo.GetPendingList(ctx, req.Limit)
if err != nil {
return nil, err
}
successCount := 0
failCount := 0
for _, video := range videos {
log, err := serviceDataengine.MaterialVerify.VerifyVideoByID(ctx, video.VideoID)
if err != nil {
failCount++
g.Log().Errorf(ctx, "视频校验失败: %s, error: %v", video.VideoID, err)
} else {
successCount++
g.Log().Infof(ctx, "视频校验已提交: %s, logId: %d", video.VideoID, log.Id)
}
time.Sleep(100 * time.Millisecond)
}
// 等待易盾处理,然后自动查询结果
msg := fmt.Sprintf("批量校验完成,成功: %d失败: %d", successCount, failCount)
if successCount > 0 {
g.Log().Infof(ctx, "提交完成等待2秒后自动查询结果...")
time.Sleep(2 * time.Second)
pollSuccess, pollFail, _ := serviceDataengine.MaterialVerify.PollPendingResults(ctx)
msg = fmt.Sprintf("批量校验完成,提交成功: %d提交失败: %d自动查询成功: %d未就绪: %d",
successCount, failCount, pollSuccess, pollFail)
}
return &BatchVerifyRes{
Success: successCount,
Fail: failCount,
Total: len(videos),
Message: msg,
}, nil
}
// =============================================================================
// 回调处理接口
// =============================================================================
// CallbackRes 回调响应
type CallbackRes struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
// ImageCallback 图片校验回调
func (c *MaterialVerifyController) ImageCallback(ctx context.Context, req *ImageCallbackReq) (res *CallbackRes, err error) {
if req.CallbackData == "" {
return &CallbackRes{Code: 400, Msg: "callbackData不能为空"}, nil
}
err = serviceDataengine.MaterialVerify.ProcessImageCallback(ctx, req.CallbackData)
if err != nil {
return &CallbackRes{Code: 500, Msg: err.Error()}, nil
}
return &CallbackRes{Code: 200, Msg: "处理成功"}, nil
}
// VideoCallback 视频校验回调
func (c *MaterialVerifyController) VideoCallback(ctx context.Context, req *VideoCallbackReq) (res *CallbackRes, err error) {
if req.CallbackData == "" {
return &CallbackRes{Code: 400, Msg: "callbackData不能为空"}, nil
}
err = serviceDataengine.MaterialVerify.ProcessVideoCallback(ctx, req.CallbackData)
if err != nil {
return &CallbackRes{Code: 500, Msg: err.Error()}, nil
}
return &CallbackRes{Code: 200, Msg: "处理成功"}, nil
}
// ResultRes 结果查询响应
type ResultRes struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
// ImageResult 图片校验结果查询(轮询模式)
func (c *MaterialVerifyController) ImageResult(ctx context.Context, req *TaskIDReq) (res *ResultRes, err error) {
if req.TaskID == "" {
return &ResultRes{Code: 400, Msg: "taskId不能为空"}, nil
}
err = serviceDataengine.MaterialVerify.ProcessImageResultByTask(ctx, req.TaskID)
if err != nil {
return &ResultRes{Code: 500, Msg: err.Error()}, nil
}
return &ResultRes{Code: 200, Msg: "处理成功"}, nil
}
// VideoResult 视频校验结果查询(轮询模式)
func (c *MaterialVerifyController) VideoResult(ctx context.Context, req *TaskIDReq) (res *ResultRes, err error) {
if req.TaskID == "" {
return &ResultRes{Code: 400, Msg: "taskId不能为空"}, nil
}
err = serviceDataengine.MaterialVerify.ProcessVideoResultByTask(ctx, req.TaskID)
if err != nil {
return &ResultRes{Code: 500, Msg: err.Error()}, nil
}
return &ResultRes{Code: 200, Msg: "处理成功"}, nil
}