فهرست منبع

Merge branch 'eta/2.6.4' into debug

# Conflicts:
#	routers/router.go
Roc 2 هفته پیش
والد
کامیت
097ff80166

+ 67 - 0
controllers/data_manage/ai_predict_model/index.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	aiPredictModel "eta/eta_api/models/ai_predict_model"
+	"eta/eta_api/models/ai_predict_model/request"
 	"eta/eta_api/models/data_manage"
 	dataSourceModel "eta/eta_api/models/data_source"
 	"eta/eta_api/models/system"
@@ -1130,3 +1131,69 @@ func (this *AiPredictModelIndexController) SearchByEs() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// ScriptPathSave
+// @Title 保存标的关联脚本路径
+// @Description 保存标的关联脚本路径
+// @Param	request	body request.AiPredictModelIndexSaveScriptPathReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /index/script_path/save [post]
+func (this *AiPredictModelIndexController) ScriptPathSave() {
+	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 request.AiPredictModelIndexSaveScriptPathReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常"
+		br.ErrMsg = fmt.Sprintf("参数解析异常, %v", e)
+		return
+	}
+	if req.IndexId < 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("标的ID有误, IndexId: %d", req.IndexId)
+		return
+	}
+	req.ScriptPath = strings.TrimSpace(req.ScriptPath)
+	if req.ScriptPath == "" {
+		br.Msg = "标的路径不能为空"
+		br.ErrMsg = fmt.Sprintf("标的路径有误, ScriptPath: %s", req.ScriptPath)
+		return
+	}
+
+	indexOb := new(aiPredictModel.AiPredictModelIndex)
+	indexItem, e := indexOb.GetItemById(req.IndexId)
+	if e != nil {
+		if utils.IsErrNoRow(e) {
+			br.Msg = "标的已被删除,请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = fmt.Sprintf("获取标的失败, %v", e)
+		return
+	}
+
+	indexItem.ScriptPath = req.ScriptPath
+	indexItem.ModifyTime = time.Now()
+	updateCols := []string{indexOb.Cols().ScriptPath, indexOb.Cols().ModifyTime}
+	if e = indexItem.Update(updateCols); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = fmt.Sprintf("保存标的失败, %v", e)
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "操作成功"
+	br.Success = true
+}

+ 512 - 0
controllers/data_manage/ai_predict_model/index_config.go

