Browse Source

Merge branch 'feature/eta_1.1.9'

hsun 1 year ago
parent
commit
530cf209e0
9 changed files with 332 additions and 0 deletions
  1. 1 0
      go.mod
  2. 1 0
      go.sum
  3. 10 0
      models/db.go
  4. 100 0
      models/smart_report.go
  5. 59 0
      services/elastic.go
  6. 133 0
      services/smart_report.go
  7. 5 0
      services/task.go
  8. 18 0
      utils/config.go
  9. 5 0
      utils/constants.go

+ 1 - 0
go.mod

@@ -26,6 +26,7 @@ require (
 	github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20211218165449-dd623ecc2f02 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.1 // indirect
+	github.com/garyburd/redigo v1.6.3 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/josharian/intern v1.0.0 // indirect

+ 1 - 0
go.sum

@@ -100,6 +100,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
 github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/garyburd/redigo v1.6.3 h1:HCeeRluvAgMusMomi1+6Y5dmFOdYV/JzoRrrbFlkGIc=
 github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=

+ 10 - 0
models/db.go

@@ -78,6 +78,9 @@ func init() {
 
 	//注册持仓分析 数据表
 	initTradePositionTop()
+
+	// 智能研报数据表
+	initSmartReport()
 }
 
 // initEdbDataTable 注册Edb指标 数据表
@@ -130,3 +133,10 @@ func initTradePositionTop() {
 		new(data_manage.BaseFromTradeClassify), // 交易所分类
 	)
 }
+
+// initSmartReport 注册智能研报数据表
+func initSmartReport() {
+	orm.RegisterModel(
+		new(SmartReport),
+	)
+}

+ 100 - 0
models/smart_report.go

@@ -0,0 +1,100 @@
+package models
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// SmartReport 智能研报
+type SmartReport struct {
+	SmartReportId      int       `orm:"column(smart_report_id)" description:"智能研报ID"`
+	ReportCode         string    `description:"报告唯一编码"`
+	ClassifyIdFirst    int       `description:"一级分类ID"`
+	ClassifyNameFirst  string    `description:"一级分类名称"`
+	ClassifyIdSecond   int       `description:"二级分类ID"`
+	ClassifyNameSecond string    `description:"二级分类名称"`
+	AddType            int       `description:"新增方式:1-新增报告;2-继承报告"`
+	Title              string    `description:"标题"`
+	Abstract           string    `description:"摘要"`
+	Author             string    `description:"作者"`
+	Frequency          string    `description:"频度"`
+	Stage              int       `description:"期数"`
+	Content            string    `description:"内容"`
+	ContentSub         string    `description:"内容前两个章节"`
+	ContentStruct      string    `description:"内容组件"`
+	VideoUrl           string    `description:"音频文件URL"`
+	VideoName          string    `description:"音频文件名称"`
+	VideoPlaySeconds   string    `description:"音频播放时长"`
+	VideoSize          string    `description:"音频文件大小,单位M"`
+	AdminId            int       `description:"创建者ID"`
+	AdminRealName      string    `description:"创建者姓名"`
+	State              int       `description:"发布状态:1-待发布;2-已发布"`
+	PublishTime        time.Time `description:"发布时间"`
+	PrePublishTime     time.Time `description:"预发布时间"`
+	PreMsgSend         int       `description:"定时发布后是否推送模版消息:0-否;1-是"`
+	MsgIsSend          int       `description:"消息是否已发送:0-否;1-是"`
+	MsgSendTime        time.Time `description:"模版消息发送时间"`
+	CreateTime         time.Time `description:"创建时间"`
+	ModifyTime         time.Time `description:"修改时间"`
+}
+
+func (m *SmartReport) TableName() string {
+	return "smart_report"
+}
+
+func (m *SmartReport) PrimaryId() string {
+	return "smart_report_id"
+}
+
+func (m *SmartReport) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *SmartReport) GetItemById(id int) (item *SmartReport, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// GetPrePublishSmartReports 获取定时发布时间为当前时间的未发布的报告列表
+func GetPrePublishSmartReports(startTime, endTime string) (list []*SmartReport, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM smart_report WHERE state = 1 AND pre_publish_time >= ? AND pre_publish_time <= ?`
+	_, err = o.Raw(sql, startTime, endTime).QueryRows(&list)
+	return
+}
+
+// PublishSmartReportById 发布智能报告
+func PublishSmartReportById(reportId int, publishTime time.Time) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE smart_report SET state = 2, publish_time = ?, msg_is_send = 1, msg_send_time = NOW(), modify_time = NOW() WHERE smart_report_id = ?`
+	_, err = o.Raw(sql, publishTime, reportId).Exec()
+	return
+}
+
+// ElasticSmartReport 智能研报es
+type ElasticSmartReport struct {
+	SmartReportId      int    `description:"智能研报ID"`
+	Title              string `description:"标题"`
+	Abstract           string `description:"摘要"`
+	BodyContent        string `description:"内容"`
+	PublishTime        string `description:"发布时间"`
+	PublishState       int    `description:"发布状态 1-未发布 2-已发布"`
+	Author             string `description:"作者"`
+	ClassifyIdFirst    int    `description:"一级分类ID"`
+	ClassifyNameFirst  string `description:"一级分类名称"`
+	ClassifyIdSecond   int    `description:"二级分类ID"`
+	ClassifyNameSecond string `description:"二级分类名称"`
+	StageStr           string `description:"报告期数"`
+	Frequency          string `description:"频度"`
+}
+
+// Report2ImgQueueReq 报告详情生成长图队列请求体
+type Report2ImgQueueReq struct {
+	ReportType int    `description:"报告类型: 1-研报; 2-智能研报"`
+	ReportCode string `description:"报告唯一编码"`
+}

+ 59 - 0
services/elastic.go

@@ -150,3 +150,62 @@ func EsAddOrEditEnglishReport(indexName, docId string, item *models.ElasticEngli
 	}
 	return
 }
+
+// EsAddOrEditSmartReport 新增编辑es智能研报
+func EsAddOrEditSmartReport(indexName, docId string, item *models.ElasticSmartReport) (err error) {
+	defer func() {
+		if err != nil {
+			fmt.Println("EsAddOrEditSmartReport Err:", err.Error())
+		}
+	}()
+	client, err := NewClient()
+	if err != nil {
+		return
+	}
+	// docId为报告ID
+	searchById, err := client.Get().Index(indexName).Id(docId).Do(context.Background())
+	if err != nil && !strings.Contains(err.Error(), "404") {
+		fmt.Println("Get Err" + err.Error())
+		return
+	}
+	if searchById != nil && searchById.Found {
+		resp, err := client.Update().Index(indexName).Id(docId).Doc(map[string]interface{}{
+			"SmartReportId":      item.SmartReportId,
+			"Title":              item.Title,
+			"Abstract":           item.Abstract,
+			"BodyContent":        item.BodyContent,
+			"PublishTime":        item.PublishTime,
+			"PublishState":       item.PublishState,
+			"Author":             item.Author,
+			"ClassifyIdFirst":    item.ClassifyIdFirst,
+			"ClassifyNameFirst":  item.ClassifyNameFirst,
+			"ClassifyIdSecond":   item.ClassifyIdSecond,
+			"ClassifyNameSecond": item.ClassifyNameSecond,
+			"StageStr":           item.StageStr,
+			"Frequency":          item.Frequency,
+		}).Do(context.Background())
+		if err != nil {
+			return err
+		}
+		//fmt.Println(resp.Status, resp.Result)
+		if resp.Status == 0 {
+			fmt.Println("修改成功" + docId)
+			err = nil
+		} else {
+			fmt.Println("EditData", resp.Status, resp.Result)
+		}
+	} else {
+		resp, err := client.Index().Index(indexName).Id(docId).BodyJson(item).Do(context.Background())
+		if err != nil {
+			fmt.Println("新增失败:", err.Error())
+			return err
+		}
+		if resp.Status == 0 && resp.Result == "created" {
+			fmt.Println("新增成功" + docId)
+			return nil
+		} else {
+			fmt.Println("AddData", resp.Status, resp.Result)
+		}
+	}
+	return
+}

