// ========================================================================== // GFast自动生成controller操作代码。 // 生成日期:2024-03-01 12:49:32 // 生成路径: internal/app/system/controller/ys7devices.go // 生成人:gfast // desc:荧石摄像头 // company:云南奇讯科技有限公司 // ========================================================================== package controller import ( "context" "encoding/json" "errors" "fmt" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/util/gconv" "github.com/tiger1103/gfast/v3/api/v1/common/coryCommon" "github.com/tiger1103/gfast/v3/api/v1/common/shp" "github.com/tiger1103/gfast/v3/api/v1/system" "github.com/tiger1103/gfast/v3/internal/app/system/consts" "github.com/tiger1103/gfast/v3/internal/app/system/dao" logic "github.com/tiger1103/gfast/v3/internal/app/system/logic/busViolationLevel" "github.com/tiger1103/gfast/v3/internal/app/system/model" "github.com/tiger1103/gfast/v3/internal/app/system/model/do" "github.com/tiger1103/gfast/v3/internal/app/system/service" "github.com/tiger1103/gfast/v3/library/liberr" "github.com/tiger1103/gfast/v3/third/arithmetic/SpartaApi" "github.com/tiger1103/gfast/v3/third/ys7" "log" "os" "path/filepath" "strconv" "strings" "sync" "time" ) type ys7DevicesController struct { BaseController } var Ys7Devices = new(ys7DevicesController) // List 列表 func (c *ys7DevicesController) List(ctx context.Context, req *system.Ys7DevicesSearchReq) (res *system.Ys7DevicesSearchRes, err error) { res, err = service.Ys7Devices().List(ctx, req) return } // Get 获取荧石摄像头 func (c *ys7DevicesController) Get(ctx context.Context, req *system.Ys7DevicesGetReq) (res *system.Ys7DevicesGetRes, err error) { res = new(system.Ys7DevicesGetRes) res.Ys7DevicesInfoRes, err = service.Ys7Devices().GetById(ctx, req.Id) return } // Add 添加荧石摄像头 func (c *ys7DevicesController) Add(ctx context.Context, req *system.Ys7DevicesAddReq) (res *system.Ys7DevicesAddRes, err error) { err = service.Ys7Devices().Add(ctx, req) return } // Edit 修改荧石摄像头 func (c *ys7DevicesController) Edit(ctx context.Context, req *system.Ys7DevicesEditReq) (res *system.Ys7DevicesEditRes, err error) { err = service.Ys7Devices().Edit(ctx, req) return } // Delete 删除荧石摄像头 func (c *ys7DevicesController) Delete(ctx context.Context, req *system.Ys7DevicesDeleteReq) (res *system.Ys7DevicesDeleteRes, err error) { err = service.Ys7Devices().Delete(ctx, req.Ids) return } // BindProject摄像头绑定项目 func (c *ys7DevicesController) BindProject(ctx context.Context, req *system.Ys7DevicesBindProjectReq) (*system.Ys7DevicesBindProjectRes, error) { // 遍历 DeviceSerial 更新项目ID for _, deviceSerial := range req.List.DeviceSerial { _, err := dao.Ys7Devices.Ctx(ctx).Where("DeviceSerial", deviceSerial). Update(g.Map{ "ProjectId": req.List.ProjectId, }) if err != nil { return nil, err } } return &system.Ys7DevicesBindProjectRes{}, nil } func (s *ys7DevicesController) EditPosition(ctx context.Context, req *system.Ys7DevicesEditPositionReq) (*system.Ys7DevicesEditPositionRes, error) { err := g.Try(ctx, func(ctx context.Context) { dt := shp.Detail{} if err := json.Unmarshal([]byte(req.Position), &dt); err != nil { return } dt.Position.Lng, dt.Position.Lat = coryCommon.GCJ02toWGS84(dt.Position.Lng, dt.Position.Lat) data, err := json.Marshal(dt) if err != nil { return } _, err = dao.Ys7Devices.Ctx(ctx).WherePri(req.Id).Update(g.Map{ "Detail": string(data), }) liberr.ErrIsNil(ctx, err, "修改失败") }) return &system.Ys7DevicesEditPositionRes{}, err } // 根据项目ID获取摄像头列表 func (s *ys7DevicesController) GetListByProjectId(ctx context.Context, req *system.Ys7DevicesGetByProjectIdReq) (listRes *system.Ys7DevicesGetByProjectIdRes, err error) { listRes = new(system.Ys7DevicesGetByProjectIdRes) m := dao.Ys7Devices.Ctx(ctx).WithAll().Where(dao.Ys7Devices.Columns().ProjectId, req.ProjectId) listRes.Total, err = m.Count() if err != nil { return nil, err } if req.PageNum == 0 { req.PageNum = 1 } listRes.CurrentPage = req.PageNum if req.PageSize == 0 { req.PageSize = consts.PageSize } order := "sort desc,id desc" var res []*model.Ys7DevicesInfoRes err = m.Page(req.PageNum, req.PageSize).Order(order).Scan(&res) if err != nil { return nil, err } listRes.List = make([]*model.Ys7DevicesList2Res, len(res)) for k, v := range res { listRes.List[k] = &model.Ys7DevicesList2Res{ Id: v.Id, DeviceSerial: v.DeviceSerial, DeviceName: v.DeviceName, ProjectId: v.ProjectId, Token: ys7.Ys72Instance.GetAccessToken(), } } return } // 获取视频播放地址 func (s *ys7DevicesController) GetVideoUrl(ctx context.Context, req *system.Ys7DevicesGetVideoUrlReq) (res *system.Ys7DevicesGetVideoUrlRes, err error) { Device, err := ys7.Ys72Instance.GetDevice(req.DeviecesSerial) if err != nil { return nil, err } liveUrl, err := Device.GetLiveAddress() if err != nil { return nil, err } return &system.Ys7DevicesGetVideoUrlRes{ VideoUrl: liveUrl, }, nil } // 获取AccessToken func (s *ys7DevicesController) GetAccessToken(ctx context.Context, req *system.Ys7DevicesGetAccessTokenReq) (res *system.Ys7DevicesGetAccessTokenRes, err error) { return &system.Ys7DevicesGetAccessTokenRes{ Token: ys7.GetAccessToken(), }, nil } // GIS 前端调用修改摄像头信息 func (s *ys7DevicesController) EditGis(ctx context.Context, req *system.Ys7DevicesEditGisReq) (res *system.Ys7DevicesEditGisRes, err error) { err = g.Try(ctx, func(ctx context.Context) { _, err := dao.Ys7Devices.Ctx(ctx).WherePri(req.Id).Update(do.Ys7Devices{ DeviceSerial: req.DeviceSerial, DeviceName: req.DeviceName, Detail: req.Detail, }) liberr.ErrIsNil(ctx, err, "修改失败") }) return &system.Ys7DevicesEditGisRes{}, err } // 开启视频加密 func (s *ys7DevicesController) OpenEncrypt(ctx context.Context, req *system.Ys7DevicesOpenEncryptReq) (res *system.Ys7DevicesOpenEncryptRes, err error) { Device, err := ys7.Ys72Instance.GetDevice(req.DeviceSerial) if err != nil { return nil, err } r := ghttp.RequestFromCtx(ctx) r.Response.ClearBuffer() err = Device.OpenEncrypt() if err != nil { r.Response.WriteJson(fmt.Sprintf(`{"code":1,"message":"开启加密失败:%s"}`, err.Error())) return nil, err } r.Response.WriteJson(`{"code":0,"message":"开启加密成功"}`) return &system.Ys7DevicesOpenEncryptRes{}, nil } // 关闭视频加密 func (s *ys7DevicesController) CloseEncrypt(ctx context.Context, req *system.Ys7DevicesCloseEncryptReq) (res *system.Ys7DevicesCloseEncryptRes, err error) { Device, err := ys7.Ys72Instance.GetDevice(req.DeviceSerial) if err != nil { return nil, err } r := ghttp.RequestFromCtx(ctx) r.Response.ClearBuffer() err = Device.CloseEncrypt() if err != nil { r.Response.WriteJson(fmt.Sprintf(`{"code":1,"message":"%s"}`, err.Error())) return nil, err } r.Response.WriteJson(`{"code":0,"message":"关闭加密成功"}`) return &system.Ys7DevicesCloseEncryptRes{}, nil } // 小程序获取设备列表 func (s *ys7DevicesController) GetListByProjectIdForMini(ctx context.Context, req *system.Ys7DevicesGetListReq) (listRes *system.Ys7DevicesGetListRes, err error) { listRes = new(system.Ys7DevicesGetListRes) m := dao.Ys7Devices.Ctx(ctx).WithAll() if req.Id != "" { m = m.Where(dao.Ys7Devices.Columns().Id+" = ?", req.Id) } if len(req.DateRange) != 0 { m = m.Where(dao.Ys7Devices.Columns().CreatedAt+" >=? AND "+dao.Ys7Devices.Columns().CreatedAt+" <=?", req.DateRange[0], req.DateRange[1]) } if req.DeviceSerial != "" { m = m.Where(dao.Ys7Devices.Columns().DeviceSerial+" = ?", req.DeviceSerial) } if req.DeviceName != "" { m = m.Where(dao.Ys7Devices.Columns().DeviceName+" like ?", "%"+req.DeviceName+"%") } if req.DeviceType != "" { m = m.Where(dao.Ys7Devices.Columns().DeviceType+" = ?", req.DeviceType) } if req.Status != "" { m = m.Where(dao.Ys7Devices.Columns().Status+" = ?", gconv.Int(req.Status)) } if req.Defence != "" { m = m.Where(dao.Ys7Devices.Columns().Defence+" = ?", gconv.Int64(req.Defence)) } if req.DeviceVersion != "" { m = m.Where(dao.Ys7Devices.Columns().DeviceVersion+" = ?", req.DeviceVersion) } if req.ProjectId != "" { m = m.Where(dao.Ys7Devices.Columns().ProjectId+" = ?", req.ProjectId) } listRes.Total, err = m.Count() liberr.ErrIsNil(ctx, err, "获取总数失败") if req.PageNum == 0 { req.PageNum = 1 } listRes.CurrentPage = req.PageNum if req.PageSize == 0 { req.PageSize = consts.PageSize } order := "id desc" if req.OrderBy != "" { order = req.OrderBy } var res []*model.Ys7DevicesInfoRes err = m.Fields(system.Ys7DevicesSearchRes{}).Page(req.PageNum, req.PageSize).Order(order).Scan(&res) liberr.ErrIsNil(ctx, err, "获取数据失败") listRes.List = make([]*model.Ys7DevicesList3Res, len(res)) for k, v := range res { // redis 中获取封面图 value, err := g.Redis().Get(ctx, "ys7:capture:"+v.DeviceSerial) cover := value.String() if err != nil { cover = "" } listRes.List[k] = &model.Ys7DevicesList3Res{ Id: v.Id, CreatedAt: v.CreatedAt, DeviceSerial: v.DeviceSerial, DeviceName: v.DeviceName, DeviceType: v.DeviceType, Status: v.Status, Defence: v.Defence, DeviceVersion: v.DeviceVersion, ProjectId: v.ProjectId, Detail: v.Detail, Token: ys7.Ys72Instance.GetAccessToken(), Cover: cover, } } return } // ManualSnapshotInterfaceFunc 手动摄像头抓拍 func (s *ys7DevicesController) ManualSnapshotInterfaceFunc(ctx context.Context, req *system.ManualSnapshotInterfaceReq) (res *system.ManualSnapshotInterfaceRes, err error) { err = ManualSnapshotFunc(ctx, req.DeviceSerial) return } // PtzStartFunc 开启云台控制 func (s *ys7DevicesController) PtzStartFunc(ctx context.Context, req *system.PtzStartReq) (res *system.PtzStartRes, err error) { flag := true err = StartOrEndFunc(ctx, req.DeviceSerial, req.Direction, flag) return } // PtzEndFunc 关闭云台控制 func (s *ys7DevicesController) PtzEndFunc(ctx context.Context, req *system.PtzEndReq) (res *system.PtzEndRes, err error) { flag := false err = StartOrEndFunc(ctx, req.DeviceSerial, req.Direction, flag) return } func StartOrEndFunc(ctx context.Context, deviceSerial string, direction int, isStart bool) (err error) { err = g.Try(ctx, func(ctx context.Context) { //1、得到设备 device, err := ys7.GetDevice(deviceSerial) if err != nil { liberr.ErrIsNil(ctx, err, "获取信息失败") } //2、判断设备是否在线 if device.Online() { var start *ys7.Public if isStart { //true 为开启 start, err = device.PTZStart(direction) } else { //flase 为停止 start, err = device.PTZEnd(direction) } liberr.ErrIsNil(ctx, err) if start.Code != ys7.Ok { err = errors.New(start.Msg) liberr.ErrIsNil(ctx, err) } } else { err = errors.New("设备不在线") liberr.ErrIsNil(ctx, err) } }) return err } // ManualSnapshotFunc 摄像头手动快照 func ManualSnapshotFunc(ctx context.Context, serial string) error { var str []string err := g.Try(ctx, func(ctx context.Context) { str = append(str, serial) entity, err := SelectBySerial(ctx, str) liberr.ErrIsNil(ctx, err, "获取信息失败") for _, res := range entity { ProjectId, _ := strconv.ParseInt(res.ProjectId, 10, 64) tableID := int64(res.Id) _, err = StatrDevice(ctx, res.DeviceSerial, ProjectId, tableID, "1", res.DeviceName) liberr.ErrIsNil(ctx, err) } }) return err } // PeriodicSnapshotFunc 摄像头定时快照 func PeriodicSnapshotFunc(ctx context.Context) { err := g.Try(ctx, func(ctx context.Context) { //1、获取到摄像头列表 _map := ys7.GetDeviceMap() //2、遍历获取在线的-设备串号 var str []string for _, entity := range _map { if entity.Online() { str = append(str, entity.DeviceSerial) } } //3、定时抓拍 if len(str) > 0 { entity, err := SelectBySerial(ctx, str) liberr.ErrIsNil(ctx, err, "获取信息失败") for _, res := range entity { ProjectId, _ := strconv.ParseInt(res.ProjectId, 10, 64) tableID := int64(res.Id) _, err = StatrDevice(ctx, res.DeviceSerial, ProjectId, tableID, "2", res.DeviceName) } } }) fmt.Println("摄像头定时快照:", err) return } func SelectBySerial(ctx context.Context, serial []string) (entity []*model.Ys7DevicesInfoRes, err error) { dao.Ys7Devices.Ctx(ctx).Where("DeviceSerial in (?)", serial).Scan(&entity) return } func StatrDevice(ctx context.Context, serial string, projectId int64, table int64, typeStr string, sxtName string) (device ys7.Ys7Device, err error) { device, err = ys7.GetDevice(serial) if err != nil { liberr.ErrIsNil(ctx, err) return } if typeStr == "1" { //手动拍照 //err = TakAPictureFunc(ctx, device, projectId, table, sxtName) err = CaptureAndEnqueue(ctx, cameraQueue, device, projectId, table, sxtName) } else { go func() { goFunc(ctx, device, projectId, table, sxtName) }() } return } func goFunc(ctx context.Context, device ys7.Ys7Device, projectId int64, table int64, sxtName string) (err error) { err = g.Try(ctx, func(ctx context.Context) { //1、查询预置位 var devicePresetEntity []*model.DevicePresetInfoRes _ = dao.DevicePreset.Ctx(ctx).Where("deviceSerial", device.DeviceSerial).Scan(&devicePresetEntity) //2、将在线的摄像头预置位进行遍历,每个预置点停留20秒 for _, one := range devicePresetEntity { res, err := device.MovePreset(one.Index) if err != nil { g.Log("camera").Error(ctx, res.Msg) continue } if res.Code != "200" { g.Log("camera").Error(ctx, res.Msg) continue } //停留20秒 time.Sleep(time.Second * 20) //err = TakAPictureFunc(ctx, device, projectId, table, sxtName) // 在每个摄像头抓图回调中调用: err = CaptureAndEnqueue(ctx, cameraQueue, device, projectId, table, sxtName) if err != nil { g.Log("camera").Error(ctx, res.Msg) continue } } return }) return } //func TakAPictureFunc(ctx context.Context, device ys7.Ys7Device, projectId int64, table int64, sxtName string) (err error) { // err = g.Try(ctx, func(ctx context.Context) { // //3、预置位停留的时候进行抓图 // capture, err := device.Capture() // if err != nil { // var str = "定时快照错误:" + err.Error() // err = errors.New(str) // return // } // if capture.Code != "200" { // var str = "抓图操作失败,错误码为:" + capture.Code + ",错误描述:" + capture.Msg // err = errors.New(str) // return // } // //4、把图片存储到本地(临时地址)、把临时地址图片给到AI进行识别 // lsPath, err := DownloadTheImagToLocalViaUrl(ctx, capture.Data.PicUrl, coryCommon.Temporary+"/") // if err != nil { // g.Log("camera").Error(ctx, err) // return // } else { // rpath := coryCommon.ResourcePublicToFunc(lsPath, 1) // lsPath = coryCommon.GlobalPath + rpath // // //5、需要记录摄像头的工作(拍摄的所有图片),让用户知道摄像头在正常工作 // addReq := system.Ys7DevicesImgAddReq{ // FatherId: uint64(table), // Name: sxtName, // Path: rpath, // } // if err = service.Ys7DevicesImg().Add(ctx, &addReq); err != nil { // g.Log("camera").Error(ctx, "记录摄像头工作记录失败") // } // } // //6、抓图完毕将URL给到AI那边进行算法操作 // result, flag, err := RequestToSendFunc(ctx, lsPath, SpartaApi.YJCAMERA) // if err != nil { // return // } // if flag { // num, path, mp, err := BlockDiagramFunc(ctx, result, flag, lsPath) // if err != nil { // return // } // //5、通过算法且满足要求就进行数据存储 // AddCameraImg(ctx, projectId, num, table, path, mp, sxtName) // } // return // }) // return err //} // AddCameraImg 项目id,违规次数,表的主键ID,算法图片 func AddCameraImg(ctx context.Context, projectId int64, num int, table int64, imgPath string, mp map[string]string, sxtName string, result *SpartaApi.RecognizeRes) (err error) { err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err = g.Try(ctx, func(ctx context.Context) { mpkStr := "" mpvStr := "" for key, value := range mp { mpkStr = mpkStr + key + "," mpvStr = mpvStr + value + "、" } mpkStr = strings.TrimRight(mpkStr, ",") mpvStr = strings.TrimRight(mpvStr, "、") //5、生成数据存储到数据表中(识别记录) path := coryCommon.ResourcePublicToFunc(imgPath, 1) addReq := system.BusTourAddReq{ ProjectId: projectId, TourCategory: "2", TourType: mpkStr, Picture: path, Describe: mpvStr, Num: num, TableName: dao.Ys7Devices.Table(), TableId: table, SxtName: sxtName, } err2 := service.BusTour().Add(ctx, &addReq) if err2 == nil { //1、本地创建一个text来记录日志 // 定义文件路径 filePath := coryCommon.GetCWD() + "/coryLogs/logs/ai_log.txt" // 打开文件,如果文件不存在则创建 file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Fatal(err) } defer file.Close() // 写入日志信息 marshal, _ := json.Marshal(result) _, err = file.WriteString(fmt.Sprintf("项目ID:%d,违规次数:%d,表的主键ID:%d,算法图片:%s,识别结果:%s,----------%s\n", projectId, num, table, imgPath, mpvStr, string(marshal))) if err != nil { log.Fatal(err) } } //6、生成数据存储到违规记录里面 var bvl *model.BusViolationLevelInfoRes llike := dao.BusViolationLevel.Ctx(ctx).As("a").Safe() for _, zd := range strings.Split(mpkStr, ",") { llike = llike.WhereOr("a.tour_type like ?", "%"+zd+"%") } err := llike.LeftJoin("sys_dict_data", "c", "c.dict_type = 'risx' and c.dict_value = a.risx").Fields("a.id,a.grade,c.dict_label").Scan(&bvl) liberr.ErrIsNil(ctx, err) if bvl == nil { err = errors.New("请设置违章等级!") g.Log().Error(ctx, "请设置违章等级!") return } recordAddReq := do.BusViolationRecord{ ProjectId: projectId, LevelId: bvl.Id, Level: bvl.Grade + ":" + bvl.DictLabel, TourType: mpkStr, DataSource: "camera", SxtName: sxtName, //Picture: path, //WxOrPc: "1", } info, err := dao.BusViolationRecord.Ctx(ctx).Insert(recordAddReq) liberr.ErrIsNil(ctx, err) id, _ := info.LastInsertId() if path != "" { //给BusViolationRecord插入附件信息 pathSplit := strings.Split(path, "/") fileInfo := strings.Split(pathSplit[len(pathSplit)-1], ".") _, err = g.DB().Model("bus_violation_record_path").Ctx(ctx).Insert( g.Map{ "ticket_id": id, "type": 1, "name": fileInfo[0], "path": path, "file_type": fileInfo[1]}) liberr.ErrIsNil(ctx, err) } //7、通过违章记录拿到等级关联的岗位信息,再根据岗位拿到具体需要通知的人(需要存储通知的人),然后给他们发通知信息 err, posts := logic.SelectLevelByPostInfo(ctx, bvl.Id) liberr.ErrIsNil(ctx, err) var violationRecordCorrelationEntity []*model.ViolationRecordCorrelation var postId []int for _, post := range posts { userIDs, _ := dao.SysUserPost.Ctx(ctx).Where("post_id", post.PostId).Fields(dao.SysUserPost.Columns().UserId).Distinct().Array() for _, d := range userIDs { violationRecordCorrelationEntity = append(violationRecordCorrelationEntity, &model.ViolationRecordCorrelation{ RecordId: id, UserId: d.Int64(), PostId: int64(post.PostId), }) postId = append(postId, int(post.PostId)) } } _, err = g.DB().Model("bus_violation_record_correlation").Ctx(ctx).Insert(violationRecordCorrelationEntity) liberr.ErrIsNil(ctx, err, "存储通知的人失败") var userId uint64 = 1 err = PublicPublish(ctx, &system.NotificationsPublishReq{ NotificationText: "【您有一份重要的违章需要处理!】工单号为:" + strconv.FormatInt(id, 10), Positions: postId, ProjectId: int(projectId), }, userId) liberr.ErrIsNil(ctx, err) }) return err }) return err } // DownloadTheImagToLocalViaUrl 通过url下载图片到本地 func DownloadTheImagToLocalViaUrl(ctx context.Context, picUrl string, lj string) (imgPath string, err error) { get, err := g.Client().Get(gctx.New(), picUrl) if err != nil { return "", err } st := strings.Split(picUrl, ".") sp := strings.Split(st[len(st)-1], "?") imgPath = coryCommon.GetCWD() + "/" + coryCommon.Ynr(lj) + coryCommon.FileName("sxt_") + "." + sp[0] imgPath = filepath.ToSlash(imgPath) err = os.WriteFile(imgPath, get.ReadAll(), 0666) if err != nil { err = errors.New("存储图片失败") } return } func RequestToSendFunc(ctx context.Context, lsPath, recType string) (result *SpartaApi.RecognizeRes, flag bool, err error) { req := SpartaApi.RecognizeReq{ CapUrl: lsPath, RecType: recType, Async: "False", CallBackUrl: "", AreaHigh: "", } result, flag, err = SpartaApi.CommonAlgorithmTwoFunc(ctx, &req) if err != nil { return } else { ewflag := false //把精度不高的数据剔除 if result.HasTarget == 1 { for i := 0; i < len(result.Targets); i++ { if result.Targets[i].Score < SpartaApi.Sensitivity { result.Targets = append(result.Targets[:i], result.Targets[i+1:]...) i-- } else { ewflag = true } } } if ewflag == false { flag = false result.HasTarget = 0 } } return } // @Title BlockDiagramFunc 2024/8/7 17:12:00 // @Description 函数的详细描述 // @Auth Cory // @param 输入参数名 ---> "参数解释" // @Return error ---> "错误信息" func BlockDiagramFunc(ctx context.Context, result *SpartaApi.RecognizeRes, flag bool, lsPath string) (num int, imgPath string, mp map[string]string, err error) { imgPath, err = DownloadTheImagToLocalViaUrl(ctx, lsPath, coryCommon.Helmet) if err != nil { return } /** 框出图片中有错误的地方 */ num = 0 mp = make(map[string]string) entity := coryCommon.TestDrawRectTextEntity{ ImPath: imgPath, } var zuobiao []*coryCommon.CoordinatesListEntity for _, data := range result.Targets { if data.Score >= SpartaApi.Sensitivity { tp := data.Type mp[tp] = SpartaApi.GetDescription(tp) flag = true num = num + 1 zuobiao = append(zuobiao, &coryCommon.CoordinatesListEntity{ X: data.LeftTopPoint[0], Y: data.LeftTopPoint[1], W: data.Size[0], H: data.Size[1], }) } } entity.Coordinates = zuobiao coryCommon.TestDrawRectTextFunc(&entity) //coryCommon.Test_draw_rect_text(imgPath, data.LeftTopPoint[0], data.LeftTopPoint[1], data.Size[0], data.Size[1]) return } /** ================================================ 固定协程池(Worker Pool)并发处理,外加无限队列 ================================================ */ var cameraQueue *TaskQueue func init() { fmt.Println("初始化摄像头算法队列*8") once.Do(func() { cameraQueue = InitCameraQueueSystem(gctx.New()) }) } type TaskQueue struct { lock sync.Mutex cond *sync.Cond tasks []CameraImageTask } func NewTaskQueue() *TaskQueue { q := &TaskQueue{} q.cond = sync.NewCond(&q.lock) return q } func (q *TaskQueue) Enqueue(task CameraImageTask) { q.lock.Lock() q.tasks = append(q.tasks, task) q.cond.Signal() // 通知一个等待的 worker q.lock.Unlock() } func (q *TaskQueue) Dequeue() CameraImageTask { q.lock.Lock() for len(q.tasks) == 0 { q.cond.Wait() // 等待入队 } task := q.tasks[0] q.tasks = q.tasks[1:] q.lock.Unlock() return task } type CameraImageTask struct { ProjectId int64 Table int64 SxtName string LsPath string } // StartWorkerPool 启动协程池消费任务 func StartWorkerPool(ctx context.Context, queue *TaskQueue, workerNum int) { for i := 0; i < workerNum; i++ { go func(workerId int) { for { task := queue.Dequeue() // 阻塞直到有任务 err := ProcessCameraImageTask(ctx, task) if err != nil { g.Log("camera").Errorf(ctx, "Worker %d 执行任务失败: %v", workerId, err) } } }(i) } } // CaptureAndEnqueue 抓图后入队 func CaptureAndEnqueue(ctx context.Context, queue *TaskQueue, device ys7.Ys7Device, projectId, table int64, sxtName string) error { capture, err := device.Capture() if err != nil { return fmt.Errorf("定时快照错误:%w", err) } if capture.Code != "200" { return fmt.Errorf("抓图操作失败,错误码为:%s, 错误描述:%s", capture.Code, capture.Msg) } lsPath, err := DownloadTheImagToLocalViaUrl(ctx, capture.Data.PicUrl, coryCommon.Temporary+"/") if err != nil { return fmt.Errorf("图片下载失败:%w", err) } rpath := coryCommon.ResourcePublicToFunc(lsPath, 1) fullPath := coryCommon.GlobalPath + rpath addReq := system.Ys7DevicesImgAddReq{ FatherId: uint64(table), Name: sxtName, Path: rpath, } if err = service.Ys7DevicesImg().Add(ctx, &addReq); err != nil { g.Log("camera").Error(ctx, "记录摄像头工作记录失败:", err) } // 入队 queue.Enqueue(CameraImageTask{ ProjectId: projectId, Table: table, SxtName: sxtName, LsPath: fullPath, }) return nil } // ProcessCameraImageTask 处理任务逻辑 func ProcessCameraImageTask(ctx context.Context, task CameraImageTask) error { fmt.Println("已进入队列算法---------》", task.SxtName) result, flag, err := RequestToSendFunc(ctx, task.LsPath, SpartaApi.YJCAMERA) fmt.Println("==>", result) if err != nil { return fmt.Errorf("AI识别失败:%w", err) } if flag { num, path, mp, err := BlockDiagramFunc(ctx, result, flag, task.LsPath) if err != nil { return fmt.Errorf("图像分析失败:%w", err) } AddCameraImg(ctx, task.ProjectId, num, task.Table, path, mp, task.SxtName, result) } return nil } // 启动 func InitCameraQueueSystem(ctx context.Context) *TaskQueue { queue := NewTaskQueue() StartWorkerPool(ctx, queue, 1) return queue // 🔁 返回 queue 供调用者使用 } // // //func init() { // fmt.Println("初始化队列形式处理算法(同时10个协程来跑数据)") // ctx := gctx.New() // StartCameraImageWorkerPool(ctx, 10) // 启动10个工作协程 //} // //type CameraImageTask struct { // ProjectId int64 // Table int64 // SxtName string // LsPath string //} // //var cameraImageQueue = make(chan CameraImageTask, 100) // 队列容量视实际情况设置 // //func TakAPictureFunc(ctx context.Context, device ys7.Ys7Device, projectId, table int64, sxtName string) error { // capture, err := device.Capture() // if err != nil { // return fmt.Errorf("定时快照错误:%w", err) // } // if capture.Code != "200" { // return fmt.Errorf("抓图操作失败,错误码为:%s, 错误描述:%s", capture.Code, capture.Msg) // } // // lsPath, err := DownloadTheImagToLocalViaUrl(ctx, capture.Data.PicUrl, coryCommon.Temporary+"/") // if err != nil { // return fmt.Errorf("图片下载失败:%w", err) // } // // rpath := coryCommon.ResourcePublicToFunc(lsPath, 1) // fullPath := coryCommon.GlobalPath + rpath // // addReq := system.Ys7DevicesImgAddReq{ // FatherId: uint64(table), // Name: sxtName, // Path: rpath, // } // if err = service.Ys7DevicesImg().Add(ctx, &addReq); err != nil { // g.Log("camera").Error(ctx, "记录摄像头工作记录失败:", err) // } // // // 入队任务 // cameraImageQueue <- CameraImageTask{ // ProjectId: projectId, // Table: table, // SxtName: sxtName, // LsPath: fullPath, // } // return nil //} // //func StartCameraImageWorkerPool(ctx context.Context, workerNum int) { // for i := 0; i < workerNum; i++ { // go func(workerId int) { // for task := range cameraImageQueue { // err := ProcessCameraImageTask(ctx, task) // if err != nil { // g.Log("camera").Errorf(ctx, "Worker %d 处理任务出错: %v", workerId, err) // } // } // }(i) // } //} // //func ProcessCameraImageTask(ctx context.Context, task CameraImageTask) error { // result, flag, err := RequestToSendFunc(ctx, task.LsPath, SpartaApi.YJCAMERA) // if err != nil { // return fmt.Errorf("AI 请求失败:%w", err) // } // if flag { // num, path, mp, err := BlockDiagramFunc(ctx, result, flag, task.LsPath) // if err != nil { // return fmt.Errorf("图像处理失败:%w", err) // } // AddCameraImg(ctx, task.ProjectId, num, task.Table, path, mp, task.SxtName) // } // return nil //}