audio.go 14 KB

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