Files
zmkgC/internal/app/system/controller/ys7devices.go
2025-07-07 20:11:59 +08:00

922 lines
28 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==========================================================================
// 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
//}