Parcourir la source

Merge remote-tracking branch 'origin/master' into rag/3.1

# Conflicts:
#	models/rag/promote_train_record.go
#	services/llm/facade/llm_service.go
Roc il y a 4 jours
Parent
commit
0cd340d28c
41 fichiers modifiés avec 616 ajouts et 134 suppressions
  1. 20 0
      controllers/base_auth.go
  2. 9 1
      controllers/data_manage/ccf_data.go
  3. 42 4
      controllers/data_manage/edb_info.go
  4. 6 1
      controllers/data_manage/excel/balance_table.go
  5. 6 0
      controllers/data_manage/excel/excel_info.go
  6. 55 12
      controllers/data_manage/mysteel_chemical_data.go
  7. 44 13
      controllers/data_manage/sci_hq_data.go
  8. 2 0
      controllers/llm/llm_http/request.go
  9. 11 0
      controllers/llm/promote_controller.go
  10. 2 0
      controllers/llm/question.go
  11. 6 0
      controllers/report.go
  12. 2 2
      controllers/report_chapter.go
  13. 11 7
      controllers/report_v2.go
  14. 12 7
      controllers/smart_report/smart_report.go
  15. 7 0
      models/business_conf.go
  16. 10 1
      models/cloud_disk_resource.go
  17. 14 12
      models/data_manage/base_from_ccf.go
  18. 27 0
      models/data_manage/base_from_sci_hq_classify.go
  19. 10 4
      models/data_manage/base_from_sci_hq_index.go
  20. 15 0
      models/data_manage/excel/excel_info_rule_mapping.go
  21. 51 13
      models/data_manage/mysteel_chemical_index.go
  22. 4 4
      models/data_manage/request/sci_hq_data.go
  23. 3 0
      models/rag/promote_train_record.go
  24. 1 0
      models/report.go
  25. 88 15
      services/data/base_from_sci_hq.go
  26. 17 0
      services/data/excel/excel_op.go
  27. 1 0
      services/elastic.go
  28. 1 0
      services/eta_forum/eta_forum_hub.go
  29. 15 15
      services/excel/lucky_sheet.go
  30. 44 4
      services/llm/facade/llm_service.go
  31. 20 0
      services/material/material.go
  32. 6 4
      services/report.go
  33. 21 0
      services/report_v2.go
  34. 3 2
      services/smart_report.go
  35. 8 7
      services/wechat_platform.go
  36. 0 0
      static/imgs/ai/article/【专题报告】关税来袭黑色怎么看.md
  37. 0 0
      static/imgs/ai/article/【东海首席】黑色金属专题报告新一轮钢铁供给侧改革能否全面开启.md
  38. 0 0
      static/imgs/ai/article/【开源宏观】财政支出力度如何12月财政数据点评.md
  39. 0 0
      static/imgs/ai/article/巴菲特2025股东信1000字精华版来了附全文.md
  40. 21 5
      utils/llm/eta_llm/eta_llm_client.go
  41. 1 1
      utils/llm/llm_client.go

+ 20 - 0
controllers/base_auth.go