+ 133 - 0
services/smart_report.go

@@ -0,0 +1,133 @@
+package services
+
+import (
+	"context"
+	"eta/eta_task/models"
+	"eta/eta_task/services/alarm_msg"
+	"eta/eta_task/utils"
+	"fmt"
+	"html"
+	"strconv"
+	"time"
+)
+
+// PublishSmartReport 定时发布智能研报
+func PublishSmartReport(cont context.Context) (err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("PublishSmartReport-定时发布智能研报失败, ErrMsg:\n"+err.Error(), 3)
+		}
+	}()
+
+	now := time.Now().Format(utils.FormatDateTimeMinute)
+	startTime := now + ":00"
+	endTime := now + ":59"
+
+	list, e := models.GetPrePublishSmartReports(startTime, endTime)
+	if e != nil {
+		err = fmt.Errorf("GetPrePublishSmartReports err: %s", e.Error())
+		return
+	}
+	listLen := len(list)
+	if listLen == 0 {
+		return
+	}
+
+	// 比对时间(分钟), 时间相等则发布并推送
+	for i := 0; i < listLen; i++ {
+		item := list[i]
+		var publishTime time.Time
+		// 如果报告曾经发布过,并且已经发送过模版消息,则发布时间为原发布时间
+		if item.MsgIsSend == 1 && !item.PublishTime.IsZero() {
+			publishTime = item.PublishTime
+		} else {
+			publishTime = time.Now()
+		}
+		// 发布报告, 同时更新消息推送状态, 消息推送目前仅为预留功能, 后面小程序需要售卖的时候再细化消息推送
+		if err = models.PublishSmartReportById(item.SmartReportId, publishTime); err != nil {
+			return
+		}
+
+		// 写入队列
+		var queue models.Report2ImgQueueReq
+		queue.ReportType = 2
+		queue.ReportCode = item.ReportCode
+		_ = utils.Rc.LPush(utils.CACHE_CREATE_REPORT_IMGPDF_QUEUE, queue)
+
+		// 生成音频, 更新ES
+		go func() {
+			if item.VideoUrl == "" {
+				SmartReportBuildVideoAndUpdate(item)
+			}
+			_ = SmartReportElasticUpsert(item.SmartReportId, 2)
+		}()
+	}
+	return
+}
+
+// SmartReportBuildVideoAndUpdate 生成音频
+func SmartReportBuildVideoAndUpdate(item *models.SmartReport) {
+	if item == nil {
+		return
+	}
+	var err error
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("智能研报-音频生成, errMsg: %s", err.Error())
+			go alarm_msg.SendAlarmMsg(tips, 2)
+		}
+	}()
+
+	videoUrl, videoName, videoSize, videoPlaySeconds, e := CreateReportVideo(item.Title, item.Content, time.Now().Local().Format(utils.FormatDateTime))
+	if e != nil {
+		err = fmt.Errorf("create audio err: %s", e.Error())
+		return
+	}
+	item.VideoUrl = videoUrl
+	item.VideoName = videoName
+	item.VideoSize = videoSize
+	item.VideoPlaySeconds = fmt.Sprintf("%.2f", videoPlaySeconds)
+	item.ModifyTime = time.Now().Local()
+	cols := []string{"VideoUrl", "VideoName", "VideoSize", "VideoPlaySeconds", "ModifyTime"}
+	if e = item.Update(cols); e != nil {
+		err = fmt.Errorf("smart report update err: %s", e.Error())
+		return
+	}
+}
+
+// SmartReportElasticUpsert 新增/编辑报告es
+func SmartReportElasticUpsert(smartReportId int, state int) (err error) {
+	if smartReportId <= 0 {
+		return
+	}
+
+	reportOB := new(models.SmartReport)
+	item, e := reportOB.GetItemById(smartReportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			// 可能被删了就直接忽略掉
+			return
+		}
+		err = fmt.Errorf("获取报告失败, Err: %s", e.Error())
+		return
+	}
+
+	esReport := new(models.ElasticSmartReport)
+	esReport.SmartReportId = item.SmartReportId
+	esReport.Title = item.Title
+	esReport.Abstract = item.Abstract
+	esReport.BodyContent = utils.TrimHtml(html.UnescapeString(item.Content))
+	esReport.PublishTime = item.PublishTime.Format(utils.FormatDateTime)
+	esReport.PublishState = state
+	esReport.Author = item.Author
+	esReport.ClassifyIdFirst = item.ClassifyIdFirst
+	esReport.ClassifyNameFirst = item.ClassifyNameFirst
+	esReport.ClassifyIdSecond = item.ClassifyIdSecond
+	esReport.ClassifyNameSecond = item.ClassifyNameSecond
+	esReport.StageStr = strconv.Itoa(item.Stage)
+	esReport.Frequency = item.Frequency
+	if err = EsAddOrEditSmartReport(utils.SmartReportIndexName, strconv.Itoa(item.SmartReportId), esReport); err != nil {
+		return
+	}
+	return
+}

