Explorar el Código

Merge branch 'master_nsh' into debug

# Conflicts:
#	utils/llm/eta_llm/eta_llm_client.go
#	utils/llm/eta_llm/eta_llm_http/request.go
xyxie hace 5 días
padre
commit
0e24b0b13d

+ 315 - 0
controllers/fe_calendar/fe_calendar_ai_article.go

@@ -0,0 +1,315 @@
+package fe_calendar
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/fe_calendar"
+	"eta/eta_api/services"
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+)
+
+// FeCalendarAiArticleController 外汇日历-AI数据点评数据点评
+type FeCalendarAiArticleController struct {
+	controllers.BaseAuthController
+}
+// Detail
+// @Title AI数据点评详情
+// @Description AI数据点评详情
+// @Param   FeCalendarAiArticleId  query  int  true  "数据点评ID"
+// @Success 200 {object} fe_calendar.FeCalendarAiArticle
+// @router /ai_article/detail [get]
+func (this *FeCalendarAiArticleController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	articleId, err := this.GetInt("FeCalendarAiArticleId")
+	if err != nil || articleId <= 0 {
+		br.Msg = "请提供有效的数据点评ID"
+		return
+	}
+
+	articleOb := new(fe_calendar.FeCalendarAiArticle)
+	if err := articleOb.GetByID(uint(articleId)); err != nil {
+		if utils.IsErrNoRow(err) {
+			br.Msg = "数据点评不存在"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取AI数据点评详情失败, ArticleId: %d, Err: %s", articleId, err.Error())
+		return
+	}
+
+	// 查询指标
+	edbInfo, err := data_manage.GetEdbInfoById(articleOb.EdbInfoId)
+	if err != nil {
+		if utils.IsErrNoRow(err) {
+			br.Msg = "指标不存在"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取指标失败, Err: " + err.Error()
+		return
+	}
+
+	data := &fe_calendar.FeCalendarAiArticleDetailResp{
+		FeCalendarAiArticleId: articleOb.FeCalendarAiArticleId,
+		EdbName: edbInfo.EdbName,
+		EdbInfoId: articleOb.EdbInfoId,
+		EdbCode: edbInfo.EdbCode,
+		Content: articleOb.Content,
+		ModifyTime: articleOb.ModifyTime.Format(utils.FormatDateTime),
+	}
+	br.Data = data
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Create
+// @Title 创建AI数据点评
+// @Description 创建AI数据点评
+// @Param   request	body fe_calendar.FeCalendarAiArticle true "type json string"
+// @Success 200 string "操作成功"
+// @router /ai_article/generate [post]
+func (this *FeCalendarAiArticleController) Generate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req *fe_calendar.FeCalendarAiArticleGenerateReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + err.Error()
+		return
+	}
+	if req.EdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	// 查询指标
+	edbInfo, err := data_manage.GetEdbInfoById(req.EdbInfoId)
+	if err != nil {
+		if utils.IsErrNoRow(err) {
+			br.Msg = "指标不存在"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取指标失败, Err: " + err.Error()
+		return
+	}
+	if req.EdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+
+	if req.MatterDate == "" {
+		br.Msg = "请选择日期"
+		return
+	}
+
+	// 获取当月的最后一天
+	matterDateTime, e := time.Parse(utils.FormatDate, req.MatterDate)
+	if e != nil {
+		br.Msg = "请选择正确的日期"
+		return
+	}
+    
+	data, err := services.GetFeCalendarAiArticle(req, matterDateTime, edbInfo, sysUser)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "保存AI数据点评失败, Err: " + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	br.Data = data
+}
+// Save
+// @Title 保存AI数据点评
+// @Description 保存AI数据点评
+// @Param   request	body fe_calendar.FeCalendarAiArticle true "type json string"
+// @Success 200 string "操作成功"
+// @router /ai_article/save [post]
+func (this *FeCalendarAiArticleController) Save() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req *fe_calendar.FeCalendarAiArticleSaveReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + err.Error()
+		return
+	}
+	if req.EdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	// 查询指标
+	edbInfo, err := data_manage.GetEdbInfoById(req.EdbInfoId)
+	if err != nil {
+		if utils.IsErrNoRow(err) {
+			br.Msg = "指标不存在"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取指标失败, Err: " + err.Error()
+		return
+	}
+	
+	// 参数校验
+	if req.ChartPermissionId <= 0 {
+		br.Msg = "请选择品种"
+		return
+	}
+
+	if req.MatterDate == "" {
+		br.Msg = "请选择日期"
+		return
+	}
+
+	if req.Content == "" {
+		br.Msg = "请输入内容"
+		return
+	}
+	feCalendarAiArticleId := req.FeCalendarAiArticleId
+    // 获取当月的最后一天
+	matterDateTime, e := time.Parse(utils.FormatDate, req.MatterDate)
+	if e != nil {
+		br.Msg = "请选择正确的日期"
+		return
+	}
+    
+	// 获取品种信息
+	permissionItem, err := models.GetChartPermissionById(req.ChartPermissionId)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取品种信息失败, Err: " + err.Error()
+		return
+	}
+
+	matterOb := new(fe_calendar.FeCalendarMatter)
+	if req.FeCalendarMatterId > 0 {
+	    matterItem, err := matterOb.GetItemById(req.FeCalendarMatterId)
+	    if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取事项失败, Err: " + err.Error()
+			return
+		}
+	    if matterItem.MatterType != fe_calendar.MatterTypePredict {
+		    br.Msg = "事项类型不匹配"
+			return
+		}
+	}
+
+	if req.FeCalendarAiArticleId <= 0 { // 创建数据点评
+		article := new(fe_calendar.FeCalendarAiArticle)
+		article.Title = edbInfo.EdbName
+		article.Content = req.Content
+		article.Prompt = ""
+		article.ChartPermissionId = req.ChartPermissionId
+		article.ChartPermissionName = permissionItem.PermissionName
+		article.EdbCode = edbInfo.EdbCode
+		article.EdbInfoId = edbInfo.EdbInfoId
+		article.MatterDate = req.MatterDate
+		article.MatterMonth = matterDateTime.Format("2006-01")
+		article.SysUserId = sysUser.AdminId
+		article.SysUserName = sysUser.RealName
+		err = article.Create()
+		if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "保存AI数据点评失败, Err: " + err.Error()
+			return
+		}
+		feCalendarAiArticleId = article.FeCalendarAiArticleId
+	}else{ // 更新数据点评
+		articleOb := new(fe_calendar.FeCalendarAiArticle)
+		if err := articleOb.GetByID(uint(req.FeCalendarAiArticleId)); err != nil {
+			if utils.IsErrNoRow(err) {
+				br.Msg = "数据点评不存在"
+				return
+			}
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取AI数据点评失败, Err: " + err.Error()
+			return
+		}
+		if articleOb.EdbInfoId != edbInfo.EdbInfoId {
+			br.Msg = "指标不匹配"
+			return
+		}
+		if articleOb.MatterDate != req.MatterDate {
+			br.Msg = "日期不匹配"
+			return
+		}
+		articleOb.Content = req.Content
+		articleOb.ModifyTime = time.Now()
+		err = articleOb.Update([]string{"content", "modify_time"})
+		if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新AI数据点评失败, Err: " + err.Error()
+			return
+		}
+	}
+	// 更新事项
+	if req.FeCalendarMatterId > 0 && matterOb != nil && matterOb.FeCalendarMatterId > 0 && matterOb.FeCalendarAiArticleId != feCalendarAiArticleId {
+		matterOb.FeCalendarAiArticleId = feCalendarAiArticleId
+		matterOb.ModifyTime = time.Now()
+		err = matterOb.Update([]string{"fe_calendar_ai_article_id", "modify_time"})
+		if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新事项失败, Err: " + err.Error()
+			return
+		}
+	}
+	data := &fe_calendar.FeCalendarAiArticleSaveResp{
+		FeCalendarAiArticleId: feCalendarAiArticleId,
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	br.Data = data
+} 
+
+