@@ -174,12 +174,32 @@ func (c *BaseAuthController) Prepare() {
 				loginKey := fmt.Sprint(utils.CACHE_ACCESS_TOKEN_LOGIN, session.Id)
 				loginInfo, _ := utils.Rc.RedisString(loginKey)
 				if loginInfo == `` {
+					// 超时退出的时候,也记录下当前请求日志,避免数据丢失
+					requestBody, err := url.QueryUnescape(string(c.Ctx.Input.RequestBody))
+					if err != nil {
+						requestBody = string(c.Ctx.Input.RequestBody)
+					}
+					if requestBody == "" {
+						requestBody = c.Ctx.Input.URI()
+					}
+					utils.ApiLog.Info("uri:%s, authorization:%s, requestBody:%s", c.Ctx.Input.URI(), authorization, requestBody)
+
 					c.JSON(models.BaseResponse{Ret: 408, Msg: "超时未操作,系统自动退出!", ErrMsg: "超时未操作,系统自动退出!"}, false, false)
 					c.StopRun()
 					return
 				}
 
 				if loginInfo != "1" {
+					// 超时退出的时候,也记录下当前请求日志,避免数据丢失
+					requestBody, err := url.QueryUnescape(string(c.Ctx.Input.RequestBody))
+					if err != nil {
+						requestBody = string(c.Ctx.Input.RequestBody)
+					}
+					if requestBody == "" {
+						requestBody = c.Ctx.Input.URI()
+					}
+					utils.ApiLog.Info("uri:%s, authorization:%s, requestBody:%s", c.Ctx.Input.URI(), authorization, requestBody)
+
 					msg := `该账号于` + admin.LastLoginTime + "在其他网络登录。此客户端已退出登录。"
 					c.JSON(models.BaseResponse{Ret: 408, Msg: msg, ErrMsg: msg}, false, false)
 					c.StopRun()

+ 9 - 1
controllers/data_manage/ccf_data.go

@@ -327,9 +327,17 @@ func (this *EdbInfoController) CCFSingleData() {
 		br.ErrMsg = "获取数据失败,Err:" + err.Error()
 		return
 	}
+	edbInfo, err := data_manage.GetEdbInfoByEdbCode(utils.DATA_SOURCE_CCF, indexCode)
+	if err != nil && !utils.IsErrNoRow(err) {
+		br.Msg = "获取指标库信息失败"
+		br.ErrMsg = "获取数据源失败,Err:" + err.Error()
+		return
+	}
 	var ret data_manage.CCFSingleDataResp
 	var dataList []*data_manage.CCFSingleData
-
+	if edbInfo != nil {
+		ret.EdbInfoId = edbInfo.EdbInfoId
+	}
 	ret.ClassifyId = indexInfo.ClassifyId
 	ret.BaseFromCcfIndexId = indexInfo.BaseFromCcfIndexId
 	ret.IndexCode = indexInfo.IndexCode

+ 42 - 4
controllers/data_manage/edb_info.go

@@ -6820,18 +6820,56 @@ func (this *EdbInfoController) ModifyEdbList() {
 			br.ErrMsg = "获取已授权分类id数据失败,Err:" + err.Error()
 			return
 		}
-		classifyIdsArr := make([]int, 0)
+
+		// 提交上来的分类id
+		tmpClassifyIdsArr := make([]int, 0)
 		for _, v := range classifyIds {
 			if v != `` {
 				id, _ := strconv.Atoi(v)
-				classifyIdsArr = append(classifyIdsArr, id)
+				tmpClassifyIdsArr = append(tmpClassifyIdsArr, id)
 			}
 		}
 
-		if len(permissionClassifyIdList) > 0 {
-			classifyIdsArr = utils.IntersectInt(permissionClassifyIdList, classifyIdsArr)
+		// 我有权限的分类id
+		classifyIdsArr := make([]int, 0)
+		if len(tmpClassifyIdsArr) > 0 {
+			classifyInfoList, err := data_manage.GetEdbClassifyByIdList(tmpClassifyIdsArr)
+			if err != nil && !utils.IsErrNoRow(err) {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取数据失败,Err:" + err.Error()
+				return
+			}
+
+			permissionClassifyIdMap := make(map[int]bool)
+			for _, classifyId := range permissionClassifyIdList {
+				permissionClassifyIdMap[classifyId] = true
+			}
+			for _, v := range classifyInfoList {
+				// 没有加入指标目录管控,那么就直接加入并进入下个循环
+				if v.IsJoinPermission == 0 {
+					classifyIdsArr = append(classifyIdsArr, v.ClassifyId)
+					continue
+				}
+
+				// 如果加入指标目录管控了,同时自己有权限,那么就加入
+				if _, ok := permissionClassifyIdMap[v.ClassifyId]; ok {
+					classifyIdsArr = append(classifyIdsArr, v.ClassifyId)
+					continue
+				}
+
+			}
 		}
 
+		if len(classifyIds) > 0 && len(classifyIdsArr) <= 0 {
+			br.Msg = `所选中的指标目录没有权限`
+			br.IsSendEmail = false
+			return
+		}
+
+		//if len(permissionClassifyIdList) > 0 {
+		//	classifyIdsArr = utils.IntersectInt(permissionClassifyIdList, classifyIdsArr)
+		//}
+
 		condition += " AND edb_info_type = 0 "
 		if len(classifyIdsArr) > 0 {
 			if !req.SubClassify {

+ 6 - 1
controllers/data_manage/excel/balance_table.go

@@ -1425,7 +1425,12 @@ func downloadBalanceTable(excelInfo *excel.ExcelInfo, lang string) (savePath, zi
 				err = fmt.Errorf("转换成table失败,Err:" + err.Error())
 				return
 			}
-
+			//tableData, err = excel2.HandleRuleToTableCell(childExcelInfo.ExcelInfoId, tableData)
+			//if err != nil {
+			//	errMsg = "获取失败"
+			//	err = fmt.Errorf("处理条件格式管理规则失败,Err:%w", err)
+			//	return
+			//}
 			// 将单个sheet的数据写入到excel
 			err = tableData.WriteExcelSheetData(xlsxFile, childExcelInfo.ExcelName)
 			if err != nil {

+ 6 - 0
controllers/data_manage/excel/excel_info.go

@@ -2725,6 +2725,12 @@ func (c *ExcelInfoController) Download() {
 			br.ErrMsg = "转换成table失败,Err:" + err.Error()
 			return
 		}
+		//tableData, err = excel.HandleRuleToTableCell(excelInfo.ExcelInfoId, tableData)
+		//if err != nil {
+		//	br.Msg = "获取失败"
+		//	br.ErrMsg = "处理条件格式管理规则失败,Err:" + err.Error()
+		//	return
+		//}
 	case utils.BALANCE_TABLE: // 混合表格
 		savePath, fileName, uploadDir, err, errMsg := downloadBalanceTable(excelInfo, c.Lang)
 		if err != nil {

+ 55 - 12
controllers/data_manage/mysteel_chemical_data.go

@@ -1745,7 +1745,7 @@ func (c *EdbInfoController) AddCheck() {
 	br.Success = true
 }
 
-// MysteelChemicalSearch
+// MysteelChemicalBatchSearch
 // @Title 钢联化工指标查询
 // @Description 钢联化工指标查询
 // @Param   BaseFromMysteelChemicalClassifyIds   query   string  true       "分类id"
@@ -1779,17 +1779,58 @@ func (this *EdbInfoController) MysteelChemicalBatchSearch() {
 		condition += " AND (index_name like ? OR index_code like ?) "
 		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
+	// 频度(多选)
+	frequencies := this.GetString("Frequencies")
+	frequencies = strings.TrimSpace(frequencies)
+	if frequencies != "" {
+		freArr := strings.Split(frequencies, ",")
+		if len(freArr) > 0 {
+			condition += " AND frequency IN ?"
+			pars = append(pars, freArr)
+		}
+	}
+	resp := new(data_manage.MysteelChemicalPageListResp)
+	resp.List = make([]*data_manage.MysteelChemicalList, 0)
+
+	//if classifyIdStr == `` && keyword == `` {
+	//	var list = make([]*data_manage.MysteelChemicalList, 0)
+	//	br.Ret = 200
+	//	br.Success = true
+	//	br.Msg = "获取成功"
+	//	br.Data = list
+	//	return
+	//}
+
+	// 分页查询
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize10
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
 
-	if classifyIdStr == `` && keyword == `` {
-		var list = make([]*data_manage.MysteelChemicalList, 0)
+	// 获取未加入指标库的原始指标
+	total, e := data_manage.GetNoEdbMysteelChemicalIndexCount(condition, pars)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取未加入指标库的钢联指标数失败, %v", e)
+		return
+	}
+	if total <= 0 {
+		page := paging.GetPaging(currentIndex, pageSize, 0)
+		resp.Paging = page
+		br.Data = resp
 		br.Ret = 200
 		br.Success = true
 		br.Msg = "获取成功"
-		br.Data = list
 		return
 	}
 
-	list, err := data_manage.GetMysteelChemicalIndex(condition, pars)
+	list, err := data_manage.GetNoEdbMysteelChemicalIndexPageList(condition, pars, startSize, pageSize)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取失败,Err:" + err.Error()
@@ -1802,6 +1843,7 @@ func (this *EdbInfoController) MysteelChemicalBatchSearch() {
 			classifyIdInts = append(classifyIdInts, v.BaseFromMysteelChemicalClassifyId)
 		}
 	}
+	classifyListMap := make(map[int]int, 0)
 	if len(classifyIdInts) > 0 {
 		// 查询父级分类信息
 		classifyList, e := data_manage.GetBaseFromMysteelChemicalClassifyByIds(classifyIdInts)
@@ -1810,20 +1852,21 @@ func (this *EdbInfoController) MysteelChemicalBatchSearch() {
 			br.ErrMsg = "获取失获取目录信息失败,Err:" + e.Error()
 			return
 		}
-		classifyListMap := make(map[int]int, 0)
 		for _, v := range classifyList {
 			classifyListMap[v.BaseFromMysteelChemicalClassifyId] = v.ParentId
 		}
-		for _, v := range list {
-			v.UniqueCode = fmt.Sprint(v.BaseFromMysteelChemicalClassifyId, "_", v.Id)
-			if p, ok := classifyListMap[v.BaseFromMysteelChemicalClassifyId]; ok {
-				v.ParentClassifyId = p
-			}
+	}
+	for _, v := range list {
+		if p, ok := classifyListMap[v.BaseFromMysteelChemicalClassifyId]; ok {
+			v.ParentClassifyId = p
 		}
+		resp.List = append(resp.List, v)
 	}
 
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp.Paging = page
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
-	br.Data = list
+	br.Data = resp
 }

+ 44 - 13
controllers/data_manage/sci_hq_data.go

@@ -264,7 +264,7 @@ func (this *SciHqDataController) MoveClassify() {
 		return
 	}
 
-	err, errMsg := data.MoveSciHqClassify(req.ClassifyId, req.ParentId, req.PrevClassifyId, req.NextClassifyId)
+	err, errMsg := data.MoveSciHqClassify(req.ClassifyId, req.ParentClassifyId, req.PrevClassifyId, req.NextClassifyId)
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg
@@ -333,12 +333,12 @@ func (this *SciHqDataController) BatchIndexList() {
 	}
 	if req.IsSelectAll {
 		if len(req.SelectedId) > 0 {
-			condition += ` AND base_from_sci_hq_index_id NOT IN (` + utils.GetOrmInReplace(len(req.SelectedId)) + `)`
+			condition += ` AND base_from_sci_hq_index_id NOT IN (?)`
 			pars = append(pars, req.SelectedId)
 		}
 	} else {
 		if len(req.SelectedId) > 0 {
-			condition += ` AND base_from_sci_hq_index_id IN (` + utils.GetOrmInReplace(len(req.SelectedId)) + `)`
+			condition += ` AND base_from_sci_hq_index_id IN (?)`
 			pars = append(pars, req.SelectedId)
 		}
 	}
@@ -353,11 +353,14 @@ func (this *SciHqDataController) BatchIndexList() {
 			br.ErrMsg = "获取分类失败,Err:" + err.Error()
 			return
 		}
-		if len(childClassify) > 0 {
-			condition += `AND classify_id IN (` + utils.GetOrmInReplace(len(childClassify)) + `)`
-			for _, child := range childClassify {
-				pars = append(pars, child.ClassifyId)
-			}
+		var childIds []int
+		for _, v := range childClassify {
+			childIds = append(childIds, v.ClassifyId)
+		}
+		if len(childIds) > 0 {
+			childIds = append(childIds, req.ClassifyId)
+			condition += `AND classify_id IN (?)`
+			pars = append(pars, childIds)
 		} else {
 			condition += ` AND classify_id=?`
 			pars = append(pars, req.ClassifyId)
@@ -757,6 +760,19 @@ func (this *SciHqDataController) AddEdbInfo() {
 		return
 	}
 
+	// 刷新指标数据
+	refreshRes, e := data.RefreshEdbData(edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, "")
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = fmt.Sprintf("刷新指标数据失败, %v", e)
+		return
+	}
+	if refreshRes != nil && refreshRes.Ret != 200 {
+		br.Msg = "操作失败"
+		br.ErrMsg = fmt.Sprintf("刷新指标数据失败, Ret: %d, Msg: %s, ErrMsg: %s", refreshRes.Ret, refreshRes.Msg, refreshRes.ErrMsg)
+		return
+	}
+
 	// 试用平台更新用户累计新增指标数
 	adminItem, e := system.GetSysAdminById(sysUser.AdminId)
 	if e != nil {
@@ -1091,6 +1107,19 @@ func (this *SciHqDataController) BatchAdd() {
 			continue
 		}
 
+		// 刷新指标数据
+		refreshRes, e := data.RefreshEdbData(edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, "")
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = fmt.Sprintf("刷新指标数据失败, %v", e)
+			return
+		}
+		if refreshRes != nil && refreshRes.Ret != 200 {
+			br.Msg = "操作失败"
+			br.ErrMsg = fmt.Sprintf("刷新指标数据失败, Ret: %d, Msg: %s, ErrMsg: %s", refreshRes.Ret, refreshRes.Msg, refreshRes.ErrMsg)
+			return
+		}
+
 		// 试用平台更新用户累计新增指标数
 		if utils.BusinessCode == utils.BusinessCodeSandbox {
 			go func() {
@@ -1417,11 +1446,13 @@ func (this *SciHqDataController) ExportSciHqList() {
 			br.ErrMsg = "获取分类失败,Err:" + err.Error()
 			return
 		}
-		if len(childClassify) > 0 {
-			condition += `AND classify_id IN (` + utils.GetOrmInReplace(len(childClassify)) + `)`
-			for _, child := range childClassify {
-				pars = append(pars, child.ClassifyId)
-			}
+		var childIds []int
+		for _, v := range childClassify {
+			childIds = append(childIds, v.ClassifyId)
+		}
+		if len(childIds) > 0 {
+			condition += `AND classify_id IN (?)`
+			pars = append(pars, childIds)
 		} else {
 			condition += ` AND classify_id=?`
 			pars = append(pars, classifyId)

+ 2 - 0
controllers/llm/llm_http/request.go

@@ -25,11 +25,13 @@ type GenerateContentReq struct {
 	Source          int    `json:"Source" description:"来源,0:公众号文章,1:eta报告"`
 	WechatArticleId int    `json:"WechatArticleId" description:"公众号文章Id"`
 	Promote         string `json:"Promote" description:"提示词"`
+	LLMModel        string `json:"LLMModel"`
 }
 type SaveContentReq struct {
 	Source          int             `json:"Source" description:"来源,0:公众号文章,1:eta报告"`
 	WechatArticleId int             `json:"WechatArticleId" description:"公众号文章Id"`
 	Title           string          `json:"Title" description:"标题"`
+	Llm             string          `json:"LLM"`
 	Promote         json.RawMessage `json:"Promote" description:"提示词"`
 	AigcContent     json.RawMessage `json:"AigcContent" description:"生成内容"`
 }

+ 11 - 0
controllers/llm/promote_controller.go

@@ -9,6 +9,7 @@ import (
 	"eta/eta_api/services/llm/facade"
 	"eta/eta_api/utils"
 	"fmt"
+	"strings"
 	"time"
 )
 
@@ -50,6 +51,11 @@ func (pCtrl *PromoteController) GenerateContent() {
 		br.ErrMsg = "公众号文章编号非法"
 		return
 	}
+	if gcReq.LLMModel == "" {
+		br.Msg = "LLM模型不能为空"
+		br.ErrMsg = "LLM模型不能为空"
+		return
+	}
 	userSendTime := time.Now()
 	userContent := llm_http.Content{
 		Content:  gcReq.Promote,
@@ -71,6 +77,7 @@ func (pCtrl *PromoteController) GenerateContent() {
 		Promote:   gcReq.Promote,
 		Source:    gcReq.Source,
 		ArticleId: gcReq.WechatArticleId,
+		LLMModel:  gcReq.LLMModel,
 	})
 	if err != nil {
 		br.Msg = err.Error()
@@ -87,10 +94,12 @@ func (pCtrl *PromoteController) GenerateContent() {
 		Promote: userContent,
 		Answer:  aiContent,
 	}
+	llm := strings.ReplaceAll(gcReq.LLMModel, ":", "")
 	saveContentReq := rag.PromoteTrainRecord{
 		Source:          gcReq.Source,
 		WechatArticleId: gcReq.WechatArticleId,
 		Title:           userContent.Content,
+		Llm:             llm,
 		AigcContent:     res.Answer,
 		AigcSendTime:    aiSendTime,
 		TemplatePromote: userContent.Content,
@@ -191,10 +200,12 @@ func (pCtrl *PromoteController) SavePromoteContent() {
 		br.ErrMsg = "AI生成时间不能为空"
 		return
 	}
+	llm := strings.ReplaceAll(gcReq.Llm, ":", "")
 	saveContentReq := rag.PromoteTrainRecord{
 		Source:          gcReq.Source,
 		WechatArticleId: gcReq.WechatArticleId,
 		Title:           titile,
+		Llm:             llm,
 		AigcContent:     assistantContent.Content,
 		AigcSendTime:    assistantSendTime,
 		TemplatePromote: userContent.Content,

+ 2 - 0
controllers/llm/question.go

@@ -343,6 +343,8 @@ func (c *QuestionController) Edit() {
 		br.ErrMsg = "修改失败,Err:" + err.Error()
 		return
 	}
+	// 新增/编辑ES数据
+	go services.AddOrEditEsRagQuestion(item.QuestionId)
 
 	br.Ret = 200
 	br.Success = true

+ 6 - 0
controllers/report.go

@@ -1919,6 +1919,12 @@ func (this *ReportController) SendMsg() {
 		return
 	}
 
+	//
+	if reportInfo.IsPublicPublish != 1 {
+		br.Msg = "报告未公开"
+		return
+	}
+
 	// 更新报告发布时间
 	videoNameDate := `(` + time.Now().Format("0102") + `)`
 	if err = models.UpdateReportPublishTime(req.ReportId, videoNameDate); err != nil {

+ 2 - 2
controllers/report_chapter.go

@@ -1368,7 +1368,7 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 
 	// 更新章节ES
 	{
-		go services.UpdateReportChapterEs(chapterInfo.ReportChapterId)
+		go services.UpdateReportChapterEs(chapterInfo.ReportChapterId, reportInfo.IsPublicPublish)
 	}
 
 	// 同时发布报告
@@ -1652,7 +1652,7 @@ func (this *ReportController) CancelPublishReportChapter() {
 
 	// 更新章节ES
 	{
-		go services.UpdateReportChapterEs(chapterInfo.ReportChapterId)
+		go services.UpdateReportChapterEs(chapterInfo.ReportChapterId, reportInfo.IsPublicPublish)
 	}
 
 	br.Ret = 200

+ 11 - 7
controllers/report_v2.go

@@ -692,24 +692,28 @@ func (this *ReportController) Detail() {
 
 	if item.HeadResourceId > 0 {
 		headResource, err := smart_report.GetResourceItemById(item.HeadResourceId)
-		if err != nil {
+		if err != nil && err.Error() != utils.ErrNoRow() {
 			br.Msg = "操作失败"
 			br.ErrMsg = "获取资源库版头失败, Err: " + err.Error()
 			return
 		}
-		item.HeadImg = headResource.ImgUrl
-		item.HeadStyle = headResource.Style
+		if headResource != nil && headResource.ResourceId > 0 {
+			item.HeadImg = headResource.ImgUrl
+			item.HeadStyle = headResource.Style
+		}
 	}
 
 	if item.EndResourceId > 0 {
 		endResource, err := smart_report.GetResourceItemById(item.EndResourceId)
-		if err != nil {
+		if err != nil && err.Error() != utils.ErrNoRow() {
 			br.Msg = "操作失败"
-			br.ErrMsg = "获取资源库版失败, Err: " + err.Error()
+			br.ErrMsg = "获取资源库版失败, Err: " + err.Error()
 			return
 		}
-		item.EndImg = endResource.ImgUrl
-		item.EndStyle = endResource.Style
+		if endResource != nil && endResource.ResourceId > 0 {
+			item.EndImg = endResource.ImgUrl
+			item.EndStyle = endResource.Style
+		}
 	}
 
 	item.Content = services.HandleReportContentTable(item.Id, item.Content)

+ 12 - 7
controllers/smart_report/smart_report.go

@@ -391,24 +391,29 @@ func (this *SmartReportController) Detail() {
 	resp := smart_report.FormatSmartReport2Item(item)
 	if resp.HeadResourceId > 0 {
 		headResource, err := smart_report.GetResourceItemById(resp.HeadResourceId)
-		if err != nil {
+		if err != nil && err.Error() != utils.ErrNoRow() {
 			br.Msg = "操作失败"
 			br.ErrMsg = "获取资源库版头失败, Err: " + err.Error()
 			return
 		}
-		resp.HeadImg = headResource.ImgUrl
-		resp.HeadStyle = headResource.Style
+		if headResource != nil && headResource.ResourceId > 0 {
+			resp.HeadImg = headResource.ImgUrl
+			resp.HeadStyle = headResource.Style
+		}
 	}
 
 	if resp.EndResourceId > 0 {
 		endResource, err := smart_report.GetResourceItemById(resp.EndResourceId)
-		if err != nil {
+		if err != nil && err.Error() != utils.ErrNoRow() {
 			br.Msg = "操作失败"
-			br.ErrMsg = "获取资源库版失败, Err: " + err.Error()
+			br.ErrMsg = "获取资源库版失败, Err: " + err.Error()
 			return
 		}
-		resp.EndImg = endResource.ImgUrl
-		resp.EndStyle = endResource.Style
+		if endResource != nil && endResource.ResourceId > 0 {
+			resp.EndImg = endResource.ImgUrl
+			resp.EndStyle = endResource.Style
+		}
+
 	}
 	br.Ret = 200
 	br.Success = true

+ 7 - 0
models/business_conf.go

@@ -67,6 +67,7 @@ const (
 	BusinessConfEsRagQuestion                = "EsIndexNameRagQuestion"           // ES索引名称-知识库问题
 	BusinessConfIsOpenChartExpired           = "IsOpenChartExpired"               // 是否开启图表有效期鉴权/报告禁止复制
 	BusinessConfReportChartExpiredTime       = "ReportChartExpiredTime"           // 图表有效期鉴权时间,单位:分钟
+	BusinessConfOssUrlReplace                = "OssUrlReplace"                    // OSS地址替换-兼容内网客户用
 )
 
 const (
@@ -305,3 +306,9 @@ func InitBusinessConf() {
 	}
 
 }
+
+type OssUrlReplace struct {
+	IsReplace    bool   `description:"是否替换"`
+	OssUrlOrigin string `description:"被替换的资源地址"`
+	OssUrlNew    string `description:"新的资源地址"`
+}

+ 10 - 1
models/cloud_disk_resource.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	sql2 "database/sql"
 	"eta/eta_api/global"
 	"eta/eta_api/utils"
 	"fmt"
@@ -169,8 +170,16 @@ func GetSizeTotalByMenuIds(menuIds []int) (sizeTotal int64, err error) {
 	if len(menuIds) == 0 {
 		return
 	}
+	var sizeTotalNull sql2.NullInt64
 	sql := `SELECT SUM(size) FROM cloud_disk_resource WHERE menu_id IN (` + utils.GetOrmInReplace(len(menuIds)) + `)`
-	err = global.DEFAULT_DB.Raw(sql, menuIds).Scan(&sizeTotal).Error
+	err = global.DEFAULT_DB.Raw(sql, menuIds).Scan(&sizeTotalNull).Error
+	if err != nil {
+		return
+	}
+	if sizeTotalNull.Valid {
+		sizeTotal = sizeTotalNull.Int64
+	}
+
 	return
 }
 

+ 14 - 12
models/data_manage/base_from_ccf.go

@@ -39,18 +39,20 @@ type BaseFromCCFIndexList struct {
 	DataList           []*BaseFromCCFData `gorm:"-"`
 	Paging             *paging.PagingItem `description:"分页数据" gorm:"-"`
 }
+
 func (b *BaseFromCCFIndexList) TableName() string {
 	return "base_from_ccf_index"
 }
 
 func (b *BaseFromCCFIndexList) AfterFind(tx *gorm.DB) (err error) {
-		b.ModifyTime = utils.GormDateStrToDateTimeStr(b.ModifyTime)
-		b.CreateTime = utils.GormDateStrToDateTimeStr(b.CreateTime)
-		b.EndDate = utils.GormDateStrToDateStr(b.EndDate)
+	b.ModifyTime = utils.GormDateStrToDateTimeStr(b.ModifyTime)
+	b.CreateTime = utils.GormDateStrToDateTimeStr(b.CreateTime)
+	b.EndDate = utils.GormDateStrToDateStr(b.EndDate)
 	return
 }
 
 type CCFSingleDataResp struct {
+	EdbInfoId          int
 	BaseFromCcfIndexId int
 	ClassifyId         int
 	IndexCode          string
@@ -130,9 +132,9 @@ type BaseFromCCFData struct {
 }
 
 func (baseFromCCFData *BaseFromCCFData) AfterFind(tx *gorm.DB) (err error) {
-			baseFromCCFData.ModifyTime = utils.GormDateStrToDateTimeStr(baseFromCCFData.ModifyTime)
-			baseFromCCFData.CreateTime = utils.GormDateStrToDateTimeStr(baseFromCCFData.CreateTime)
-			baseFromCCFData.DataTime = utils.GormDateStrToDateStr(baseFromCCFData.DataTime)
+	baseFromCCFData.ModifyTime = utils.GormDateStrToDateTimeStr(baseFromCCFData.ModifyTime)
+	baseFromCCFData.CreateTime = utils.GormDateStrToDateTimeStr(baseFromCCFData.CreateTime)
+	baseFromCCFData.DataTime = utils.GormDateStrToDateStr(baseFromCCFData.DataTime)
 	return
 }
 
@@ -226,9 +228,9 @@ func GetCCFIndexDataByDataTime(indexCodes []string, startDate, endDate string) (
 func GetCCFIndexDataTimePageByCodes(indexCodes []string, startSize, pageSize int) (dataTimes []string, err error) {
 	sql := ` SELECT data_time FROM base_from_ccf_data WHERE index_code in (` + utils.GetOrmInReplace(len(indexCodes)) + `) GROUP BY data_time ORDER BY data_time DESC LIMIT ?,? `
 	err = global.DbMap[utils.DbNameIndex].Raw(sql, indexCodes, startSize, pageSize).Find(&dataTimes).Error
-		for i := range dataTimes {
-			dataTimes[i] = utils.GormDateStrToDateStr(dataTimes[i])
-		}
+	for i := range dataTimes {
+		dataTimes[i] = utils.GormDateStrToDateStr(dataTimes[i])
+	}
 	return
 }
 
@@ -255,9 +257,9 @@ func GetCCFDataDataTimeByIndexId(indexIdList []int) (items []string, err error)
 	if err != nil {
 		return
 	}
-		for i := range items {
-			items[i] = utils.GormDateStrToDateStr(items[i])
-		}
+	for i := range items {
+		items[i] = utils.GormDateStrToDateStr(items[i])
+	}
 	return
 }
 

+ 27 - 0
models/data_manage/base_from_sci_hq_classify.go

@@ -3,6 +3,7 @@ package data_manage
 import (
 	"eta/eta_api/global"
 	"eta/eta_api/utils"
+	"fmt"
 	"time"
 )
 
@@ -218,3 +219,29 @@ func MoveDownSciHqIndexClassifyBySort(parentId, prevSort, currentSort int) (err
 	err = o.Exec(sql, parentId, prevSort, currentSort).Error
 	return
 }
+
+// UpdateSciHqClassifySortByParentId 根据父类id更新排序
+func UpdateSciHqClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string) (err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := ` update base_from_sci_hq_classify set sort = ` + updateSort + ` WHERE parent_id = ? AND sort > ? `
+	if classifyId > 0 {
+		sql += ` or ( classify_id > ` + fmt.Sprint(classifyId) + ` and sort = ` + fmt.Sprint(nowSort) + `)`
+	}
+	err = o.Exec(sql, parentId, nowSort).Error
+	return
+}
+
+// GetFirstSciHqClassifyByParentId 获取当前父级分类下,且排序数相同 的排序第一条的数据
+func GetFirstSciHqClassifyByParentId(parentId int) (item *BaseFromSciHqClassify, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := ` SELECT * FROM base_from_sci_hq_classify WHERE parent_id = ? ORDER BY sort ASC,classify_id ASC LIMIT 1`
+	err = o.Raw(sql, parentId).First(&item).Error
+	return
+}
+
+func GetSciHqClassifySortMaxByParentId(parentId int) (sort int, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := `SELECT COALESCE(Max(sort), 0) AS sort FROM base_from_sci_hq_classify WHERE parent_id = ?`
+	err = o.Raw(sql, parentId).Scan(&sort).Error
+	return
+}

+ 10 - 4
models/data_manage/base_from_sci_hq_index.go

@@ -25,6 +25,12 @@ type BaseFromSciHqIndex struct {
 	ModifyTime           time.Time
 }
 
+func (m *BaseFromSciHqIndex) AfterFind(db *gorm.DB) (err error) {
+	m.StartDate = utils.GormDateStrToDateStr(m.StartDate)
+	m.EndDate = utils.GormDateStrToDateStr(m.EndDate)
+	return
+}
+
 type BaseFromSciHqIndexView struct {
 	BaseFromSciHqIndexId int     `orm:"pk" gorm:"primaryKey"`
 	EdbInfoId            int     `description:"指标库id"`
@@ -44,10 +50,10 @@ type BaseFromSciHqIndexView struct {
 }
 
 func (b *BaseFromSciHqIndexView) AfterFind(db *gorm.DB) (err error) {
-			b.LatestDate = utils.GormDateStrToDateStr(b.LatestDate)
-			b.StartDate = utils.GormDateStrToDateStr(b.StartDate)
-			b.EndDate = utils.GormDateStrToDateStr(b.EndDate)
-			b.ModifyTime = utils.GormDateStrToDateTimeStr(b.ModifyTime)
+	b.LatestDate = utils.GormDateStrToDateStr(b.LatestDate)
+	b.StartDate = utils.GormDateStrToDateStr(b.StartDate)
+	b.EndDate = utils.GormDateStrToDateStr(b.EndDate)
+	b.ModifyTime = utils.GormDateStrToDateTimeStr(b.ModifyTime)
 	return
 }
 func (b *BaseFromSciHqIndex) Update(cols []string) (err error) {

+ 15 - 0
models/data_manage/excel/excel_info_rule_mapping.go

@@ -76,3 +76,18 @@ func DeleteExcelRuleMappingById(id int) (err error) {
 	err = global.DbMap[utils.DbNameIndex].Exec(sql, id).Error
 	return
 }
+
+func (e *ExcelInfoRuleMapping) CreateMulti(items []*ExcelInfoRuleMapping) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	err = global.DbMap[utils.DbNameIndex].CreateInBatches(items, utils.MultiAddNum).Error
+	return
+}
+
+// GetExcelRuleMappingsByExcelInfoId 根据excelInfoId获取规则映射信息
+func GetExcelRuleMappingsByExcelInfoId(id int) (items []*ExcelInfoRuleMapping, err error) {
+	sql := `SELECT * FROM excel_info_rule_mapping WHERE excel_info_id = ? ORDER BY create_time ASC`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, id).Find(&items).Error
+	return
+}

+ 51 - 13
models/data_manage/mysteel_chemical_index.go

@@ -45,7 +45,7 @@ type BaseFromMysteelChemicalIndexItem struct {
 	IndexName                      string `description:"指标名称"`
 	Unit                           string `description:"单位"`
 	Frequency                      string `description:"频度"`
-	Source                         string    `description:"数据来源"`
+	Source                         string `description:"数据来源"`
 	StartDate                      string `description:"开始日期"`
 	EndDate                        string `description:"结束日期"`
 	CreateTime                     string `description:"创建时间"`
@@ -56,13 +56,15 @@ type BaseFromMysteelChemicalIndexItem struct {
 	IsStop                         int    `description:"是否停更:1:停更,0:未停更"`
 	EdbExist                       int    `description:"指标库是否已添加:0-否;1-是"`
 }
-func (m *BaseFromMysteelChemicalIndexItem) AfterFind(tx * gorm.DB) (err error) {
-	m.StartDate=utils.GormDateStrToDateStr(m.StartDate)
-	m.EndDate =utils.GormDateStrToDateStr(m.EndDate)
-	m.CreateTime=utils.GormDateStrToDateTimeStr(m.CreateTime)
-	m.ModifyTime=utils.GormDateStrToDateTimeStr(m.ModifyTime)
+
+func (m *BaseFromMysteelChemicalIndexItem) AfterFind(tx *gorm.DB) (err error) {
+	m.StartDate = utils.GormDateStrToDateStr(m.StartDate)
+	m.EndDate = utils.GormDateStrToDateStr(m.EndDate)
+	m.CreateTime = utils.GormDateStrToDateTimeStr(m.CreateTime)
+	m.ModifyTime = utils.GormDateStrToDateTimeStr(m.ModifyTime)
 	return
 }
+
 var BaseFromMysteelChemicalIndexCols = struct {
 	BaseFromMysteelChemicalIndexId string
 	IndexCode                      string
@@ -98,7 +100,7 @@ func (m *BaseFromMysteelChemicalIndex) GeItemsByCondition(condition string, pars
 		pars = make([]interface{}, 0)
 	}
 	//pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
-	pars=utils.ForwardPars(pars,utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+	pars = utils.ForwardPars(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
 	sql := `select a.*,b.edb_info_id,b.unique_code as edb_unique_code,b.classify_id as edb_classify_id FROM base_from_mysteel_chemical_index AS a LEFT JOIN edb_info b on a.index_code=b.edb_code AND b.source=? WHERE 1=1 `
 	if condition != "" {
 		sql += condition
@@ -201,11 +203,14 @@ type MysteelChemicalList struct {
 	IsStop                            int                    `description:"是否停更:1:停更,0:未停更"`
 	IsSupplierStop                    int                    `description:"是否供应商停更:1:停更,0:未停更"`
 	Paging                            *paging.PagingItem     `description:"分页数据" gorm:"-"`
+	EndDate                           string                 `description:"结束日期"`
+	EndValue                          float64                `description:"最新值"`
 	DataList                          []*MysteelChemicalData `gorm:"-"`
 }
 
 func (m *MysteelChemicalList) AfterFind(tx *gorm.DB) (err error) {
-			m.UpdateTime = utils.GormDateStrToDateTimeStr(m.UpdateTime)
+	m.UpdateTime = utils.GormDateStrToDateTimeStr(m.UpdateTime)
+	m.EndDate = utils.GormDateStrToDateStr(m.EndDate)
 	return
 }
 
@@ -216,7 +221,7 @@ type MysteelChemicalData struct {
 }
 
 func (m *MysteelChemicalData) AfterFind(tx *gorm.DB) (err error) {
-			m.DataTime = utils.GormDateStrToDateStr(m.DataTime)
+	m.DataTime = utils.GormDateStrToDateStr(m.DataTime)
 	return
 }
 
@@ -346,9 +351,9 @@ func GetBaseFromMysteelChemicalDataTimeByIndexId(indexIdList []int) (items []str
 	if err != nil {
 		return
 	}
-		for i := range items {
-			items[i] = utils.GormDateStrToDateStr(items[i])
-		}
+	for i := range items {
+		items[i] = utils.GormDateStrToDateStr(items[i])
+	}
 	return
 }
 
@@ -548,7 +553,7 @@ type BaseRefreshEdbInfo struct {
 }
 
 func (obj *BaseRefreshEdbInfo) AfterFind(tx *gorm.DB) (err error) {
-			obj.EndDate = utils.GormDateStrToDateStr(obj.EndDate)
+	obj.EndDate = utils.GormDateStrToDateStr(obj.EndDate)
 	return
 }
 
@@ -755,3 +760,36 @@ func GetNotIsSupplierStopIndexByCodeList(codeList []string, isStop int) (items [
 
 	return
 }
+
+type MysteelChemicalPageListResp struct {
+	List   []*MysteelChemicalList
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// GetNoEdbMysteelChemicalIndexCount 获取未加入指标库的钢联原始指标-分页
+func GetNoEdbMysteelChemicalIndexCount(condition string, pars []interface{}) (count int, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM base_from_mysteel_chemical_index WHERE 1=1 AND index_code NOT IN (
+		  SELECT DISTINCT edb_code FROM edb_info WHERE source = %d
+		) `, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, pars...).Scan(&count).Error
+	return
+}
+
+// GetNoEdbMysteelChemicalIndexPageList 获取未加入指标库的钢联原始指标-分页
+func GetNoEdbMysteelChemicalIndexPageList(condition string, pars []interface{}, startSize, pageSize int) (items []*MysteelChemicalList, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := fmt.Sprintf(`SELECT * FROM base_from_mysteel_chemical_index WHERE 1=1 AND index_code NOT IN (
+		  SELECT DISTINCT edb_code FROM edb_info WHERE source = %d
+		) `, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY base_from_mysteel_chemical_index_id ASC LIMIT ?,?`
+	pars = append(pars, startSize, pageSize)
+	err = o.Raw(sql, pars...).Find(&items).Error
+	return
+}

+ 4 - 4
models/data_manage/request/sci_hq_data.go

@@ -48,10 +48,10 @@ type SciHqDataBatchListReq struct {
 
 // MoveBaseFromSciHqClassifyReq 移动分类请求参数
 type MoveBaseFromSciHqClassifyReq struct {
-	ClassifyId     int `description:"分类id"`
-	ParentId       int `description:"父级分类id"`
-	PrevClassifyId int `description:"上一个兄弟节点分类id"`
-	NextClassifyId int `description:"下一个兄弟节点分类id"`
+	ClassifyId       int `description:"分类id"`
+	ParentClassifyId int `description:"父级分类id"`
+	PrevClassifyId   int `description:"上一个兄弟节点分类id"`
+	NextClassifyId   int `description:"下一个兄弟节点分类id"`
 }
 
 // MoveBaseFromSciHqReq 移动指标请求参数

+ 3 - 0
models/rag/promote_train_record.go

@@ -9,6 +9,7 @@ import (
 type PromoteTrainRecord struct {
 	Id              int       `gorm:"id;primaryKey"`
 	Title           string    `gorm:"title"`
+	Llm             string    `gorm:"llm"`
 	Source          int       `gorm:"source" description:"来源,0:公众号文章,1:eta报告"`
 	WechatArticleId int       `gorm:"wechat_article_id"`
 	TemplatePromote string    `gorm:"template_promote"`
@@ -24,6 +25,7 @@ func (p *PromoteTrainRecord) ToView() *PromoteTrainRecordView {
 	return &PromoteTrainRecordView{
 		Id:              p.Id,
 		Title:           p.Title,
+		Llm:             p.Llm,
 		Source:          p.Source,
 		WechatArticleId: p.WechatArticleId,
 		TemplatePromote: p.TemplatePromote,
@@ -36,6 +38,7 @@ func (p *PromoteTrainRecord) ToView() *PromoteTrainRecordView {
 type PromoteTrainRecordView struct {
 	Id              int
 	Title           string
+	Llm             string
 	Source          int
 	WechatArticleId int
 	TemplatePromote string

+ 1 - 0
models/report.go

@@ -997,6 +997,7 @@ type ElasticReportDetail struct {
 	BodyContent        string `description:"内容"`
 	PublishTime        string `description:"发布时间"`
 	PublishState       int    `description:"发布状态 1-未发布 2-已发布"`
+	IsPublicPublish    int8   `description:"是否公开发布,1:是,2:否"`
 	Author             string `description:"作者"`
 	ClassifyIdFirst    int    `description:"一级分类ID"`
 	ClassifyNameFirst  string `description:"一级分类名称"`

+ 88 - 15
services/data/base_from_sci_hq.go

@@ -366,8 +366,9 @@ func MoveSciHqClassify(classifyId, parentClassifyId, prevClassifyId, nextClassif
 		classifyInfo.Level = parentClassifyInfo.Level + 1
 		updateCol = append(updateCol, "ParentId", "Level")
 	}
-	var currentSort, prevSort, nextSort int
-	currentSort = classifyInfo.Sort
+	var prevSort, nextSort int
+	//var currentSort, prevSort, nextSort int
+	//currentSort = classifyInfo.Sort
 
 	var prevClassify *data_manage.BaseFromSciHqClassify
 	var nextClassify *data_manage.BaseFromSciHqClassify
@@ -425,25 +426,97 @@ func MoveSciHqClassify(classifyId, parentClassifyId, prevClassifyId, nextClassif
 		}
 	}
 	//移到两个排序值中间操作
-	if prevSort >= currentSort {
-		//往下移动
-		err = data_manage.MoveDownSciHqIndexClassifyBySort(parentClassifyId, prevSort, currentSort)
+	//if prevSort >= currentSort {
+	//	//往下移动
+	//	err = data_manage.MoveDownSciHqIndexClassifyBySort(parentClassifyId, prevSort, currentSort)
+	//	if err != nil {
+	//		err = errors.New("向下移动出错:" + err.Error())
+	//		return
+	//	}
+	//	classifyInfo.Sort = prevSort
+	//} else if nextSort <= currentSort && nextSort != 0 {
+	//	//往上移动
+	//	err = data_manage.MoveUpSciHqIndexClassifyBySort(parentClassifyId, nextSort, currentSort)
+	//	if err != nil {
+	//		err = errors.New("向上移动出错:" + err.Error())
+	//		return
+	//	}
+	//	classifyInfo.Sort = nextSort
+	//}
+	//classifyInfo.ModifyTime = time.Now()
+	//updateCol = append(updateCol, "Sort", "ModifyTime")
+	//err = classifyInfo.Update(updateCol)
+	//if err != nil {
+	//	errMsg = "移动失败"
+	//	err = errors.New("修改失败,Err:" + err.Error())
+	//	return
+	//}
+
+	if prevSort >= 0 {
+		//如果是移动在两个兄弟节点之间
+		if nextSort > 0 {
+			//下一个兄弟节点
+			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+			if prevSort == nextSort || prevSort == classifyInfo.Sort {
+				//变更兄弟节点的排序
+				updateSortStr := `sort + 2`
+
+				//变更分类
+				if prevClassify != nil {
+					_ = data_manage.UpdateSciHqClassifySortByParentId(parentClassifyId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr)
+				} else {
+					_ = data_manage.UpdateSciHqClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr)
+				}
+			} else {
+				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+				if nextSort-prevSort == 1 {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 1`
+
+					//变更分类
+					if prevClassify != nil {
+						_ = data_manage.UpdateSciHqClassifySortByParentId(parentClassifyId, prevClassify.ClassifyId, prevSort, updateSortStr)
+					} else {
+						_ = data_manage.UpdateSciHqClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr)
+					}
+				}
+			}
+		}
+
+		classifyInfo.Sort = prevSort + 1
+		classifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	} else if prevClassify == nil && nextClassify == nil && parentClassifyId > 0 {
+		//处理只拖动到目录里,默认放到目录底部的情况
+		var maxSort int
+		maxSort, err = data_manage.GetSciHqClassifySortMaxByParentId(parentClassifyId)
 		if err != nil {
-			err = errors.New("向下移动出错:" + err.Error())
+			errMsg = "移动失败"
+			err = errors.New("查询组内排序信息失败,Err:" + err.Error())
 			return
 		}
-		classifyInfo.Sort = prevSort
-	} else if nextSort <= currentSort && nextSort != 0 {
-		//往上移动
-		err = data_manage.MoveUpSciHqIndexClassifyBySort(parentClassifyId, nextSort, currentSort)
-		if err != nil {
-			err = errors.New("向上移动出错:" + err.Error())
+		classifyInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+		classifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	} else {
+		// 拖动到父级分类的第一位
+		firstClassify, tmpErr := data_manage.GetFirstSciHqClassifyByParentId(parentClassifyId)
+		if tmpErr != nil && !utils.IsErrNoRow(tmpErr) {
+			errMsg = "移动失败"
+			err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
 			return
 		}
-		classifyInfo.Sort = nextSort
+
+		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+		if firstClassify != nil && firstClassify.Sort == 0 {
+			updateSortStr := ` sort + 1 `
+			_ = data_manage.UpdateSciHqClassifySortByParentId(parentClassifyId, firstClassify.ClassifyId-1, 0, updateSortStr)
+		}
+		classifyInfo.Sort = 0 //那就是排在第一位
+		classifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
 	}
-	classifyInfo.ModifyTime = time.Now()
-	updateCol = append(updateCol, "Sort", "ModifyTime")
+
 	err = classifyInfo.Update(updateCol)
 	if err != nil {
 		errMsg = "移动失败"

+ 17 - 0
services/data/excel/excel_op.go

@@ -222,6 +222,23 @@ func Copy(oldExcelInfo *excelModel.ExcelInfo, excelClassifyId int, excelName str
 			errMsg = "保存失败"
 		}
 
+		// 混合表格-条件格式配置
+		excelRules, e := excelModel.GetExcelRuleMappingsByExcelInfoId(oldExcelInfo.ExcelInfoId)
+		if e != nil {
+			err = fmt.Errorf("获取条件格式配置失败, %v", e)
+			return
+		}
+		if len(excelRules) > 0 {
+			for _, v := range excelRules {
+				v.ExcelInfoRuleMappingId = 0
+				v.ExcelInfoId = excelInfo.ExcelInfoId
+			}
+			mappingOb := new(excelModel.ExcelInfoRuleMapping)
+			if e = mappingOb.CreateMulti(excelRules); e != nil {
+				err = fmt.Errorf("复制条件格式配置失败, %v", e)
+				return
+			}
+		}
 		return
 	}
 

+ 1 - 0
services/elastic.go

@@ -102,6 +102,7 @@ func EsAddOrEditReport(indexName, docId string, item *models.ElasticReportDetail
 			"BodyContent":        item.BodyContent,
 			"PublishTime":        item.PublishTime,
 			"PublishState":       item.PublishState,
+			"IsPublicPublish":    item.IsPublicPublish,
 			"Author":             item.Author,
 			"ClassifyIdFirst":    item.ClassifyIdFirst,
 			"ClassifyNameFirst":  item.ClassifyNameFirst,

+ 1 - 0
services/eta_forum/eta_forum_hub.go

@@ -1062,6 +1062,7 @@ func getChartDescriptionWithAdminNameByChartInfoId(chartInfoId int) (list []*dat
 			adminName = ""
 		}
 		list = append(list, &data_manage.ChartDescriptionReq{
+			Id: v.Id,
 			ChartInfoId: v.ChartInfoId,
 			Description: v.Description,
 			AdminName:   adminName,

+ 15 - 15
services/excel/lucky_sheet.go

@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"os"
 	"reflect"
+	"regexp"
 	"strconv"
 	"strings"
 	"time"
@@ -824,13 +825,12 @@ func getExcelFontConf(cellInfo LuckySheetDataValue) xlsx.Font {
 		}
 		familyName = tmpFamilyName
 	}
-
 	return xlsx.Font{
 		Size: fontSize,
 		Name: familyName,
 		//Family: v2.FontFamily,
 		//Charset:   0,
-		Color:     strings.TrimPrefix(cellInfo.FontColor, "#"),
+		Color:     strings.TrimPrefix(getColor(cellInfo.FontColor), "#"),
 		Bold:      isBold,
 		Italic:    isItalic,
 		Underline: isUnderline,
@@ -1429,22 +1429,22 @@ func getExcelizeAlignmentConf(cellInfo LuckySheetDataValue) *excelize.Alignment
 
 // getColor 获取hex颜色
 func getColor(bgStr string) string {
-	if strings.Contains(bgStr, "(") {
-		arr := strings.Split(bgStr, ",")
-		if len(arr) != 3 {
+	isRgb := strings.HasPrefix(bgStr, "rgb")
+	re := regexp.MustCompile(`\(([^)]+)\)`)
+	matches := re.FindStringSubmatch(bgStr)
+	if len(matches) != 2 {
+		return bgStr
+	}
+	if isRgb {
+		arr := strings.Split(matches[1], ",")
+		if len(arr) < 3 {
 			return bgStr
 		}
-
-		// 第一位
-		tmpFirstArr := strings.Split(arr[0], "(")
-		arr[0] = tmpFirstArr[len(tmpFirstArr)-1]
-
-		// 最后一位
-		tmpLastArr := strings.Split(arr[2], ")")
-		arr[2] = tmpLastArr[0]
-
 		rgbArr := make([]int64, 0)
-		for _, v := range arr {
+		for i, v := range arr {
+			if i >= 3 {
+				continue
+			}
 			tmpInt, err := strconv.Atoi(utils.TrimStr(v))
 			if err != nil {
 				return bgStr

+ 44 - 4
services/llm/facade/llm_service.go

@@ -49,6 +49,10 @@ func LLMKnowledgeBaseSearchDocs(search LLMKnowledgeSearch) (resp bus_response.Se
 
 // AIGCBaseOnPromote aigc 生成内容
 func AIGCBaseOnPromote(aigc AIGC) (resp bus_response.AIGCEtaResponse, err error) {
+	param := make(map[string]interface{})
+	if aigc.LLMModel != "" {
+		param["LLM"] = aigc.LLMModel
+	}
 	mapping, queryErr := rag.GetArticleKbMapping(aigc.ArticleId, aigc.Source)
 	if queryErr != nil && !errors.Is(queryErr, gorm.ErrRecordNotFound) {
 		utils.FileLog.Error("获取文章知识库信息失败,err: %v", queryErr)
@@ -102,7 +106,7 @@ func AIGCBaseOnPromote(aigc AIGC) (resp bus_response.AIGCEtaResponse, err error)
 				utils.FileLog.Error("打开文件失败,err:", err)
 				return
 			}
-			uploadResp, httpErr := llmService.UploadFileToTemplate([]*os.File{file}, nil)
+			uploadResp, httpErr := llmService.UploadFileToTemplate([]*os.File{file}, param)
 			if httpErr != nil {
 				utils.FileLog.Error("上传文件失败,err:", err.Error())
 				err = fmt.Errorf("上传文件失败,err:%v", httpErr)
@@ -129,9 +133,9 @@ func AIGCBaseOnPromote(aigc AIGC) (resp bus_response.AIGCEtaResponse, err error)
 			kbId = mapping.KbId
 		}
 		//知识库对话
-		response, httpErr := llmService.FileChat(aigc.Promote, kbId, nil)
+		response, httpErr := llmService.FileChat(aigc.Promote, kbId, aigc.LLMModel, nil)
 		if httpErr != nil {
-			utils.FileLog.Error("内容生成失败,err:", err.Error())
+			utils.FileLog.Error("内容生成失败,err:", httpErr.Error())
 			err = fmt.Errorf("内容生成失败,err:%v", httpErr)
 			return
 		}
@@ -147,7 +151,42 @@ func AIGCBaseOnPromote(aigc AIGC) (resp bus_response.AIGCEtaResponse, err error)
 			return
 		}
 		if gcResp.Code == 404 {
-			response, httpErr = llmService.FileChat(aigc.Promote, kbId, nil)
+			param["PrevId"] = kbId
+			article, fileErr := rag.GetArticleById(aigc.ArticleId)
+			if fileErr != nil {
+				// 找不到就处理失败
+				utils.FileLog.Error("公众号文章不存在")
+				err = fmt.Errorf("公众号文章不存在")
+				return
+			}
+			if article.TextContent == "" {
+				utils.FileLog.Error("暂不支持纯文本以外的内容生成")
+				err = fmt.Errorf("暂不支持纯文本以外的内容生成")
+				return
+			}
+			// 文章加入到知识库
+			path, fileErr := localService.CreateArticleFile(article)
+			if fileErr != nil {
+				utils.FileLog.Error("创建文章文件失败,err: %v", fileErr)
+				err = fmt.Errorf("创建文章文件失败,err: %v", fileErr)
+				return
+			}
+			defer func() {
+				_ = os.Remove(path)
+			}()
+			file, err = os.Open(path)
+			if err != nil {
+				utils.FileLog.Error("打开文件失败,err:", err)
+				return
+			}
+			_, httpErr = llmService.UploadFileToTemplate([]*os.File{file}, param)
+			if httpErr != nil {
+				utils.FileLog.Error("上传文件失败,err:", err.Error())
+				err = fmt.Errorf("上传文件失败,err:%v", httpErr)
+				return
+			}
+
+			response, httpErr = llmService.FileChat(aigc.Promote, kbId, aigc.LLMModel, nil)
 			if httpErr != nil {
 				utils.FileLog.Error("内容生成失败,err:%v", httpErr.Error())
 				err = fmt.Errorf("内容生成失败,err:%v", httpErr)
@@ -183,6 +222,7 @@ type AIGC struct {
 	Promote   string
 	Source    int
 	ArticleId int
+	LLMModel  string
 }
 
 func dealFileChatResp(response eta_llm_http.BaseResponse) (httpResponse bus_response.FileChatBaseResponse, err error) {

+ 20 - 0
services/material/material.go

@@ -1,6 +1,7 @@
 package materialService
 
 import (
+	"encoding/json"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/data_manage/excel"
@@ -168,6 +169,25 @@ func AddToMaterial(req material.SaveAsMaterialReq, opUserId int, opUserName stri
 		return
 	}
 
+	// 兼容部分内网客户替换OSS地址
+	conf, e := models.GetBusinessConfByKey(models.BusinessConfOssUrlReplace)
+	if e != nil && !utils.IsErrNoRow(e) {
+		errMsg = "操作失败"
+		err = fmt.Errorf("获取内网配置失败, %v", e)
+		return
+	}
+	if conf != nil && conf.ConfVal != "" {
+		var urlReplace models.OssUrlReplace
+		if e := json.Unmarshal([]byte(conf.ConfVal), &urlReplace); e != nil {
+			errMsg = "操作失败"
+			err = fmt.Errorf("内网配置解析失败, %v", e)
+			return
+		}
+		if urlReplace.IsReplace && urlReplace.OssUrlOrigin != "" {
+			oldRsourceUrl = strings.ReplaceAll(oldRsourceUrl, urlReplace.OssUrlOrigin, urlReplace.OssUrlNew)
+		}
+	}
+
 	resourceUrl, err, errMsg := uploadToMaterial(oldRsourceUrl)
 	if err != nil {
 		return

+ 6 - 4
services/report.go

@@ -143,7 +143,7 @@ func UpdateReportEs(reportId int, publishState int) (err error) {
 		if len(chapterList) > 0 {
 			// 更新章节的es数据
 			for _, chapterInfo := range chapterList {
-				err = updateReportChapterEsByChapter(chapterInfo)
+				err = updateReportChapterEsByChapter(chapterInfo, reportInfo.IsPublicPublish)
 				if err != nil {
 					return
 				}
@@ -183,6 +183,7 @@ func UpdateReportEs(reportId int, publishState int) (err error) {
 		BodyContent:        utils.TrimHtml(html.UnescapeString(reportInfo.Content)),
 		PublishTime:        reportInfo.PublishTime.Format(utils.FormatDateTime),
 		PublishState:       publishState,
+		IsPublicPublish:    reportInfo.IsPublicPublish,
 		Author:             reportInfo.Author,
 		ClassifyIdFirst:    reportInfo.ClassifyIdFirst,
 		ClassifyNameFirst:  reportInfo.ClassifyNameFirst,
@@ -241,7 +242,7 @@ func addCategoryAliasToArr(categoryArr []string) (aliasArr []string, err error)
 // @datetime 2024-06-20 13:16:22
 // @param reportChapterId int
 // @return err error
-func UpdateReportChapterEs(reportChapterId int) (err error) {
+func UpdateReportChapterEs(reportChapterId int, isPublicPublish int8) (err error) {
 	if reportChapterId <= 0 {
 		return
 	}
@@ -250,7 +251,7 @@ func UpdateReportChapterEs(reportChapterId int) (err error) {
 		return
 	}
 
-	err = updateReportChapterEsByChapter(chapterInfo)
+	err = updateReportChapterEsByChapter(chapterInfo, isPublicPublish)
 	if err != nil {
 		return
 	}
@@ -264,7 +265,7 @@ func UpdateReportChapterEs(reportChapterId int) (err error) {
 // @datetime 2024-06-20 13:16:11
 // @param chapterInfo *models.ReportChapter
 // @return err error
-func updateReportChapterEsByChapter(chapterInfo *models.ReportChapter) (err error) {
+func updateReportChapterEsByChapter(chapterInfo *models.ReportChapter, isPublicPublish int8) (err error) {
 	// 章节对应的品种
 	obj := report.ReportChapterPermissionMapping{}
 	permissionList, tmpErr := obj.GetPermissionItemListById(chapterInfo.ReportChapterId)
@@ -289,6 +290,7 @@ func updateReportChapterEsByChapter(chapterInfo *models.ReportChapter) (err erro
 		BodyContent:        utils.TrimHtml(html.UnescapeString(chapterInfo.Content)),
 		PublishTime:        chapterInfo.PublishTime.Format(utils.FormatDateTime),
 		PublishState:       chapterInfo.PublishState,
+		IsPublicPublish:    isPublicPublish,
 		Author:             chapterInfo.Author,
 		ClassifyIdFirst:    chapterInfo.ClassifyIdFirst,
 		ClassifyNameFirst:  chapterInfo.ClassifyNameFirst,

+ 21 - 0
services/report_v2.go

@@ -144,6 +144,7 @@ func AddReportAndChapter(reportInfo *models.Report, inheritReportId int, grantAd
 // @return errMsg string
 func EditReport(reportInfo *models.Report, req models.EditReq, sysUser *system.Admin) (err error, errMsg string) {
 	errMsg = `保存失败`
+	oldIsPublicPublish := reportInfo.IsPublicPublish
 	//var stage int
 	//if reportInfo.ClassifyNameFirst != req.ClassifyNameFirst || reportInfo.ClassifyNameSecond != req.ClassifyNameSecond {
 	//	// 报告期数
@@ -278,6 +279,26 @@ func EditReport(reportInfo *models.Report, req models.EditReq, sysUser *system.A
 		go handleReportPermission(int64(reportInfo.Id), minClassifyId)
 	}
 
+	// 更新es里的章节数据
+	if oldIsPublicPublish != reportInfo.IsPublicPublish {
+		if reportInfo.HasChapter == 1 {
+			// 晨周报
+			chapterList, tmpErr := models.GetPublishedChapterListByReportId(reportInfo.Id)
+			if tmpErr != nil {
+				return
+			}
+			if len(chapterList) > 0 {
+				// 更新章节的es数据
+				for _, chapterInfo := range chapterList {
+					err = updateReportChapterEsByChapter(chapterInfo, reportInfo.IsPublicPublish)
+					if err != nil {
+						return
+					}
+				}
+			}
+		}
+	}
+
 	return
 }
 

+ 3 - 2
services/smart_report.go

@@ -152,7 +152,7 @@ async def main():
     page = await browser.newPage()
     await page.setViewport({
         'width': %d,
-        'height': 1080,
+        'height': 1697
     })
     await page.goto('%s', {
         'waitUntil': 'networkidle0',
@@ -164,6 +164,7 @@ async def main():
 
     await page.pdf({
 		'width': %d,
+        'height': 1697,
         'path': "%s",
         'printBackground': True,
         'margin': {
@@ -223,7 +224,7 @@ async def main():
         # 设置视口大小
         await page.setViewport({
             'width': %d,
-            'height': 1080
+            'height': 1697
         })
         
         # 导航到页面

+ 8 - 7
services/wechat_platform.go

@@ -271,7 +271,7 @@ func GenerateArticleAbstract(item *rag.WechatArticle) {
 
 	// 生成临时文件
 	dateDir := time.Now().Format("20060102")
-	uploadDir := utils.STATIC_DIR + "ai/" + dateDir
+	uploadDir := "./static/ai/" + dateDir
 	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())
@@ -382,7 +382,7 @@ func ReGenerateArticleAbstract(item *rag.WechatArticle) {
 
 	// 生成临时文件
 	dateDir := time.Now().Format("20060102")
-	uploadDir := utils.STATIC_DIR + "ai/" + dateDir
+	uploadDir := "./static/ai/" + dateDir
 	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())
@@ -610,14 +610,15 @@ func ArticleToKnowledge(item *rag.WechatArticle) {
 
 	// 生成临时文件
 	//dateDir := time.Now().Format("20060102")
-	//uploadDir := utils.STATIC_DIR + "ai/article/" + dateDir
-	uploadDir := utils.STATIC_DIR + "ai/article"
+	//uploadDir :=   "./static/ai/article/" + dateDir
+	uploadDir := "./static/ai/article"
 	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())
 		return
 	}
-	fileName := utils.RemoveSpecialChars(item.Title) + `.md`
+	//fileName := utils.RemoveSpecialChars(item.Title) + `.md`
+	fileName := utils.MD5(item.Title) + `.md`
 	tmpFilePath := uploadDir + "/" + fileName
 	err = utils.SaveToFile(item.TextContent, tmpFilePath)
 	if err != nil {
@@ -675,8 +676,8 @@ func AbstractToKnowledge(wechatArticleItem *rag.WechatArticle, abstractItem *rag
 
 	// 生成临时文件
 	//dateDir := time.Now().Format("20060102")
-	//uploadDir := utils.STATIC_DIR + "ai/article/" + dateDir
-	uploadDir := utils.STATIC_DIR + "ai/abstract"
+	//uploadDir :=  + "./static/ai/article/" + dateDir
+	uploadDir := "./static/ai/abstract"
 	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		err = fmt.Errorf("存储目录创建失败,Err:" + err.Error())

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
static/imgs/ai/article/【专题报告】关税来袭黑色怎么看.md


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
static/imgs/ai/article/【东海首席】黑色金属专题报告新一轮钢铁供给侧改革能否全面开启.md


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
static/imgs/ai/article/【开源宏观】财政支出力度如何12月财政数据点评.md


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
static/imgs/ai/article/巴菲特2025股东信1000字精华版来了附全文.md


+ 21 - 5
utils/llm/eta_llm/eta_llm_client.go

@@ -22,6 +22,10 @@ var (
 	dsOnce sync.Once
 
 	etaLlmClient *ETALLMClient
+	modelRouter  = map[string]string{
+		"deepseek-r1:32b": "/dsr1",
+		"qwq:32b":         "/qwq",
+	}
 )
 
 const (
@@ -59,7 +63,7 @@ func GetInstance() llm.LLMService {
 		}
 		if etaLlmClient == nil {
 			etaLlmClient = &ETALLMClient{
-				LLMClient: llm.NewLLMClient(config.LlmAddress, 120),
+				LLMClient: llm.NewLLMClient(config.LlmAddress, 300),
 				LlmModel:  config.LlmModel,
 			}
 		}
@@ -140,7 +144,7 @@ func (ds *ETALLMClient) KnowledgeBaseChat(query string, KnowledgeBaseName string
 	return ds.DoStreamPost(KNOWLEDGE_BASE_CHAT_API, body)
 }
 
-func (ds *ETALLMClient) FileChat(query string, KnowledgeId string, history []json.RawMessage) (resp eta_llm_http.BaseResponse, err error) {
+func (ds *ETALLMClient) FileChat(query string, KnowledgeId string, llmModel string, history []json.RawMessage) (resp eta_llm_http.BaseResponse, err error) {
 	ChatHistory := make([]eta_llm_http.HistoryContent, 0)
 	for _, historyItemStr := range history {
 		var historyItem eta_llm_http.HistoryContentWeb
@@ -153,8 +157,14 @@ func (ds *ETALLMClient) FileChat(query string, KnowledgeId string, history []jso
 			Role:    historyItem.Role,
 		})
 	}
+	var model string
+	if llmModel != "" {
+		model = llmModel
+	} else {
+		model = ds.LlmModel
+	}
 	kbReq := eta_llm_http.DocumentChatRequest{
-		ModelName:      ds.LlmModel,
+		ModelName:      model,
 		Query:          query,
 		KnowledgeId:    KnowledgeId,
 		History:        ChatHistory,
@@ -171,7 +181,7 @@ func (ds *ETALLMClient) FileChat(query string, KnowledgeId string, history []jso
 		err = fmt.Errorf("内容生成失败,序列化请求参数失败,err:%v", err)
 		return
 	}
-	return ds.DoPost(DOCUMENT_CHAT_API, body)
+	return ds.DoPost(fmt.Sprintf("%s%s", modelRouter[model], DOCUMENT_CHAT_API), body)
 }
 
 func (ds *ETALLMClient) UploadFileToTemplate(files []*os.File, param map[string]interface{}) (data interface{}, err error) {
@@ -179,6 +189,12 @@ func (ds *ETALLMClient) UploadFileToTemplate(files []*os.File, param map[string]
 	if value, ok := param["PrevId"]; ok {
 		pervId = value.(string)
 	}
+	var model string
+	if value, ok := param["LLM"]; ok {
+		model = value.(string)
+	} else {
+		model = ds.LlmModel
+	}
 	docReq := eta_llm_http.UploadTempDocsRequest{
 		ChunkOverlap:   "150",
 		ChunkSize:      "750",
@@ -189,7 +205,7 @@ func (ds *ETALLMClient) UploadFileToTemplate(files []*os.File, param map[string]
 	if err != nil {
 		return
 	}
-	resp, err := ds.DoFile(UPLOAD_TEMP_DOCS_API, body, files)
+	resp, err := ds.DoFile(fmt.Sprintf("%s%s", modelRouter[model], UPLOAD_TEMP_DOCS_API), body, files)
 	if !resp.Success {
 		err = errors.New(resp.Msg)
 		return

+ 1 - 1
utils/llm/llm_client.go

@@ -27,5 +27,5 @@ type LLMService interface {
 	DocumentChat(query string, KnowledgeId string, history []json.RawMessage, stream bool) (llmRes *http.Response, err error)
 	SearchKbDocs(query string, KnowledgeBaseName string) (data interface{}, err error)
 	UploadFileToTemplate(files []*os.File, param map[string]interface{}) (data interface{}, err error)
-	FileChat(query string, KnowledgeId string, history []json.RawMessage) (resp eta_llm_http.BaseResponse, err error)
+	FileChat(query string, KnowledgeId string, llmModel string, history []json.RawMessage) (resp eta_llm_http.BaseResponse, err error)
 }

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff