wechat_platform.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266
  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. // 标签ID
  361. {
  362. tagIdList := make([]int, 0)
  363. tagIdMap := make(map[int]bool)
  364. if abstractItem != nil && abstractItem.Tags != `` {
  365. tmpErr = json.Unmarshal([]byte(abstractItem.Tags), &tagIdList)
  366. if tmpErr != nil {
  367. utils.FileLog.Info(fmt.Sprintf("json.Unmarshal 失败,标签数据:%s,Err:%s", abstractItem.Tags, tmpErr.Error()))
  368. } else {
  369. for _, tagId := range tagIdList {
  370. tagIdMap[tagId] = true
  371. }
  372. }
  373. }
  374. for _, tagName := range industryTags {
  375. tagId, tmpErr := GetTagIdByName(tagName)
  376. if tmpErr != nil {
  377. utils.FileLog.Info(fmt.Sprintf("获取标签ID失败,标签名称:%s,Err:%s", tagName, tmpErr.Error()))
  378. }
  379. if _, ok := tagIdMap[tagId]; !ok {
  380. tagIdList = append(tagIdList, tagId)
  381. tagIdMap[tagId] = true
  382. }
  383. }
  384. //for _, tagName := range varietyTags {
  385. // tagId, tmpErr := GetTagIdByName(tagName)
  386. // if tmpErr != nil {
  387. // utils.FileLog.Info(fmt.Sprintf("获取标签ID失败,标签名称:%s,Err:%s", tagName, tmpErr.Error()))
  388. // }
  389. // if _, ok := tagIdMap[tagId]; !ok {
  390. // tagIdList = append(tagIdList, tagId)
  391. // tagIdMap[tagId] = true
  392. // }
  393. //}
  394. tagIdJsonByte, err := json.Marshal(tagIdList)
  395. if err != nil {
  396. utils.FileLog.Info(fmt.Sprintf("标签ID序列化失败,Err:%s", tmpErr.Error()))
  397. } else {
  398. tagIdJsonStr = string(tagIdJsonByte)
  399. }
  400. }
  401. if abstract == `sorry` || strings.Index(abstract, `根据已知信息无法回答该问题`) == 0 {
  402. item.AbstractStatus = 2
  403. item.ModifyTime = time.Now()
  404. err = item.Update([]string{"AbstractStatus", "ModifyTime"})
  405. return
  406. }
  407. item.AbstractStatus = 1
  408. item.ModifyTime = time.Now()
  409. err = item.Update([]string{"AbstractStatus", "ModifyTime"})
  410. if abstractItem == nil || abstractItem.WechatArticleAbstractId <= 0 {
  411. abstractItem = &rag.WechatArticleAbstract{
  412. WechatArticleAbstractId: 0,
  413. WechatArticleId: item.WechatArticleId,
  414. Content: abstract,
  415. Version: 1,
  416. VectorKey: "",
  417. ModifyTime: time.Now(),
  418. CreateTime: time.Now(),
  419. QuestionId: question.QuestionId,
  420. Tags: tagIdJsonStr,
  421. QuestionContent: question.QuestionContent,
  422. }
  423. err = abstractItem.Create()
  424. } else {
  425. // 添加历史记录
  426. rag.AddArticleAbstractHistoryByWechatArticleAbstract(abstractItem)
  427. abstractItem.Content = abstract
  428. abstractItem.Version++
  429. abstractItem.ModifyTime = time.Now()
  430. abstractItem.Tags = ""
  431. abstractItem.QuestionContent = question.QuestionContent
  432. err = abstractItem.Update([]string{"content", "version", "modify_time", "tags", "question_content"})
  433. }
  434. if err != nil {
  435. return
  436. }
  437. // 数据入ES库
  438. go AddOrEditEsWechatArticleAbstract(abstractItem.WechatArticleAbstractId)
  439. WechatArticleAbstractToKnowledge(item, abstractItem, false)
  440. }
  441. // DelDoc
  442. // @Description: 删除摘要向量库
  443. // @author: Roc
  444. // @datetime 2025-03-12 16:55:05
  445. // @param wechatArticleAbstractList []*rag.WechatArticleAbstract
  446. // @return err error
  447. func DelDoc(wechatArticleAbstractList []*rag.WechatArticleAbstract) (err error) {
  448. defer func() {
  449. if err != nil {
  450. utils.FileLog.Error("删除摘要向量库文件失败,err:%v", err)
  451. fmt.Println("删除摘要向量库文件失败,err:", err)
  452. }
  453. }()
  454. vectorKeyList := make([]string, 0)
  455. wechatArticleAbstractIdList := make([]int, 0)
  456. for _, v := range wechatArticleAbstractList {
  457. if v.VectorKey == `` {
  458. continue
  459. }
  460. vectorKeyList = append(vectorKeyList, v.VectorKey)
  461. wechatArticleAbstractIdList = append(wechatArticleAbstractIdList, v.WechatArticleAbstractId)
  462. }
  463. // 没有就不删除
  464. if len(vectorKeyList) <= 0 {
  465. return
  466. }
  467. _, err = llm.DelDocsToKnowledge(models.BusinessConfMap[models.KnowledgeBaseName], vectorKeyList)
  468. if err != nil {
  469. err = fmt.Errorf("删除LLM摘要向量库文件失败,Err:" + err.Error())
  470. return
  471. }
  472. //fmt.Println(resp)
  473. obj := rag.WechatArticleAbstract{}
  474. err = obj.DelVectorKey(wechatArticleAbstractIdList)
  475. return
  476. }
  477. // DelLlmDoc
  478. // @Description: 删除摘要向量库
  479. // @author: Roc
  480. // @datetime 2025-03-12 16:55:05
  481. // @param wechatArticleAbstractList []*rag.WechatArticleAbstract
  482. // @return err error
  483. func DelLlmDoc(vectorKeyList []string, wechatArticleAbstractIdList []int) (err error) {
  484. defer func() {
  485. if err != nil {
  486. utils.FileLog.Error("删除摘要向量库文件失败,err:%v", err)
  487. fmt.Println("删除摘要向量库文件失败,err:", err)
  488. }
  489. }()
  490. // 没有就不删除
  491. if len(vectorKeyList) <= 0 {
  492. return
  493. }
  494. _, err = llm.DelDocsToKnowledge(models.BusinessConfMap[models.KnowledgeBaseName], vectorKeyList)
  495. if err != nil {
  496. err = fmt.Errorf("删除LLM摘要向量库文件失败,Err:" + err.Error())
  497. return
  498. }
  499. //fmt.Println(resp)
  500. obj := rag.WechatArticleAbstract{}
  501. err = obj.DelVectorKey(wechatArticleAbstractIdList)
  502. return
  503. }
  504. func getAnswerByContent(articleId int, source int, questionStr string) (answer string, industryTags, varietyTags []string, err error) {
  505. //addArticleChatRecordList = make([]*rag.WechatArticleChatRecord, 0)
  506. result, err := facade.AIGCBaseOnPromote(facade.AIGC{
  507. Promote: questionStr,
  508. Source: source,
  509. ArticleId: articleId,
  510. LLMModel: `deepseek-r1:32b`,
  511. })
  512. if err != nil {
  513. return
  514. }
  515. // JSON字符串转字节
  516. //answerByte, err := json.Marshal(result)
  517. //if err != nil {
  518. // return
  519. //}
  520. //originalAnswer := string(answerByte)
  521. // 提取 </think> 后面的内容
  522. thinkEndIndex := strings.Index(result.Answer, "</think>")
  523. if thinkEndIndex != -1 {
  524. answer = strings.TrimSpace(result.Answer[thinkEndIndex+len("</think>"):])
  525. } else {
  526. answer = result.Answer
  527. }
  528. answer = strings.TrimSpace(answer)
  529. // 提取标签
  530. industryTags, varietyTags = extractLabels(answer)
  531. //// 待入库的数据
  532. //addArticleChatRecordList = append(addArticleChatRecordList, &rag.WechatArticleChatRecord{
  533. // WechatArticleChatRecordId: 0,
  534. // WechatArticleId: articleId,
  535. // ChatUserType: "user",
  536. // Content: questionStr,
  537. // SendTime: time.Now(),
  538. // CreatedTime: time.Now(),
  539. // UpdateTime: time.Now(),
  540. //}, &rag.WechatArticleChatRecord{
  541. // WechatArticleChatRecordId: 0,
  542. // WechatArticleId: articleId,
  543. // ChatUserType: "assistant",
  544. // Content: originalAnswer,
  545. // SendTime: time.Now(),
  546. // CreatedTime: time.Now(),
  547. // UpdateTime: time.Now(),
  548. //})
  549. return
  550. }
  551. func getAnswerByContentBak(wechatArticleId int, docId string) (answer string, addArticleChatRecordList []*rag.WechatArticleChatRecord, err error) {
  552. historyList := make([]eta_llm_http.HistoryContent, 0)
  553. addArticleChatRecordList = make([]*rag.WechatArticleChatRecord, 0)
  554. questionObj := rag.Question{}
  555. questionList, err := questionObj.GetListByCondition(``, ``, []interface{}{}, 0, 100)
  556. if err != nil {
  557. err = fmt.Errorf("获取问题列表失败,Err:" + err.Error())
  558. return
  559. }
  560. // 没问题就不生成了
  561. if len(questionList) <= 0 {
  562. return
  563. }
  564. //你现在是一名资深的期货行业分析师,请基于以下的问题进行汇总总结,如果不能正常总结出来,那么就只需要回复我:sorry
  565. questionStrList := []string{`你现在是一名资深的期货行业分析师,请基于以下的问题进行汇总总结,如果不能正常总结出来,那么就只需要回复我:sorry。以下是问题:`}
  566. for _, v := range questionList {
  567. questionStrList = append(questionStrList, v.QuestionContent)
  568. }
  569. questionStr := strings.Join(questionStrList, "\n")
  570. originalAnswer, result, err := llm.ChatByFile(docId, questionStr, historyList)
  571. fmt.Println(result)
  572. if err != nil {
  573. err = fmt.Errorf("LLM对话失败,Err:" + err.Error())
  574. return
  575. }
  576. // 提取 </think> 后面的内容
  577. thinkEndIndex := strings.Index(result.Answer, "</think>")
  578. if thinkEndIndex != -1 {
  579. answer = strings.TrimSpace(result.Answer[thinkEndIndex+len("</think>"):])
  580. } else {
  581. answer = result.Answer
  582. }
  583. answer = strings.TrimSpace(answer)
  584. // 待入库的数据
  585. addArticleChatRecordList = append(addArticleChatRecordList, &rag.WechatArticleChatRecord{
  586. WechatArticleChatRecordId: 0,
  587. WechatArticleId: wechatArticleId,
  588. ChatUserType: "user",
  589. Content: questionStr,
  590. SendTime: time.Now(),
  591. CreatedTime: time.Now(),
  592. UpdateTime: time.Now(),
  593. }, &rag.WechatArticleChatRecord{
  594. WechatArticleChatRecordId: 0,
  595. WechatArticleId: wechatArticleId,
  596. ChatUserType: "assistant",
  597. Content: originalAnswer,
  598. SendTime: time.Now(),
  599. CreatedTime: time.Now(),
  600. UpdateTime: time.Now(),
  601. })
  602. return
  603. }
  604. // ArticleToKnowledge
  605. // @Description: 原文入向量库
  606. // @author: Roc
  607. // @datetime 2025-03-10 16:13:16
  608. // @param item *rag.WechatArticle
  609. func ArticleToKnowledge(item *rag.WechatArticle) {
  610. if item.TextContent == `` {
  611. return
  612. }
  613. var err error
  614. defer func() {
  615. if err != nil {
  616. utils.FileLog.Error("上传文章原文到知识库失败,err:%v", err)
  617. fmt.Println("上传文章原文到知识库失败,err:", err)
  618. }
  619. }()
  620. // 生成临时文件
  621. //dateDir := time.Now().Format("20060102")
  622. //uploadDir := "./static/ai/article/" + dateDir
  623. uploadDir := "./static/ai/article"
  624. err = os.MkdirAll(uploadDir, utils.DIR_MOD)
  625. if err != nil {
  626. err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())
  627. return
  628. }
  629. //fileName := utils.RemoveSpecialChars(item.Title) + `.md`
  630. fileName := utils.MD5(item.Title) + `.md`
  631. tmpFilePath := uploadDir + "/" + fileName
  632. err = utils.SaveToFile(item.TextContent, tmpFilePath)
  633. if err != nil {
  634. err = fmt.Errorf("生成临时文件失败,Err:" + err.Error())
  635. return
  636. }
  637. defer func() {
  638. os.Remove(tmpFilePath)
  639. }()
  640. knowledgeArticleName := models.BusinessConfMap[models.KnowledgeArticleName]
  641. // 上传临时文件到LLM
  642. uploadFileResp, err := llm.UploadDocsToKnowledge(tmpFilePath, knowledgeArticleName)
  643. if err != nil {
  644. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + err.Error())
  645. return
  646. }
  647. if len(uploadFileResp.FailedFiles) > 0 {
  648. for _, v := range uploadFileResp.FailedFiles {
  649. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + v)
  650. }
  651. }
  652. item.VectorKey = tmpFilePath
  653. item.ModifyTime = time.Now()
  654. err = item.Update([]string{"vector_key", "modify_time"})
  655. }
  656. // WechatArticleAbstractToKnowledge
  657. // @Description: 摘要入向量库
  658. // @author: Roc
  659. // @datetime 2025-03-10 16:14:59
  660. // @param wechatArticleItem *rag.WechatArticle
  661. // @param abstractItem *rag.WechatArticleAbstract
  662. func WechatArticleAbstractToKnowledge(wechatArticleItem *rag.WechatArticle, abstractItem *rag.WechatArticleAbstract, isReUpload bool) {
  663. if abstractItem.Content == `` {
  664. return
  665. }
  666. // 已经生成了,那就不处理了
  667. if abstractItem.VectorKey != `` && !isReUpload {
  668. return
  669. }
  670. var err error
  671. defer func() {
  672. if err != nil {
  673. utils.FileLog.Error("摘要入向量库失败,err:%v", err)
  674. fmt.Println("摘要入向量库失败,err:", err)
  675. }
  676. // 数据入ES库
  677. go AddOrEditEsWechatArticleAbstract(abstractItem.WechatArticleAbstractId)
  678. }()
  679. // 生成临时文件
  680. //dateDir := time.Now().Format("20060102")
  681. //uploadDir := + "./static/ai/article/" + dateDir
  682. uploadDir := "./static/ai/abstract"
  683. err = os.MkdirAll(uploadDir, utils.DIR_MOD)
  684. if err != nil {
  685. err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())
  686. return
  687. }
  688. fileName := utils.MD5(fmt.Sprintf("%d_%d", utils.AI_ARTICLE_SOURCE_WECHAT, wechatArticleItem.WechatArticleId)) + `.md`
  689. tmpFilePath := uploadDir + "/" + fileName
  690. err = utils.SaveToFile(abstractItem.Content, tmpFilePath)
  691. if err != nil {
  692. err = fmt.Errorf("生成临时文件失败,Err:" + err.Error())
  693. return
  694. }
  695. defer func() {
  696. os.Remove(tmpFilePath)
  697. }()
  698. knowledgeArticleName := models.BusinessConfMap[models.KnowledgeBaseName]
  699. // 上传临时文件到LLM
  700. uploadFileResp, err := llm.UploadDocsToKnowledge(tmpFilePath, knowledgeArticleName)
  701. if err != nil {
  702. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + err.Error())
  703. return
  704. }
  705. if len(uploadFileResp.FailedFiles) > 0 {
  706. for _, v := range uploadFileResp.FailedFiles {
  707. err = fmt.Errorf("上传文章原文到知识库失败,Err:" + v)
  708. }
  709. }
  710. abstractItem.VectorKey = tmpFilePath
  711. abstractItem.ModifyTime = time.Now()
  712. err = abstractItem.Update([]string{"vector_key", "modify_time"})
  713. }
  714. // replaceWechatPlatformPic
  715. // @Description: 替换公众号头像
  716. // @author: Roc
  717. // @datetime 2025-03-11 09:38:24
  718. // @param item *rag.WechatPlatform
  719. func replaceWechatPlatformPic(item *rag.WechatPlatform) {
  720. var err error
  721. defer func() {
  722. if err != nil {
  723. utils.FileLog.Error("替换公众号头像失败,err:%v", err)
  724. fmt.Println("替换公众号头像失败,err:", err)
  725. }
  726. }()
  727. if item.RoundHeadImg == `` {
  728. return
  729. }
  730. resourceUrl, err := downloadWxPicAndUploadToOss(item.RoundHeadImg, `head_img`)
  731. if err != nil {
  732. return
  733. }
  734. item.RoundHeadImg = resourceUrl
  735. err = item.Update([]string{"round_head_img"})
  736. }
  737. // replaceWechatArticleCoverPic
  738. // @Description: 替换文章封面图
  739. // @author: Roc
  740. // @datetime 2025-03-11 09:38:35
  741. // @param item *rag.WechatArticle
  742. func replaceWechatArticleCoverPic(item *rag.WechatArticle) {
  743. var err error
  744. defer func() {
  745. if err != nil {
  746. utils.FileLog.Error("替换公众号头像失败,err:%v", err)
  747. fmt.Println("替换公众号头像失败,err:", err)
  748. }
  749. // 数据入ES库
  750. AddOrEditEsWechatArticle(item.WechatArticleId)
  751. }()
  752. if item.CoverUrl == `` {
  753. return
  754. }
  755. resourceUrl, err := downloadWxPicAndUploadToOss(item.CoverUrl, `cover_url`)
  756. if err != nil {
  757. return
  758. }
  759. item.CoverUrl = resourceUrl
  760. err = item.Update([]string{"cover_url"})
  761. }
  762. // replaceWechatArticlePic
  763. // @Description: 替换文章内容图
  764. // @author: Roc
  765. // @datetime 2025-03-11 09:38:35
  766. // @param item *rag.WechatArticle
  767. func ReplaceWechatArticlePic(item *rag.WechatArticle) {
  768. var err error
  769. defer func() {
  770. if err != nil {
  771. utils.FileLog.Error("替换公众号头像失败,err:%v", err)
  772. fmt.Println("替换公众号头像失败,err:", err)
  773. }
  774. }()
  775. if item.Content == `` {
  776. return
  777. }
  778. content, err := ReplaceHtmlImg(html.UnescapeString(item.Content))
  779. if err != nil {
  780. return
  781. }
  782. item.Content = html.EscapeString(content)
  783. err = item.Update([]string{"content"})
  784. return
  785. }
  786. // downloadWxPicAndUploadToOss
  787. // @Description: 下载微信图片并上传到OSS
  788. // @author: Roc
  789. // @datetime 2025-03-11 09:28:49
  790. // @param wxPicUrl string
  791. // @return resourceUrl string
  792. // @return err error
  793. func downloadWxPicAndUploadToOss(wxPicUrl, source string) (resourceUrl string, err error) {
  794. localFilePath, err := utils.DownloadWxImage(wxPicUrl)
  795. if err != nil {
  796. return
  797. }
  798. defer func() {
  799. os.Remove(localFilePath)
  800. }()
  801. ossClient := NewOssClient()
  802. if ossClient == nil {
  803. err = fmt.Errorf(`初始化OSS服务失败`)
  804. return
  805. }
  806. ext := path.Ext(localFilePath)
  807. fileName := fmt.Sprintf(`%s%s%s`, time.Now().Format(utils.FormatShortDateTimeUnSpace), utils.GetRandStringNoSpecialChar(16), ext)
  808. //savePath := utils.UploadDir + `wx/wx_article/` + time.Now().Format("200601/20060102/") + fileName
  809. savePath := fmt.Sprintf(`%swx/%s/%s%s`, utils.UploadDir, source, time.Now().Format("200601/20060102/"), fileName)
  810. resourceUrl, err = ossClient.UploadFile(fileName, localFilePath, savePath)
  811. if err != nil {
  812. err = fmt.Errorf("文件上传失败,Err:" + err.Error())
  813. return
  814. }
  815. return
  816. }
  817. // ReplaceHtmlImg
  818. // @Description: 将html中的图片替换成自己的
  819. // @author: Roc
  820. // @datetime 2025-03-11 14:32:00
  821. // @param htmlStr string
  822. // @return newHtml string
  823. // @return err error
  824. func ReplaceHtmlImg(htmlStr string) (newHtml string, err error) {
  825. doc, err := html2.Parse(strings.NewReader(htmlStr))
  826. if err != nil {
  827. return
  828. }
  829. if err != nil {
  830. return
  831. }
  832. handleNode(doc)
  833. // 将处理后的HTML节点重新渲染为HTML字符串
  834. var buf bytes.Buffer
  835. if err = html2.Render(&buf, doc); err != nil {
  836. fmt.Println(err)
  837. return
  838. }
  839. newHtml = buf.String()
  840. return
  841. }
  842. // handleNode
  843. // @Description: html节点处理
  844. // @author: Roc
  845. // @datetime 2025-03-11 14:32:45
  846. // @param n *html2.Node
  847. func handleNode(n *html2.Node) {
  848. if n.Type == html2.ElementNode {
  849. if n.Data == "img" {
  850. for k, attr := range n.Attr {
  851. // 新增代码:如果标签是img且存在data-src属性,则将data-src的值赋给src
  852. if n.Data == "img" && attr.Key == "src" {
  853. resourceUrl, tmpErr := downloadWxPicAndUploadToOss(attr.Val, `article`)
  854. if tmpErr != nil {
  855. continue
  856. }
  857. attr.Val = resourceUrl
  858. }
  859. n.Attr[k] = attr
  860. }
  861. }
  862. }
  863. for c := n.FirstChild; c != nil; c = c.NextSibling {
  864. handleNode(c)
  865. }
  866. }
  867. // AddOrEditEsWechatPlatformId
  868. // @Description: 批量处理某个公众号下的文章到ES
  869. // @author: Roc
  870. // @datetime 2025-03-13 11:01:28
  871. // @param articleId int
  872. func AddOrEditEsWechatPlatformId(wechatPlatformId int) {
  873. if utils.EsWechatArticleName == `` {
  874. return
  875. }
  876. obj := rag.WechatArticle{}
  877. list, _ := obj.GetListByCondition(` wechat_article_id `, ` AND wechat_platform_id = ? `, []interface{}{wechatPlatformId}, 0, 1000000)
  878. for _, item := range list {
  879. AddOrEditEsWechatArticle(item.WechatArticleId)
  880. }
  881. }
  882. // AddOrEditEsWechatArticle
  883. // @Description: 新增/编辑微信文章入ES
  884. // @author: Roc
  885. // @datetime 2025-03-13 11:01:28
  886. // @param articleId int
  887. func AddOrEditEsWechatArticle(articleId int) {
  888. if utils.EsWechatArticleName == `` {
  889. return
  890. }
  891. var err error
  892. defer func() {
  893. if err != nil {
  894. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  895. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  896. }
  897. }()
  898. obj := rag.WechatArticle{}
  899. articleInfo, err := obj.GetById(articleId)
  900. if err != nil {
  901. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  902. return
  903. }
  904. platformObj := rag.WechatPlatform{}
  905. platformInfo, err := platformObj.GetById(articleInfo.WechatPlatformId)
  906. if err != nil {
  907. err = fmt.Errorf("获取公众号平台信息失败,Err:" + err.Error())
  908. return
  909. }
  910. esItem := elastic.WechatArticleAndPlatform{
  911. WechatArticleId: articleInfo.WechatArticleId,
  912. WechatPlatformId: articleInfo.WechatPlatformId,
  913. FakeId: articleInfo.FakeId,
  914. Title: articleInfo.Title,
  915. Link: articleInfo.Link,
  916. CoverUrl: articleInfo.CoverUrl,
  917. Description: articleInfo.Description,
  918. //Content: articleInfo.Content,
  919. //TextContent: articleInfo.TextContent,
  920. //AbstractStatus: articleInfo.AbstractStatus,
  921. Country: articleInfo.Country,
  922. Province: articleInfo.Province,
  923. City: articleInfo.City,
  924. ArticleCreateTime: articleInfo.ArticleCreateTime,
  925. IsDeleted: articleInfo.IsDeleted,
  926. ModifyTime: articleInfo.ModifyTime,
  927. CreateTime: articleInfo.CreateTime,
  928. Nickname: platformInfo.Nickname,
  929. Alias: platformInfo.Alias,
  930. RoundHeadImg: platformInfo.RoundHeadImg,
  931. }
  932. err = elastic.WechatArticleEsAddOrEdit(strconv.Itoa(articleInfo.WechatArticleId), esItem)
  933. }
  934. // AddOrEditEsWechatArticleAbstract
  935. // @Description: 新增/编辑微信文章摘要入ES
  936. // @author: Roc
  937. // @datetime 2025-03-13 14:13:47
  938. // @param articleAbstractId int
  939. func AddOrEditEsWechatArticleAbstract(articleAbstractId int) {
  940. if utils.EsWechatArticleAbstractName == `` {
  941. return
  942. }
  943. var err error
  944. defer func() {
  945. if err != nil {
  946. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  947. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  948. }
  949. }()
  950. obj := rag.WechatArticleAbstract{}
  951. abstractInfo, err := obj.GetById(articleAbstractId)
  952. if err != nil {
  953. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  954. return
  955. }
  956. articleObj := rag.WechatArticle{}
  957. articleInfo, err := articleObj.GetById(abstractInfo.WechatArticleId)
  958. if err != nil {
  959. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  960. return
  961. }
  962. // 标签ID
  963. tagIdList := make([]int, 0)
  964. if abstractInfo.Tags != `` {
  965. err = json.Unmarshal([]byte(abstractInfo.Tags), &tagIdList)
  966. if err != nil {
  967. err = fmt.Errorf("报告标签ID转int失败,Err:" + err.Error())
  968. utils.FileLog.Info(fmt.Sprintf("json.Unmarshal 报告标签ID转int失败,标签数据:%s,Err:%s", abstractInfo.Tags, err.Error()))
  969. }
  970. }
  971. esItem := elastic.WechatArticleAbstractItem{
  972. WechatArticleAbstractId: abstractInfo.WechatArticleAbstractId,
  973. WechatArticleId: abstractInfo.WechatArticleId,
  974. WechatPlatformId: articleInfo.WechatPlatformId,
  975. Abstract: abstractInfo.Content,
  976. QuestionId: abstractInfo.QuestionId,
  977. Version: abstractInfo.Version,
  978. VectorKey: abstractInfo.VectorKey,
  979. ModifyTime: articleInfo.ModifyTime,
  980. CreateTime: articleInfo.CreateTime,
  981. Title: articleInfo.Title,
  982. Link: articleInfo.Link,
  983. TagIdList: tagIdList,
  984. }
  985. err = elastic.WechatArticleAbstractEsAddOrEdit(strconv.Itoa(articleAbstractId), esItem)
  986. }
  987. // DelEsWechatArticleAbstract
  988. // @Description: 删除ES中的微信文章摘要
  989. // @author: Roc
  990. // @datetime 2025-03-13 14:13:47
  991. // @param articleAbstractId int
  992. func DelEsWechatArticleAbstract(articleAbstractId int) {
  993. if utils.EsWechatArticleAbstractName == `` {
  994. return
  995. }
  996. var err error
  997. defer func() {
  998. if err != nil {
  999. utils.FileLog.Error("删除公众号微信信息到ES失败,err:%v", err)
  1000. fmt.Println("删除公众号微信信息到ES失败,err:", err)
  1001. }
  1002. }()
  1003. err = elastic.WechatArticleAbstractEsDel(strconv.Itoa(articleAbstractId))
  1004. }
  1005. // AddOrEditEsRagQuestion
  1006. // @Description: 新增/编辑知识库问题入ES
  1007. // @author: Roc
  1008. // @datetime 2025-03-28 11:25:50
  1009. // @param questionId int
  1010. func AddOrEditEsRagQuestion(questionId int) {
  1011. if utils.EsWechatArticleName == `` {
  1012. return
  1013. }
  1014. var err error
  1015. defer func() {
  1016. if err != nil {
  1017. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  1018. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  1019. }
  1020. }()
  1021. obj := rag.Question{}
  1022. questionInfo, err := obj.GetByID(questionId)
  1023. if err != nil {
  1024. err = fmt.Errorf("获取公众号文章信息失败,Err:" + err.Error())
  1025. return
  1026. }
  1027. esItem := elastic.RagQuestionItem{
  1028. QuestionId: questionInfo.QuestionId,
  1029. QuestionTitle: questionInfo.QuestionTitle,
  1030. QuestionContent: questionInfo.QuestionContent,
  1031. Sort: questionInfo.Sort,
  1032. SysUserId: questionInfo.SysUserId,
  1033. SysUserRealName: questionInfo.SysUserRealName,
  1034. ModifyTime: questionInfo.ModifyTime,
  1035. CreateTime: questionInfo.CreateTime,
  1036. }
  1037. err = elastic.RagQuestionEsAddOrEdit(strconv.Itoa(questionInfo.QuestionId), esItem)
  1038. }
  1039. // DelEsRagQuestion
  1040. // @Description: 删除ES中的知识库问题
  1041. // @author: Roc
  1042. // @datetime 2025-03-28 11:26:40
  1043. // @param questionId int
  1044. func DelEsRagQuestion(questionId int) {
  1045. if utils.EsWechatArticleAbstractName == `` {
  1046. return
  1047. }
  1048. var err error
  1049. defer func() {
  1050. if err != nil {
  1051. utils.FileLog.Error("添加公众号微信信息到ES失败,err:%v", err)
  1052. fmt.Println("添加公众号微信信息到ES失败,err:", err)
  1053. }
  1054. }()
  1055. err = elastic.RagQuestionEsDel(strconv.Itoa(questionId))
  1056. }
  1057. // extractLabels
  1058. // @Description: 提取摘要中的标签
  1059. // @author: Roc
  1060. // @datetime 2025-04-18 17:16:05
  1061. // @param text string
  1062. // @return industryTags []string
  1063. // @return varietyTags []string
  1064. func extractLabels(text string) (industryTags []string, varietyTags []string) {
  1065. reIndustry := regexp.MustCompile(`行业标签((?:【[^】]*】)+)`)
  1066. industryMatch := reIndustry.FindStringSubmatch(text)
  1067. if len(industryMatch) > 1 {
  1068. industryContent := industryMatch[1]
  1069. reSplit := regexp.MustCompile(`【([^】]*)】`)
  1070. industryTags = make([]string, 0)
  1071. for _, m := range reSplit.FindAllStringSubmatch(industryContent, -1) {
  1072. if len(m) > 1 {
  1073. industryTags = append(industryTags, m[1])
  1074. }
  1075. }
  1076. }
  1077. reVariety := regexp.MustCompile(`品种标签((?:【[^】]*】)+)`)
  1078. varietyMatch := reVariety.FindStringSubmatch(text)
  1079. if len(varietyMatch) > 1 {
  1080. varietyContent := varietyMatch[1]
  1081. reSplit := regexp.MustCompile(`【([^】]*)】`)
  1082. varietyTags = make([]string, 0)
  1083. for _, m := range reSplit.FindAllStringSubmatch(varietyContent, -1) {
  1084. if len(m) > 1 {
  1085. varietyTags = append(varietyTags, m[1])
  1086. }
  1087. }
  1088. }
  1089. return
  1090. }
  1091. var aiAbstractTagMap = map[string]int{}
  1092. // GetTagIdByName
  1093. // @Description: 获取标签ID
  1094. // @author: Roc
  1095. // @datetime 2025-04-18 17:25:46
  1096. // @param tagName string
  1097. // @return tagId int
  1098. // @return err error
  1099. func GetTagIdByName(tagName string) (tagId int, err error) {
  1100. tagName = strings.TrimSpace(tagName)
  1101. tagId, ok := aiAbstractTagMap[tagName]
  1102. if ok {
  1103. return
  1104. }
  1105. obj := rag.Tag{}
  1106. item, err := obj.GetByCondition(fmt.Sprintf(` AND %s = ? `, rag.TagColumns.TagName), []interface{}{tagName})
  1107. if err != nil {
  1108. if !utils.IsErrNoRow(err) {
  1109. err = fmt.Errorf("获取标签失败,Err:" + err.Error())
  1110. return
  1111. }
  1112. item = &rag.Tag{
  1113. TagId: 0,
  1114. TagName: tagName,
  1115. Sort: 0,
  1116. ModifyTime: time.Now(),
  1117. CreateTime: time.Now(),
  1118. }
  1119. err = item.Create()
  1120. if err != nil {
  1121. err = fmt.Errorf("添加标签失败,Err:" + err.Error())
  1122. return
  1123. }
  1124. }
  1125. tagId = item.TagId
  1126. aiAbstractTagMap[tagName] = tagId
  1127. return
  1128. }