@@ -0,0 +1,512 @@
+package ai_predict_model
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	data_manage "eta/eta_api/models/ai_predict_model"
+	"eta/eta_api/models/ai_predict_model/request"
+	"eta/eta_api/models/ai_predict_model/response"
+	"eta/eta_api/services"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+// AiPredictModelIndexConfigController AI预测模型标的配置项
+type AiPredictModelIndexConfigController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 列表
+// @Description 列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   AiPredictModelIndexId   query   int  true       "标的id"
+// @Success 200 {object} []*data_manage.AiPredictModelIndexConfigView
+// @router /index_config/list [get]
+func (c *AiPredictModelIndexConfigController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		return
+	}
+	pageSize, _ := c.GetInt("PageSize")
+	currentIndex, _ := c.GetInt("CurrentIndex")
+	indexId, _ := c.GetInt("AiPredictModelIndexId")
+
+	if indexId <= 0 {
+		br.Msg = "标的id不能为空"
+		br.ErrMsg = "标的id不能为空"
+		return
+	}
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	var total int
+	viewList := make([]data_manage.AiPredictModelIndexConfigView, 0)
+
+	var condition string
+	var pars []interface{}
+
+	condition += fmt.Sprintf(` AND %s = ? `, data_manage.AiPredictModelIndexConfigColumns.AiPredictModelIndexId)
+	pars = append(pars, indexId)
+
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	tmpTotal, list, err := obj.GetPageListByCondition(condition, pars, startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	total = tmpTotal
+
+	if list != nil && len(list) > 0 {
+		viewList = list[0].ListToViewList(list)
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := response.AiPredictModelIndexConfigListResp{
+		List:   viewList,
+		Paging: page,
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// CurrVersion
+// @Title 获取当前版本参数信息
+// @Description 获取当前版本参数信息
+// @Param   IndexId   query   int   true   "标的ID"
+// @Success 200 {object} []*data_manage.AiPredictModelIndexConfigView
+// @router /index_config/version/curr [get]
+func (c *AiPredictModelIndexConfigController) CurrVersion() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		return
+	}
+	indexId, _ := c.GetInt("IndexId")
+	if indexId <= 0 {
+		br.Msg = "标的id不能为空"
+		br.ErrMsg = "标的id不能为空"
+		return
+	}
+
+	// 查询标的情况
+	indexOb := new(data_manage.AiPredictModelIndex)
+	indexItem, e := indexOb.GetItemById(indexId)
+	if e != nil {
+		if utils.IsErrNoRow(e) {
+			br.Msg = "标的已被删除,请刷新页面"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取标的失败, %v", e)
+		return
+	}
+
+	if indexItem.AiPredictModelIndexConfigId <= 0 {
+		br.Msg = "标的默认配置为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	configItem, err := obj.GetById(indexItem.AiPredictModelIndexConfigId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	br.Data = configItem.ToView()
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// SetCurr
+// @Title 设置为当前版本
+// @Description 设置为当前版本
+// @Param	request	body request.DelConfigReq true "type json string"
+// @Success 200 Ret=200 设置成功
+// @router /index_config/version/set_curr [post]
+func (c *AiPredictModelIndexConfigController) SetCurr() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		return
+	}
+
+	var req request.DelConfigReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	// 查找配置
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	configItem, err := obj.GetById(req.AiPredictModelIndexConfigId)
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改失败,查找配置失败,Err:" + err.Error()
+		if utils.IsErrNoRow(err) {
+			br.Msg = "配置不存在"
+			br.IsSendEmail = false
+		}
+		return
+	}
+
+	// 查询标的情况
+	indexOb := new(data_manage.AiPredictModelIndex)
+	indexItem, e := indexOb.GetItemById(configItem.AiPredictModelIndexId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = fmt.Sprintf("获取失败,根据配置ID获取标的信息失败, %v", e)
+		return
+	}
+
+	indexItem.AiPredictModelIndexConfigId = configItem.AiPredictModelIndexConfigId
+	indexItem.ModifyTime = time.Now()
+	err = indexItem.Update([]string{indexOb.Cols().ModifyTime, indexOb.Cols().AiPredictModelIndexConfigId})
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = fmt.Sprintf("配置失败,Err:%v", e)
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Del
+// @Title 删除模型配置
+// @Description 删除模型配置
+// @Param	request	body request.DelConfigReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /index_config/del [post]
+func (c *AiPredictModelIndexConfigController) Del() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.DelConfigReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.AiPredictModelIndexConfigId <= 0 {
+		br.Msg = "配置id不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 查找配置
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	item, err := obj.GetById(req.AiPredictModelIndexConfigId)
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改失败,查找配置失败,Err:" + err.Error()
+		if utils.IsErrNoRow(err) {
+			br.Msg = "配置不存在"
+			br.IsSendEmail = false
+		}
+		return
+	}
+
+	// 查找是否被标的引用为默认模型
+	{
+		// 查询标的情况
+		indexOb := new(data_manage.AiPredictModelIndex)
+		count, e := indexOb.GetCountByCondition(fmt.Sprintf(` AND %s = ? `, indexOb.Cols().AiPredictModelIndexConfigId), []interface{}{item.AiPredictModelIndexConfigId})
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = fmt.Sprintf("删除失败,根据配置ID获取标的信息失败, %v", e)
+			return
+		}
+
+		if count > 0 {
+			br.Msg = "删除失败,该版本配置正在被使用"
+			br.IsSendEmail = false
+			return
+		}
+	}
+
+	if !utils.InArrayByStr([]string{data_manage.TrainStatusSuccess, data_manage.TrainStatusFailed}, item.TrainStatus) {
+		br.Msg = "删除失败,该版本配置正在训练中"
+		br.IsSendEmail = false
+		return
+	}
+
+	item.IsDeleted = 1
+	item.ModifyTime = time.Now()
+	err = item.Update([]string{"IsDeleted", "ModifyTime"})
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = `删除成功`
+}
+
+// ChartDetail
+// @Title 获取当前版本的图表信息
+// @Description 获取当前版本的图表信息
+// @Param   AiPredictModelIndexConfigId   query   int   true   "标的配置ID"
+// @Success 200 {object} []*data_manage.AiPredictModelIndexConfigView
+// @router /index_config/chart/detail [get]
+func (c *AiPredictModelIndexConfigController) ChartDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		return
+	}
+	indexConfigId, _ := c.GetInt("AiPredictModelIndexConfigId")
+	if indexConfigId <= 0 {
+		br.Msg = "标的配置id不能为空"
+		br.ErrMsg = "标的配置id不能为空"
+		return
+	}
+
+	resp := response.AiPredictModelDetailResp{}
+
+	// TODO 后面加上数据缓存
+
+	// 查找配置
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	configItem, err := obj.GetById(indexConfigId)
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改失败,查找配置失败,Err:" + err.Error()
+		if utils.IsErrNoRow(err) {
+			br.Msg = "配置不存在"
+			br.IsSendEmail = false
+		}
+		return
+	}
+
+	// 查找是否被标的引用为默认模型
+	// 查询标的情况
+	indexOb := new(data_manage.AiPredictModelIndex)
+	indexItem, e := indexOb.GetItemByConfigId(configItem.AiPredictModelIndexConfigId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取失败,根据配置ID获取标的信息失败, %v", e)
+		return
+	}
+
+	// 获取标的数据
+	dailyData := make([]*data_manage.AiPredictModelIndexConfigTrainData, 0)
+	{
+		dataOb := new(data_manage.AiPredictModelIndexConfigTrainData)
+		dataCond := fmt.Sprintf(` AND %s = ?`, data_manage.AiPredictModelIndexConfigTrainDataColumns.AiPredictModelIndexConfigId)
+		dataPars := make([]interface{}, 0)
+		dataPars = append(dataPars, configItem.AiPredictModelIndexConfigId)
+		list, e := dataOb.GetAllListByCondition(dataCond, dataPars, []string{}, fmt.Sprintf("%s DESC", data_manage.AiPredictModelIndexConfigTrainDataColumns.DataTime))
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprintf("获取标的数据失败, %v", e)
+			return
+		}
+
+		for _, v := range list {
+			// 日度数据
+			if v.Source == data_manage.ModelDataSourceDaily {
+				dailyData = append(dailyData, v)
+				continue
+			}
+		}
+	}
+
+	// 日度图表
+	if len(dailyData) > 0 {
+		dailyChartDetail, e := services.GetAiPredictConfigChartDetailByData(indexItem.IndexName, configItem, dailyData, data_manage.ModelDataSourceDaily)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprintf("获取日度图表失败, %v", e)
+			return
+		}
+		resp.DailyChartView = dailyChartDetail
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Train
+// @Title 训练模型
+// @Description 训练模型
+// @Param	request	body request.TrainReq true "type json string"
+// @Success 200 Ret=200 训练中
+// @router /index_config/train [post]
+func (c *AiPredictModelIndexConfigController) Train() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.TrainReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.AiPredictModelIndexId <= 0 {
+		br.Msg = "标的id不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	paramsStrByte, err := json.Marshal(req.Params)
+	if err != nil {
+		br.Msg = "训练失败!"
+		br.ErrMsg = "训练失败,参数转json失败,Err:" + err.Error()
+		return
+	}
+
+	// 查询标的情况
+	indexOb := new(data_manage.AiPredictModelIndex)
+	indexItem, err := indexOb.GetItemById(req.AiPredictModelIndexId)
+	if err != nil {
+		br.Msg = "训练失败,查找标的失败"
+		br.ErrMsg = fmt.Sprintf("训练失败,查找标的失败, %v", err)
+		if utils.IsErrNoRow(err) {
+			br.Msg = "标的不存在"
+			br.IsSendEmail = false
+		}
+		return
+	}
+	if indexItem.ScriptPath == `` {
+		br.Msg = "训练失败,脚本路径不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	obj := new(data_manage.AiPredictModelIndexConfig)
+
+	// 查找当前标的是否存在待训练/训练中的模型
+	count, err := obj.GetCountByCondition(fmt.Sprintf(` AND %s = ? AND %s IN (?,?)`, data_manage.AiPredictModelIndexConfigColumns.AiPredictModelIndexId, data_manage.AiPredictModelIndexConfigColumns.TrainStatus), []interface{}{indexItem.AiPredictModelIndexId, data_manage.TrainStatusWaiting, data_manage.TrainStatusTraining})
+	if err != nil {
+		br.Msg = "训练失败"
+		br.ErrMsg = "训练失败,查找待训练的模型失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "该标的存在待训练/训练中的模型,不允许重复训练"
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.AiPredictModelIndexConfigId > 0 {
+		// 查找配置
+		item, err := obj.GetById(req.AiPredictModelIndexConfigId)
+		if err != nil {
+			br.Msg = "训练失败"
+			br.ErrMsg = "训练失败,查找配置失败,Err:" + err.Error()
+			if utils.IsErrNoRow(err) {
+				br.Msg = "配置不存在"
+				br.IsSendEmail = false
+			}
+			return
+		}
+
+		if item.AiPredictModelIndexId != indexItem.AiPredictModelIndexId {
+			br.Msg = "训练失败"
+			br.ErrMsg = "训练失败,配置与标的不匹配"
+			return
+		}
+
+		if item.TrainStatus != data_manage.TrainStatusFailed {
+			br.Msg = "该模型训练状态异常,不允许重新训练"
+			br.ErrMsg = "该模型训练状态异常,不允许重新训练,当前状态:" + item.TrainStatus
+			br.IsSendEmail = false
+			return
+		}
+		item.Params = string(paramsStrByte)
+		item.ModifyTime = time.Now()
+		err = item.Update([]string{"params", "modify_time"})
+		if err != nil {
+			br.Msg = "训练失败"
+			br.ErrMsg = "训练失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		// 新增训练模型
+		item := &data_manage.AiPredictModelIndexConfig{
+			AiPredictModelIndexConfigId: 0,
+			AiPredictModelIndexId:       indexItem.AiPredictModelIndexId,
+			TrainStatus:                 data_manage.TrainStatusWaiting,
+			Params:                      string(paramsStrByte),
+			TrainMse:                    "",
+			TrainR2:                     "",
+			TestMse:                     "",
+			TestR2:                      "",
+			Remark:                      "",
+			IsDeleted:                   0,
+			LeftMin:                     "",
+			LeftMax:                     "",
+			ModifyTime:                  time.Now(),
+			CreateTime:                  time.Now(),
+		}
+		err = item.Create()
+		if err != nil {
+			br.Msg = "训练失败"
+			br.ErrMsg = "训练失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	// TODO 加入训练任务中
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = `训练中`
+}

+ 108 - 80
models/ai_predict_model/ai_predict_model_index.go

@@ -13,24 +13,26 @@ import (
 
 // AiPredictModelIndex AI预测模型标的
 type AiPredictModelIndex struct {
-	AiPredictModelIndexId int       `orm:"column(ai_predict_model_index_id);pk" gorm:"primaryKey"`
-	IndexName             string    `description:"标的名称"`
-	IndexCode             string    `description:"自生成的指标编码"`
-	ClassifyId            int       `description:"分类ID"`
-	ModelFramework        string    `description:"模型框架"`
-	PredictDate           time.Time `description:"预测日期"`
-	PredictValue          float64   `description:"预测值"`
-	PredictFrequency      string    `description:"预测频度"`
-	DirectionAccuracy     string    `description:"方向准确度"`
-	AbsoluteDeviation     string    `description:"绝对偏差"`
-	ExtraConfig           string    `description:"模型参数"`
-	Sort                  int       `description:"排序"`
-	SysUserId             int       `description:"创建人ID"`
-	SysUserRealName       string    `description:"创建人姓名"`
-	LeftMin               string    `description:"图表左侧最小值"`
-	LeftMax               string    `description:"图表左侧最大值"`
-	CreateTime            time.Time `description:"创建时间"`
-	ModifyTime            time.Time `description:"修改时间"`
+	AiPredictModelIndexId       int       `orm:"column(ai_predict_model_index_id);pk" gorm:"primaryKey"`
+	IndexName                   string    `description:"标的名称"`
+	IndexCode                   string    `description:"自生成的指标编码"`
+	ClassifyId                  int       `description:"分类ID"`
+	ModelFramework              string    `description:"模型框架"`
+	PredictDate                 time.Time `description:"预测日期"`
+	PredictValue                float64   `description:"预测值"`
+	PredictFrequency            string    `description:"预测频度"`
+	DirectionAccuracy           string    `description:"方向准确度"`
+	AbsoluteDeviation           string    `description:"绝对偏差"`
+	ExtraConfig                 string    `description:"模型参数"`
+	Sort                        int       `description:"排序"`
+	SysUserId                   int       `description:"创建人ID"`
+	SysUserRealName             string    `description:"创建人姓名"`
+	LeftMin                     string    `description:"图表左侧最小值"`
+	LeftMax                     string    `description:"图表左侧最大值"`
+	CreateTime                  time.Time `description:"创建时间"`
+	ModifyTime                  time.Time `description:"修改时间"`
+	AiPredictModelIndexConfigId int       `gorm:"column:ai_predict_model_index_config_id" description:"标的当前的配置id"`
+	ScriptPath                  string    `gorm:"column:script_path" description:"脚本的路径"`
 }
 
 func (m *AiPredictModelIndex) TableName() string {
@@ -38,44 +40,48 @@ func (m *AiPredictModelIndex) TableName() string {
 }
 
 type AiPredictModelIndexCols struct {
-	PrimaryId         string
-	IndexName         string
-	IndexCode         string
-	ClassifyId        string
-	ModelFramework    string
-	PredictDate       string
-	PredictValue      string
-	DirectionAccuracy string
-	AbsoluteDeviation string
-	ExtraConfig       string
-	Sort              string
-	SysUserId         string
-	SysUserRealName   string
-	LeftMin           string
-	LeftMax           string
-	CreateTime        string
-	ModifyTime        string
+	PrimaryId                   string
+	IndexName                   string
+	IndexCode                   string
+	ClassifyId                  string
+	ModelFramework              string
+	PredictDate                 string
+	PredictValue                string
+	DirectionAccuracy           string
+	AbsoluteDeviation           string
+	ExtraConfig                 string
+	Sort                        string
+	SysUserId                   string
+	SysUserRealName             string
+	LeftMin                     string
+	LeftMax                     string
+	CreateTime                  string
+	ModifyTime                  string
+	AiPredictModelIndexConfigId string
+	ScriptPath                  string
 }
 
 func (m *AiPredictModelIndex) Cols() AiPredictModelIndexCols {
 	return AiPredictModelIndexCols{
-		PrimaryId:         "ai_predict_model_index_id",
-		IndexName:         "index_name",
-		IndexCode:         "index_code",
-		ClassifyId:        "classify_id",
-		ModelFramework:    "model_framework",
-		PredictDate:       "predict_date",
-		PredictValue:      "predict_value",
-		DirectionAccuracy: "direction_accuracy",
-		AbsoluteDeviation: "absolute_deviation",
-		ExtraConfig:       "extra_config",
-		Sort:              "sort",
-		SysUserId:         "sys_user_id",
-		SysUserRealName:   "sys_user_real_name",
-		LeftMin:           "left_min",
-		LeftMax:           "left_max",
-		CreateTime:        "create_time",
-		ModifyTime:        "modify_time",
+		PrimaryId:                   "ai_predict_model_index_id",
+		IndexName:                   "index_name",
+		IndexCode:                   "index_code",
+		ClassifyId:                  "classify_id",
+		ModelFramework:              "model_framework",
+		PredictDate:                 "predict_date",
+		PredictValue:                "predict_value",
+		DirectionAccuracy:           "direction_accuracy",
+		AbsoluteDeviation:           "absolute_deviation",
+		ExtraConfig:                 "extra_config",
+		Sort:                        "sort",
+		SysUserId:                   "sys_user_id",
+		SysUserRealName:             "sys_user_real_name",
+		LeftMin:                     "left_min",
+		LeftMax:                     "left_max",
+		CreateTime:                  "create_time",
+		ModifyTime:                  "modify_time",
+		AiPredictModelIndexConfigId: "ai_predict_model_index_config_id",
+		ScriptPath:                  "script_path",
 	}
 }
 
@@ -134,6 +140,21 @@ func (m *AiPredictModelIndex) GetItemById(id int) (item *AiPredictModelIndex, er
 	return
 }
 
+// GetItemByConfigId
+// @Description: 根据配置id获取标的信息
+// @author: Roc
+// @receiver m
+// @datetime 2025-05-06 13:31:24
+// @param configId int
+// @return item *AiPredictModelIndex
+// @return err error
+func (m *AiPredictModelIndex) GetItemByConfigId(configId int) (item *AiPredictModelIndex, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().AiPredictModelIndexConfigId)
+	err = o.Raw(sql, configId).First(&item).Error
+	return
+}
+
 func (m *AiPredictModelIndex) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *AiPredictModelIndex, err error) {
 	o := global.DbMap[utils.DbNameIndex]
 	order := ``
@@ -185,23 +206,25 @@ func (m *AiPredictModelIndex) GetPageItemsByCondition(condition string, pars []i
 
 // AiPredictModelIndexItem AI预测模型标的信息
 type AiPredictModelIndexItem struct {
-	IndexId           int     `description:"标的ID"`
-	IndexName         string  `description:"标的名称"`
-	IndexCode         string  `description:"自生成的指标编码"`
-	ClassifyId        int     `description:"分类ID"`
-	ClassifyName      string  `description:"分类名称"`
-	ModelFramework    string  `description:"模型框架"`
-	PredictDate       string  `description:"预测日期"`
-	PredictValue      float64 `description:"预测值"`
-	PredictFrequency  string  `description:"预测频度"`
-	DirectionAccuracy string  `description:"方向准确度"`
-	AbsoluteDeviation string  `description:"绝对偏差"`
-	ExtraConfig       string  `description:"模型参数"`
-	SysUserId         int     `description:"创建人ID"`
-	SysUserRealName   string  `description:"创建人姓名"`
-	CreateTime        string  `description:"创建时间"`
-	ModifyTime        string  `description:"修改时间"`
-	SearchText        string  `description:"搜索结果(含高亮)"`
+	IndexId                     int     `description:"标的ID"`
+	IndexName                   string  `description:"标的名称"`
+	IndexCode                   string  `description:"自生成的指标编码"`
+	ClassifyId                  int     `description:"分类ID"`
+	ClassifyName                string  `description:"分类名称"`
+	ModelFramework              string  `description:"模型框架"`
+	PredictDate                 string  `description:"预测日期"`
+	PredictValue                float64 `description:"预测值"`
+	PredictFrequency            string  `description:"预测频度"`
+	DirectionAccuracy           string  `description:"方向准确度"`
+	AbsoluteDeviation           string  `description:"绝对偏差"`
+	ExtraConfig                 string  `description:"模型参数"`
+	SysUserId                   int     `description:"创建人ID"`
+	SysUserRealName             string  `description:"创建人姓名"`
+	CreateTime                  string  `description:"创建时间"`
+	ModifyTime                  string  `description:"修改时间"`
+	SearchText                  string  `description:"搜索结果(含高亮)"`
+	AiPredictModelIndexConfigId int     `gorm:"column:ai_predict_model_index_config_id" description:"标的当前的配置id"`
+	ScriptPath                  string  `gorm:"column:script_path" description:"脚本的路径"`
 }
 
 func (m *AiPredictModelIndex) Format2Item() (item *AiPredictModelIndexItem) {
@@ -219,6 +242,8 @@ func (m *AiPredictModelIndex) Format2Item() (item *AiPredictModelIndexItem) {
 	item.ExtraConfig = m.ExtraConfig
 	item.SysUserId = m.SysUserId
 	item.SysUserRealName = m.SysUserRealName
+	item.AiPredictModelIndexConfigId = m.AiPredictModelIndexConfigId
+	item.ScriptPath = m.ScriptPath
 	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, m.CreateTime)
 	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, m.ModifyTime)
 	return
@@ -432,17 +457,20 @@ type AiPredictModelIndexSaveChart struct {
 }
 
 type AiPredictModelIndexExtraConfig struct {
-	MonthlyChart struct {
-		LeftMin string `description:"图表左侧最小值"`
-		LeftMax string `description:"图表左侧最大值"`
-		Unit    string `description:"单位"`
-	}
-	DailyChart struct {
-		LeftMin           string `description:"图表左侧最小值"`
-		LeftMax           string `description:"图表左侧最大值"`
-		Unit              string `description:"单位"`
-		PredictLegendName string `description:"预测图例的名称(通常为Predicted)"`
-	}
+	MonthlyChart MonthlyChartConfig
+	DailyChart   DailyChartConfig
+}
+type MonthlyChartConfig struct {
+	LeftMin string `description:"图表左侧最小值"`
+	LeftMax string `description:"图表左侧最大值"`
+	Unit    string `description:"单位"`
+}
+
+type DailyChartConfig struct {
+	LeftMin           string `description:"图表左侧最小值"`
+	LeftMax           string `description:"图表左侧最大值"`
+	Unit              string `description:"单位"`
+	PredictLegendName string `description:"预测图例的名称(通常为Predicted)"`
 }
 
 func (m *AiPredictModelIndex) GetSortMax() (sort int, err error) {

+ 179 - 0
models/ai_predict_model/ai_predict_model_index_config.go

@@ -0,0 +1,179 @@
+package data_manage
+
+import (
+	"database/sql"
+	"eta/eta_api/global"
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+)
+
+// 训练状态
+const (
+	TrainStatusWaiting  = "待训练"
+	TrainStatusTraining = "训练中"
+	TrainStatusSuccess  = "训练成功"
+	TrainStatusFailed   = "训练失败"
+)
+
+// AiPredictModelIndexConfig ai预测模型训练配置
+type AiPredictModelIndexConfig struct {
+	AiPredictModelIndexConfigId int       `gorm:"primaryKey;column:ai_predict_model_index_config_id" description:"-"`
+	AiPredictModelIndexId       int       `gorm:"column:ai_predict_model_index_id" description:"ai预测模型id"`
+	TrainStatus                 string    `gorm:"column:train_status" description:"训练状态,枚举值:待训练,训练中,训练成功,训练失败"`
+	Params                      string    `gorm:"column:params" description:"训练参数,json字符串存储,便于以后参数扩展"`
+	TrainMse                    string    `gorm:"column:train_mse" description:"训练集mse"`
+	TrainR2                     string    `gorm:"column:train_r2" description:"训练集r2"`
+	TestMse                     string    `gorm:"column:test_mse" description:"测试集mse"`
+	TestR2                      string    `gorm:"column:test_r2" description:"测试集r2"`
+	Remark                      string    `gorm:"column:remark" description:"训练结果说明"`
+	IsDeleted                   int8      `gorm:"column:is_deleted" description:"是否删除,0:未删除,1:已删除"`
+	LeftMin                     string    `gorm:"column:left_min" description:"图表左侧下限"`
+	LeftMax                     string    `gorm:"column:left_max" description:"图表左侧下限"`
+	ModifyTime                  time.Time `gorm:"column:modify_time" description:"修改时间"`
+	CreateTime                  time.Time `gorm:"column:create_time" description:"创建时间"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *AiPredictModelIndexConfig) TableName() string {
+	return "ai_predict_model_index_config"
+}
+
+// AiPredictModelIndexConfigColumns get sql column name.获取数据库列名
+var AiPredictModelIndexConfigColumns = struct {
+	AiPredictModelIndexConfigId string
+	AiPredictModelIndexId       string
+	TrainStatus                 string
+	Params                      string
+	TrainMse                    string
+	TrainR2                     string
+	TestMse                     string
+	TestR2                      string
+	Remark                      string
+	IsDeleted                   string
+	ModifyTime                  string
+	CreateTime                  string
+	LeftMin                     string
+	LeftMax                     string
+}{
+	AiPredictModelIndexConfigId: "ai_predict_model_index_config_id",
+	AiPredictModelIndexId:       "ai_predict_model_index_id",
+	TrainStatus:                 "train_status",
+	Params:                      "params",
+	TrainMse:                    "train_mse",
+	TrainR2:                     "train_r2",
+	TestMse:                     "test_mse",
+	TestR2:                      "test_r2",
+	Remark:                      "remark",
+	LeftMin:                     "left_min",
+	LeftMax:                     "left_max",
+	IsDeleted:                   "is_deleted",
+	ModifyTime:                  "modify_time",
+	CreateTime:                  "create_time",
+}
+
+// AiPredictModelIndexConfigView ai预测模型训练配置
+type AiPredictModelIndexConfigView struct {
+	AiPredictModelIndexConfigId int    `gorm:"primaryKey;column:ai_predict_model_index_config_id" description:"-"`
+	AiPredictModelIndexId       int    `gorm:"column:ai_predict_model_index_id" description:"ai预测模型id"`
+	TrainStatus                 string `gorm:"column:train_status" description:"训练状态,枚举值:待训练,训练中,训练成功,训练失败"`
+	Params                      string `gorm:"column:params" description:"训练参数,json字符串存储,便于以后参数扩展"`
+	TrainMse                    string `gorm:"column:train_mse" description:"训练集mse"`
+	TrainR2                     string `gorm:"column:train_r2" description:"训练集r2"`
+	TestMse                     string `gorm:"column:test_mse" description:"测试集mse"`
+	TestR2                      string `gorm:"column:test_r2" description:"测试集r2"`
+	Remark                      string `gorm:"column:remark" description:"训练结果说明"`
+	LeftMin                     string `gorm:"column:left_min" description:"图表左侧下限"`
+	LeftMax                     string `gorm:"column:left_max" description:"图表左侧下限"`
+	IsCurr                      int8   `gorm:"column:is_curr" description:"是否当前版本,0:否,1:是"`
+	ModifyTime                  string `gorm:"column:modify_time" description:"修改时间"`
+	CreateTime                  string `gorm:"column:create_time" description:"创建时间"`
+}
+
+func (m *AiPredictModelIndexConfig) ToView() AiPredictModelIndexConfigView {
+	var modifyTime, createTime string
+
+	if !m.CreateTime.IsZero() {
+		createTime = m.CreateTime.Format(utils.FormatDateTime)
+	}
+	if !m.ModifyTime.IsZero() {
+		modifyTime = m.ModifyTime.Format(utils.FormatDateTime)
+	}
+	return AiPredictModelIndexConfigView{
+		AiPredictModelIndexConfigId: m.AiPredictModelIndexConfigId,
+		AiPredictModelIndexId:       m.AiPredictModelIndexId,
+		TrainStatus:                 m.TrainStatus,
+		Params:                      m.Params,
+		TrainMse:                    m.TrainMse,
+		TrainR2:                     m.TrainR2,
+		TestMse:                     m.TestMse,
+		TestR2:                      m.TestR2,
+		Remark:                      m.Remark,
+		LeftMin:                     m.LeftMin,
+		LeftMax:                     m.LeftMax,
+		ModifyTime:                  modifyTime,
+		CreateTime:                  createTime,
+	}
+}
+
+func (m *AiPredictModelIndexConfig) ListToViewList(list []*AiPredictModelIndexConfig) (AiPredictModelIndexConfigViewList []AiPredictModelIndexConfigView) {
+	AiPredictModelIndexConfigViewList = make([]AiPredictModelIndexConfigView, 0)
+
+	for _, v := range list {
+		AiPredictModelIndexConfigViewList = append(AiPredictModelIndexConfigViewList, v.ToView())
+	}
+	return
+}
+
+func (m *AiPredictModelIndexConfig) Create() (err error) {
+	err = global.DbMap[utils.DbNameIndex].Create(&m).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfig) Update(updateCols []string) (err error) {
+	err = global.DbMap[utils.DbNameIndex].Select(updateCols).Updates(&m).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfig) GetById(id int) (item *AiPredictModelIndexConfig, err error) {
+	err = global.DbMap[utils.DbNameIndex].Where(fmt.Sprintf("%s = ?", AiPredictModelIndexConfigColumns.AiPredictModelIndexConfigId), id).First(&item).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfig) GetListByCondition(field, condition string, pars []interface{}, startSize, pageSize int) (items []*AiPredictModelIndexConfig, err error) {
+	if field == "" {
+		field = "*"
+	}
+	sqlStr := fmt.Sprintf(`SELECT %s FROM %s WHERE is_deleted=0 %s order by ai_predict_model_index_config_id desc LIMIT ?,?`, field, m.TableName(), condition)
+	pars = append(pars, startSize, pageSize)
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Find(&items).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfig) GetCountByCondition(condition string, pars []interface{}) (total int, err error) {
+	var intNull sql.NullInt64
+	sqlStr := fmt.Sprintf(`SELECT COUNT(1) total FROM %s WHERE is_deleted=0 %s`, m.TableName(), condition)
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Scan(&intNull).Error
+	if err == nil && intNull.Valid {
+		total = int(intNull.Int64)
+	}
+
+	return
+}
+
+func (m *AiPredictModelIndexConfig) GetPageListByCondition(condition string, pars []interface{}, startSize, pageSize int) (total int, items []*AiPredictModelIndexConfig, err error) {
+
+	total, err = m.GetCountByCondition(condition, pars)
+	if err != nil {
+		return
+	}
+	if total > 0 {
+		items, err = m.GetListByCondition(``, condition, pars, startSize, pageSize)
+	}
+
+	return
+}

+ 132 - 0
models/ai_predict_model/ai_predict_model_index_config_train_data.go

@@ -0,0 +1,132 @@
+package data_manage
+
+import (
+	"database/sql"
+	"eta/eta_api/global"
+	"eta/eta_api/utils"
+	"fmt"
+	"strings"
+	"time"
+)
+
+// AiPredictModelIndexConfigTrainData AI预测模型标的训练数据
+type AiPredictModelIndexConfigTrainData struct {
+	AiPredictModelIndexConfigTrainDataId int             `gorm:"primaryKey;column:ai_predict_model_index_config_train_data_id" description:"-"`
+	AiPredictModelIndexConfigId          int             `gorm:"column:ai_predict_model_index_config_id" description:"标的配置Id"`
+	AiPredictModelIndexId                int             `gorm:"column:ai_predict_model_index_id" description:"标的Id"`
+	IndexCode                            string          `gorm:"column:index_code" description:"指标编码"`
+	DataTime                             time.Time       `gorm:"column:data_time" description:"数据日期"`
+	Value                                sql.NullFloat64 `gorm:"column:value" description:"实际值"`
+	PredictValue                         sql.NullFloat64 `gorm:"column:predict_value" description:"预测值"`
+	Direction                            string          `gorm:"column:direction" description:"方向"`
+	DeviationRate                        string          `gorm:"column:deviation_rate" description:"偏差率"`
+	CreateTime                           time.Time       `gorm:"column:create_time" description:"创建时间"`
+	ModifyTime                           time.Time       `gorm:"column:modify_time" description:"修改时间"`
+	DataTimestamp                        int64           `gorm:"column:data_timestamp" description:"数据日期时间戳"`
+	Source                               uint8           `gorm:"column:source" description:"来源:1-月度预测;2-日度预测"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *AiPredictModelIndexConfigTrainData) TableName() string {
+	return "ai_predict_model_index_config_train_data"
+}
+
+// AiPredictModelIndexConfigTrainDataColumns get sql column name.获取数据库列名
+var AiPredictModelIndexConfigTrainDataColumns = struct {
+	AiPredictModelIndexConfigTrainDataId string
+	AiPredictModelIndexConfigId          string
+	AiPredictModelIndexId                string
+	IndexCode                            string
+	DataTime                             string
+	Value                                string
+	PredictValue                         string
+	Direction                            string
+	DeviationRate                        string
+	CreateTime                           string
+	ModifyTime                           string
+	DataTimestamp                        string
+	Source                               string
+}{
+	AiPredictModelIndexConfigTrainDataId: "ai_predict_model_index_config_train_data_id",
+	AiPredictModelIndexConfigId:          "ai_predict_model_index_config_id",
+	AiPredictModelIndexId:                "ai_predict_model_index_id",
+	IndexCode:                            "index_code",
+	DataTime:                             "data_time",
+	Value:                                "value",
+	PredictValue:                         "predict_value",
+	Direction:                            "direction",
+	DeviationRate:                        "deviation_rate",
+	CreateTime:                           "create_time",
+	ModifyTime:                           "modify_time",
+	DataTimestamp:                        "data_timestamp",
+	Source:                               "source",
+}
+
+func (m *AiPredictModelIndexConfigTrainData) Create() (err error) {
+	err = global.DbMap[utils.DbNameIndex].Create(&m).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) Update(updateCols []string) (err error) {
+	err = global.DbMap[utils.DbNameIndex].Select(updateCols).Updates(&m).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetById(id int) (item *AiPredictModelIndexConfigTrainData, err error) {
+	err = global.DbMap[utils.DbNameIndex].Where(fmt.Sprintf("%s = ?", AiPredictModelIndexConfigTrainDataColumns.AiPredictModelIndexConfigTrainDataId), id).First(&item).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetAllListByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*AiPredictModelIndexConfigTrainData, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, AiPredictModelIndexConfigTrainDataColumns.AiPredictModelIndexConfigTrainDataId)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sqlRun := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	err = o.Raw(sqlRun, pars...).Find(&items).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetListByCondition(field, condition string, pars []interface{}, startSize, pageSize int) (items []*AiPredictModelIndexConfigTrainData, err error) {
+	if field == "" {
+		field = "*"
+	}
+	sqlStr := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s order by ai_predict_model_index_config_train_data_id desc LIMIT ?,?`, field, m.TableName(), condition)
+	pars = append(pars, startSize, pageSize)
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Find(&items).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetCountByCondition(condition string, pars []interface{}) (total int, err error) {
+	var intNull sql.NullInt64
+	sqlStr := fmt.Sprintf(`SELECT COUNT(1) total FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Scan(&intNull).Error
+	if err == nil && intNull.Valid {
+		total = int(intNull.Int64)
+	}
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetPageListByCondition(condition string, pars []interface{}, startSize, pageSize int) (total int, items []*AiPredictModelIndexConfigTrainData, err error) {
+
+	total, err = m.GetCountByCondition(condition, pars)
+	if err != nil {
+		return
+	}
+	if total > 0 {
+		items, err = m.GetListByCondition(``, condition, pars, startSize, pageSize)
+	}
+
+	return
+}

+ 6 - 0
models/ai_predict_model/request/index.go

@@ -0,0 +1,6 @@
+package request
+
+type AiPredictModelIndexSaveScriptPathReq struct {
+	IndexId    int    `description:"指标ID"`
+	ScriptPath string `description:"脚本的路径"`
+}

+ 32 - 0
models/ai_predict_model/request/index_config.go

@@ -0,0 +1,32 @@
+package request
+
+type DelConfigReq struct {
+	AiPredictModelIndexConfigId int `description:"配置id"`
+}
+
+// TrainReq
+// @Description: 训练模型请求参数
+type TrainReq struct {
+	AiPredictModelIndexId       int          `description:"模型id"`
+	AiPredictModelIndexConfigId int          `description:"配置id"`
+	Params                      ConfigParams `description:"训练参数"`
+}
+
+// ConfigParams
+// @Description: 训练参数
+type ConfigParams struct {
+	Objective       string  `json:"objective" description:"目标(回归任务),枚举值,squarederror、multi、sofamax;默认值:squarederror" `
+	LearningRate    float64 `json:"learning_rate" description:"学习率,如:0.0881"`
+	MaxDepth        int     `json:"max_depth" description:"最大深度(控制树的深度,防止过拟合),如:4;正整数,必须大于0"`
+	MinChildWeight  float64 `json:"min_child_weight" description:"最小子节点权重(防止过拟合),如:6.0601"`
+	Subsample       float64 `json:"subsample" description:"随机采样(防止过拟合),如:0.9627"`
+	ColsampleBytree float64 `json:"colsample_bytree" description:"特征随机采样(防止过拟合),如:0.7046"`
+	Gamma           float64 `json:"gamma" description:"控制分裂,如:0.4100"`
+	RegAlpha        float64 `json:"reg_alpha" description:"L1正则化系数,如:0.3738"`
+	ReqLambda       float64 `json:"reg_lambda" description:"L2正则化系数,如:1.4775"`
+	EvalMetric      string  `json:"eval_metric" description:"评估指标,枚举值,rmse、auc logloss、merror;默认值:rmse"`
+	Seed            float64 `json:"seed" description:"随机种子,如:42"`
+	MaxDeltaStep    int     `json:"max_delta_step" description:"最大步长,如:5;正整数,必须大于0"`
+	TreeMethod      string  `json:"tree_method" description:"树构建方法,枚举值:auto、exact、approx、hist;默认值:auto"`
+	NumBoostRound   int     `json:"num_boost_round" description:"迭代次数;正整数,必须大于0"`
+}

+ 16 - 0
models/ai_predict_model/response/index_config.go

@@ -0,0 +1,16 @@
+package response
+
+import (
+	aiPredictModel "eta/eta_api/models/ai_predict_model"
+	"eta/eta_api/models/data_manage"
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type AiPredictModelIndexConfigListResp struct {
+	List   []aiPredictModel.AiPredictModelIndexConfigView
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+type AiPredictModelDetailResp struct {
+	DailyChartView *data_manage.ChartInfoDetailResp `description:"日度预测数据图表"`
+}

+ 63 - 0
routers/commentsRouter.go

@@ -358,6 +358,60 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "ChartDetail",
+            Router: `/index_config/chart/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "Del",
+            Router: `/index_config/del`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/index_config/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "Train",
+            Router: `/index_config/train`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "CurrVersion",
+            Router: `/index_config/version/curr`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "SetCurr",
+            Router: `/index_config/version/set_curr`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"],
         beego.ControllerComments{
             Method: "SearchByEs",
@@ -421,6 +475,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"],
+        beego.ControllerComments{
+            Method: "ScriptPathSave",
+            Router: `/index/script_path/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartClassifyController"],
         beego.ControllerComments{
             Method: "AddChartClassify",

+ 1 - 0
routers/router.go

@@ -469,6 +469,7 @@ func init() {
 				&ai_predict_model.AiPredictModelClassifyController{},
 				&ai_predict_model.AiPredictModelIndexController{},
 				&ai_predict_model.AiPredictModelFrameworkController{},
+				&ai_predict_model.AiPredictModelIndexConfigController{},
 			),
 		),
 		web.NSNamespace("/eta_forum",

+ 193 - 1
services/ai_predict_model_index.go

@@ -59,7 +59,7 @@ func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelIm
 				b, _ := json.Marshal(oldConfig)
 				v.Index.ExtraConfig = string(b)
 			}
-			
+
 			v.Index.AiPredictModelIndexId = exist.AiPredictModelIndexId
 			v.Index.IndexCode = exist.IndexCode
 			updateIndexes = append(updateIndexes, v)
@@ -439,3 +439,195 @@ func FixAiPredictCharts() {
 	}
 	return
 }
+func GetAiPredictConfigChartDetailByData(indexName string, indexConfigItem *aiPredictModel.AiPredictModelIndexConfig, indexData []*aiPredictModel.AiPredictModelIndexConfigTrainData, source int) (resp *data_manage.ChartInfoDetailResp, err error) {
+	resp = new(data_manage.ChartInfoDetailResp)
+	// 标的配置
+	extraConfig := aiPredictModel.AiPredictModelIndexExtraConfig{
+		MonthlyChart: aiPredictModel.MonthlyChartConfig{
+			LeftMin: "",
+			LeftMax: "",
+			Unit:    "",
+		},
+		DailyChart: aiPredictModel.DailyChartConfig{
+			LeftMin:           "",
+			LeftMax:           "",
+			Unit:              "",
+			PredictLegendName: "预测值",
+		},
+	}
+
+	// 图表信息
+	var predictLegendName, confLeftMin, confLeftMax, unit string
+	if source == aiPredictModel.ModelDataSourceDaily {
+		predictLegendName = extraConfig.DailyChart.PredictLegendName
+		if predictLegendName == "" {
+			predictLegendName = "Predicted"
+		}
+		unit = extraConfig.DailyChart.Unit
+		confLeftMin = extraConfig.DailyChart.LeftMin
+		confLeftMax = extraConfig.DailyChart.LeftMax
+	}
+	if source == aiPredictModel.ModelDataSourceMonthly {
+		predictLegendName = "预测值"
+		unit = extraConfig.MonthlyChart.Unit
+		confLeftMin = extraConfig.MonthlyChart.LeftMin
+		confLeftMax = extraConfig.MonthlyChart.LeftMax
+	}
+	// 这里简单兼容下吧,暂时就不修数据了
+	if confLeftMin == "" {
+		confLeftMin = indexConfigItem.LeftMin
+	}
+	if confLeftMax == "" {
+		confLeftMax = indexConfigItem.LeftMax
+	}
+
+	// 获取曲线图主题样式
+	chartView := new(data_manage.ChartInfoView)
+	chartView.ChartName = indexName
+	chartView.ChartNameEn = indexName
+	chartView.ChartType = utils.CHART_SOURCE_DEFAULT
+	chartTheme, e := data.GetChartThemeConfig(0, chartView.ChartType, utils.CHART_TYPE_CURVE)
+	if e != nil {
+		err = fmt.Errorf("获取图表主题样式失败, %v", e)
+		return
+	}
+	chartView.ChartThemeStyle = chartTheme.Config
+	chartView.ChartThemeId = chartTheme.ChartThemeId
+
+	chartView.DateType = 3
+	chartView.Calendar = "公历"
+	chartView.ChartSource = "AI预测模型"
+	chartView.ChartSourceEn = "AI预测模型"
+	chartView.Unit = unit
+	chartView.UnitEn = unit
+
+	// EdbList-固定一条为标的实际值、一条为预测值
+	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	edbActual, edbPredict := new(data_manage.ChartEdbInfoMapping), new(data_manage.ChartEdbInfoMapping)
+	edbActual.EdbName = indexName
+	edbActual.EdbNameEn = indexName
+	edbActual.IsAxis = 1
+	edbActual.Unit = unit
+	edbActual.UnitEn = unit
+
+	edbPredict.EdbName = predictLegendName
+	edbPredict.EdbNameEn = predictLegendName
+	edbPredict.IsAxis = 1
+	edbPredict.Unit = unit
+	edbPredict.UnitEn = unit
+	actualData, predictData := make([]*data_manage.EdbDataList, 0), make([]*data_manage.EdbDataList, 0)
+
+	var startDate, endDate time.Time
+	var actualValues, predictValues []float64
+	var actualNewest, predictNewest bool
+	var actualLatestTimestamp int64 // 实际值最后一天的时间戳,作为日度图表的分割线
+	for k, v := range indexData {
+		// 如果实际值和预测值都是null那么该日期无效直接忽略
+		if !v.Value.Valid && !v.PredictValue.Valid {
+			continue
+		}
+
+		// 将有效值加入[]float64,最后取极值
+		if v.Value.Valid {
+			actualValues = append(actualValues, v.Value.Float64)
+		}
+		if v.PredictValue.Valid {
+			predictValues = append(predictValues, v.PredictValue.Float64)
+		}
+
+		// 开始结束时间
+		if k == 0 {
+			startDate = v.DataTime
+			endDate = v.CreateTime
+		}
+		if v.DataTime.Before(startDate) {
+			startDate = v.DataTime
+		}
+		if v.DataTime.After(endDate) {
+			endDate = v.DataTime
+		}
+
+		// 指标数据
+		if v.Value.Valid {
+			if !actualNewest {
+				edbActual.LatestDate = v.DataTime.Format(utils.FormatDate)
+				edbActual.LatestValue = v.Value.Float64
+				actualLatestTimestamp = v.DataTime.UnixNano() / 1e6
+				actualNewest = true
+			}
+			actualData = append(actualData, &data_manage.EdbDataList{
+				DataTime:      v.DataTime.Format(utils.FormatDate),
+				Value:         v.Value.Float64,
+				DataTimestamp: v.DataTimestamp,
+			})
+		}
+		if v.PredictValue.Valid {
+			if !predictNewest {
+				edbPredict.LatestDate = v.DataTime.Format(utils.FormatDate)
+				edbPredict.LatestValue = v.Value.Float64
+				predictNewest = true
+			}
+			predictData = append(predictData, &data_manage.EdbDataList{
+				DataTime:      v.DataTime.Format(utils.FormatDate),
+				Value:         v.PredictValue.Float64,
+				DataTimestamp: v.DataTimestamp,
+			})
+		}
+	}
+
+	// 图表数据这里均做一个升序排序
+	sort.Slice(actualData, func(i, j int) bool {
+		return actualData[i].DataTimestamp < actualData[j].DataTimestamp
+	})
+	sort.Slice(predictData, func(i, j int) bool {
+		return predictData[i].DataTimestamp < predictData[j].DataTimestamp
+	})
+
+	// 极值
+	actualMin, actualMax := utils.FindMinMax(actualValues)
+	predictMin, predictMax := utils.FindMinMax(predictValues)
+	edbActual.MinData = actualMin
+	edbActual.MaxData = actualMax
+	edbPredict.MinData = predictMin
+	edbPredict.MaxData = predictMax
+
+	edbActual.DataList = actualData
+	edbPredict.DataList = predictData
+	edbList = append(edbList, edbActual, edbPredict)
+
+	// 上下限
+	if confLeftMin != "" {
+		chartView.LeftMin = confLeftMin
+	} else {
+		leftMin := actualMin
+		if leftMin > predictMin {
+			leftMin = predictMin
+		}
+		chartView.LeftMin = fmt.Sprint(leftMin)
+	}
+	if confLeftMax != "" {
+		chartView.LeftMax = confLeftMax
+	} else {
+		leftMax := actualMax
+		if leftMax < predictMax {
+			leftMax = predictMax
+		}
+		chartView.LeftMax = fmt.Sprint(leftMax)
+	}
+
+	chartView.StartDate = startDate.Format(utils.FormatDate)
+	chartView.EndDate = endDate.Format(utils.FormatDate)
+
+	// 日度图表的分割线日期
+	if source == aiPredictModel.ModelDataSourceDaily {
+		var dataResp struct {
+			ActualLatestTimestamp int64
+		}
+		dataResp.ActualLatestTimestamp = actualLatestTimestamp
+		resp.DataResp = dataResp
+	}
+
+	resp.ChartInfo = chartView
+	resp.EdbInfoList = edbList
+	return
+}