audio.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. package controllers
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/gin-gonic/gin"
  6. "gorm.io/gorm"
  7. "io"
  8. "os"
  9. "path"
  10. "speechAnalysis/constvar"
  11. "speechAnalysis/extend/code"
  12. "speechAnalysis/extend/util"
  13. "speechAnalysis/models"
  14. "speechAnalysis/pkg/logx"
  15. "speechAnalysis/request"
  16. "speechAnalysis/response"
  17. "speechAnalysis/service"
  18. "speechAnalysis/utils/upload"
  19. "strings"
  20. "time"
  21. )
  22. type AudioCtl struct{}
  23. // Upload
  24. // @Tags 音频
  25. // @Summary 上传音频
  26. // @Produce application/json
  27. // @Param file formData file true "音频文件"
  28. // @Success 200 {object} util.Response "成功"
  29. // @Router /api-sa/v1/audio/upload [post]
  30. func (slf AudioCtl) Upload(c *gin.Context) {
  31. _, header, err := c.Request.FormFile("file")
  32. if err != nil {
  33. util.ResponseFormat(c, code.RequestParamError, err.Error())
  34. return
  35. }
  36. filename := path.Base(header.Filename)
  37. arr := strings.Split(filename, "_")
  38. if len(arr) != 6 {
  39. util.ResponseFormat(c, code.RequestParamError, "文件名称错误")
  40. return
  41. }
  42. _, err = models.NewAudioSearch().SetName(filename).First()
  43. if err != gorm.ErrRecordNotFound {
  44. util.ResponseFormat(c, code.RequestParamError, "重复上传")
  45. return
  46. }
  47. oss := upload.NewOss()
  48. filePath, filename, uploadErr := oss.UploadFile(header)
  49. if uploadErr != nil {
  50. logx.Errorf("upload audio err: %v", err)
  51. util.ResponseFormat(c, code.RequestParamError, "上传失败")
  52. return
  53. }
  54. timeStr := arr[4] + strings.Split(arr[5], ".")[0]
  55. t, err := time.ParseInLocation("20060102150405", timeStr, time.Local)
  56. if err != nil {
  57. util.ResponseFormat(c, code.RequestParamError, "时间格式不对")
  58. return
  59. }
  60. audio := &models.Audio{
  61. Name: filename,
  62. Size: header.Size,
  63. FilePath: filePath,
  64. AudioStatus: constvar.AudioStatusUploadOk,
  65. LocomotiveNumber: arr[0],
  66. TrainNumber: arr[1],
  67. DriverNumber: arr[2],
  68. Station: arr[3],
  69. OccurrenceAt: t,
  70. IsFollowed: 0,
  71. }
  72. if err = models.NewAudioSearch().Create(audio); err != nil {
  73. util.ResponseFormat(c, code.SaveFail, "上传失败")
  74. return
  75. }
  76. go func() {
  77. var trainInfoNames = []string{arr[0], arr[1], arr[3]}
  78. var (
  79. info *models.TrainInfo
  80. err error
  81. parent models.TrainInfo
  82. )
  83. for i := 0; i < 3; i++ {
  84. name := trainInfoNames[i]
  85. class := constvar.Class(i + 1)
  86. info, err = models.NewTrainInfoSearch().SetName(name).SetClass(class).First()
  87. if err == gorm.ErrRecordNotFound {
  88. info = &models.TrainInfo{
  89. Name: name,
  90. Class: class,
  91. ParentID: parent.ID,
  92. }
  93. _ = models.NewTrainInfoSearch().Create(info)
  94. }
  95. parent = *info
  96. }
  97. }()
  98. util.ResponseFormat(c, code.Success, "添加成功")
  99. }
  100. func (slf AudioCtl) ParamsCheck(filename string) (err error) {
  101. arr := strings.Split(filename, "_")
  102. if len(arr) != 6 {
  103. return errors.New("文件格式错误")
  104. }
  105. return nil
  106. }
  107. // TrainInfoList
  108. // @Tags 音频
  109. // @Summary 获取火车信息
  110. // @Produce application/json
  111. // @Param object query request.GetTrainInfoList true "参数"
  112. // @Success 200 {object} util.ResponseList{data=[]models.TrainInfo} "成功"
  113. // @Router /api-sa/v1/audio/trainInfoList [get]
  114. func (slf AudioCtl) TrainInfoList(c *gin.Context) {
  115. var params request.GetTrainInfoList
  116. if err := c.ShouldBindQuery(&params); err != nil {
  117. util.ResponseFormat(c, code.RequestParamError, err.Error())
  118. return
  119. }
  120. if !params.PageInfo.Check() {
  121. util.ResponseFormat(c, code.RequestParamError, "分页参数错误")
  122. return
  123. }
  124. list, total, err := models.NewTrainInfoSearch().
  125. SetPage(params.Page, params.PageSize).
  126. SetClass(params.Class).
  127. SetParentId(params.ParentID).
  128. Find()
  129. if err != nil {
  130. util.ResponseFormat(c, code.RequestParamError, "查找失败")
  131. return
  132. }
  133. util.ResponseFormatList(c, code.Success, list, total)
  134. }
  135. // List
  136. // @Tags 音频
  137. // @Summary 音频分析检索
  138. // @Produce application/json
  139. // @Param object query request.GetAudioList true "参数"
  140. // @Success 200 {object} util.ResponseList{data=[]models.Audio} "成功"
  141. // @Router /api-sa/v1/audio/list [get]
  142. func (slf AudioCtl) List(c *gin.Context) {
  143. var params request.GetAudioList
  144. if err := c.ShouldBindQuery(&params); err != nil {
  145. util.ResponseFormat(c, code.RequestParamError, err.Error())
  146. return
  147. }
  148. if !params.PageInfo.Check() {
  149. util.ResponseFormat(c, code.RequestParamError, "分页参数错误")
  150. return
  151. }
  152. list, total, err := models.NewAudioSearch().
  153. SetPage(params.Page, params.PageSize).
  154. SetKeyword(params.Keyword).
  155. SetLocomotiveNumber(params.LocomotiveNumber).
  156. SetTrainNumber(params.TrainNumber).
  157. SetDriverNumber(params.DriverNumber).
  158. SetStation(params.StationNumber).
  159. SetBeginTime(params.BeginTime).
  160. SetEndTime(params.EndTime).
  161. SetIsFollowed(params.IsFollowed).
  162. SetAudioStatusList(params.StatusList).
  163. Find()
  164. if err != nil {
  165. util.ResponseFormat(c, code.RequestParamError, "查找失败")
  166. return
  167. }
  168. util.ResponseFormatList(c, code.Success, list, total)
  169. }
  170. // Process
  171. // @Tags 音频
  172. // @Summary 处理音频
  173. // @Produce application/json
  174. // @Param object body request.ProcessAudio true "参数"
  175. // @Success 200 {object} util.Response "成功"
  176. // @Router /api-sa/v1/audio/process [post]
  177. func (slf AudioCtl) Process(c *gin.Context) {
  178. var params request.ProcessAudio
  179. if err := c.ShouldBind(&params); err != nil {
  180. util.ResponseFormat(c, code.RequestParamError, err.Error())
  181. return
  182. }
  183. err := service.Process(params.ID)
  184. if err != nil {
  185. util.ResponseFormat(c, code.InternalError, err.Error())
  186. return
  187. }
  188. util.ResponseFormat(c, code.UpdateSuccess, "成功")
  189. }
  190. // AudioInfo
  191. // @Tags 音频
  192. // @Summary 音频详情,含解析结果
  193. // @Produce application/json
  194. // @Param object query request.ProcessAudio true "参数"
  195. // @Success 200 {object} util.Response{data=models.Audio} "成功"
  196. // @Router /api-sa/v1/audio/info [get]
  197. func (slf AudioCtl) AudioInfo(c *gin.Context) {
  198. var params request.ProcessAudio
  199. if err := c.ShouldBindQuery(&params); err != nil {
  200. util.ResponseFormat(c, code.RequestParamError, err.Error())
  201. return
  202. }
  203. audio, err := models.NewAudioSearch().SetID(params.ID).First()
  204. if err != nil {
  205. util.ResponseFormat(c, code.InternalError, "请求失败")
  206. return
  207. }
  208. audioText, err := models.NewAudioTextSearch().SetAudioID(audio.ID).First()
  209. if err == nil {
  210. audio.AudioText = audioText.AudioText
  211. }
  212. util.ResponseFormat(c, code.UpdateSuccess, audio)
  213. }
  214. // AudioDownload
  215. // @Tags 音频
  216. // @Summary 音频下载
  217. // @Produce application/json
  218. // @Param object query request.ProcessAudio true "参数"
  219. // @Success 200 {object} util.Response{data=models.Audio} "成功"
  220. // @Router /api-sa/v1/audio/download [get]
  221. func (slf AudioCtl) AudioDownload(c *gin.Context) {
  222. var params request.ProcessAudio
  223. if err := c.ShouldBindQuery(&params); err != nil {
  224. util.ResponseFormat(c, code.RequestParamError, err.Error())
  225. return
  226. }
  227. audio, err := models.NewAudioSearch().SetID(params.ID).First()
  228. if err != nil {
  229. util.ResponseFormat(c, code.InternalError, "查询失败")
  230. return
  231. }
  232. if audio.FilePath == "" {
  233. util.ResponseFormat(c, code.InternalError, "查询失败")
  234. return
  235. }
  236. file, err := os.Open(audio.FilePath)
  237. if err != nil {
  238. util.ResponseFormat(c, code.InternalError, "文件打开失败")
  239. return
  240. }
  241. defer file.Close()
  242. fileInfo, err := file.Stat()
  243. if err != nil {
  244. util.ResponseFormat(c, code.InternalError, "获取文件信息失败")
  245. return
  246. }
  247. c.Header("Content-Disposition", "inline; filename="+audio.Name) // 在浏览器中直接打开
  248. c.Header("Content-Length", fmt.Sprint(fileInfo.Size()))
  249. c.Header("Content-Type", "audio/mpeg") // 设置音频文件类型
  250. if _, err := io.Copy(c.Writer, file); err != nil {
  251. util.ResponseFormat(c, code.InternalError, "文件传输失败")
  252. return
  253. }
  254. }
  255. // BatchProcess
  256. // @Tags 音频
  257. // @Summary 批量处理音频
  258. // @Produce application/json
  259. // @Param object body request.BatchProcessAudio true "参数"
  260. // @Success 200 {object} util.Response "成功"
  261. // @Router /api-sa/v1/audio/batchProcess [post]
  262. func (slf AudioCtl) BatchProcess(c *gin.Context) {
  263. var params request.BatchProcessAudio
  264. if err := c.ShouldBind(&params); err != nil {
  265. util.ResponseFormat(c, code.RequestParamError, err.Error())
  266. return
  267. }
  268. var failedNumber int
  269. for _, audioID := range params.IDs {
  270. err := service.Process(audioID)
  271. if err != nil {
  272. logx.Errorf("%v,编号: %v", err.Error(), audioID)
  273. failedNumber++
  274. continue
  275. }
  276. }
  277. if failedNumber == 0 {
  278. util.ResponseFormat(c, code.UpdateSuccess, "成功")
  279. return
  280. } else if failedNumber < len(params.IDs) {
  281. util.ResponseFormat(c, code.RequestParamError, "部分处理失败")
  282. return
  283. } else {
  284. util.ResponseFormat(c, code.RequestParamError, "全部处理失败")
  285. return
  286. }
  287. }
  288. // Delete
  289. // @Tags 音频
  290. // @Summary 删除音频
  291. // @Produce application/json
  292. // @Param object body request.ProcessAudio true "参数"
  293. // @Success 200 {object} util.Response "成功"
  294. // @Router /api-sa/v1/audio/delete [delete]
  295. func (slf AudioCtl) Delete(c *gin.Context) {
  296. var params request.ProcessAudio
  297. if err := c.ShouldBind(&params); err != nil {
  298. util.ResponseFormat(c, code.RequestParamError, err.Error())
  299. return
  300. }
  301. audio, err := models.NewAudioSearch().SetID(params.ID).First()
  302. if err != nil {
  303. util.ResponseFormat(c, code.RequestParamError, "音频不存在")
  304. return
  305. }
  306. if audio.AudioStatus == constvar.AudioStatusProcessing || audio.AudioStatus == constvar.AudioStatusFinish {
  307. util.ResponseFormat(c, code.RequestParamError, "音频正在处理或者处理完成,不可删除")
  308. return
  309. }
  310. err = service.DeleteAudio(params.ID)
  311. if err != nil {
  312. util.ResponseFormat(c, code.InternalError, err.Error())
  313. return
  314. }
  315. go func() {
  316. err = os.Remove(audio.FilePath)
  317. if err != nil {
  318. logx.Warnf("remove file err:%v, file:%v", err, audio.FilePath)
  319. }
  320. }()
  321. util.ResponseFormat(c, code.DeleteSuccess, "成功")
  322. }
  323. // BatchDelete
  324. // @Tags 音频
  325. // @Summary 批量删除音频
  326. // @Produce application/json
  327. // @Param object body request.BatchProcessAudio true "参数"
  328. // @Success 200 {object} util.Response "成功"
  329. // @Router /api-sa/v1/audio/batchDelete [delete]
  330. func (slf AudioCtl) BatchDelete(c *gin.Context) {
  331. var params request.BatchProcessAudio
  332. if err := c.ShouldBind(&params); err != nil {
  333. util.ResponseFormat(c, code.RequestParamError, err.Error())
  334. return
  335. }
  336. audioList, err := models.NewAudioSearch().SetIDs(params.IDs).FindNotTotal()
  337. if err != nil {
  338. util.ResponseFormat(c, code.InternalError, "内部错误")
  339. return
  340. }
  341. for _, audio := range audioList {
  342. if audio.AudioStatus == constvar.AudioStatusProcessing || audio.AudioStatus == constvar.AudioStatusFinish {
  343. util.ResponseFormat(c, code.RequestParamError, "音频正在处理或者处理完成,不可删除")
  344. return
  345. }
  346. }
  347. err = service.BatchDeleteAudio(params.IDs)
  348. if err != nil {
  349. util.ResponseFormat(c, code.InternalError, err.Error())
  350. return
  351. }
  352. go func() {
  353. for _, audio := range audioList {
  354. err = os.Remove(audio.FilePath)
  355. if err != nil {
  356. logx.Warnf("remove file err:%v, file:%v", err, audio.FilePath)
  357. }
  358. }
  359. }()
  360. util.ResponseFormat(c, code.DeleteSuccess, "成功")
  361. }
  362. // Follow
  363. // @Tags 音频
  364. // @Summary 关注/取消关注
  365. // @Produce application/json
  366. // @Param object body request.FollowReq true "参数"
  367. // @Success 200 {object} util.Response{data=response.FollowResp} "成功"
  368. // @Router /api-sa/v1/audio/follow [post]
  369. func (slf AudioCtl) Follow(c *gin.Context) {
  370. var params request.ProcessAudio
  371. if err := c.ShouldBind(&params); err != nil {
  372. util.ResponseFormat(c, code.RequestParamError, err.Error())
  373. return
  374. }
  375. followStatus, err := service.Follow(params.ID)
  376. if err != nil {
  377. util.ResponseFormat(c, code.InternalError, err.Error())
  378. return
  379. }
  380. resp := response.FollowResp{FollowStatus: followStatus}
  381. util.ResponseFormat(c, code.UpdateSuccess, resp)
  382. }