wechat_platform.go 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. package services
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "eta/eta_api/cache"
  6. "eta/eta_api/models"
  7. "eta/eta_api/models/rag"
  8. "eta/eta_api/services/elastic"
  9. "eta/eta_api/services/llm"
  10. "eta/eta_api/services/llm/facade"
  11. "eta/eta_api/utils"
  12. "eta/eta_api/utils/llm/eta_llm/eta_llm_http"
  13. "fmt"
  14. html2 "golang.org/x/net/html"
  15. "html"
  16. "os"
  17. "path"
  18. "regexp"
  19. "strconv"
  20. "strings"
  21. "time"
  22. )
  23. // AddWechatPlatform
  24. // @Description: 添加新的公众号
  25. // @param item
  26. func AddWechatPlatform(item *rag.WechatPlatform) {
  27. var err error
  28. defer func() {
  29. if err != nil {
  30. utils.FileLog.Error("公众号入库后查找最新记录失败,err:%v", err)
  31. }
  32. }()
  33. if item.FakeId != `` {
  34. return
  35. }
  36. if item.ArticleLink == `` {
  37. return
  38. }
  39. articleLink := item.ArticleLink
  40. articleDetail, err := llm.SearchByWechatArticle(item.ArticleLink)
  41. if err != nil {
  42. return
  43. }
  44. if articleDetail.Appuin == `` {
  45. err = fmt.Errorf("文章内未匹配到公众号唯一标识")
  46. return
  47. }
  48. wechatPlatform := new(rag.WechatPlatform)
  49. // 查找是否存在这个公众号id的
  50. wechatPlatformInfo, tmpErr := wechatPlatform.GetByFakeID(articleDetail.Appuin)
  51. if tmpErr != nil && !utils.IsErrNoRow(tmpErr) {
  52. err = tmpErr
  53. return
  54. }
  55. if tmpErr == nil {
  56. // 如果找到了,那么需要将当前的给移除掉
  57. err = item.Del()
  58. if err != nil {
  59. return
  60. }
  61. // 并将查出来的微信公众号摘出来的数据重新赋值
  62. item = wechatPlatformInfo
  63. } else if utils.IsErrNoRow(tmpErr) {
  64. // 如果没找到,那么就变更当前的信息
  65. item.FakeId = articleDetail.Appuin
  66. item.Nickname = articleDetail.Nickname
  67. //item.Alias = req.Alias
  68. item.RoundHeadImg = articleDetail.RoundHeadImg
  69. //item.ServiceType = req.ServiceType
  70. item.Signature = articleDetail.ProfileSignature
  71. //item.Verified = verified
  72. item.ModifyTime = time.Now()
  73. err = item.Update([]string{rag.WechatPlatformColumns.FakeID, rag.WechatPlatformColumns.Nickname, rag.WechatPlatformColumns.RoundHeadImg, rag.WechatPlatformColumns.Signature, rag.WechatPlatformColumns.ModifyTime})
  74. if err != nil {
  75. return
  76. }
  77. // 修改公众号头像
  78. go replaceWechatPlatformPic(item)
  79. }
  80. // 把刚搜索的文章加入到文章库中
  81. AddWechatArticle(item, articleLink, articleDetail, nil)
  82. BeachAddWechatArticle(item, 10)
  83. fmt.Println("公众号入库完成")
  84. return
  85. }
  86. // AddWechatArticle
  87. // @Description: 添加公众号文章入库
  88. // @author: Roc
  89. // @datetime 2025-03-05 13:24:14
  90. // @param item *rag.WechatPlatform
  91. // @param link string
  92. // @param articleDetail WechatArticleDataResp
  93. func AddWechatArticle(item *rag.WechatPlatform, articleLink string, articleDetail llm.WechatArticleDataResp, articleMenu *llm.ArticleMenu) {
  94. var err error
  95. defer func() {
  96. if err != nil {
  97. utils.FileLog.Error("公众号文章入库失败,文章链接:%s ,err:%v", articleLink, err)
  98. }
  99. }()
  100. obj := new(rag.WechatArticle)
  101. _, err = obj.GetByLink(articleLink)
  102. if err == nil {
  103. // 文章已经入库了,不需要重复入库
  104. return
  105. }
  106. // 如果不是 ErrNoRow 的时候,那么就是查询数据库出问题了,需要直接返回
  107. if !utils.IsErrNoRow(err) {
  108. return
  109. }
  110. // 这个时候,说明数据库中没有这个文章,那么需要文章入库
  111. err = nil
  112. var publishAt time.Time
  113. if articleDetail.CreateAt != `` {
  114. createAtInt, tmpErr := strconv.Atoi(articleDetail.CreateAt)
  115. if tmpErr == nil {
  116. publishAt = time.Unix(int64(createAtInt), 1000)
  117. }
  118. } else if articleMenu != nil {
  119. publishAt = time.Unix(int64(articleMenu.UpdateTime), 1000)
  120. }
  121. content := articleDetail.HtmlContent
  122. // 图片下载下来到本地,如果成功了,那么就用新的
  123. tmpContent, err := ReplaceHtmlImg(content)
  124. if tmpContent != `` {
  125. content = tmpContent
  126. }
  127. obj = &rag.WechatArticle{
  128. WechatArticleId: 0,
  129. WechatPlatformId: item.WechatPlatformId,
  130. FakeId: item.FakeId,
  131. Title: articleDetail.Title,
  132. Link: articleLink,
  133. CoverUrl: articleDetail.CoverUrl,
  134. Description: articleDetail.Desc,
  135. Content: html.EscapeString(content),
  136. TextContent: articleDetail.TextContent,
  137. Country: articleDetail.CountryName,
  138. Province: articleDetail.ProvinceName,
  139. City: articleDetail.CityName,
  140. //Abstract: "",
  141. //ArticleCreateTime: createAt,
  142. ModifyTime: time.Now(),
  143. CreateTime: time.Now(),
  144. }
  145. if !publishAt.IsZero() {
  146. obj.ArticleCreateTime = publishAt
  147. }
  148. if articleMenu != nil {
  149. obj.Title = articleMenu.Title
  150. //obj.Link = articleMenu.Link
  151. obj.CoverUrl = articleMenu.Cover
  152. obj.Description = articleMenu.Digest
  153. }
  154. err = obj.Create()
  155. // 修改文章封面图
  156. go replaceWechatArticleCoverPic(obj)
  157. // 文章入库成功后,需要将相关信息入摘要库
  158. go cache.AddWechatArticleLlmOpToCache(obj.WechatArticleId, ``)
  159. }
  160. // BeachAddWechatArticle
  161. // @Description: 批量添加公众号文章
  162. // @param item
  163. // @param num
  164. // @return err
  165. func BeachAddWechatArticle(item *rag.WechatPlatform, num int) {
  166. var err error
  167. defer func() {
  168. //fmt.Println("公众号文章批量入库完成")
  169. if err != nil {
  170. utils.FileLog.Error("公众号文章批量入库失败,err:%v", err)
  171. fmt.Println("公众号文章批量入库失败,err:", err)
  172. }
  173. }()
  174. if item.FakeId == `` {
  175. return
  176. }
  177. wechatArticleObj := new(rag.WechatArticle)
  178. // 获取公众号的文章列表
  179. articleListResp, err := llm.SearchByWechatArticleList(item.FakeId, num)
  180. if err != nil {
  181. return
  182. }
  183. for _, articleMenu := range articleListResp.List {
  184. // 判断文章是否已经入库,如果已经入库了,那么就过滤,不去重复查询微信了
  185. _, err = wechatArticleObj.GetByLink(articleMenu.Link)
  186. if err == nil {
  187. // 文章已经入库了,不需要重复入库
  188. continue
  189. }
  190. if !utils.IsErrNoRow(err) {
  191. return
  192. }
  193. err = nil
  194. articleDetail, tmpErr := llm.SearchByWechatArticle(articleMenu.Link)
  195. if tmpErr != nil {
  196. err = tmpErr
  197. return
  198. }
  199. // 把刚搜索的文章加入到指标库
  200. AddWechatArticle(item, articleMenu.Link, articleDetail, &articleMenu)
  201. //time.Sleep(10 * time.Second)
  202. // 随机休眠,至少大于10s
  203. sleepTimeInt := utils.GetRandInt(10, 20)
  204. if sleepTimeInt < 10 {
  205. sleepTimeInt = 10
  206. }
  207. time.Sleep(time.Duration(sleepTimeInt) * time.Second)
  208. }
  209. return
  210. }
  211. //
  212. //// GenerateArticleAbstract
  213. //// @Description: 文章摘要生成
  214. //// @author: Roc
  215. //// @datetime 2025-03-10 16:17:53
  216. //// @param item *rag.WechatArticle
  217. //func GenerateArticleAbstract(item *rag.WechatArticle, forceGenerate bool) {
  218. // var err error
  219. // defer func() {
  220. // if err != nil {
  221. // utils.FileLog.Error("文章转临时文件失败,err:%v", err)
  222. // fmt.Println("文章转临时文件失败,err:", err)
  223. // }
  224. // }()
  225. //
  226. // // 内容为空,那就不需要生成摘要
  227. // if item.TextContent == `` {
  228. // return
  229. // }
  230. //
  231. // abstractObj := rag.WechatArticleAbstract{}
  232. // tmpAbstractItem, err := abstractObj.GetByWechatArticleId(item.WechatArticleId)
  233. // // 如果找到了,同时不是强制生成,那么就直接处理到知识库中
  234. // if err == nil && !forceGenerate {
  235. // // 摘要已经生成,不需要重复生成,只需要重新加入到向量库中
  236. // WechatArticleAbstractToKnowledge(item, tmpAbstractItem, false)
  237. //
  238. // return
  239. // }
  240. // if !utils.IsErrNoRow(err) {
  241. // return
  242. // }
  243. //
  244. // //开始对话
  245. // abstract, addArticleChatRecordList, tmpErr := getAnswerByContent(item.WechatArticleId, utils.AI_ARTICLE_SOURCE_ETA_REPORT)
  246. // if tmpErr != nil {
  247. // err = fmt.Errorf("LLM对话失败,Err:" + tmpErr.Error())
  248. // return
  249. // }
  250. //
  251. // // 添加问答记录
  252. // if len(addArticleChatRecordList) > 0 {
  253. // recordObj := rag.WechatArticleChatRecord{}
  254. // err = recordObj.CreateInBatches(addArticleChatRecordList)
  255. // if err != nil {
  256. // return
  257. // }
  258. // }
  259. //
  260. // if abstract != `` {
  261. // if abstract == `sorry` || strings.Index(abstract, `根据已知信息无法回答该问题`) == 0 {
  262. // item.AbstractStatus = 2
  263. // item.ModifyTime = time.Now()
  264. // err = item.Update([]string{"AbstractStatus", "ModifyTime"})
  265. // return
  266. // }
  267. // item.AbstractStatus = 1
  268. // item.ModifyTime = time.Now()
  269. // err = item.Update([]string{"AbstractStatus", "ModifyTime"})
  270. //
  271. // abstractItem := &rag.WechatArticleAbstract{
  272. // WechatArticleAbstractId: 0,
  273. // WechatArticleId: item.WechatArticleId,
  274. // Content: abstract,
  275. // Version: 0,
  276. // VectorKey: "",
  277. // ModifyTime: time.Now(),
  278. // CreateTime: time.Now(),
  279. // }
  280. // err = abstractItem.Create()
  281. // if err != nil {
  282. // return
  283. // }
  284. //
  285. // // 数据入ES库
  286. // go AddOrEditEsWechatArticleAbstract(abstractItem.WechatArticleAbstractId)
  287. //
  288. // WechatArticleAbstractToKnowledge(item, abstractItem, false)
  289. // }
  290. //}
  291. // GenerateArticleAbstract
  292. // @Description: 文章摘要生成(默认提示词批量生成)
  293. // @author: Roc
  294. // @datetime 2025-03-10 16:17:53
  295. // @param item *rag.WechatArticle
  296. func GenerateWechatArticleAbstract(item *rag.WechatArticle, forceGenerate bool) {
  297. var err error
  298. defer func() {
  299. if err != nil {
  300. utils.FileLog.Error("文章转临时文件失败,err:%v", err)
  301. fmt.Println("文章转临时文件失败,err:", err)
  302. }
  303. }()
  304. // 内容为空,那就不需要生成摘要
  305. if item.TextContent == `` {
  306. return
  307. }
  308. questionObj := rag.Question{}
  309. questionList, err := questionObj.GetListByCondition(``, ` AND is_default = 1 `, []interface{}{}, 0, 100)
  310. if err != nil {
  311. err = fmt.Errorf("获取问题列表失败,Err:" + err.Error())
  312. return
  313. }
  314. // 没问题就不生成了
  315. if len(questionList) <= 0 {
  316. return
  317. }
  318. for _, question := range questionList {
  319. GenerateWechatArticleAbstractByQuestion(item, question, forceGenerate)
  320. }
  321. return
  322. }
  323. // GenerateArticleAbstractByQuestion
  324. // @Description: 文章摘要生成(根据提示词生成)
  325. // @author: Roc
  326. // @datetime 2025-03-10 16:17:53
  327. // @param item *rag.WechatArticle
  328. func GenerateWechatArticleAbstractByQuestion(item *rag.WechatArticle, question *rag.Question, forceGenerate bool) {
  329. var err error
  330. defer func() {
  331. if err != nil {
  332. utils.FileLog.Error("摘要生成失败,err:%v", err)
  333. fmt.Println("摘要生成失败,err:", err)
  334. }
  335. }()
  336. // 内容为空,那就不需要生成摘要
  337. if item.TextContent == `` {
  338. return
  339. }
  340. abstractObj := rag.WechatArticleAbstract{}
  341. abstractItem, err := abstractObj.GetByWechatArticleIdAndQuestionId(item.WechatArticleId, question.QuestionId)
  342. // 如果找到了,同时不是强制生成,那么就直接处理到知识库中
  343. if err == nil && !forceGenerate {
  344. // 摘要已经生成,不需要重复生成,只需要重新加入到向量库中
  345. WechatArticleAbstractToKnowledge(item, abstractItem, false)
  346. return
  347. }
  348. //你现在是一名资深的期货行业分析师,请基于以下的问题进行汇总总结,如果不能正常总结出来,那么就只需要回复我:sorry
  349. questionStr := fmt.Sprintf(`%s\n%s`, `你现在是一名资深的期货行业分析师,请基于以下的问题进行汇总总结,如果不能正常总结出来,那么就只需要回复我:sorry。以下是问题:`, question.QuestionContent)
  350. //开始对话
  351. abstract, industryTags, _, tmpErr := getAnswerByContent(item.WechatArticleId, utils.AI_ARTICLE_SOURCE_WECHAT, questionStr)
  352. if tmpErr != nil {
  353. err = fmt.Errorf("LLM对话失败,Err:" + tmpErr.Error())
  354. return
  355. }
  356. if abstract == `` {
  357. return
  358. }
  359. var tagIdJsonStr string
  360. var tagNameJsonStr string
  361. // 标签ID
  362. {
  363. tagIdList := make([]int, 0)
  364. tagNameList := make([]string, 0)
  365. tagIdMap := make(map[int]bool)
  366. if abstractItem != nil && abstractItem.Tags != `` {
  367. tmpErr = json.Unmarshal([]byte(abstractItem.Tags), &tagIdList)
  368. if tmpErr != nil {
  369. utils.FileLog.Info(fmt.Sprintf("json.Unmarshal Tags 失败,标签数据:%s,Err:%s", abstractItem.Tags, tmpErr.Error()))
  370. } else {
  371. for _, tagId := range tagIdList {
  372. tagIdMap[tagId] = true
  373. }
  374. }
  375. }
  376. if abstractItem.TagsName != `` {
  377. tagNameList = strings.Split(abstractItem.TagsName, ",")
  378. }
  379. for _, tagName := range industryTags {
  380. tagId, tmpErr := GetTagIdByName(tagName)
  381. if tmpErr != nil {
  382. utils.FileLog.Info(fmt.Sprintf("获取标签ID失败,标签名称:%s,Err:%s", tagName, tmpErr.Error()))
  383. }
  384. if _, ok := tagIdMap[tagId]; !ok {
  385. tagIdList = append(tagIdList, tagId)
  386. tagNameList = append(tagNameList, tagName)
  387. tagIdMap[tagId] = true
  388. }
  389. }
  390. //for _, tagName := range varietyTags {
  391. // tagId, tmpErr := GetTagIdByName(tagName)
  392. // if tmpErr != nil {
  393. // utils.FileLog.Info(fmt.Sprintf("获取标签ID失败,标签名称:%s,Err:%s", tagName, tmpErr.Error()))
  394. // }
  395. // if _, ok := tagIdMap[tagId]; !ok {
  396. // tagIdList = append(tagIdList, tagId)
  397. // tagIdMap[tagId] = true
  398. // }
  399. //}
  400. tagIdJsonByte, err := json.Marshal(tagIdList)
  401. if err != nil {
  402. utils.FileLog.Info(fmt.Sprintf("标签ID序列化失败,Err:%s", tmpErr.Error()))
  403. } else {
  404. tagIdJsonStr = string(tagIdJsonByte)
  405. }
  406. tagNameJsonStr = strings.Join(tagNameList, `,`)
  407. }
  408. if abstract == `sorry` || strings.Index(abstract, `根据已知信息无法回答该问题`) == 0 {
  409. item.AbstractStatus = 2
  410. item.ModifyTime = time.Now()
  411. err = item.Update([]string{"AbstractStatus", "ModifyTime"})
  412. return
  413. }
  414. item.AbstractStatus = 1
  415. item.ModifyTime = time.Now()
  416. err = item.Update([]string{"AbstractStatus", "ModifyTime"})
  417. if abstractItem == nil || abstractItem.WechatArticleAbstractId <= 0 {
  418. abstractItem = &rag.WechatArticleAbstract{
  419. WechatArticleAbstractId: 0,
  420. WechatArticleId: item.WechatArticleId,
  421. Content: abstract,
  422. Version: 1,
  423. VectorKey: "",
  424. ModifyTime: time.Now(),
  425. CreateTime: time.Now(),
  426. QuestionId: question.QuestionId,
  427. Tags: tagIdJsonStr,
  428. TagsName: tagNameJsonStr,
  429. QuestionContent: question.QuestionContent,
  430. }
  431. err = abstractItem.Create()
  432. } else {
  433. // 添加历史记录
  434. rag.AddArticleAbstractHistoryByWechatArticleAbstract(abstractItem)
  435. abstractItem.Content = abstract
  436. abstractItem.Version++
  437. abstractItem.ModifyTime = time.Now()
  438. abstractItem.Tags = tagIdJsonStr
  439. abstractItem.TagsName = tagNameJsonStr
  440. abstractItem.QuestionContent = question.QuestionContent
  441. err = abstractItem.Update([]string{"content", "version", "modify_time", "tags", "tags_name", "question_content"})
  442. }
  443. if err != nil {
  444. return
  445. }
  446. // 数据入ES库
  447. go AddOrEditEsWechatArticleAbstract(abstractItem.WechatArticleAbstractId)
  448. WechatArticleAbstractToKnowledge(item, abstractItem, false)
  449. }
  450. // DelDoc
  451. // @Description: 删除摘要向量库
  452. // @author: Roc
  453. // @datetime 2025-03-12 16:55:05
  454. // @param wechatArticleAbstractList []*rag.WechatArticleAbstract
  455. // @return err error
  456. func DelDoc(wechatArticleAbstractList []*rag.WechatArticleAbstract) (err error) {
  457. defer func() {
  458. if err != nil {
  459. utils.FileLog.Error("删除摘要向量库文件失败,err:%v", err)
  460. fmt.Println("删除摘要向量库文件失败,err:", err)
  461. }
  462. }()
  463. vectorKeyList := make([]string, 0)
  464. wechatArticleAbstractIdList := make([]int, 0)
  465. for _, v := range wechatArticleAbstractList {
  466. if v.VectorKey == `` {
  467. continue
  468. }
  469. vectorKeyList = append(vectorKeyList, v.VectorKey)
  470. wechatArticleAbstractIdList = append(wechatArticleAbstractIdList, v.WechatArticleAbstractId)
  471. }
  472. // 没有就不删除
  473. if len(vectorKeyList) <= 0 {
  474. return
  475. }
  476. _, err = llm.DelDocsToKnowledge(models.BusinessConfMap[models.KnowledgeBaseName], vectorKeyList)
  477. if err != nil {
  478. err = fmt.Errorf("删除LLM摘要向量库文件失败,Err:" + err.Error())
  479. return
  480. }
  481. //fmt.Println(resp)
  482. obj := rag.WechatArticleAbstract{}
  483. err = obj.DelVectorKey(wechatArticleAbstractIdList)
  484. return
  485. }
  486. // DelLlmDoc
  487. // @Description: 删除摘要向量库
  488. // @author: Roc
  489. // @datetime 2025-03-12 16:55:05
  490. // @param wechatArticleAbstractList []*rag.WechatArticleAbstract
  491. // @return err error
  492. func DelLlmDoc(vectorKeyList []string, wechatArticleAbstractIdList []int) (err error) {
  493. defer func() {
  494. if err != nil {
  495. utils.FileLog.Error("删除摘要向量库文件失败,err:%v", err)
  496. fmt.Println("删除摘要向量库文件失败,err:", err)
  497. }
  498. }()
  499. // 没有就不删除
  500. if len(vectorKeyList) <= 0 {
  501. return
  502. }
  503. _, err = llm.DelDocsToKnowledge(models.BusinessConfMap[models.KnowledgeBaseName], vectorKeyList)
  504. if err != nil {
  505. err = fmt.Errorf("删除LLM摘要向量库文件失败,Err:" + err.Error())
  506. return
  507. }
  508. //fmt.Println(resp)
  509. obj := rag.WechatArticleAbstract{}
  510. err = obj.DelVectorKey(wechatArticleAbstractIdList)
  511. return
  512. }
  513. func getAnswerByContent(articleId int, source int, questionStr string) (answer string, industryTags, varietyTags []string, err error) {
  514. //addArticleChatRecordList = make([]*rag.WechatArticleChatRecord, 0)
  515. result, err := facade.AIGCBaseOnPromote(facade.AIGC{
  516. Promote: questionStr,
  517. Source: source,
  518. ArticleId: articleId,
  519. LLMModel: `deepseek-r1:32b`,
  520. })
  521. if err != nil {
  522. return
  523. }
  524. // JSON字符串转字节
  525. //answerByte, err := json.Marshal(result)
  526. //if err != nil {
  527. // return
  528. //}
  529. //originalAnswer := string(answerByte)
  530. // 提取 </think> 后面的内容
  531. thinkEndIndex := strings.Index(result.Answer, "</think>")
  532. if thinkEndIndex != -1 {
  533. answer = strings.TrimSpace(result.Answer[thinkEndIndex+len("</think>"):])
  534. } else {
  535. answer = result.Answer
  536. }
  537. answer = strings.TrimSpace(answer)
  538. // 提取标签
  539. industryTags, varietyTags = extractLabels(answer)
  540. //// 待入库的数据
  541. //addArticleChatRecordList = append(addArticleChatRecordList, &rag.WechatArticleChatRecord{
  542. // WechatArticleChatRecordId: 0,
  543. // WechatArticleId: articleId,
  544. // ChatUserType: "user",
  545. // Content: questionStr,
  546. // SendTime: time.Now(),
  547. // CreatedTime: time.Now(),
  548. // UpdateTime: time.Now(),
  549. //}, &rag.WechatArticleChatRecord{
  550. // WechatArticleChatRecordId: 0,
  551. // WechatArticleId: articleId,
  552. // ChatUserType: "assistant",
  553. // Content: originalAnswer,
  554. // SendTime: time.Now(),
  555. // CreatedTime: time.Now(),
  556. // UpdateTime: time.Now(),
  557. //})
  558. return
  559. }
  560. func getAnswerByContentBak(wechatArticleId int, docId string) (answer string, addArticleChatRecordList []*rag.WechatArticleChatRecord, err error) {
  561. historyList := make([]eta_llm_http.HistoryContent, 0)
  562. addArticleChatRecordList = make([]*rag.WechatArticleChatRecord, 0)
  563. questionObj := rag.Question{}
  564. questionList, err := questionObj.GetListByCondition(``, ``, []interface{}{}, 0, 100)
  565. if err != nil {
  566. err = fmt.Errorf("获取问题列表失败,Err:" + err.Error())
  567. return
  568. }
  569. // 没问题就不生成了
  570. if len(questionList) <= 0 {
  571. return
  572. }
  573. //你现在是一名资深的期货行业分析师,请基于以下的问题进行汇总总结,如果不能正常总结出来,那么就只需要回复我:sorry
  574. questionStrList := []string{`你现在是一名资深的期货行业分析师,请基于以下的问题进行汇总总结,如果不能正常总结出来,那么就只需要回复我:sorry。以下是问题:`}
  575. for _, v := range questionList {
  576. questionStrList = append(questionStrList, v.QuestionContent)
  577. }
  578. questionStr := strings.Join(questionStrList, "\n")
  579. originalAnswer, result, err := llm.ChatByFile(docId, questionStr, historyList)
  580. fmt.Println(result)
  581. if err != nil {
  582. err = fmt.Errorf("LLM对话失败,Err:" + err.Error())
  583. return
  584. }
  585. // 提取 </think> 后面的内容
  586. thinkEndIndex := strings.Index(result.Answer, "</think>")
  587. if thinkEndIndex != -1 {
  588. answer = strings.TrimSpace(result.Answer[thinkEndIndex+len("</think>"):])
  589. } else {
  590. answer = result.Answer
  591. }
  592. answer = strings.TrimSpace(answer)
  593. // 待入库的数据
  594. addArticleChatRecordList = append(addArticleChatRecordList, &rag.WechatArticleChatRecord{
  595. WechatArticleChatRecordId: 0,
  596. WechatArticleId: wechatArticleId,
  597. ChatUserType: "user",
  598. Content: questionStr,
  599. SendTime: time.Now(),
  600. CreatedTime: time.Now(),
  601. UpdateTime: time.Now(),
  602. }, &rag.WechatArticleChatRecord{
  603. WechatArticleChatRecordId: 0,
  604. WechatArticleId: wechatArticleId,
  605. ChatUserType: "assistant",
  606. Content: originalAnswer,
  607. SendTime: time.Now(),
  608. CreatedTime: time.Now(),
  609. UpdateTime: time.Now(),
  610. })
  611. return
  612. }
  613. // ArticleToKnowledge
  614. // @Description: 原文入向量库
  615. // @author: Roc
  616. // @datetime 2025-03-10 16:13:16
  617. // @param item *rag.WechatArticle
  618. func ArticleToKnowledge(item *rag.WechatArticle) {
  619. if item.TextContent == `` {
  620. return
  621. }
  622. var err error
  623. defer func() {
  624. if err != nil {
  625. utils.FileLog.Error("上传文章原文到知识库失败,err:%v", err)
  626. fmt.Println("上传文章原文到知识库失败,err:", err)
  627. }
  628. }()
  629. // 生成临时文件
  630. //dateDir := time.Now().Format("20060102")
  631. //uploadDir := "./static/ai/article/" + dateDir
  632. uploadDir := "./static/ai/article"
  633. err = os.MkdirAll(uploadDir, utils.DIR_MOD)
  634. if err != nil {
  635. err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())
  636. return
  637. }
  638. //fileName := utils.RemoveSpecialChars(item.Title) + `.md`
  639. fileName := utils.MD5(item.Title) + `.md`
  640. tmpFilePath := uploadDir + "/" + fileName
  641. err = utils.SaveToFile(item.TextContent, tmpFilePath)
  642. if err != nil {
  643. err = fmt.Errorf("生成临时文件失败,Err:" + err.Error())
  644. return
  645. }
  646. defer func() {
  647. os.Remove(tmpFilePath)
  648. }()
  649. knowledgeArticleName := models.BusinessConfMap[models.KnowledgeArticleName]
  650. // 上传临时文件到LLM
  651. uploadFileResp, err := llm.UploadDocsToKnowledge(tmpFilePath, knowledgeArticleName)
  652. if err != nil {
  653. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + err.Error())
  654. return
  655. }
  656. if len(uploadFileResp.FailedFiles) > 0 {
  657. for _, v := range uploadFileResp.FailedFiles {
  658. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + v)
  659. }
  660. }
  661. item.VectorKey = tmpFilePath
  662. item.ModifyTime = time.Now()
  663. err = item.Update([]string{"vector_key", "modify_time"})
  664. }
  665. // WechatArticleAbstractToKnowledge
  666. // @Description: 摘要入向量库
  667. // @author: Roc
  668. // @datetime 2025-03-10 16:14:59
  669. // @param wechatArticleItem *rag.WechatArticle
  670. // @param abstractItem *rag.WechatArticleAbstract
  671. func WechatArticleAbstractToKnowledge(wechatArticleItem *rag.WechatArticle, abstractItem *rag.WechatArticleAbstract, isReUpload bool) {
  672. if abstractItem.Content == `` {
  673. return
  674. }
  675. // 已经生成了,那就不处理了
  676. if abstractItem.VectorKey != `` && !isReUpload {
  677. return
  678. }
  679. var err error
  680. defer func() {
  681. if err != nil {
  682. utils.FileLog.Error("摘要入向量库失败,err:%v", err)
  683. fmt.Println("摘要入向量库失败,err:", err)
  684. }
  685. // 数据入ES库
  686. go AddOrEditEsWechatArticleAbstract(abstractItem.WechatArticleAbstractId)
  687. }()
  688. // 生成临时文件
  689. //dateDir := time.Now().Format("20060102")
  690. //uploadDir := + "./static/ai/article/" + dateDir
  691. uploadDir := "./static/ai/abstract"
  692. err = os.MkdirAll(uploadDir, utils.DIR_MOD)
  693. if err != nil {
  694. err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())
  695. return
  696. }
  697. fileName := utils.MD5(fmt.Sprintf("%d_%d", utils.AI_ARTICLE_SOURCE_WECHAT, wechatArticleItem.WechatArticleId)) + `.md`
  698. tmpFilePath := uploadDir + "/" + fileName
  699. err = utils.SaveToFile(abstractItem.Content, tmpFilePath)
  700. if err != nil {
  701. err = fmt.Errorf("生成临时文件失败,Err:" + err.Error())
  702. return
  703. }
  704. defer func() {
  705. os.Remove(tmpFilePath)
  706. }()
  707. knowledgeArticleName := models.BusinessConfMap[models.KnowledgeBaseName]
  708. // 上传临时文件到LLM
  709. uploadFileResp, err := llm.UploadDocsToKnowledge(tmpFilePath, knowledgeArticleName)
  710. if err != nil {
  711. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + err.Error())
  712. return
  713. }
  714. if len(uploadFileResp.FailedFiles) > 0 {
  715. for _, v := range uploadFileResp.FailedFiles {
  716. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + v)
  717. }
  718. }
  719. abstractItem.VectorKey = tmpFilePath
  720. abstractItem.ModifyTime = time.Now()
  721. err = abstractItem.Update([]string{"vector_key", "modify_time"})
  722. }
  723. // replaceWechatPlatformPic
  724. // @Description: 替换公众号头像
  725. // @author: Roc
  726. // @datetime 2025-03-11 09:38:24
  727. // @param item *rag.WechatPlatform
  728. func replaceWechatPlatformPic(item *rag.WechatPlatform) {
  729. var err error
  730. defer func() {
  731. if err != nil {
  732. utils.FileLog.Error("替换公众号头像失败,err:%v", err)
  733. fmt.Println("替换公众号头像失败,err:", err)
  734. }
  735. }()
  736. if item.RoundHeadImg == `` {
  737. return
  738. }
  739. resourceUrl, err := downloadWxPicAndUploadToOss(item.RoundHeadImg, `head_img`)
  740. if err != nil {
  741. return
  742. }
  743. item.RoundHeadImg = resourceUrl
  744. err = item.Update([]string{"round_head_img"})
  745. }
  746. // replaceWechatArticleCoverPic
  747. // @Description: 替换文章封面图
  748. // @author: Roc
  749. // @datetime 2025-03-11 09:38:35
  750. // @param item *rag.WechatArticle
  751. func replaceWechatArticleCoverPic(item *rag.WechatArticle) {
  752. var err error
  753. defer func() {
  754. if err != nil {
  755. utils.FileLog.Error("替换公众号头像失败,err:%v", err)
  756. fmt.Println("替换公众号头像失败,err:", err)
  757. }
  758. // 数据入ES库
  759. AddOrEditEsWechatArticle(item.WechatArticleId)
  760. }()
  761. if item.CoverUrl == `` {
  762. return
  763. }
  764. resourceUrl, err := downloadWxPicAndUploadToOss(item.CoverUrl, `cover_url`)
  765. if err != nil {
  766. return
  767. }
  768. item.CoverUrl = resourceUrl
  769. err = item.Update([]string{"cover_url"})
  770. }
  771. // replaceWechatArticlePic
  772. // @Description: 替换文章内容图
  773. // @author: Roc
  774. // @datetime 2025-03-11 09:38:35
  775. // @param item *rag.WechatArticle
  776. func ReplaceWechatArticlePic(item *rag.WechatArticle) {
  777. var err error
  778. defer func() {
  779. if err != nil {
  780. utils.FileLog.Error("替换公众号头像失败,err:%v", err)
  781. fmt.Println("替换公众号头像失败,err:", err)
  782. }
  783. }()
  784. if item.Content == `` {
  785. return
  786. }
  787. content, err := ReplaceHtmlImg(html.UnescapeString(item.Content))
  788. if err != nil {
  789. return
  790. }
  791. item.Content = html.EscapeString(content)
  792. err = item.Update([]string{"content"})
  793. return
  794. }
  795. // downloadWxPicAndUploadToOss
  796. // @Description: 下载微信图片并上传到OSS
  797. // @author: Roc
  798. // @datetime 2025-03-11 09:28:49
  799. // @param wxPicUrl string
  800. // @return resourceUrl string
  801. // @return err error
  802. func downloadWxPicAndUploadToOss(wxPicUrl, source string) (resourceUrl string, err error) {
  803. localFilePath, err := utils.DownloadWxImage(wxPicUrl)
  804. if err != nil {
  805. return
  806. }
  807. defer func() {
  808. os.Remove(localFilePath)
  809. }()
  810. ossClient := NewOssClient()
  811. if ossClient == nil {
  812. err = fmt.Errorf(`初始化OSS服务失败`)
  813. return
  814. }
  815. ext := path.Ext(localFilePath)
  816. fileName := fmt.Sprintf(`%s%s%s`, time.Now().Format(utils.FormatShortDateTimeUnSpace), utils.GetRandStringNoSpecialChar(16), ext)
  817. //savePath := utils.UploadDir + `wx/wx_article/` + time.Now().Format("200601/20060102/") + fileName
  818. savePath := fmt.Sprintf(`%swx/%s/%s%s`, utils.UploadDir, source, time.Now().Format("200601/20060102/"), fileName)
  819. resourceUrl, err = ossClient.UploadFile(fileName, localFilePath, savePath)
  820. if err != nil {
  821. err = fmt.Errorf("文件上传失败,Err:" + err.Error())
  822. return
  823. }
  824. return
  825. }
  826. // ReplaceHtmlImg
  827. // @Description: 将html中的图片替换成自己的
  828. // @author: Roc
  829. // @datetime 2025-03-11 14:32:00
  830. // @param htmlStr string
  831. // @return newHtml string
  832. // @return err error
  833. func ReplaceHtmlImg(htmlStr string) (newHtml string, err error) {
  834. doc, err := html2.Parse(strings.NewReader(htmlStr))
  835. if err != nil {
  836. return
  837. }
  838. if err != nil {
  839. return
  840. }
  841. handleNode(doc)
  842. // 将处理后的HTML节点重新渲染为HTML字符串
  843. var buf bytes.Buffer
  844. if err = html2.Render(&buf, doc); err != nil {
  845. fmt.Println(err)
  846. return
  847. }
  848. newHtml = buf.String()
  849. return
  850. }
  851. // handleNode
  852. // @Description: html节点处理
  853. // @author: Roc
  854. // @datetime 2025-03-11 14:32:45
  855. // @param n *html2.Node
  856. func handleNode(n *html2.Node) {
  857. if n.Type == html2.ElementNode {
  858. if n.Data == "img" {
  859. for k, attr := range n.Attr {
  860. // 新增代码:如果标签是img且存在data-src属性,则将data-src的值赋给src
  861. if n.Data == "img" && attr.Key == "src" {
  862. resourceUrl, tmpErr := downloadWxPicAndUploadToOss(attr.Val, `article`)
  863. if tmpErr != nil {
  864. continue
  865. }
  866. attr.Val = resourceUrl
  867. }
  868. n.Attr[k] = attr
  869. }
  870. }
  871. }
  872. for c := n.FirstChild; c != nil; c = c.NextSibling {
  873. handleNode(c)
  874. }
  875. }
  876. // AddOrEditEsWechatPlatformId
  877. // @Description: 批量处理某个公众号下的文章到ES
  878. // @author: Roc
  879. // @datetime 2025-03-13 11:01:28
  880. // @param articleId int
  881. func AddOrEditEsWechatPlatformId(wechatPlatformId int) {
  882. if utils.EsWechatArticleName == `` {
  883. return
  884. }
  885. obj := rag.WechatArticle{}
  886. list, _ := obj.GetListByCondition(` wechat_article_id `, ` AND wechat_platform_id = ? `, []interface{}{wechatPlatformId}, 0, 1000000)
  887. for _, item := range list {
  888. AddOrEditEsWechatArticle(item.WechatArticleId)
  889. }
  890. }
  891. // AddOrEditEsWechatArticle
  892. // @Description: 新增/编辑微信文章入ES
  893. // @author: Roc
  894. // @datetime 2025-03-13 11:01:28
  895. // @param articleId int
  896. func AddOrEditEsWechatArticle(articleId int) {
  897. if utils.EsWechatArticleName == `` {
  898. return
  899. }
  900. var err error
  901. defer func() {
  902. if err != nil {
  903. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  904. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  905. }
  906. }()
  907. obj := rag.WechatArticle{}
  908. articleInfo, err := obj.GetById(articleId)
  909. if err != nil {
  910. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  911. return
  912. }
  913. platformObj := rag.WechatPlatform{}
  914. platformInfo, err := platformObj.GetById(articleInfo.WechatPlatformId)
  915. if err != nil {
  916. err = fmt.Errorf("获取公众号平台信息失败,Err:" + err.Error())
  917. return
  918. }
  919. esItem := elastic.WechatArticleAndPlatform{
  920. WechatArticleId: articleInfo.WechatArticleId,
  921. WechatPlatformId: articleInfo.WechatPlatformId,
  922. FakeId: articleInfo.FakeId,
  923. Title: articleInfo.Title,
  924. Link: articleInfo.Link,
  925. CoverUrl: articleInfo.CoverUrl,
  926. Description: articleInfo.Description,
  927. //Content: articleInfo.Content,
  928. //TextContent: articleInfo.TextContent,
  929. //AbstractStatus: articleInfo.AbstractStatus,
  930. Country: articleInfo.Country,
  931. Province: articleInfo.Province,
  932. City: articleInfo.City,
  933. ArticleCreateTime: articleInfo.ArticleCreateTime,
  934. IsDeleted: articleInfo.IsDeleted,
  935. ModifyTime: articleInfo.ModifyTime,
  936. CreateTime: articleInfo.CreateTime,
  937. Nickname: platformInfo.Nickname,
  938. Alias: platformInfo.Alias,
  939. RoundHeadImg: platformInfo.RoundHeadImg,
  940. }
  941. err = elastic.WechatArticleEsAddOrEdit(strconv.Itoa(articleInfo.WechatArticleId), esItem)
  942. }
  943. // AddOrEditEsWechatArticleAbstract
  944. // @Description: 新增/编辑微信文章摘要入ES
  945. // @author: Roc
  946. // @datetime 2025-03-13 14:13:47
  947. // @param articleAbstractId int
  948. func AddOrEditEsWechatArticleAbstract(articleAbstractId int) {
  949. if utils.EsWechatArticleAbstractName == `` {
  950. return
  951. }
  952. var err error
  953. defer func() {
  954. if err != nil {
  955. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  956. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  957. }
  958. }()
  959. obj := rag.WechatArticleAbstract{}
  960. abstractInfo, err := obj.GetById(articleAbstractId)
  961. if err != nil {
  962. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  963. return
  964. }
  965. articleObj := rag.WechatArticle{}
  966. articleInfo, err := articleObj.GetById(abstractInfo.WechatArticleId)
  967. if err != nil {
  968. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  969. return
  970. }
  971. // 标签ID
  972. tagIdList := make([]int, 0)
  973. if abstractInfo.Tags != `` {
  974. err = json.Unmarshal([]byte(abstractInfo.Tags), &tagIdList)
  975. if err != nil {
  976. err = fmt.Errorf("报告标签ID转int失败,Err:" + err.Error())
  977. utils.FileLog.Info(fmt.Sprintf("json.Unmarshal 报告标签ID转int失败,标签数据:%s,Err:%s", abstractInfo.Tags, err.Error()))
  978. }
  979. }
  980. esItem := elastic.WechatArticleAbstractItem{
  981. WechatArticleAbstractId: abstractInfo.WechatArticleAbstractId,
  982. WechatArticleId: abstractInfo.WechatArticleId,
  983. WechatPlatformId: articleInfo.WechatPlatformId,
  984. Abstract: abstractInfo.Content,
  985. QuestionId: abstractInfo.QuestionId,
  986. Version: abstractInfo.Version,
  987. VectorKey: abstractInfo.VectorKey,
  988. ModifyTime: articleInfo.ModifyTime,
  989. CreateTime: articleInfo.CreateTime,
  990. Title: articleInfo.Title,
  991. Link: articleInfo.Link,
  992. TagIdList: tagIdList,
  993. }
  994. err = elastic.WechatArticleAbstractEsAddOrEdit(strconv.Itoa(articleAbstractId), esItem)
  995. }
  996. // DelEsWechatArticleAbstract
  997. // @Description: 删除ES中的微信文章摘要
  998. // @author: Roc
  999. // @datetime 2025-03-13 14:13:47
  1000. // @param articleAbstractId int
  1001. func DelEsWechatArticleAbstract(articleAbstractId int) {
  1002. if utils.EsWechatArticleAbstractName == `` {
  1003. return
  1004. }
  1005. var err error
  1006. defer func() {
  1007. if err != nil {
  1008. utils.FileLog.Error("删除公众号微信信息到ES失败,err:%v", err)
  1009. fmt.Println("删除公众号微信信息到ES失败,err:", err)
  1010. }
  1011. }()
  1012. err = elastic.WechatArticleAbstractEsDel(strconv.Itoa(articleAbstractId))
  1013. }
  1014. // AddOrEditEsRagQuestion
  1015. // @Description: 新增/编辑知识库问题入ES
  1016. // @author: Roc
  1017. // @datetime 2025-03-28 11:25:50
  1018. // @param questionId int
  1019. func AddOrEditEsRagQuestion(questionId int) {
  1020. if utils.EsWechatArticleName == `` {
  1021. return
  1022. }
  1023. var err error
  1024. defer func() {
  1025. if err != nil {
  1026. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  1027. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  1028. }
  1029. }()
  1030. obj := rag.Question{}
  1031. questionInfo, err := obj.GetByID(questionId)
  1032. if err != nil {
  1033. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  1034. return
  1035. }
  1036. esItem := elastic.RagQuestionItem{
  1037. QuestionId: questionInfo.QuestionId,
  1038. QuestionTitle: questionInfo.QuestionTitle,
  1039. QuestionContent: questionInfo.QuestionContent,
  1040. Sort: questionInfo.Sort,
  1041. SysUserId: questionInfo.SysUserId,
  1042. SysUserRealName: questionInfo.SysUserRealName,
  1043. ModifyTime: questionInfo.ModifyTime,
  1044. CreateTime: questionInfo.CreateTime,
  1045. }
  1046. err = elastic.RagQuestionEsAddOrEdit(strconv.Itoa(questionInfo.QuestionId), esItem)
  1047. }
  1048. // DelEsRagQuestion
  1049. // @Description: 删除ES中的知识库问题
  1050. // @author: Roc
  1051. // @datetime 2025-03-28 11:26:40
  1052. // @param questionId int
  1053. func DelEsRagQuestion(questionId int) {
  1054. if utils.EsWechatArticleAbstractName == `` {
  1055. return
  1056. }
  1057. var err error
  1058. defer func() {
  1059. if err != nil {
  1060. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  1061. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  1062. }
  1063. }()
  1064. err = elastic.RagQuestionEsDel(strconv.Itoa(questionId))
  1065. }
  1066. // extractLabels
  1067. // @Description: 提取摘要中的标签
  1068. // @author: Roc
  1069. // @datetime 2025-04-18 17:16:05
  1070. // @param text string
  1071. // @return industryTags []string
  1072. // @return varietyTags []string
  1073. func extractLabels(text string) (industryTags []string, varietyTags []string) {
  1074. reIndustry := regexp.MustCompile(`行业标签((?:【[^】]*】)+)`)
  1075. industryMatch := reIndustry.FindStringSubmatch(text)
  1076. if len(industryMatch) > 1 {
  1077. industryContent := industryMatch[1]
  1078. reSplit := regexp.MustCompile(`【([^】]*)】`)
  1079. industryTags = make([]string, 0)
  1080. for _, m := range reSplit.FindAllStringSubmatch(industryContent, -1) {
  1081. if len(m) > 1 {
  1082. industryTags = append(industryTags, m[1])
  1083. }
  1084. }
  1085. }
  1086. reVariety := regexp.MustCompile(`品种标签((?:【[^】]*】)+)`)
  1087. varietyMatch := reVariety.FindStringSubmatch(text)
  1088. if len(varietyMatch) > 1 {
  1089. varietyContent := varietyMatch[1]
  1090. reSplit := regexp.MustCompile(`【([^】]*)】`)
  1091. varietyTags = make([]string, 0)
  1092. for _, m := range reSplit.FindAllStringSubmatch(varietyContent, -1) {
  1093. if len(m) > 1 {
  1094. varietyTags = append(varietyTags, m[1])
  1095. }
  1096. }
  1097. }
  1098. return
  1099. }
  1100. var aiAbstractTagMap = map[string]int{}
  1101. // GetTagIdByName
  1102. // @Description: 获取标签ID
  1103. // @author: Roc
  1104. // @datetime 2025-04-18 17:25:46
  1105. // @param tagName string
  1106. // @return tagId int
  1107. // @return err error
  1108. func GetTagIdByName(tagName string) (tagId int, err error) {
  1109. tagName = strings.TrimSpace(tagName)
  1110. tagId, ok := aiAbstractTagMap[tagName]
  1111. if ok {
  1112. return
  1113. }
  1114. obj := rag.Tag{}
  1115. item, err := obj.GetByCondition(fmt.Sprintf(` AND %s = ? `, rag.TagColumns.TagName), []interface{}{tagName})
  1116. if err != nil {
  1117. if !utils.IsErrNoRow(err) {
  1118. err = fmt.Errorf("获取标签失败,Err:" + err.Error())
  1119. return
  1120. }
  1121. item = &rag.Tag{
  1122. TagId: 0,
  1123. TagName: tagName,
  1124. Sort: 0,
  1125. ModifyTime: time.Now(),
  1126. CreateTime: time.Now(),
  1127. }
  1128. err = item.Create()
  1129. if err != nil {
  1130. err = fmt.Errorf("添加标签失败,Err:" + err.Error())
  1131. return
  1132. }
  1133. }
  1134. tagId = item.TagId
  1135. aiAbstractTagMap[tagName] = tagId
  1136. return
  1137. }