+ 2 - 1
controllers/fe_calendar/fe_calendar_matter.go

@@ -265,7 +265,7 @@ func (this *FeCalendarMatterController) Save() {
 	addMatters := make([]*fe_calendar.FeCalendarMatter, 0)
 	editMatters := make([]*fe_calendar.FeCalendarMatter, 0)
 	removeMatters := make([]*fe_calendar.FeCalendarMatter, 0)
-	updateCols := []string{fe_calendar.FeCalendarMatterCols.Title, fe_calendar.FeCalendarMatterCols.FontColor, fe_calendar.FeCalendarMatterCols.FillingColor, fe_calendar.FeCalendarMatterCols.FontBold, fe_calendar.FeCalendarMatterCols.Sort, fe_calendar.FeCalendarMatterCols.ChartPermissionName, fe_calendar.FeCalendarMatterCols.ModifyTime}
+	updateCols := []string{fe_calendar.FeCalendarMatterCols.Title, fe_calendar.FeCalendarMatterCols.FontColor, fe_calendar.FeCalendarMatterCols.FillingColor, fe_calendar.FeCalendarMatterCols.FontBold, fe_calendar.FeCalendarMatterCols.Sort, fe_calendar.FeCalendarMatterCols.ChartPermissionName, fe_calendar.FeCalendarMatterCols.FeCalendarAiArticleId, fe_calendar.FeCalendarMatterCols.ModifyTime}
 
 	editIds := make([]int, 0)
 	editMatterMap := make(map[int]*fe_calendar.FeCalendarMatterSaveItem)
@@ -312,6 +312,7 @@ func (this *FeCalendarMatterController) Save() {
 			v.FontBold = ed.FontBold
 			v.Sort = ed.Sort
 			v.ChartPermissionName = permissionItem.PermissionName
+			v.FeCalendarAiArticleId = ed.FeCalendarAiArticleId
 			v.ModifyTime = time.Now().Local()
 			editMatters = append(editMatters, v)
 		}

+ 1 - 0
models/business_conf.go

@@ -70,6 +70,7 @@ const (
 	BusinessConfIsOpenChartExpired           = "IsOpenChartExpired"               // 是否开启图表有效期鉴权/报告禁止复制
 	BusinessConfReportChartExpiredTime       = "ReportChartExpiredTime"           // 图表有效期鉴权时间,单位:分钟
 	BusinessConfOssUrlReplace                = "OssUrlReplace"                    // OSS地址替换-兼容内网客户用
+	BusinessConfFeCalendarAiArticlePromote   = "FeCalendarAiArticlePromote"       // 事件日历上创建数据点评的提示词
 )
 
 const (

+ 186 - 0
models/fe_calendar/fe_calendar_ai_article.go

@@ -0,0 +1,186 @@
+package fe_calendar
+
+import (
+	"eta/eta_api/global"
+	"eta/eta_api/utils"
+	"time"
+)
+
+// FeCalendarAiArticle 外汇日历-AI数据点评文章表
+type FeCalendarAiArticle struct {
+	FeCalendarAiArticleId int       `gorm:"column:fe_calendar_ai_article_id;primaryKey;autoIncrement"` // 文章ID
+	ChartPermissionId     int       `gorm:"column:chart_permission_id"`                                 // 品种ID
+	ChartPermissionName   string    `gorm:"column:chart_permission_name"`                                   // 品种名称
+	MatterMonth           string    `gorm:"column:matter_month"`                                               // 事项年月:格式2006-01
+	MatterDate           string `gorm:"column:matter_date"`                                                // 事项日期
+	Title                string    `gorm:"column:title"`                                                                   // 标题
+	EdbInfoId           int       `gorm:"column:edb_info_id"`                                                       // 指标ID
+	EdbCode             string    `gorm:"column:edb_code"`                                                             // 指标编码
+	SysUserId           int       `gorm:"column:sys_user_id"`                                                       // 创建人ID
+	SysUserName         string    `gorm:"column:sys_user_name"`                                                   // 创建人姓名
+	Prompt              string    `gorm:"column:prompt;type:text"`                                                        // 提示词内容
+	Content             string    `gorm:"column:content;type:text"`                                                      // 内容
+	CreateTime          time.Time `gorm:"column:create_time"`                                                       // 创建时间
+	ModifyTime          time.Time `gorm:"column:modify_time"`                                                       // 更新时间
+}
+
+// TableName 指定表名
+func (FeCalendarAiArticle) TableName() string {
+	return "fe_calendar_ai_article"
+} 
+
+// Create 创建文章
+func (f *FeCalendarAiArticle) Create() error {
+	now := time.Now()
+	f.CreateTime = now
+	f.ModifyTime = now
+	o := global.DbMap[utils.DbNameIndex]
+	return o.Create(f).Error
+}
+
+// Update 更新文章
+func (f *FeCalendarAiArticle) Update(cols []string) error {
+	now := time.Now()
+	f.ModifyTime = now
+	o := global.DbMap[utils.DbNameIndex]
+	return o.Model(f).Where("fe_calendar_ai_article_id = ?", f.FeCalendarAiArticleId).Select(cols).Updates(f).Error
+}
+
+// Delete 删除文章
+func (f *FeCalendarAiArticle) Delete() error {
+	o := global.DbMap[utils.DbNameIndex]
+	return o.Delete(f, "fe_calendar_ai_article_id = ?", f.FeCalendarAiArticleId).Error
+}
+
+// GetByID 根据ID获取文章
+func (f *FeCalendarAiArticle) GetByID(id uint) error {
+	o := global.DbMap[utils.DbNameIndex]
+	return o.Where("fe_calendar_ai_article_id = ?", id).First(f).Error
+}
+
+// QueryParams 查询参数结构体
+type QueryParams struct {
+	EdbInfoId        uint       // 指标ID
+	ChartPermissionId uint       // 品种权限ID
+	StartDate        *time.Time // 开始日期
+	EndDate          *time.Time // 结束日期
+	MatterMonth      string     // 事项月份
+	Page             int        // 页码
+	PageSize         int        // 每页数量
+}
+
+// QueryArticles 查询文章列表
+func (f *FeCalendarAiArticle) QueryArticles(params QueryParams) ([]FeCalendarAiArticle, int64, error) {
+	var articles []FeCalendarAiArticle
+	var total int64
+	o := global.DbMap[utils.DbNameIndex]
+	query := o.Model(&FeCalendarAiArticle{})
+
+	// 添加查询条件
+	if params.EdbInfoId > 0 {
+		query = query.Where("edb_info_id = ?", params.EdbInfoId)
+	}
+	if params.ChartPermissionId > 0 {
+		query = query.Where("chart_permission_id = ?", params.ChartPermissionId)
+	}
+	if params.MatterMonth != "" {
+		query = query.Where("matter_month = ?", params.MatterMonth)
+	}
+	if params.StartDate != nil {
+		query = query.Where("matter_date >= ?", params.StartDate)
+	}
+	if params.EndDate != nil {
+		query = query.Where("matter_date <= ?", params.EndDate)
+	}
+
+	// 获取总数
+	err := query.Count(&total).Error
+	if err != nil {
+		return nil, 0, err
+	}
+
+	// 分页查询
+	if params.Page > 0 && params.PageSize > 0 {
+		offset := (params.Page - 1) * params.PageSize
+		query = query.Offset(offset).Limit(params.PageSize)
+	}
+
+	// 按时间倒序排序
+	query = query.Order("matter_date DESC")
+
+	// 执行查询
+	err = query.Find(&articles).Error
+	if err != nil {
+		return nil, 0, err
+	}
+
+	return articles, total, nil
+}
+
+// GetByEdbInfoID 根据指标ID获取文章列表
+func (f *FeCalendarAiArticle) GetByEdbInfoID(edbInfoID uint) ([]FeCalendarAiArticle, error) {
+	var articles []FeCalendarAiArticle
+	o := global.DbMap[utils.DbNameIndex]
+	err := o.Where("edb_info_id = ?", edbInfoID).Order("matter_date DESC").Find(&articles).Error
+	return articles, err
+}
+
+// GetByChartPermissionID 根据品种权限ID获取文章列表
+func (f *FeCalendarAiArticle) GetByChartPermissionID(chartPermissionID uint) ([]FeCalendarAiArticle, error) {
+	var articles []FeCalendarAiArticle
+	o := global.DbMap[utils.DbNameIndex]
+	err := o.Where("chart_permission_id = ?", chartPermissionID).Order("matter_date DESC").Find(&articles).Error
+	return articles, err
+}
+
+// GetByDateRange 根据日期范围获取文章列表
+func (f *FeCalendarAiArticle) GetByDateRange(startDate, endDate time.Time) ([]FeCalendarAiArticle, error) {
+	var articles []FeCalendarAiArticle
+	o := global.DbMap[utils.DbNameIndex]
+	err := o.Where("matter_date BETWEEN ? AND ?", startDate, endDate).
+		Order("matter_date DESC").
+		Find(&articles).Error
+	return articles, err
+}
+
+// GetByMatterMonth 根据事项月份获取文章列表
+func (f *FeCalendarAiArticle) GetByMatterMonth(matterMonth string) ([]FeCalendarAiArticle, error) {
+	var articles []FeCalendarAiArticle
+	o := global.DbMap[utils.DbNameIndex]
+	err := o.Where("matter_month = ?", matterMonth).
+		Order("matter_date DESC").
+		Find(&articles).Error
+	return articles, err
+}
+
+type FeCalendarAiArticleGenerateReq struct {
+	MatterDate            string                 // 事项日期
+	EdbInfoId             int                      // 指标ID
+}
+
+type FeCalendarAiArticleGenerateResp struct {
+	Content               string    // 内容
+	ModifyTime            string // 修改时间
+}
+
+type FeCalendarAiArticleSaveReq struct {
+	FeCalendarAiArticleId int       // 文章ID
+	ChartPermissionId     int            // 品种ID
+	MatterDate            string                 // 事项日期
+	EdbInfoId             int                      // 指标ID
+	Content               string    // 内容
+	FeCalendarMatterId    int                      // 事项ID
+}
+
+type FeCalendarAiArticleSaveResp struct {
+	FeCalendarAiArticleId int       // 文章ID
+}
+
+type FeCalendarAiArticleDetailResp struct {
+	FeCalendarAiArticleId int       // 文章ID
+	EdbName               string    // 指标名称
+	EdbInfoId             int                      // 指标ID
+	EdbCode               string    // 指标编码
+	Content               string    // 内容
+	ModifyTime            string    // 修改时间
+}

+ 6 - 0
models/fe_calendar/fe_calendar_matter.go

@@ -34,6 +34,7 @@ type FeCalendarMatter struct {
 	SysUserName         string    `description:"创建人姓名"`
 	CreateTime          time.Time `description:"创建时间"`
 	ModifyTime          time.Time `description:"更新时间"`
+	FeCalendarAiArticleId int       `description:"生成的AI数据点评文章ID"`
 }
 
 var FeCalendarMatterCols = struct {
@@ -55,6 +56,7 @@ var FeCalendarMatterCols = struct {
 	SysUserName         string
 	CreateTime          string
 	ModifyTime          string
+	FeCalendarAiArticleId string
 }{
 	FeCalendarMatterId:  "fe_calendar_matter_id",
 	ChartPermissionId:   "chart_permission_id",
@@ -74,6 +76,7 @@ var FeCalendarMatterCols = struct {
 	SysUserName:         "sys_user_name",
 	CreateTime:          "create_time",
 	ModifyTime:          "modify_time",
+	FeCalendarAiArticleId: "fe_calendar_ai_article_id",
 }
 
 func (m *FeCalendarMatter) TableName() string {
@@ -192,6 +195,7 @@ type FeCalendarMatterItem struct {
 	FillingColor        string `description:"填充颜色"`
 	FontBold            int    `description:"字体加粗:0-否;1-是"`
 	Sort                int    `description:"排序"`
+	FeCalendarAiArticleId int    `description:"生成的AI数据点评文章ID"`
 }
 
 func FormatFeCalendarMatter2Item(origin *FeCalendarMatter) (item *FeCalendarMatterItem) {
@@ -212,6 +216,7 @@ func FormatFeCalendarMatter2Item(origin *FeCalendarMatter) (item *FeCalendarMatt
 	item.FillingColor = origin.FillingColor
 	item.FontBold = origin.FontBold
 	item.Sort = origin.Sort
+	item.FeCalendarAiArticleId = origin.FeCalendarAiArticleId
 	return
 }
 
@@ -246,6 +251,7 @@ type FeCalendarMatterSaveItem struct {
 	FillingColor       string `description:"填充颜色"`
 	FontBold           int    `description:"字体加粗:0-否;1-是"`
 	Sort               int    `description:"排序"`
+	FeCalendarAiArticleId int    `description:"生成的AI数据点评文章ID"`
 }
 
 func (m *FeCalendarMatter) Save(addMatters, editMatters, removeMatters []*FeCalendarMatter, updateCols []string) (err error) {

+ 27 - 0
routers/commentsRouter.go

@@ -8971,6 +8971,33 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarAiArticleController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarAiArticleController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/ai_article/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarAiArticleController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarAiArticleController"],
+        beego.ControllerComments{
+            Method: "Generate",
+            Router: `/ai_article/generate`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarAiArticleController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarAiArticleController"],
+        beego.ControllerComments{
+            Method: "Save",
+            Router: `/ai_article/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"],
         beego.ControllerComments{
             Method: "Detail",

+ 1 - 0
routers/router.go

@@ -420,6 +420,7 @@ func init() {
 		web.NSNamespace("/fe_calendar",
 			web.NSInclude(
 				&fe_calendar.FeCalendarMatterController{},
+				&fe_calendar.FeCalendarAiArticleController{},
 			),
 		),
 		web.NSNamespace("/message",

+ 174 - 0
services/feCalendar_ai.go

@@ -0,0 +1,174 @@
+package services
+
+import (
+	"errors"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/fe_calendar"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
+	"eta/eta_api/utils"
+	"eta/eta_api/utils/llm"
+	"eta/eta_api/utils/llm/eta_llm"
+	"fmt"
+	"net/http"
+	"time"
+)
+
+func GetFeCalendarAiArticle(req *fe_calendar.FeCalendarAiArticleGenerateReq, matterDateTime time.Time, edbInfo *data_manage.EdbInfo, sysUser *system.Admin) (ret *fe_calendar.FeCalendarAiArticleGenerateResp, err error) {
+	defer func() {
+		if err != nil {
+			utils.FileLog.Error(fmt.Sprintf("获取AI文章失败: %s", err.Error()))
+		}
+	}()
+	
+	
+	var endDate string
+	if edbInfo.EndDate <= req.MatterDate {
+		endDate = edbInfo.EndDate
+	}else{
+		month := matterDateTime.Month()
+		year := matterDateTime.Year()
+		endDate = time.Date(year, month+1, 1, 0, 0, 0, 0, matterDateTime.Location()).AddDate(0, 0, -1).Format(utils.FormatDate)
+	}
+	
+	classifyList, err, errMsg := data.GetFullClassifyByClassifyId(edbInfo.ClassifyId)
+	if err != nil {
+		err = errors.New(errMsg)
+		return
+	}
+
+	classifyName := ""
+	for _, v := range classifyList {
+		classifyName += v.ClassifyName + "/"
+	}
+	edbData := make([]*data_manage.EdbDataList, 0)
+	switch edbInfo.EdbInfoType {
+		case 0: //普通源指标
+			//dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDateReal, endDate)
+			// 获取指标数据
+	        edbData, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, "", endDate)
+			if err != nil {
+				err = errors.New("获取指标数据失败, Err: " + err.Error())
+				return
+			}
+			
+		case 1: //预测指标
+			edbData, _, _, err, _ = data.GetPredictDataListByPredictEdbInfo(edbInfo, "", endDate, true)
+			if err != nil {
+				err = errors.New("获取预测指标数据失败, Err: " + err.Error())
+				return
+			}
+			
+	}
+	if len(edbData) == 0 {
+		err = errors.New("指标数据为空")
+		return
+	}
+
+	dataStr := "日期 值\n"
+	for _, v := range edbData {
+		dataStr += fmt.Sprintf("%s %f.8\n", v.DataTime, v.Value)
+	}
+
+	endDate = edbData[len(edbData) - 1].DataTime
+
+	// 获取提示词内容
+	promote := models.BusinessConfMap[models.BusinessConfFeCalendarAiArticlePromote]
+	
+    // 调用大模型的接口
+	edbName := edbInfo.EdbName
+	frequency := edbInfo.Frequency
+	startDate := edbInfo.StartDate
+	sourceName := edbInfo.SourceName
+	
+	
+	llmService, _ := llm.GetInstance(llm.ETA_LLM_CLIENT)
+	promote = fmt.Sprintf(promote, edbName, frequency, startDate, endDate, sourceName, dataStr, classifyName)
+	resp, err := llmService.CompletionChat(promote, nil)
+	if err != nil {
+		err = errors.New("获取AI文章失败, Err: " + err.Error())
+		return
+	}
+
+	defer func() {
+		if resp != nil && resp.Body != nil && err == nil {
+			_ = resp.Body.Close()
+		}
+	}()
+	if resp == nil {
+		err = errors.New("知识库问答失败: 无应答")
+		return
+	}
+	if err != nil {
+		err = errors.New(fmt.Sprintf("知识库问答失败: httpCode:%d,错误信息:%s", resp.StatusCode, http.StatusText(resp.StatusCode)))
+		return
+	}
+
+	if resp.StatusCode != http.StatusOK {
+		utils.FileLog.Error(fmt.Sprintf("知识库问答失败: httpCode:%d,错误信息:%s", resp.StatusCode, http.StatusText(resp.StatusCode)))
+		err = errors.New(fmt.Sprintf("知识库问答失败: httpCode:%d,错误信息:%s", resp.StatusCode, http.StatusText(resp.StatusCode)))
+		return
+	}
+
+	text := ""
+
+	// 解析流式响应
+	contentChan, errChan, closeChan, _ := eta_llm.ParseStreamResponse(resp)
+	for {
+		select {
+		case content, ok := <-contentChan:
+			if !ok {
+				err = errors.New("未知的内容错误异常")
+				// 标记llm提问状态:未提问
+				return nil, err
+			}
+			text += content
+		case chanErr, ok := <-errChan:
+			if !ok {
+				err = errors.New("未知的错误异常")
+			} else if chanErr != nil {
+				err = errors.New(chanErr.Error())
+			}
+			// 标记llm提问状态:未提问
+			return nil, err
+		case <-closeChan:
+			goto LOOP_END
+		}
+	}
+LOOP_END:
+   
+	// 获取品种信息
+	// permissionItem, err := models.GetChartPermissionById(req.ChartPermissionId)
+	// if err != nil {
+	// 	err = errors.New("获取品种信息失败, Err: " + err.Error())
+	// 	return
+	// }
+
+	// article := new(fe_calendar.FeCalendarAiArticle)
+	// article.Title = edbInfo.EdbName
+	// article.Content = text
+	// article.Prompt = promote
+	// article.ChartPermissionId = req.ChartPermissionId
+	// article.ChartPermissionName = permissionItem.PermissionName
+	// article.EdbCode = edbInfo.EdbCode
+	// article.EdbInfoId = edbInfo.EdbInfoId
+	// article.MatterDate = req.MatterDate
+	// article.MatterMonth = req.MatterDate
+	// article.SysUserId = sysUser.AdminId
+	// article.SysUserName = sysUser.RealName
+
+	// // 设置月份
+	// article.MatterMonth = matterDateTime.Format("2006-01")
+
+	// err = article.Create()
+	// if err != nil {
+	// 	err = errors.New("保存AI文章失败, Err: " + err.Error())
+	// 	return
+	// }
+	ret = &fe_calendar.FeCalendarAiArticleGenerateResp{
+		Content:               text,
+		ModifyTime:            time.Now().Format(utils.FormatDateTime),
+	}
+	return ret, nil
+}

+ 1 - 0
utils/llm/eta_llm/eta_llm_client.go

@@ -35,6 +35,7 @@ const (
 	KNOWLEDGE_BASE_CHAT_API        = "/chat/kb_chat"
 	COMPLETION_CHAT_API            = "/chat/chat/completions"
 	DOCUMENT_CHAT_API              = "/chat/file_chat"
+	COMPLETION_CHAT_API            = "/chat/chat/completions"
 	KNOWLEDGE_BASE_SEARCH_DOCS_API = "/knowledge_base/search_docs"
 	UPLOAD_TEMP_DOCS_API           = "/knowledge_base/upload_temp_docs"
 )

+ 11 - 11
utils/llm/eta_llm/eta_llm_http/request.go

@@ -51,15 +51,15 @@ type UploadTempDocsRequest struct {
 }
 
 type CompletionChatRequest struct {
-	Mode           string           `json:"mode"`
-	KbName         string           `json:"kb_name"`
-	TopK           int              `json:"top_k"`
-	ScoreThreshold float32          `json:"score_threshold"`
-	Messages        []HistoryContent `json:"messages"`
-	Stream         bool             `json:"stream"`
-	Model          string           `json:"model"`
-	Temperature    float32          `json:"temperature"`
-	MaxTokens      int              `json:"max_tokens"`
-	PromptName     string           `json:"prompt_name"`
-	ReturnDirect   bool             `json:"return_direct"`
+    Mode           string           `json:"mode"`
+    KbName         string           `json:"kb_name"`
+    TopK           int              `json:"top_k"`
+    ScoreThreshold float32          `json:"score_threshold"`
+    Messages        []HistoryContent `json:"messages"`
+    Stream         bool             `json:"stream"`
+    Model          string           `json:"model"`
+    Temperature    float32          `json:"temperature"`
+    MaxTokens      int              `json:"max_tokens"`
+    PromptName     string           `json:"prompt_name"`
+    ReturnDirect   bool             `json:"return_direct"`
 }