Compare commits
10 Commits
v2025.7.19
...
v2025.7.28
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1b34d950b | ||
|
|
83aa4331ad | ||
|
|
d4d3c44cf4 | ||
|
|
81a9cc5927 | ||
|
|
3fc89a85da | ||
|
|
0605c8442d | ||
|
|
cf8591c208 | ||
|
|
7607c4356f | ||
|
|
4aae2ece00 | ||
|
|
369d14025c |
25
app.go
25
app.go
@@ -256,7 +256,7 @@ func (a *App) CheckUpdate(flag int) {
|
||||
}
|
||||
go runtime.EventsEmit(a.ctx, "newsPush", map[string]any{
|
||||
"time": "发现新版本:" + releaseVersion.TagName,
|
||||
"isRed": false,
|
||||
"isRed": true,
|
||||
"source": "go-stock",
|
||||
"content": fmt.Sprintf("%s", commit.Message),
|
||||
})
|
||||
@@ -272,7 +272,7 @@ func (a *App) CheckUpdate(flag int) {
|
||||
}
|
||||
body := resp.Body()
|
||||
|
||||
if len(body) < 1024 {
|
||||
if len(body) < 1024*500 {
|
||||
go runtime.EventsEmit(a.ctx, "newsPush", map[string]any{
|
||||
"time": "新版本:" + releaseVersion.TagName,
|
||||
"isRed": true,
|
||||
@@ -299,7 +299,7 @@ func (a *App) CheckUpdate(flag int) {
|
||||
if flag == 1 {
|
||||
go runtime.EventsEmit(a.ctx, "newsPush", map[string]any{
|
||||
"time": "当前版本:" + Version,
|
||||
"isRed": false,
|
||||
"isRed": true,
|
||||
"source": "go-stock",
|
||||
"content": "当前版本无更新",
|
||||
})
|
||||
@@ -438,7 +438,7 @@ func (a *App) domReady(ctx context.Context) {
|
||||
//检查新版本
|
||||
go func() {
|
||||
a.CheckUpdate(0)
|
||||
//a.CheckStockBaseInfo(a.ctx)
|
||||
a.CheckStockBaseInfo(a.ctx)
|
||||
a.cron.AddFunc("30 05 8,12,20 * * *", func() {
|
||||
logger.SugaredLogger.Errorf("Checking for updates...")
|
||||
a.CheckUpdate(0)
|
||||
@@ -545,10 +545,21 @@ func (a *App) CheckStockBaseInfo(ctx context.Context) {
|
||||
|
||||
}
|
||||
func (a *App) NewsPush(news *[]models.Telegraph) {
|
||||
|
||||
follows := data.NewStockDataApi().GetFollowList(0)
|
||||
stockNames := slice.Map(*follows, func(index int, item data.FollowedStock) string {
|
||||
return item.Name
|
||||
})
|
||||
|
||||
for _, telegraph := range *news {
|
||||
//if telegraph.IsRed {
|
||||
go runtime.EventsEmit(a.ctx, "newsPush", telegraph)
|
||||
go data.NewAlertWindowsApi("go-stock", telegraph.Source+" "+telegraph.Time, telegraph.Content, string(icon)).SendNotification()
|
||||
if a.GetConfig().EnableOnlyPushRedNews {
|
||||
if telegraph.IsRed || strutil.ContainsAny(telegraph.Content, stockNames) {
|
||||
go runtime.EventsEmit(a.ctx, "newsPush", telegraph)
|
||||
}
|
||||
} else {
|
||||
go runtime.EventsEmit(a.ctx, "newsPush", telegraph)
|
||||
}
|
||||
//go data.NewAlertWindowsApi("go-stock", telegraph.Source+" "+telegraph.Time, telegraph.Content, string(icon)).SendNotification()
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,9 +551,14 @@ func (m MarketNewsApi) EMDictCode(code string, cache *freecache.Cache) []any {
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) TradingViewNews() *[]models.TVNews {
|
||||
client := resty.New()
|
||||
config := GetSettingConfig()
|
||||
if config.HttpProxyEnabled && config.HttpProxy != "" {
|
||||
client.SetProxy(config.HttpProxy)
|
||||
}
|
||||
TVNews := &[]models.TVNews{}
|
||||
url := "https://news-mediator.tradingview.com/news-flow/v2/news?filter=lang:zh-Hans&filter=provider:panews,reuters&client=screener&streaming=false"
|
||||
resp, err := resty.New().SetProxy("http://127.0.0.1:10809").SetTimeout(time.Duration(30)*time.Second).R().
|
||||
resp, err := client.SetTimeout(time.Duration(5)*time.Second).R().
|
||||
SetHeader("Host", "news-mediator.tradingview.com").
|
||||
SetHeader("Origin", "https://cn.tradingview.com").
|
||||
SetHeader("Referer", "https://cn.tradingview.com/").
|
||||
@@ -833,7 +838,7 @@ func (m MarketNewsApi) GetPMI() *models.PMIResp {
|
||||
return res
|
||||
|
||||
}
|
||||
func (m MarketNewsApi) GetIndustryReportInfo(infoCode string) {
|
||||
func (m MarketNewsApi) GetIndustryReportInfo(infoCode string) string {
|
||||
url := "https://data.eastmoney.com/report/zw_industry.jshtml?infocode=" + infoCode
|
||||
resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
|
||||
SetHeader("Host", "data.eastmoney.com").
|
||||
@@ -843,7 +848,7 @@ func (m MarketNewsApi) GetIndustryReportInfo(infoCode string) {
|
||||
Get(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("GetIndustryReportInfo err:%s", err.Error())
|
||||
return
|
||||
return ""
|
||||
}
|
||||
body := resp.Body()
|
||||
//logger.SugaredLogger.Debugf("GetIndustryReportInfo:%s", body)
|
||||
@@ -853,7 +858,31 @@ func (m MarketNewsApi) GetIndustryReportInfo(infoCode string) {
|
||||
//logger.SugaredLogger.Infof("GetIndustryReportInfo:\n%s\n%s", title, content)
|
||||
markdown, err := util.HTMLToMarkdown(title + content)
|
||||
if err != nil {
|
||||
return
|
||||
return ""
|
||||
}
|
||||
logger.SugaredLogger.Infof("GetIndustryReportInfo markdown:\n%s", markdown)
|
||||
return markdown
|
||||
}
|
||||
|
||||
func (m MarketNewsApi) ReutersNew() *models.ReutersNews {
|
||||
client := resty.New()
|
||||
config := GetSettingConfig()
|
||||
if config.HttpProxyEnabled && config.HttpProxy != "" {
|
||||
client.SetProxy(config.HttpProxy)
|
||||
}
|
||||
news := &models.ReutersNews{}
|
||||
url := "https://www.reuters.com/pf/api/v3/content/fetch/articles-by-section-alias-or-id-v1?query={\"arc-site\":\"reuters\",\"fetch_type\":\"collection\",\"offset\":0,\"section_id\":\"/world/\",\"size\":9,\"uri\":\"/world/\",\"website\":\"reuters\"}&d=300&mxId=00000000&_website=reuters"
|
||||
_, err := client.SetTimeout(time.Duration(5)*time.Second).R().
|
||||
SetHeader("Host", "www.reuters.com").
|
||||
SetHeader("Origin", "https://www.reuters.com").
|
||||
SetHeader("Referer", "https://www.reuters.com/world/china/").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
|
||||
SetResult(news).
|
||||
Get(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("ReutersNew err:%s", err.Error())
|
||||
return news
|
||||
}
|
||||
logger.SugaredLogger.Infof("Articles:%+v", news.Result.Articles)
|
||||
return news
|
||||
}
|
||||
|
||||
@@ -79,11 +79,13 @@ func TestStockResearchReport(t *testing.T) {
|
||||
|
||||
func TestIndustryResearchReport(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
resp := NewMarketNewsApi().IndustryResearchReport("", 7)
|
||||
resp := NewMarketNewsApi().IndustryResearchReport("735", 7)
|
||||
for _, a := range resp {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
data := a.(map[string]any)
|
||||
logger.SugaredLogger.Debugf("value: %s infoCode:%s", data["title"], data["infoCode"])
|
||||
NewMarketNewsApi().GetIndustryReportInfo(data["infoCode"].(string))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestStockNotice(t *testing.T) {
|
||||
@@ -101,6 +103,11 @@ func TestEMDictCode(t *testing.T) {
|
||||
for _, a := range resp {
|
||||
logger.SugaredLogger.Debugf("value: %+v", a)
|
||||
}
|
||||
bytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
logger.SugaredLogger.Debugf("value: %s", string(bytes))
|
||||
|
||||
}
|
||||
|
||||
@@ -204,3 +211,8 @@ func TestGetPMI(t *testing.T) {
|
||||
func TestGetIndustryReportInfo(t *testing.T) {
|
||||
NewMarketNewsApi().GetIndustryReportInfo("AP202507151709216483")
|
||||
}
|
||||
|
||||
func TestReutersNew(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
NewMarketNewsApi().ReutersNew()
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func (o *OpenAi) NewSummaryStockNewsStreamWithTools(userQuestion string, sysProm
|
||||
"content": "当前本地时间是:" + time.Now().Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(3)
|
||||
wg.Add(5)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
@@ -219,17 +219,24 @@ func (o *OpenAi) NewSummaryStockNewsStreamWithTools(userQuestion string, sysProm
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var market strings.Builder
|
||||
market.WriteString(getZSInfo("上证指数", "sh000001", 30) + "\n")
|
||||
market.WriteString(getZSInfo("深证成指", "sz399001", 30) + "\n")
|
||||
market.WriteString(getZSInfo("创业板指数", "sz399006", 30) + "\n")
|
||||
market.WriteString(getZSInfo("上证综合指数", "sh000001", 30) + "\n")
|
||||
market.WriteString(getZSInfo("科创50", "sh000688", 30) + "\n")
|
||||
market.WriteString(getZSInfo("沪深300指数", "sh000300", 30) + "\n")
|
||||
market.WriteString(getZSInfo("中证银行", "sz399986", 30) + "\n")
|
||||
market.WriteString(getZSInfo("科创芯片", "sh000685", 30) + "\n")
|
||||
market.WriteString(getZSInfo("上证医药", "sh000037", 30) + "\n")
|
||||
market.WriteString(getZSInfo("证券龙头", "sz399437", 30) + "\n")
|
||||
market.WriteString(getZSInfo("中证白酒", "sz399997", 30) + "\n")
|
||||
//logger.SugaredLogger.Infof("NewChatStream getZSInfo=\n%s", market.String())
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": "当前市场指数行情",
|
||||
"content": "当前市场/大盘/行业/指数行情",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": "当前市场指数行情情况如下:\n" + market.String(),
|
||||
"content": "当前市场/大盘/行业/指数行情如下:\n" + market.String(),
|
||||
})
|
||||
}()
|
||||
|
||||
@@ -264,9 +271,45 @@ func (o *OpenAi) NewSummaryStockNewsStreamWithTools(userQuestion string, sysProm
|
||||
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
resp := NewMarketNewsApi().TradingViewNews()
|
||||
var newsText strings.Builder
|
||||
|
||||
for _, a := range *resp {
|
||||
logger.SugaredLogger.Debugf("TradingViewNews: %s", a.Title)
|
||||
newsText.WriteString(a.Title + "\n")
|
||||
}
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": "全球新闻资讯",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": newsText.String(),
|
||||
})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
news := NewMarketNewsApi().ReutersNew()
|
||||
messageText := strings.Builder{}
|
||||
for _, article := range news.Result.Articles {
|
||||
messageText.WriteString("## " + article.Title + "\n")
|
||||
messageText.WriteString("### " + article.Description + "\n")
|
||||
}
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": "外媒全球新闻资讯",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": messageText.String(),
|
||||
})
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
news := NewMarketNewsApi().GetNewsList("财联社电报", random.RandInt(50, 150))
|
||||
news := NewMarketNewsApi().GetNewsList("财联社电报", random.RandInt(100, 500))
|
||||
messageText := strings.Builder{}
|
||||
for _, telegraph := range *news {
|
||||
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
|
||||
@@ -338,13 +381,20 @@ func (o *OpenAi) NewSummaryStockNewsStream(userQuestion string, sysPromptId *int
|
||||
"content": "当前本地时间是:" + time.Now().Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
wg.Add(3)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
var market strings.Builder
|
||||
market.WriteString(getZSInfo("上证指数", "sh000001", 30) + "\n")
|
||||
market.WriteString(getZSInfo("深证成指", "sz399001", 30) + "\n")
|
||||
market.WriteString(getZSInfo("创业板指数", "sz399006", 30) + "\n")
|
||||
market.WriteString(getZSInfo("上证综合指数", "sh000001", 30) + "\n")
|
||||
market.WriteString(getZSInfo("科创50", "sh000688", 30) + "\n")
|
||||
market.WriteString(getZSInfo("沪深300指数", "sh000300", 30) + "\n")
|
||||
market.WriteString(getZSInfo("中证银行", "sz399986", 30) + "\n")
|
||||
market.WriteString(getZSInfo("科创芯片", "sh000685", 30) + "\n")
|
||||
market.WriteString(getZSInfo("上证医药", "sh000037", 30) + "\n")
|
||||
market.WriteString(getZSInfo("证券龙头", "sz399437", 30) + "\n")
|
||||
market.WriteString(getZSInfo("中证白酒", "sz399997", 30) + "\n")
|
||||
//logger.SugaredLogger.Infof("NewChatStream getZSInfo=\n%s", market.String())
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
@@ -355,6 +405,43 @@ func (o *OpenAi) NewSummaryStockNewsStream(userQuestion string, sysPromptId *int
|
||||
"content": "当前市场指数行情情况如下:\n" + market.String(),
|
||||
})
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
resp := NewMarketNewsApi().TradingViewNews()
|
||||
var newsText strings.Builder
|
||||
|
||||
for _, a := range *resp {
|
||||
logger.SugaredLogger.Debugf("TradingViewNews: %s", a.Title)
|
||||
newsText.WriteString(a.Title + "\n")
|
||||
}
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": "外媒全球新闻资讯",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": newsText.String(),
|
||||
})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
news := NewMarketNewsApi().ReutersNew()
|
||||
messageText := strings.Builder{}
|
||||
for _, article := range news.Result.Articles {
|
||||
messageText.WriteString("## " + article.Title + "\n")
|
||||
messageText.WriteString("### " + article.Description + "\n")
|
||||
}
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": "外媒全球新闻资讯",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": messageText.String(),
|
||||
})
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
news := NewMarketNewsApi().GetNewsList("", 100)
|
||||
@@ -468,9 +555,8 @@ func (o *OpenAi) NewChatStream(stock, stockCode, userQuestion string, sysPromptI
|
||||
logger.SugaredLogger.Infof("NewChatStream stock:%s stockCode:%s", stock, stockCode)
|
||||
logger.SugaredLogger.Infof("Prompt:%s", sysPrompt)
|
||||
logger.SugaredLogger.Infof("final question:%s", question)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(7)
|
||||
wg.Add(8)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
@@ -714,6 +800,25 @@ func (o *OpenAi) NewChatStream(stock, stockCode, userQuestion string, sysPromptI
|
||||
})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
resp := NewMarketNewsApi().TradingViewNews()
|
||||
var newsText strings.Builder
|
||||
|
||||
for _, a := range *resp {
|
||||
logger.SugaredLogger.Debugf("value: %s", a.Title)
|
||||
newsText.WriteString(a.Title + "\n")
|
||||
}
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": "外媒全球新闻资讯",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": newsText.String(),
|
||||
})
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
|
||||
@@ -57,3 +57,9 @@ func TestSearchGuShiTongStockInfo(t *testing.T) {
|
||||
SearchGuShiTongStockInfo("gb_goog", 60)
|
||||
|
||||
}
|
||||
|
||||
func TestGetZSInfo(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
getZSInfo("中证银行", "sz399986", 30)
|
||||
getZSInfo("科创50", "sh000688", 30)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,10 @@ type Settings struct {
|
||||
BrowserPoolSize int `json:"browserPoolSize"`
|
||||
EnableFund bool `json:"enableFund"`
|
||||
EnablePushNews bool `json:"enablePushNews"`
|
||||
EnableOnlyPushRedNews bool `json:"enableOnlyPushRedNews"`
|
||||
SponsorCode string `json:"sponsorCode"`
|
||||
HttpProxy string `json:"httpProxy"`
|
||||
HttpProxyEnabled bool `json:"httpProxyEnabled"`
|
||||
}
|
||||
|
||||
func (receiver Settings) TableName() string {
|
||||
@@ -98,7 +101,10 @@ func UpdateConfig(s *SettingConfig) string {
|
||||
"dark_theme": s.DarkTheme,
|
||||
"enable_fund": s.EnableFund,
|
||||
"enable_push_news": s.EnablePushNews,
|
||||
"enable_only_push_red_news": s.EnableOnlyPushRedNews,
|
||||
"sponsor_code": s.SponsorCode,
|
||||
"http_proxy": s.HttpProxy,
|
||||
"http_proxy_enabled": s.HttpProxyEnabled,
|
||||
})
|
||||
|
||||
//更新AiConfig
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
// -----------------------------------------------------------------------------------
|
||||
func TestGetDaily(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
tushareApi := NewTushareApi(GetConfig())
|
||||
tushareApi := NewTushareApi(GetSettingConfig())
|
||||
res := tushareApi.GetDaily("00927.HK", "20250101", "20250217", 30)
|
||||
t.Log(res)
|
||||
|
||||
@@ -19,7 +19,7 @@ func TestGetDaily(t *testing.T) {
|
||||
|
||||
func TestGetUSDaily(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
tushareApi := NewTushareApi(GetConfig())
|
||||
tushareApi := NewTushareApi(GetSettingConfig())
|
||||
|
||||
res := tushareApi.GetDaily("gb_AAPL", "20250101", "20250217", 30)
|
||||
t.Log(res)
|
||||
|
||||
@@ -465,3 +465,173 @@ type PMIResp struct {
|
||||
DCResp
|
||||
PMIResult PMIResult `json:"result"`
|
||||
}
|
||||
|
||||
type OldSettings struct {
|
||||
gorm.Model
|
||||
TushareToken string `json:"tushareToken"`
|
||||
LocalPushEnable bool `json:"localPushEnable"`
|
||||
DingPushEnable bool `json:"dingPushEnable"`
|
||||
DingRobot string `json:"dingRobot"`
|
||||
UpdateBasicInfoOnStart bool `json:"updateBasicInfoOnStart"`
|
||||
RefreshInterval int64 `json:"refreshInterval"`
|
||||
|
||||
OpenAiEnable bool `json:"openAiEnable"`
|
||||
OpenAiBaseUrl string `json:"openAiBaseUrl"`
|
||||
OpenAiApiKey string `json:"openAiApiKey"`
|
||||
OpenAiModelName string `json:"openAiModelName"`
|
||||
OpenAiMaxTokens int `json:"openAiMaxTokens"`
|
||||
OpenAiTemperature float64 `json:"openAiTemperature"`
|
||||
OpenAiApiTimeOut int `json:"openAiApiTimeOut"`
|
||||
Prompt string `json:"prompt"`
|
||||
CheckUpdate bool `json:"checkUpdate"`
|
||||
QuestionTemplate string `json:"questionTemplate"`
|
||||
CrawlTimeOut int64 `json:"crawlTimeOut"`
|
||||
KDays int64 `json:"kDays"`
|
||||
EnableDanmu bool `json:"enableDanmu"`
|
||||
BrowserPath string `json:"browserPath"`
|
||||
EnableNews bool `json:"enableNews"`
|
||||
DarkTheme bool `json:"darkTheme"`
|
||||
BrowserPoolSize int `json:"browserPoolSize"`
|
||||
EnableFund bool `json:"enableFund"`
|
||||
EnablePushNews bool `json:"enablePushNews"`
|
||||
SponsorCode string `json:"sponsorCode"`
|
||||
}
|
||||
|
||||
func (receiver OldSettings) TableName() string {
|
||||
return "settings"
|
||||
}
|
||||
|
||||
type ReutersNews struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
Result struct {
|
||||
ParentSectionName string `json:"parent_section_name"`
|
||||
Pagination struct {
|
||||
Size int `json:"size"`
|
||||
ExpectedSize int `json:"expected_size"`
|
||||
TotalSize int `json:"total_size"`
|
||||
Orderby string `json:"orderby"`
|
||||
} `json:"pagination"`
|
||||
DateModified time.Time `json:"date_modified"`
|
||||
FetchType string `json:"fetch_type"`
|
||||
Articles []struct {
|
||||
Id string `json:"id"`
|
||||
CanonicalUrl string `json:"canonical_url"`
|
||||
Website string `json:"website"`
|
||||
Web string `json:"web"`
|
||||
Native string `json:"native"`
|
||||
UpdatedTime time.Time `json:"updated_time"`
|
||||
PublishedTime time.Time `json:"published_time"`
|
||||
ArticleType string `json:"article_type"`
|
||||
DisplayMyNews bool `json:"display_my_news"`
|
||||
DisplayNewsletterSignup bool `json:"display_newsletter_signup"`
|
||||
DisplayNotifications bool `json:"display_notifications"`
|
||||
DisplayRelatedMedia bool `json:"display_related_media"`
|
||||
DisplayRelatedOrganizations bool `json:"display_related_organizations"`
|
||||
ContentCode string `json:"content_code"`
|
||||
Source struct {
|
||||
Name string `json:"name"`
|
||||
OriginalName string `json:"original_name"`
|
||||
} `json:"source"`
|
||||
Title string `json:"title"`
|
||||
BasicHeadline string `json:"basic_headline"`
|
||||
Distributor string `json:"distributor"`
|
||||
Description string `json:"description"`
|
||||
PrimaryMediaType string `json:"primary_media_type,omitempty"`
|
||||
PrimaryTag struct {
|
||||
ShortBio string `json:"short_bio"`
|
||||
Description string `json:"description"`
|
||||
Slug string `json:"slug"`
|
||||
Text string `json:"text"`
|
||||
TopicUrl string `json:"topic_url"`
|
||||
CanFollow bool `json:"can_follow,omitempty"`
|
||||
IsTopic bool `json:"is_topic,omitempty"`
|
||||
} `json:"primary_tag"`
|
||||
WordCount int `json:"word_count"`
|
||||
ReadMinutes int `json:"read_minutes"`
|
||||
Kicker struct {
|
||||
Path string `json:"path"`
|
||||
Names []string `json:"names"`
|
||||
Name string `json:"name,omitempty"`
|
||||
} `json:"kicker"`
|
||||
AdTopics []string `json:"ad_topics"`
|
||||
Thumbnail struct {
|
||||
Url string `json:"url"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
Type string `json:"type"`
|
||||
ResizerUrl string `json:"resizer_url"`
|
||||
Location string `json:"location,omitempty"`
|
||||
Id string `json:"id"`
|
||||
Authors string `json:"authors,omitempty"`
|
||||
AltText string `json:"alt_text"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Subtitle string `json:"subtitle"`
|
||||
Slug string `json:"slug,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Company string `json:"company,omitempty"`
|
||||
PurchaseLicensingPath string `json:"purchase_licensing_path,omitempty"`
|
||||
} `json:"thumbnail"`
|
||||
Authors []struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Company string `json:"company"`
|
||||
Thumbnail struct {
|
||||
Url string `json:"url"`
|
||||
Type string `json:"type"`
|
||||
ResizerUrl string `json:"resizer_url"`
|
||||
} `json:"thumbnail"`
|
||||
SocialLinks []struct {
|
||||
Site string `json:"site"`
|
||||
Url string `json:"url"`
|
||||
} `json:"social_links,omitempty"`
|
||||
Byline string `json:"byline"`
|
||||
Description string `json:"description,omitempty"`
|
||||
TopicUrl string `json:"topic_url,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
} `json:"authors"`
|
||||
DisplayTime time.Time `json:"display_time"`
|
||||
ThumbnailDark struct {
|
||||
Url string `json:"url"`
|
||||
Type string `json:"type"`
|
||||
ResizerUrl string `json:"resizer_url"`
|
||||
Id string `json:"id"`
|
||||
AltText string `json:"alt_text"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Subtitle string `json:"subtitle"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
} `json:"thumbnail_dark,omitempty"`
|
||||
} `json:"articles"`
|
||||
Section struct {
|
||||
Id string `json:"id"`
|
||||
AdUnitCode string `json:"ad_unit_code"`
|
||||
Website string `json:"website"`
|
||||
Name string `json:"name"`
|
||||
PageTitle string `json:"page_title"`
|
||||
CanFollow bool `json:"can_follow"`
|
||||
Language string `json:"language"`
|
||||
Type string `json:"type"`
|
||||
Advertising struct {
|
||||
Sponsored string `json:"sponsored"`
|
||||
} `json:"advertising"`
|
||||
VideoPlaylistId string `json:"video_playlistId"`
|
||||
MobileAdUnitPath string `json:"mobile_ad_unit_path"`
|
||||
AdUnitPath string `json:"ad_unit_path"`
|
||||
CollectionAlias string `json:"collection_alias"`
|
||||
SectionAbout string `json:"section_about"`
|
||||
Title string `json:"title"`
|
||||
Personalization struct {
|
||||
Id string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
ShowTags bool `json:"show_tags"`
|
||||
CanFollow bool `json:"can_follow"`
|
||||
} `json:"personalization"`
|
||||
} `json:"section"`
|
||||
AdUnitPath string `json:"ad_unit_path"`
|
||||
ResponseTime int64 `json:"response_time"`
|
||||
} `json:"result"`
|
||||
Id string `json:"_id"`
|
||||
}
|
||||
|
||||
@@ -702,7 +702,7 @@ onMounted(() => {
|
||||
</n-spin>
|
||||
</n-gi>
|
||||
<n-gi style="position: fixed;bottom:0;z-index: 9;width: 100%;">
|
||||
<n-card size="small" style="--wails-draggable:drag">
|
||||
<n-card size="small" style="--wails-draggable:no-drag">
|
||||
<n-menu style="font-size: 18px;"
|
||||
v-model:value="activeKey"
|
||||
mode="horizontal"
|
||||
|
||||
@@ -104,7 +104,7 @@ EventsOn("updateVersion",async (msg) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-space vertical size="large" style="--wails-draggable:drag">
|
||||
<n-space vertical size="large" style="--wails-draggable:no-drag">
|
||||
<!-- 软件描述 -->
|
||||
<n-card size="large">
|
||||
<n-divider title-placement="center">关于软件</n-divider>
|
||||
|
||||
@@ -102,6 +102,7 @@ onBeforeMount(() => {
|
||||
|
||||
GetAiConfigs().then(res=>{
|
||||
aiConfigs.value = res
|
||||
aiConfigId.value = res[0].ID
|
||||
})
|
||||
|
||||
GetTelegraphList("财联社电报").then((res) => {
|
||||
@@ -317,7 +318,7 @@ function ReFlesh(source) {
|
||||
|
||||
<template>
|
||||
<n-card>
|
||||
<n-tabs type="line" animated @update-value="updateTab" :value="nowTab" style="--wails-draggable:drag">
|
||||
<n-tabs type="line" animated @update-value="updateTab" :value="nowTab" style="--wails-draggable:no-drag">
|
||||
<n-tab-pane name="市场快讯" tab="市场快讯">
|
||||
<n-grid :cols="2" :y-gap="0">
|
||||
<n-gi>
|
||||
|
||||
@@ -41,7 +41,10 @@ const formValue = ref({
|
||||
darkTheme: true,
|
||||
enableFund: false,
|
||||
enablePushNews: false,
|
||||
enableOnlyPushRedNews: false,
|
||||
sponsorCode: "",
|
||||
httpProxy:"",
|
||||
httpProxyEnabled:false,
|
||||
})
|
||||
|
||||
// 添加一个新的AI配置到列表
|
||||
@@ -96,7 +99,11 @@ onMounted(() => {
|
||||
formValue.value.darkTheme = res.darkTheme
|
||||
formValue.value.enableFund = res.enableFund
|
||||
formValue.value.enablePushNews = res.enablePushNews
|
||||
formValue.value.enableOnlyPushRedNews = res.enableOnlyPushRedNews
|
||||
formValue.value.sponsorCode = res.sponsorCode
|
||||
formValue.value.httpProxy=res.httpProxy;
|
||||
formValue.value.httpProxyEnabled=res.httpProxyEnabled;
|
||||
|
||||
})
|
||||
|
||||
GetPromptTemplates("", "").then(res => {
|
||||
@@ -131,7 +138,10 @@ function saveConfig() {
|
||||
darkTheme: formValue.value.darkTheme,
|
||||
enableFund: formValue.value.enableFund,
|
||||
enablePushNews: formValue.value.enablePushNews,
|
||||
sponsorCode: formValue.value.sponsorCode
|
||||
enableOnlyPushRedNews: formValue.value.enableOnlyPushRedNews,
|
||||
sponsorCode: formValue.value.sponsorCode,
|
||||
httpProxy:formValue.value.httpProxy,
|
||||
httpProxyEnabled:formValue.value.httpProxyEnabled,
|
||||
})
|
||||
|
||||
if (config.sponsorCode) {
|
||||
@@ -217,7 +227,10 @@ function importConfig() {
|
||||
formValue.value.darkTheme = config.darkTheme
|
||||
formValue.value.enableFund = config.enableFund
|
||||
formValue.value.enablePushNews = config.enablePushNews
|
||||
formValue.value.enableOnlyPushRedNews = config.enableOnlyPushRedNews
|
||||
formValue.value.sponsorCode = config.sponsorCode
|
||||
formValue.value.httpProxy=config.httpProxy
|
||||
formValue.value.httpProxyEnabled=config.httpProxyEnabled
|
||||
};
|
||||
reader.readAsText(file);
|
||||
};
|
||||
@@ -283,7 +296,7 @@ function deletePrompt(ID) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-flex justify="left" style="text-align: left; --wails-draggable:drag">
|
||||
<n-flex justify="left" style="text-align: left; --wails-draggable:no-drag">
|
||||
<n-form ref="formRef" :label-placement="'left'" :label-align="'left'">
|
||||
<n-space vertical size="large">
|
||||
<n-card :title="() => h(NTag, { type: 'primary', bordered: false }, () => '基础设置')" size="small">
|
||||
@@ -321,21 +334,25 @@ function deletePrompt(ID) {
|
||||
|
||||
<n-card :title="() => h(NTag, { type: 'primary', bordered: false }, () => '通知设置')" size="small">
|
||||
<n-grid :cols="24" :x-gap="24" style="text-align: left">
|
||||
<n-form-item-gi :span="4" label="钉钉推送:" path="dingPush.enable">
|
||||
<n-form-item-gi :span="3" label="钉钉推送:" path="dingPush.enable">
|
||||
<n-switch v-model:value="formValue.dingPush.enable"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="4" label="本地推送:" path="localPush.enable">
|
||||
<n-form-item-gi :span="3" label="本地推送:" path="localPush.enable">
|
||||
<n-switch v-model:value="formValue.localPush.enable"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="4" label="弹幕功能:" path="enableDanmu">
|
||||
<n-form-item-gi :span="3" label="弹幕功能:" path="enableDanmu">
|
||||
<n-switch v-model:value="formValue.enableDanmu"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="4" label="显示滚动快讯:" path="enableNews">
|
||||
<n-form-item-gi :span="3" label="显示滚动快讯:" path="enableNews">
|
||||
<n-switch v-model:value="formValue.enableNews"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="4" label="市场资讯提醒:" path="enablePushNews">
|
||||
<n-form-item-gi :span="3" label="市场资讯提醒:" path="enablePushNews">
|
||||
<n-switch v-model:value="formValue.enablePushNews"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi v-if="formValue.enablePushNews" :span="4" label="只提醒红字或关注个股的新闻:" path="enableOnlyPushRedNews">
|
||||
<n-switch v-model:value="formValue.enableOnlyPushRedNews"/>
|
||||
</n-form-item-gi>
|
||||
|
||||
<n-form-item-gi :span="22" v-if="formValue.dingPush.enable" label="钉钉机器人接口地址:"
|
||||
path="dingPush.dingRobot">
|
||||
<n-input placeholder="请输入钉钉机器人接口地址" v-model:value="formValue.dingPush.dingRobot"/>
|
||||
@@ -354,10 +371,18 @@ function deletePrompt(ID) {
|
||||
title="资讯采集超时时间(秒)" path="openAI.crawlTimeOut">
|
||||
<n-input-number min="30" step="1" v-model:value="formValue.openAI.crawlTimeOut"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="6" v-if="formValue.openAI.enable" title="天数越多消耗tokens越多"
|
||||
<n-form-item-gi :span="4" v-if="formValue.openAI.enable" title="天数越多消耗tokens越多"
|
||||
label="日K线数据(天)" path="openAI.kDays">
|
||||
<n-input-number min="30" step="1" max="365" v-model:value="formValue.openAI.kDays"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="2" label="http代理" path="httpProxyEnabled">
|
||||
<n-switch v-model:value="formValue.httpProxyEnabled"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="10" v-if="formValue.httpProxyEnabled" title="http代理地址"
|
||||
label="http代理地址" path="httpProxy">
|
||||
<n-input type="text" placeholder="http代理地址" v-model:value="formValue.httpProxy" clearable/>
|
||||
</n-form-item-gi>
|
||||
|
||||
|
||||
<n-gi :span="24" v-if="formValue.openAI.enable">
|
||||
<n-divider title-placement="left">Prompt 内容设置</n-divider>
|
||||
@@ -445,7 +470,6 @@ function deletePrompt(ID) {
|
||||
|
||||
</n-grid>
|
||||
</n-card>
|
||||
|
||||
</n-space>
|
||||
</n-form>
|
||||
</n-flex>
|
||||
|
||||
@@ -220,6 +220,7 @@ onBeforeMount(() => {
|
||||
|
||||
GetAiConfigs().then(res=>{
|
||||
aiConfigs.value = res
|
||||
data.aiConfigId =res[0].ID
|
||||
})
|
||||
|
||||
})
|
||||
@@ -1722,7 +1723,7 @@ function searchStockReport(stockCode) {
|
||||
</n-gradient-text>
|
||||
</template>
|
||||
</vue-danmaku>
|
||||
<n-tabs type="card" style="--wails-draggable:drag" animated addable :data-currentGroupId="currentGroupId"
|
||||
<n-tabs type="card" style="--wails-draggable:no-drag" animated addable :data-currentGroupId="currentGroupId"
|
||||
:value="currentGroupId" @add="addTab" @update-value="updateTab" placement="top" @close="(key)=>{delTab(key)}">
|
||||
<n-tab-pane :name="0" :tab="'全部'">
|
||||
<n-grid :x-gap="8" :cols="3" :y-gap="8">
|
||||
|
||||
@@ -389,7 +389,10 @@ export namespace data {
|
||||
browserPoolSize: number;
|
||||
enableFund: boolean;
|
||||
enablePushNews: boolean;
|
||||
enableOnlyPushRedNews: boolean;
|
||||
sponsorCode: string;
|
||||
httpProxy: string;
|
||||
httpProxyEnabled: boolean;
|
||||
aiConfigs: AIConfig[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
@@ -421,7 +424,10 @@ export namespace data {
|
||||
this.browserPoolSize = source["browserPoolSize"];
|
||||
this.enableFund = source["enableFund"];
|
||||
this.enablePushNews = source["enablePushNews"];
|
||||
this.enableOnlyPushRedNews = source["enableOnlyPushRedNews"];
|
||||
this.sponsorCode = source["sponsorCode"];
|
||||
this.httpProxy = source["httpProxy"];
|
||||
this.httpProxyEnabled = source["httpProxyEnabled"];
|
||||
this.aiConfigs = this.convertValues(source["aiConfigs"], AIConfig);
|
||||
}
|
||||
|
||||
|
||||
22
main.go
22
main.go
@@ -188,6 +188,26 @@ func main() {
|
||||
|
||||
}
|
||||
|
||||
func updateMultipleModel() {
|
||||
oldSettings := &models.OldSettings{}
|
||||
db.Dao.Model(oldSettings).First(oldSettings)
|
||||
aiConfig := &data.AIConfig{}
|
||||
db.Dao.Model(aiConfig).First(aiConfig)
|
||||
if oldSettings.OpenAiEnable && oldSettings.OpenAiApiKey != "" && aiConfig.ID == 0 {
|
||||
aiConfig.Name = oldSettings.OpenAiModelName
|
||||
aiConfig.ApiKey = oldSettings.OpenAiApiKey
|
||||
aiConfig.BaseUrl = oldSettings.OpenAiBaseUrl
|
||||
aiConfig.ModelName = oldSettings.OpenAiModelName
|
||||
aiConfig.Temperature = oldSettings.OpenAiTemperature
|
||||
aiConfig.MaxTokens = oldSettings.OpenAiMaxTokens
|
||||
aiConfig.TimeOut = oldSettings.OpenAiApiTimeOut
|
||||
err := db.Dao.Model(aiConfig).Create(aiConfig).Error
|
||||
if err != nil {
|
||||
log.SugaredLogger.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AutoMigrate() {
|
||||
db.Dao.AutoMigrate(&data.StockInfo{})
|
||||
db.Dao.AutoMigrate(&data.StockBasic{})
|
||||
@@ -207,6 +227,8 @@ func AutoMigrate() {
|
||||
db.Dao.AutoMigrate(&models.TelegraphTags{})
|
||||
db.Dao.AutoMigrate(&models.LongTigerRankData{})
|
||||
db.Dao.AutoMigrate(&data.AIConfig{})
|
||||
|
||||
updateMultipleModel()
|
||||
}
|
||||
|
||||
func initStockDataUS(ctx context.Context) {
|
||||
|
||||
Reference in New Issue
Block a user