mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(cron):设置cron时,cron任务实时生效,避免重启
- 新增 AddCronTask 函数用于添加 cron 任务 - 在 App 结构中添加 cronEntrys 字典用于管理 cron 任务 ID- 优化 SetStockAICron 函数,支持更新和删除 cron 任务 - 新增 GetFollowedStockByStockCode 函数用于获取关注的股票信息 - 更新前端 API 接口,添加 AddCronTask 方法
This commit is contained in:
parent
95c3909dc9
commit
b186a17a81
86
app.go
86
app.go
@ -30,9 +30,10 @@ import (
|
||||
|
||||
// App struct
|
||||
type App struct {
|
||||
ctx context.Context
|
||||
cache *freecache.Cache
|
||||
cron *cron.Cron
|
||||
ctx context.Context
|
||||
cache *freecache.Cache
|
||||
cron *cron.Cron
|
||||
cronEntrys map[string]cron.EntryID
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
@ -42,8 +43,9 @@ func NewApp() *App {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
c.Start()
|
||||
return &App{
|
||||
cache: cache,
|
||||
cron: c,
|
||||
cache: cache,
|
||||
cron: c,
|
||||
cronEntrys: make(map[string]cron.EntryID),
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,35 +174,45 @@ func (a *App) domReady(ctx context.Context) {
|
||||
if follow.Cron == "" {
|
||||
continue
|
||||
}
|
||||
logger.SugaredLogger.Errorf("添加自动分析任务:%s cron=%s", follow.Name, follow.Cron)
|
||||
a.cron.AddFunc(follow.Cron, func() {
|
||||
go runtime.EventsEmit(a.ctx, "warnMsg", "开始自动分析"+follow.Name+"_"+follow.StockCode)
|
||||
ai := data.NewDeepSeekOpenAi(a.ctx)
|
||||
msgs := ai.NewChatStream(follow.Name, follow.StockCode, "", nil)
|
||||
var res strings.Builder
|
||||
|
||||
chatId := ""
|
||||
question := ""
|
||||
for msg := range msgs {
|
||||
if msg["extraContent"] != nil {
|
||||
res.WriteString(msg["extraContent"].(string) + "\n")
|
||||
}
|
||||
if msg["content"] != nil {
|
||||
res.WriteString(msg["content"].(string))
|
||||
}
|
||||
if msg["chatId"] != nil {
|
||||
chatId = msg["chatId"].(string)
|
||||
}
|
||||
if msg["question"] != nil {
|
||||
question = msg["question"].(string)
|
||||
}
|
||||
}
|
||||
data.NewDeepSeekOpenAi(a.ctx).SaveAIResponseResult(follow.StockCode, follow.Name, res.String(), chatId, question)
|
||||
})
|
||||
entryID, err := a.cron.AddFunc(follow.Cron, a.AddCronTask(follow))
|
||||
logger.SugaredLogger.Errorf("添加自动分析任务:%s cron=%s entryID:%v", follow.Name, follow.Cron, entryID)
|
||||
a.cronEntrys[follow.StockCode] = entryID
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (a *App) AddCronTask(follow data.FollowedStock) func() {
|
||||
return func() {
|
||||
go runtime.EventsEmit(a.ctx, "warnMsg", "开始自动分析"+follow.Name+"_"+follow.StockCode)
|
||||
ai := data.NewDeepSeekOpenAi(a.ctx)
|
||||
msgs := ai.NewChatStream(follow.Name, follow.StockCode, "", nil)
|
||||
var res strings.Builder
|
||||
|
||||
chatId := ""
|
||||
question := ""
|
||||
for msg := range msgs {
|
||||
if msg["extraContent"] != nil {
|
||||
res.WriteString(msg["extraContent"].(string) + "\n")
|
||||
}
|
||||
if msg["content"] != nil {
|
||||
res.WriteString(msg["content"].(string))
|
||||
}
|
||||
if msg["chatId"] != nil {
|
||||
chatId = msg["chatId"].(string)
|
||||
}
|
||||
if msg["question"] != nil {
|
||||
question = msg["question"].(string)
|
||||
}
|
||||
}
|
||||
data.NewDeepSeekOpenAi(a.ctx).SaveAIResponseResult(follow.StockCode, follow.Name, res.String(), chatId, question)
|
||||
go runtime.EventsEmit(a.ctx, "warnMsg", "AI分析完成:"+follow.Name+"_"+follow.StockCode)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func refreshTelegraphList() *[]string {
|
||||
url := "https://www.cls.cn/telegraph"
|
||||
response, err := resty.New().R().
|
||||
@ -860,8 +872,18 @@ func (a *App) AddPrompt(prompt models.Prompt) string {
|
||||
func (a *App) DelPrompt(id uint) string {
|
||||
return data.NewPromptTemplateApi().DelPrompt(id)
|
||||
}
|
||||
func (a *App) SetStockAICron(cron, stockCode string) {
|
||||
data.NewStockDataApi().SetStockAICron(cron, stockCode)
|
||||
func (a *App) SetStockAICron(cronText, stockCode string) {
|
||||
data.NewStockDataApi().SetStockAICron(cronText, stockCode)
|
||||
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
|
||||
stockCode = strings.ToUpper(stockCode)
|
||||
stockCode = strings.Replace(stockCode, "gb_", "us", 1)
|
||||
stockCode = strings.Replace(stockCode, "GB_", "us", 1)
|
||||
}
|
||||
if entryID, exists := a.cronEntrys[stockCode]; exists {
|
||||
a.cron.Remove(entryID)
|
||||
}
|
||||
follow := data.NewStockDataApi().GetFollowedStockByStockCode(stockCode)
|
||||
a.cron.AddFunc(cronText, a.AddCronTask(follow))
|
||||
}
|
||||
func OnSecondInstanceLaunch(secondInstanceData options.SecondInstanceData) {
|
||||
notification := toast.Notification{
|
||||
|
@ -426,6 +426,7 @@ func (receiver StockDataApi) SetStockAICron(cron string, stockCode string) {
|
||||
stockCode = strings.Replace(stockCode, "GB_", "us", 1)
|
||||
}
|
||||
db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).Update("cron", cron)
|
||||
|
||||
}
|
||||
func (receiver StockDataApi) GetFollowList() *[]FollowedStock {
|
||||
var result *[]FollowedStock
|
||||
@ -475,6 +476,12 @@ func (receiver StockDataApi) GetStockList(key string) []StockBasic {
|
||||
return result
|
||||
}
|
||||
|
||||
func (receiver StockDataApi) GetFollowedStockByStockCode(code string) FollowedStock {
|
||||
var result FollowedStock
|
||||
db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(code)).First(&result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GB18030ToUTF8 GB18030 转换为 UTF8
|
||||
func GB18030ToUTF8(bs []byte) string {
|
||||
reader := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GB18030.NewDecoder())
|
||||
|
4
frontend/wailsjs/go/main/App.d.ts
vendored
4
frontend/wailsjs/go/main/App.d.ts
vendored
@ -1,7 +1,9 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
import {models} from '../models';
|
||||
import {data} from '../models';
|
||||
import {models} from '../models';
|
||||
|
||||
export function AddCronTask(arg1:data.FollowedStock):Promise<any>;
|
||||
|
||||
export function AddPrompt(arg1:models.Prompt):Promise<string>;
|
||||
|
||||
|
@ -2,6 +2,10 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function AddCronTask(arg1) {
|
||||
return window['go']['main']['App']['AddCronTask'](arg1);
|
||||
}
|
||||
|
||||
export function AddPrompt(arg1) {
|
||||
return window['go']['main']['App']['AddPrompt'](arg1);
|
||||
}
|
||||
|
@ -142,6 +142,61 @@ export namespace data {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
export class FollowedStock {
|
||||
StockCode: string;
|
||||
Name: string;
|
||||
Volume: number;
|
||||
CostPrice: number;
|
||||
Price: number;
|
||||
PriceChange: number;
|
||||
ChangePercent: number;
|
||||
AlarmChangePercent: number;
|
||||
AlarmPrice: number;
|
||||
// Go type: time
|
||||
Time: any;
|
||||
Sort: number;
|
||||
Cron: string;
|
||||
IsDel: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new FollowedStock(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.StockCode = source["StockCode"];
|
||||
this.Name = source["Name"];
|
||||
this.Volume = source["Volume"];
|
||||
this.CostPrice = source["CostPrice"];
|
||||
this.Price = source["Price"];
|
||||
this.PriceChange = source["PriceChange"];
|
||||
this.ChangePercent = source["ChangePercent"];
|
||||
this.AlarmChangePercent = source["AlarmChangePercent"];
|
||||
this.AlarmPrice = source["AlarmPrice"];
|
||||
this.Time = this.convertValues(source["Time"], null);
|
||||
this.Sort = source["Sort"];
|
||||
this.Cron = source["Cron"];
|
||||
this.IsDel = source["IsDel"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
export class Settings {
|
||||
ID: number;
|
||||
|
Loading…
x
Reference in New Issue
Block a user