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 }