scene.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. package controllers
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "image"
  7. "image/draw"
  8. _ "image/gif"
  9. "image/jpeg"
  10. _ "image/png"
  11. "shudao-chat-go/models"
  12. "shudao-chat-go/utils"
  13. "strings"
  14. "time"
  15. "github.com/beego/beego/v2/server/web"
  16. )
  17. type SceneController struct {
  18. web.Controller
  19. }
  20. // 隐患识别获取历史记录
  21. func (c *SceneController) GetHistoryRecognitionRecord() {
  22. // 从token中获取用户信息
  23. userInfo, err := utils.GetUserInfoFromContext(c.Ctx.Input.GetData("userInfo"))
  24. if err != nil {
  25. c.Data["json"] = map[string]interface{}{
  26. "statusCode": 401,
  27. "msg": "获取用户信息失败: " + err.Error(),
  28. }
  29. c.ServeJSON()
  30. return
  31. }
  32. user_id := int64(userInfo.ID)
  33. if user_id == 0 {
  34. user_id = 1
  35. }
  36. var recognitionRecords []models.RecognitionRecord
  37. models.DB.Model(&models.RecognitionRecord{}).Where("user_id = ? AND is_deleted = ?", user_id, 0).Order("-updated_at").Find(&recognitionRecords)
  38. // 将原始OSS URL转换为代理URL,前端需要显示图片
  39. for i := range recognitionRecords {
  40. if recognitionRecords[i].OriginalImageUrl != "" {
  41. // 检查是否已经是代理URL格式
  42. if !strings.Contains(recognitionRecords[i].OriginalImageUrl, "/apiv1/oss/parse/?url=") {
  43. recognitionRecords[i].OriginalImageUrl = utils.GetProxyURL(recognitionRecords[i].OriginalImageUrl)
  44. }
  45. }
  46. if recognitionRecords[i].RecognitionImageUrl != "" {
  47. // 检查是否已经是代理URL格式
  48. if !strings.Contains(recognitionRecords[i].RecognitionImageUrl, "/apiv1/oss/parse/?url=") {
  49. recognitionRecords[i].RecognitionImageUrl = utils.GetProxyURL(recognitionRecords[i].RecognitionImageUrl)
  50. }
  51. }
  52. }
  53. //计算返回的总共的数据数量
  54. var total int64
  55. models.DB.Model(&models.RecognitionRecord{}).Where("user_id = ? AND is_deleted = ?", user_id, 0).Count(&total)
  56. c.Data["json"] = map[string]interface{}{
  57. "statusCode": 200,
  58. "msg": "success",
  59. "data": recognitionRecords, // 返回处理后的数据,包含代理URL
  60. "total": total,
  61. }
  62. c.ServeJSON()
  63. }
  64. // 获取识别记录详情
  65. func (c *SceneController) GetRecognitionRecordDetail() {
  66. recognition_record_id, _ := c.GetInt64("recognition_record_id")
  67. if recognition_record_id == 0 {
  68. c.Data["json"] = map[string]interface{}{
  69. "statusCode": 400,
  70. "msg": "识别记录ID不能为空",
  71. }
  72. c.ServeJSON()
  73. return
  74. }
  75. var record models.RecognitionRecord
  76. if err := models.DB.Where("id = ? AND is_deleted = ?", recognition_record_id, 0).First(&record).Error; err != nil {
  77. c.Data["json"] = map[string]interface{}{
  78. "statusCode": 404,
  79. "msg": "识别记录不存在",
  80. }
  81. c.ServeJSON()
  82. return
  83. }
  84. // 将Description字符串转换为数组
  85. var thirdScenes []string
  86. if record.Description != "" {
  87. thirdScenes = strings.Split(record.Description, " ")
  88. }
  89. // 通过关联表查询二级场景名称及其对应的三级隐患
  90. var displayLabels []string
  91. elementHazards := make(map[string][]string)
  92. var recognitionRecordSecondScenes []models.RecognitionRecordSecondScene
  93. models.DB.Preload("SecondScene").Where("recognition_record_id = ?", record.ID).Find(&recognitionRecordSecondScenes)
  94. for _, relation := range recognitionRecordSecondScenes {
  95. label := relation.SecondScene.SecondSceneName
  96. if label == "" {
  97. continue
  98. }
  99. displayLabels = append(displayLabels, label)
  100. var thirdSceneRecords []models.ThirdScene
  101. models.DB.Where("second_scene_id = ? and is_deleted = ?", relation.SecondSceneID, 0).Find(&thirdSceneRecords)
  102. for _, thirdSceneRecord := range thirdSceneRecords {
  103. elementHazards[label] = append(elementHazards[label], thirdSceneRecord.ThirdSceneName)
  104. }
  105. elementHazards[label] = removeDuplicates(elementHazards[label])
  106. }
  107. if len(displayLabels) == 0 && record.Labels != "" {
  108. for _, label := range strings.Split(record.Labels, ",") {
  109. normalizedLabel := strings.TrimSpace(normalizeSceneLabel(label, record.TagType))
  110. if normalizedLabel != "" {
  111. displayLabels = append(displayLabels, normalizedLabel)
  112. }
  113. }
  114. }
  115. displayLabels = removeDuplicates(displayLabels)
  116. // 将原始OSS URL转换为代理URL,前端需要显示图片
  117. originalImageURL := record.OriginalImageUrl
  118. recognitionImageURL := record.RecognitionImageUrl
  119. if originalImageURL != "" {
  120. // 检查是否已经是代理URL格式
  121. if !strings.Contains(originalImageURL, "/apiv1/oss/parse/?url=") {
  122. originalImageURL = utils.GetProxyURL(originalImageURL)
  123. }
  124. }
  125. if recognitionImageURL != "" {
  126. // 检查是否已经是代理URL格式
  127. if !strings.Contains(recognitionImageURL, "/apiv1/oss/parse/?url=") {
  128. recognitionImageURL = utils.GetProxyURL(recognitionImageURL)
  129. }
  130. }
  131. // 构建详情数据
  132. detailData := map[string]interface{}{
  133. "id": record.ID,
  134. "original_image_url": originalImageURL,
  135. "recognition_image_url": recognitionImageURL,
  136. "user_id": record.UserID,
  137. "title": record.Title,
  138. "description": record.Description,
  139. "created_at": record.CreatedAt,
  140. "updated_at": record.UpdatedAt,
  141. // 添加与隐患识别接口一致的字段
  142. "labels": record.Labels, // 二级场景名称数组
  143. "display_labels": displayLabels,
  144. "third_scenes": thirdScenes, // 三级场景名称数组
  145. "element_hazards": elementHazards,
  146. "tag_type": record.TagType,
  147. "scene_match": record.SceneMatch,
  148. "tip_accuracy": record.TipAccuracy,
  149. "effect_evaluation": record.EffectEvaluation,
  150. "user_remark": record.UserRemark,
  151. }
  152. c.Data["json"] = map[string]interface{}{
  153. "statusCode": 200,
  154. "msg": "success",
  155. "data": detailData,
  156. }
  157. c.ServeJSON()
  158. }
  159. // 用户提交点评
  160. func (c *SceneController) SubmitEvaluation() {
  161. var requestData models.RecognitionRecord
  162. if err := json.Unmarshal(c.Ctx.Input.RequestBody, &requestData); err != nil {
  163. c.Data["json"] = map[string]interface{}{
  164. "statusCode": 400,
  165. "msg": "JSON解析失败: " + err.Error(),
  166. }
  167. }
  168. scene_match := requestData.SceneMatch
  169. tip_accuracy := requestData.TipAccuracy
  170. effect_evaluation := requestData.EffectEvaluation
  171. tx := models.DB.Begin()
  172. if err := tx.Model(&models.RecognitionRecord{}).Where("id = ?", requestData.ID).Updates(map[string]interface{}{
  173. "scene_match": scene_match,
  174. "tip_accuracy": tip_accuracy,
  175. "effect_evaluation": effect_evaluation,
  176. "user_remark": requestData.UserRemark,
  177. }).Error; err != nil {
  178. tx.Rollback()
  179. c.Data["json"] = map[string]interface{}{
  180. "statusCode": 500,
  181. "msg": "点评失败: " + err.Error(),
  182. }
  183. }
  184. tx.Commit()
  185. c.Data["json"] = map[string]interface{}{
  186. "statusCode": 200,
  187. "msg": "success",
  188. }
  189. c.ServeJSON()
  190. }
  191. // 查询用户最新的一条识别记录是否点评
  192. func (c *SceneController) GetLatestRecognitionRecord() {
  193. // 从token中获取用户信息
  194. userInfo, err := utils.GetUserInfoFromContext(c.Ctx.Input.GetData("userInfo"))
  195. if err != nil {
  196. c.Data["json"] = map[string]interface{}{
  197. "statusCode": 401,
  198. "msg": "获取用户信息失败: " + err.Error(),
  199. }
  200. c.ServeJSON()
  201. return
  202. }
  203. user_id := int64(userInfo.ID)
  204. if user_id == 0 {
  205. user_id = 1
  206. }
  207. var recognitionRecord models.RecognitionRecord
  208. models.DB.Model(&models.RecognitionRecord{}).Where("user_id = ? AND is_deleted = ?", user_id, 0).Order("-created_at").First(&recognitionRecord)
  209. //如果数据为空,则无需判断上一条是否点评则构架一个假数据EffectEvaluation=1给前端
  210. if recognitionRecord.ID == 0 {
  211. recognitionRecord = models.RecognitionRecord{
  212. EffectEvaluation: 1,
  213. }
  214. }
  215. c.Data["json"] = map[string]interface{}{
  216. "statusCode": 200,
  217. "msg": "success",
  218. "data": recognitionRecord,
  219. }
  220. c.ServeJSON()
  221. }
  222. // 获取隐患识别三级场景标题查询正确和错误的示例图
  223. func (c *SceneController) GetThirdSceneExampleImage() {
  224. // 从token中获取用户信息用于生成水印
  225. userInfo, err := utils.GetUserInfoFromContext(c.Ctx.Input.GetData("userInfo"))
  226. if err != nil {
  227. c.Data["json"] = map[string]interface{}{
  228. "statusCode": 401,
  229. "msg": "获取用户信息失败: " + err.Error(),
  230. }
  231. c.ServeJSON()
  232. return
  233. }
  234. third_scene_name := c.GetString("third_scene_name")
  235. if third_scene_name == "" {
  236. c.Data["json"] = map[string]interface{}{
  237. "statusCode": 400,
  238. "msg": "三级场景名称不能为空",
  239. }
  240. c.ServeJSON()
  241. return
  242. }
  243. var thirdScene models.ThirdScene
  244. models.DB.Where("third_scene_name = ? and is_deleted = ?", third_scene_name, 0).First(&thirdScene)
  245. if thirdScene.ID == 0 {
  246. c.Data["json"] = map[string]interface{}{
  247. "statusCode": 404,
  248. "msg": "三级场景不存在",
  249. }
  250. c.ServeJSON()
  251. return
  252. }
  253. watermarkDate := time.Now().Format("2006/01/02")
  254. if thirdScene.CorrectExampleImage != "" {
  255. correctURL, err := generateWatermarkedExampleImage(thirdScene.CorrectExampleImage, userInfo.Name, userInfo.ContactNumber, watermarkDate, fmt.Sprintf("third_scene_correct_%d", thirdScene.ID))
  256. if err != nil {
  257. c.Data["json"] = map[string]interface{}{
  258. "statusCode": 500,
  259. "msg": "正确示例图加水印失败: " + err.Error(),
  260. }
  261. c.ServeJSON()
  262. return
  263. }
  264. thirdScene.CorrectExampleImage = correctURL
  265. }
  266. if thirdScene.WrongExampleImage != "" {
  267. wrongURL, err := generateWatermarkedExampleImage(thirdScene.WrongExampleImage, userInfo.Name, userInfo.ContactNumber, watermarkDate, fmt.Sprintf("third_scene_wrong_%d", thirdScene.ID))
  268. if err != nil {
  269. c.Data["json"] = map[string]interface{}{
  270. "statusCode": 500,
  271. "msg": "错误示例图加水印失败: " + err.Error(),
  272. }
  273. c.ServeJSON()
  274. return
  275. }
  276. thirdScene.WrongExampleImage = wrongURL
  277. }
  278. // 将示例图URL转换为代理URL,前端需要显示图片
  279. if thirdScene.CorrectExampleImage != "" {
  280. // 检查是否已经是代理URL格式
  281. if !strings.Contains(thirdScene.CorrectExampleImage, "/apiv1/oss/parse/?url=") {
  282. thirdScene.CorrectExampleImage = utils.GetProxyURL(thirdScene.CorrectExampleImage)
  283. }
  284. }
  285. if thirdScene.WrongExampleImage != "" {
  286. // 检查是否已经是代理URL格式
  287. if !strings.Contains(thirdScene.WrongExampleImage, "/apiv1/oss/parse/?url=") {
  288. thirdScene.WrongExampleImage = utils.GetProxyURL(thirdScene.WrongExampleImage)
  289. }
  290. }
  291. c.Data["json"] = map[string]interface{}{
  292. "statusCode": 200,
  293. "msg": "success",
  294. "data": thirdScene,
  295. }
  296. c.ServeJSON()
  297. }
  298. // generateWatermarkedExampleImage 为示例图添加水印并返回新的OSS代理URL
  299. func generateWatermarkedExampleImage(originalURL, username, account, date, keyPrefix string) (string, error) {
  300. if originalURL == "" {
  301. return "", fmt.Errorf("示例图地址为空")
  302. }
  303. imageData, err := downloadImageFromOSS(originalURL)
  304. if err != nil {
  305. return "", fmt.Errorf("下载示例图失败: %w", err)
  306. }
  307. img, _, err := image.Decode(bytes.NewReader(imageData))
  308. if err != nil {
  309. return "", fmt.Errorf("解析示例图失败: %w", err)
  310. }
  311. bounds := img.Bounds()
  312. drawableImg := image.NewRGBA(bounds)
  313. draw.Draw(drawableImg, bounds, img, image.Point{}, draw.Src)
  314. drawableImg = addLogoToImage(drawableImg)
  315. drawableImg = addTextWatermark(drawableImg, username, account, date)
  316. var buf bytes.Buffer
  317. if err := jpeg.Encode(&buf, drawableImg, &jpeg.Options{Quality: 95}); err != nil {
  318. return "", fmt.Errorf("编码水印示例图失败: %w", err)
  319. }
  320. now := time.Now().UTC()
  321. fileName := fmt.Sprintf("third_scene_examples/%d/%s_%s_%d.jpg",
  322. now.Year(),
  323. now.Format("0102"),
  324. keyPrefix,
  325. now.UnixNano())
  326. url, err := uploadImageToOSS(buf.Bytes(), fileName)
  327. if err != nil {
  328. return "", fmt.Errorf("上传水印示例图失败: %w", err)
  329. }
  330. return url, nil
  331. }