| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- package controllers
- import (
- "errors"
- "fmt"
- "github.com/360EntSecGroup-Skylar/excelize/v2"
- "github.com/gin-gonic/gin"
- "gorm.io/gorm"
- "io"
- "mime/multipart"
- "net/url"
- "os"
- "path"
- "path/filepath"
- "speechAnalysis/constvar"
- "speechAnalysis/extend/code"
- "speechAnalysis/extend/util"
- "speechAnalysis/models"
- "speechAnalysis/pkg/logx"
- "speechAnalysis/request"
- "speechAnalysis/response"
- "speechAnalysis/service"
- "speechAnalysis/utils/upload"
- "strings"
- "time"
- )
- type AudioCtl struct{}
- // Upload
- // @Tags 音频
- // @Summary 上传音频
- // @Accept multipart/form-data
- // @Produce application/json
- // @Param file formData []file false "多文件上传"
- // @Success 200 {object} util.Response "成功"
- // @Router /api-sa/v1/audio/upload [post]
- func (slf AudioCtl) Upload(c *gin.Context) {
- var headers []*multipart.FileHeader
- files, _ := c.MultipartForm()
- if len(files.File["file"]) > 1 {
- headers = files.File["file"]
- } else {
- util.ResponseFormat(c, code.RequestParamError, "文件需要一一对应")
- return
- }
- audio := &models.Audio{}
- for _, header := range headers {
- filename := path.Base(header.Filename)
- arr := strings.Split(filename, "_")
- if len(arr) != 6 {
- util.ResponseFormat(c, code.RequestParamError, "文件名称错误")
- return
- }
- _, err := models.NewAudioSearch().SetName(filename).First()
- if err != gorm.ErrRecordNotFound {
- util.ResponseFormat(c, code.RequestParamError, "重复上传")
- return
- }
- oss := upload.NewOss()
- filePath, filename, uploadErr := oss.UploadFile(header)
- if uploadErr != nil {
- logx.Errorf("upload audio err: %v", err)
- util.ResponseFormat(c, code.RequestParamError, "上传失败")
- return
- }
- if filepath.Ext(filename) == ".mp3" || filepath.Ext(filename) == ".wav" {
- timeStr := arr[4] + strings.Split(arr[5], ".")[0]
- t, err := time.ParseInLocation("20060102150405", timeStr, time.Local)
- if err != nil {
- util.ResponseFormat(c, code.RequestParamError, "时间格式不对")
- return
- }
- audio.Name = filename
- audio.Size = header.Size
- audio.FilePath = filePath
- audio.AudioStatus = constvar.AudioStatusUploadOk
- audio.LocomotiveNumber = arr[0]
- audio.TrainNumber = arr[1]
- audio.DriverNumber = arr[2]
- audio.Station = arr[3]
- audio.OccurrenceAt = t
- audio.IsFollowed = 0
- }
- if filepath.Ext(filename) == ".txt" {
- audio.TxtFilePath = filePath
- //读取filepath文件内容到bts
- bts, err := os.ReadFile(filePath)
- if err != nil {
- util.ResponseFormat(c, code.RequestParamError, "读取文件失败")
- return
- }
- //解析 交路号:123_公里标:321
- fileds := string(bts)
- //按照换行或者回车分割
- arr := strings.Split(fileds, "\n")
- if len(arr) != 2 {
- util.ResponseFormat(c, code.RequestParamError, "文件内容格式不对")
- return
- } else {
- RouteNumber := strings.Split(arr[0], ":")
- KilometerMarker := strings.Split(arr[1], ":")
- if len(RouteNumber) > 1 && len(KilometerMarker) > 1 {
- audio.RouteNumber = RouteNumber[1]
- audio.KilometerMarker = KilometerMarker[1]
- } else {
- util.ResponseFormat(c, code.RequestParamError, "文件内容格式不对")
- return
- }
- }
- }
- }
- if err := models.NewAudioSearch().Create(audio); err != nil {
- util.ResponseFormat(c, code.SaveFail, "上传失败")
- return
- } else {
- go func() {
- var trainInfoNames = []string{audio.LocomotiveNumber, audio.TrainNumber, audio.Station}
- var (
- info *models.TrainInfo
- err error
- parent models.TrainInfo
- )
- for i := 0; i < 3; i++ {
- name := trainInfoNames[i]
- class := constvar.Class(i + 1)
- info, err = models.NewTrainInfoSearch().SetName(name).SetClass(class).First()
- if err == gorm.ErrRecordNotFound {
- info = &models.TrainInfo{
- Name: name,
- Class: class,
- ParentID: parent.ID,
- }
- _ = models.NewTrainInfoSearch().Create(info)
- }
- parent = *info
- }
- }()
- util.ResponseFormat(c, code.Success, "上传成功")
- return
- }
- }
- func (slf AudioCtl) ParamsCheck(filename string) (err error) {
- arr := strings.Split(filename, "_")
- if len(arr) != 6 {
- return errors.New("文件格式错误")
- }
- return nil
- }
- // TrainInfoList
- // @Tags 音频
- // @Summary 获取火车信息
- // @Produce application/json
- // @Param object query request.GetTrainInfoList true "参数"
- // @Success 200 {object} util.ResponseList{data=[]models.TrainInfo} "成功"
- // @Router /api-sa/v1/audio/trainInfoList [get]
- func (slf AudioCtl) TrainInfoList(c *gin.Context) {
- var params request.GetTrainInfoList
- if err := c.ShouldBindQuery(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- if !params.PageInfo.Check() {
- util.ResponseFormat(c, code.RequestParamError, "分页参数错误")
- return
- }
- list, total, err := models.NewTrainInfoSearch().
- SetPage(params.Page, params.PageSize).
- SetClass(params.Class).
- SetParentId(params.ParentID).
- Find()
- if err != nil {
- util.ResponseFormat(c, code.RequestParamError, "查找失败")
- return
- }
- util.ResponseFormatList(c, code.Success, list, total)
- }
- // List
- // @Tags 音频
- // @Summary 音频分析检索
- // @Produce application/json
- // @Param object query request.GetAudioList true "参数"
- // @Success 200 {object} util.ResponseList{data=[]models.Audio} "成功"
- // @Router /api-sa/v1/audio/list [get]
- func (slf AudioCtl) List(c *gin.Context) {
- var params request.GetAudioList
- if err := c.ShouldBindQuery(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- if !params.PageInfo.Check() {
- util.ResponseFormat(c, code.RequestParamError, "分页参数错误")
- return
- }
- list, total, err := models.NewAudioSearch().
- SetPage(params.Page, params.PageSize).
- SetKeyword(params.Keyword).
- SetLocomotiveNumber(params.LocomotiveNumber).
- SetTrainNumber(params.TrainNumber).
- SetDriverNumber(params.DriverNumber).
- SetStation(params.StationNumber).
- SetBeginTime(params.BeginTime).
- SetEndTime(params.EndTime).
- SetIsFollowed(params.IsFollowed).
- SetAudioStatusList(params.StatusList).
- SetOrder("created_at desc").
- Find()
- if err != nil {
- util.ResponseFormat(c, code.RequestParamError, "查找失败")
- return
- }
- util.ResponseFormatList(c, code.Success, list, total)
- }
- // Export
- // @Tags 音频检索结果到处
- // @Summary 音频检索结果到处
- // @Produce application/json
- // @Param object query request.GetAudioList true "参数"
- // @Success 200 {object} util.ResponseList{data=[]models.Audio} "成功"
- // @Router /api-sa/v1/audio/export [get]
- func (slf AudioCtl) Export(c *gin.Context) {
- var params request.GetAudioList
- if err := c.ShouldBindQuery(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- list, _, err := models.NewAudioSearch().
- SetKeyword(params.Keyword).
- SetLocomotiveNumber(params.LocomotiveNumber).
- SetTrainNumber(params.TrainNumber).
- SetDriverNumber(params.DriverNumber).
- SetStation(params.StationNumber).
- SetBeginTime(params.BeginTime).
- SetEndTime(params.EndTime).
- SetIsFollowed(params.IsFollowed).
- SetAudioStatusList(params.StatusList).
- SetOrder("created_at desc").
- Find()
- if err != nil {
- util.ResponseFormat(c, code.RequestParamError, "查找失败")
- return
- }
- sheet := "auto_result"
- f := excelize.NewFile()
- index := f.NewSheet(sheet)
- //设置f的列名,车号,车次,司机号,车站号,日期
- f.SetCellValue(sheet, "A1", "机车号")
- f.SetCellValue(sheet, "B1", "车次")
- f.SetCellValue(sheet, "C1", "司机号")
- f.SetCellValue(sheet, "D1", "车站号")
- f.SetCellValue(sheet, "E1", "日期")
- f.SetCellValue(sheet, "F1", "分数")
- // 将数据写入工作表
- for i, auto := range list {
- row := i + 2
- cell1, _ := excelize.CoordinatesToCellName(1, row)
- f.SetCellValue(sheet, cell1, auto.LocomotiveNumber)
- cell2, _ := excelize.CoordinatesToCellName(2, row)
- f.SetCellValue(sheet, cell2, auto.TrainNumber)
- cell3, _ := excelize.CoordinatesToCellName(3, row)
- f.SetCellValue(sheet, cell3, auto.DriverNumber)
- cell4, _ := excelize.CoordinatesToCellName(4, row)
- f.SetCellValue(sheet, cell4, auto.Station)
- cell5, _ := excelize.CoordinatesToCellName(5, row)
- f.SetCellValue(sheet, cell5, auto.OccurrenceAt)
- cell6, _ := excelize.CoordinatesToCellName(6, row)
- f.SetCellValue(sheet, cell6, auto.Score)
- }
- // 设置默认打开的工作表
- f.SetActiveSheet(index)
- //// 保存文件
- //if err := f.SaveAs("result.xlsx"); err != nil {
- // fmt.Println(err)
- //}
- // Set the headers for the file download
- c.Header("Content-Description", "File Transfer")
- c.Header("Content-Disposition", "attachment; filename=result.xlsx")
- c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
- // Send the file to the client
- if err := f.Write(c.Writer); err != nil {
- util.ResponseFormat(c, code.InternalError, err.Error())
- return
- }
- util.ResponseFormat(c, code.Success, "success")
- }
- // Process
- // @Tags 音频
- // @Summary 处理音频
- // @Produce application/json
- // @Param object body request.ProcessAudio true "参数"
- // @Success 200 {object} util.Response "成功"
- // @Router /api-sa/v1/audio/process [post]
- func (slf AudioCtl) Process(c *gin.Context) {
- var params request.ProcessAudio
- if err := c.ShouldBind(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- err := service.Process(params.ID)
- if err != nil {
- util.ResponseFormat(c, code.InternalError, err.Error())
- return
- }
- util.ResponseFormat(c, code.UpdateSuccess, "成功")
- }
- // AudioInfo
- // @Tags 音频
- // @Summary 音频详情,含解析结果
- // @Produce application/json
- // @Param object query request.ProcessAudio true "参数"
- // @Success 200 {object} util.Response{data=models.Audio} "成功"
- // @Router /api-sa/v1/audio/info [get]
- func (slf AudioCtl) AudioInfo(c *gin.Context) {
- var params request.ProcessAudio
- if err := c.ShouldBindQuery(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- audio, err := models.NewAudioSearch().SetID(params.ID).First()
- if err != nil {
- util.ResponseFormat(c, code.InternalError, "请求失败")
- return
- }
- audioText, err := models.NewAudioTextSearch().SetAudioID(audio.ID).First()
- if err == nil {
- audio.AudioText = audioText.AudioText
- }
- util.ResponseFormat(c, code.UpdateSuccess, audio)
- }
- // AudioDownload
- // @Tags 音频
- // @Summary 音频下载
- // @Produce application/json
- // @Param object query request.ProcessAudio true "参数"
- // @Success 200 {object} util.Response{data=models.Audio} "成功"
- // @Router /api-sa/v1/audio/download [get]
- func (slf AudioCtl) AudioDownload(c *gin.Context) {
- var params request.ProcessAudio
- if err := c.ShouldBindQuery(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- audio, err := models.NewAudioSearch().SetID(params.ID).First()
- if err != nil {
- util.ResponseFormat(c, code.InternalError, "查询失败")
- return
- }
- filepath := ""
- if params.Filetype == 1 {
- filepath = audio.FilePath
- c.Header("Content-Type", "audio/mpeg") // 设置音频文件类型
- c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(audio.Name)) // 在浏览器中直接打开
- }
- if params.Filetype == 2 {
- filepath = audio.TxtFilePath
- //设置Content-Type为txt文件类型,避免中文乱码
- c.Header("Content-Type", "text/plain; charset=utf-8")
- c.Header("Content-Transfer-Encoding", "binary")
- //去掉audio.Name中.之后的内容,只保留文件名称
- fileName := strings.Split(audio.Name, ".")[0]
- c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(fmt.Sprintf("%s.txt", fileName))) // 在浏览器中直接打开
- }
- if filepath == "" {
- util.ResponseFormat(c, code.InternalError, "查询失败")
- return
- }
- file, err := os.Open(filepath)
- if err != nil {
- util.ResponseFormat(c, code.InternalError, "文件打开失败")
- return
- }
- defer file.Close()
- fileInfo, err := file.Stat()
- if err != nil {
- util.ResponseFormat(c, code.InternalError, "获取文件信息失败")
- return
- }
- c.Header("Content-Length", fmt.Sprint(fileInfo.Size()))
- if _, err := io.Copy(c.Writer, file); err != nil {
- util.ResponseFormat(c, code.InternalError, "文件传输失败")
- return
- }
- }
- // BatchProcess
- // @Tags 音频
- // @Summary 批量处理音频
- // @Produce application/json
- // @Param object body request.BatchProcessAudio true "参数"
- // @Success 200 {object} util.Response "成功"
- // @Router /api-sa/v1/audio/batchProcess [post]
- func (slf AudioCtl) BatchProcess(c *gin.Context) {
- var params request.BatchProcessAudio
- if err := c.ShouldBind(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- var failedNumber int
- for _, audioID := range params.IDs {
- err := service.Process(audioID)
- if err != nil {
- logx.Errorf("%v,编号: %v", err.Error(), audioID)
- failedNumber++
- continue
- }
- }
- if failedNumber == 0 {
- util.ResponseFormat(c, code.UpdateSuccess, "成功")
- return
- } else if failedNumber < len(params.IDs) {
- util.ResponseFormat(c, code.RequestParamError, "部分处理失败")
- return
- } else {
- util.ResponseFormat(c, code.RequestParamError, "全部处理失败")
- return
- }
- }
- // Delete
- // @Tags 音频
- // @Summary 删除音频
- // @Produce application/json
- // @Param object body request.ProcessAudio true "参数"
- // @Success 200 {object} util.Response "成功"
- // @Router /api-sa/v1/audio/delete [delete]
- func (slf AudioCtl) Delete(c *gin.Context) {
- var params request.ProcessAudio
- if err := c.ShouldBind(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- audio, err := models.NewAudioSearch().SetID(params.ID).First()
- if err != nil {
- util.ResponseFormat(c, code.RequestParamError, "音频不存在")
- return
- }
- if audio.AudioStatus == constvar.AudioStatusProcessing || audio.AudioStatus == constvar.AudioStatusFinish {
- util.ResponseFormat(c, code.RequestParamError, "音频正在处理或者处理完成,不可删除")
- return
- }
- err = service.DeleteAudio(params.ID)
- if err != nil {
- util.ResponseFormat(c, code.InternalError, err.Error())
- return
- }
- go func() {
- err = os.Remove(audio.FilePath)
- if err != nil {
- logx.Warnf("remove file err:%v, file:%v", err, audio.FilePath)
- }
- }()
- util.ResponseFormat(c, code.DeleteSuccess, "成功")
- }
- // BatchDelete
- // @Tags 音频
- // @Summary 批量删除音频
- // @Produce application/json
- // @Param object body request.BatchProcessAudio true "参数"
- // @Success 200 {object} util.Response "成功"
- // @Router /api-sa/v1/audio/batchDelete [delete]
- func (slf AudioCtl) BatchDelete(c *gin.Context) {
- var params request.BatchProcessAudio
- if err := c.ShouldBind(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- audioList, err := models.NewAudioSearch().SetIDs(params.IDs).FindNotTotal()
- if err != nil {
- util.ResponseFormat(c, code.InternalError, "内部错误")
- return
- }
- for _, audio := range audioList {
- if audio.AudioStatus == constvar.AudioStatusProcessing || audio.AudioStatus == constvar.AudioStatusFinish {
- util.ResponseFormat(c, code.RequestParamError, "音频正在处理或者处理完成,不可删除")
- return
- }
- }
- err = service.BatchDeleteAudio(params.IDs)
- if err != nil {
- util.ResponseFormat(c, code.InternalError, err.Error())
- return
- }
- go func() {
- for _, audio := range audioList {
- err = os.Remove(audio.FilePath)
- if err != nil {
- logx.Warnf("remove file err:%v, file:%v", err, audio.FilePath)
- }
- }
- }()
- util.ResponseFormat(c, code.DeleteSuccess, "成功")
- }
- // Follow
- // @Tags 音频
- // @Summary 关注/取消关注
- // @Produce application/json
- // @Param object body request.FollowReq true "参数"
- // @Success 200 {object} util.Response{data=response.FollowResp} "成功"
- // @Router /api-sa/v1/audio/follow [post]
- func (slf AudioCtl) Follow(c *gin.Context) {
- var params request.ProcessAudio
- if err := c.ShouldBind(¶ms); err != nil {
- util.ResponseFormat(c, code.RequestParamError, err.Error())
- return
- }
- followStatus, err := service.Follow(params.ID)
- if err != nil {
- util.ResponseFormat(c, code.InternalError, err.Error())
- return
- }
- resp := response.FollowResp{FollowStatus: followStatus}
- util.ResponseFormat(c, code.UpdateSuccess, resp)
- }
- // PreLoadPath
- // @Tags 音频自动加载路径
- // @Summary 音频自动加载路径
- // @Produce application/json
- // @Success 200 {object} util.Response{data=response.PreLoadPathResp} "成功"
- // @Router /api-sa/v1/audio/preLoadPath [get]
- func (slf AudioCtl) PreLoadPath(c *gin.Context) {
- //获取PRELOAD_PATH环境变量
- preLoadPath := os.Getenv("PRELOAD_PATH")
- if len(preLoadPath) == 0 {
- preLoadPath = "./preloads"
- }
- resp := response.PreLoadPathResp{PreLoadPath: preLoadPath}
- util.ResponseFormat(c, code.UpdateSuccess, resp)
- }
|