+ 5 - 0
services/task.go

@@ -17,6 +17,11 @@ func Task() {
 	if utils.RunMode == "release" {
 		releaseTask()
 	}
+
+	// 定时发布智能研报
+	publishSmartReport := task.NewTask("publishSmartReport", "0 */1 * * * *", PublishSmartReport)
+	task.AddTask("定时发布智能研报", publishSmartReport)
+
 	task.StartTask()
 	fmt.Println("task end")
 }

+ 18 - 0
utils/config.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	beego "github.com/beego/beego/v2/adapter"
 	"github.com/beego/beego/v2/server/web"
+	"github.com/rdlucklib/rdluck_tools/cache"
 	"strconv"
 )
 
@@ -15,6 +16,10 @@ var (
 	MYSQL_URL_DATA string
 	MYSQL_URL_GL   string
 	MYSQL_URL_ETA  string
+
+	REDIS_CACHE string       //缓存地址
+	Rc          *cache.Cache //redis缓存
+	Re          error        //redis错误
 )
 
 var (
@@ -83,9 +88,11 @@ var (
 	ES_PASSWORD string // ES密码
 )
 
+// ES索引配置
 var (
 	EsReportIndexName        string //研报ES索引
 	EsEnglishReportIndexName string //英文研报ES索引
+	SmartReportIndexName     string //智能研报ES索引
 )
 
 // 科大讯飞--语音合成
@@ -145,6 +152,16 @@ func init() {
 	MYSQL_URL_GL = config["mysql_url_gl"]
 	MYSQL_URL_ETA = config["mysql_url_eta"]
 
+	REDIS_CACHE = config["beego_cache"]
+	if len(REDIS_CACHE) <= 0 {
+		panic(any("redis链接参数没有配置"))
+	}
+	Rc, Re = cache.NewCache(REDIS_CACHE) //初始化缓存
+	if Re != nil {
+		fmt.Println(Re)
+		panic(any(Re))
+	}
+
 	// 项目中文名称
 	appNameCn, err := web.AppConfig.String("app_name_cn")
 	if err != nil {
@@ -197,6 +214,7 @@ func init() {
 	{
 		EsReportIndexName = config["es_report_index_name"]
 		EsEnglishReportIndexName = config["es_english_report_index_name"]
+		SmartReportIndexName = config["es_smart_report_index_name"]
 	}
 
 	// 科大讯飞

+ 5 - 0
utils/constants.go

@@ -116,3 +116,8 @@ var (
 const (
 	TEMPLATE_MSG_REPORT = iota + 1 //日度点评报告推送
 )
+
+// 缓存key
+const (
+	CACHE_CREATE_REPORT_IMGPDF_QUEUE = "eta_report:report_img_pdf_queue" // 生成报告长图PDF队列
+)