package controllers
|
|
import (
|
"errors"
|
"fmt"
|
"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, "_")
|
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 {
|
util.ResponseFormat(c, code.SaveFail, "上传成功")
|
return
|
}
|
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
|
}
|
}()
|
}
|
|
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)
|
}
|
|
// 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)
|
}
|