From d27bcbd3348ec7dee5195f4fd6c422accf805713 Mon Sep 17 00:00:00 2001 From: spark Date: Wed, 12 Feb 2025 17:03:25 +0800 Subject: [PATCH] =?UTF-8?q?feat(backend):=E6=B7=BB=E5=8A=A0=E8=B5=84?= =?UTF-8?q?=E8=AE=AF=E9=87=87=E9=9B=86=E8=B6=85=E6=97=B6=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 OpenAi 结构中添加 CrawlTimeOut 字段,用于设置资讯采集超时时间 - 修改相关函数以支持新的超时设置,包括 GetFinancialReports、GetTelegraphList、GetTopNewsList等 - 在前端设置页面添加 Crawler Timeout 设置项 - 优化浏览器检查逻辑,优先检查 Chrome 浏览器 --- backend/data/openai_api.go | 38 ++++++++++++++++---------- backend/data/openai_api_test.go | 2 +- backend/data/settings_api.go | 3 +++ backend/data/stock_data_api.go | 40 ++++++++++++++++++++++------ frontend/src/components/settings.vue | 27 +++++++++++-------- frontend/wailsjs/go/models.ts | 2 ++ 6 files changed, 78 insertions(+), 34 deletions(-) diff --git a/backend/data/openai_api.go b/backend/data/openai_api.go index 9c6b199..e571fab 100644 --- a/backend/data/openai_api.go +++ b/backend/data/openai_api.go @@ -32,10 +32,19 @@ type OpenAi struct { Prompt string `json:"prompt"` TimeOut int `json:"time_out"` QuestionTemplate string `json:"question_template"` + CrawlTimeOut int64 `json:"crawl_time_out"` } func NewDeepSeekOpenAi(ctx context.Context) *OpenAi { config := getConfig() + if config.OpenAiEnable { + if config.OpenAiApiTimeOut <= 0 { + config.OpenAiApiTimeOut = 60 * 5 + } + if config.CrawlTimeOut <= 0 { + config.CrawlTimeOut = 60 + } + } return &OpenAi{ ctx: ctx, BaseUrl: config.OpenAiBaseUrl, @@ -46,6 +55,7 @@ func NewDeepSeekOpenAi(ctx context.Context) *OpenAi { Prompt: config.Prompt, TimeOut: config.OpenAiApiTimeOut, QuestionTemplate: config.QuestionTemplate, + CrawlTimeOut: config.CrawlTimeOut, } } @@ -117,7 +127,7 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string { wg.Add(5) go func() { defer wg.Done() - messages := SearchStockPriceInfo(stockCode) + messages := SearchStockPriceInfo(stockCode, o.CrawlTimeOut) if messages == nil || len(*messages) == 0 { logger.SugaredLogger.Error("获取股票价格失败") ch <- "***❗获取股票价格失败,分析结果可能不准确***
" @@ -136,7 +146,7 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string { go func() { defer wg.Done() - messages := GetFinancialReports(stockCode) + messages := GetFinancialReports(stockCode, o.CrawlTimeOut) if messages == nil || len(*messages) == 0 { logger.SugaredLogger.Error("获取股票财报失败") ch <- "***❗获取股票财报失败,分析结果可能不准确***
" @@ -153,7 +163,7 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string { go func() { defer wg.Done() - messages := GetTelegraphList() + messages := GetTelegraphList(o.CrawlTimeOut) if messages == nil || len(*messages) == 0 { logger.SugaredLogger.Error("获取市场资讯失败") ch <- "***❗获取市场资讯失败,分析结果可能不准确***
" @@ -166,7 +176,7 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string { "content": message, }) } - messages = GetTopNewsList() + messages = GetTopNewsList(o.CrawlTimeOut) if messages == nil || len(*messages) == 0 { logger.SugaredLogger.Error("获取新闻资讯失败") ch <- "***❗获取新闻资讯失败,分析结果可能不准确***
" @@ -183,7 +193,7 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string { go func() { defer wg.Done() - messages := SearchStockInfo(stock, "depth") + messages := SearchStockInfo(stock, "depth", o.CrawlTimeOut) if messages == nil || len(*messages) == 0 { logger.SugaredLogger.Error("获取股票资讯失败") ch <- "***❗获取股票资讯失败,分析结果可能不准确***
" @@ -199,7 +209,7 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string { }() go func() { defer wg.Done() - messages := SearchStockInfo(stock, "telegram") + messages := SearchStockInfo(stock, "telegram", o.CrawlTimeOut) if messages == nil || len(*messages) == 0 { logger.SugaredLogger.Error("获取股票电报资讯失败") ch <- "***❗获取股票电报资讯失败,分析结果可能不准确***
" @@ -298,13 +308,13 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string { return ch } -func GetFinancialReports(stockCode string) *[]string { +func GetFinancialReports(stockCode string, crawlTimeOut int64) *[]string { // 创建一个 chromedp 上下文 - timeoutCtx, timeoutCtxCancel := context.WithTimeout(context.Background(), 30*time.Second) + timeoutCtx, timeoutCtxCancel := context.WithTimeout(context.Background(), time.Duration(crawlTimeOut)*time.Second) defer timeoutCtxCancel() var ctx context.Context var cancel context.CancelFunc - path, e := checkEdgeOnWindows() + path, e := checkBrowserOnWindows() logger.SugaredLogger.Infof("GetFinancialReports path:%s", path) if e { @@ -388,7 +398,7 @@ func (o OpenAi) NewCommonChatStream(stock, stockCode, apiURL, apiKey, Model stri wg.Add(1) go func() { defer wg.Done() - messages := SearchStockPriceInfo(stockCode) + messages := SearchStockPriceInfo(stockCode, o.CrawlTimeOut) price := "" for _, message := range *messages { price += message + ";" @@ -477,9 +487,9 @@ func (o OpenAi) NewCommonChatStream(stock, stockCode, apiURL, apiKey, Model stri return ch } -func GetTelegraphList() *[]string { +func GetTelegraphList(crawlTimeOut int64) *[]string { url := "https://www.cls.cn/telegraph" - response, err := resty.New().R(). + response, err := resty.New().SetTimeout(time.Duration(crawlTimeOut)*time.Second).R(). SetHeader("Referer", "https://www.cls.cn/"). SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.60"). Get(fmt.Sprintf(url)) @@ -499,9 +509,9 @@ func GetTelegraphList() *[]string { return &telegraph } -func GetTopNewsList() *[]string { +func GetTopNewsList(crawlTimeOut int64) *[]string { url := "https://www.cls.cn" - response, err := resty.New().R(). + response, err := resty.New().SetTimeout(time.Duration(crawlTimeOut)*time.Second).R(). SetHeader("Referer", "https://www.cls.cn/"). SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.60"). Get(fmt.Sprintf(url)) diff --git a/backend/data/openai_api_test.go b/backend/data/openai_api_test.go index 19c7a85..f097aa6 100644 --- a/backend/data/openai_api_test.go +++ b/backend/data/openai_api_test.go @@ -22,5 +22,5 @@ func TestNewDeepSeekOpenAiConfig(t *testing.T) { } func TestGetTopNewsList(t *testing.T) { - GetTopNewsList() + GetTopNewsList(30) } diff --git a/backend/data/settings_api.go b/backend/data/settings_api.go index 5b946d9..71c1ca1 100644 --- a/backend/data/settings_api.go +++ b/backend/data/settings_api.go @@ -26,6 +26,7 @@ type Settings struct { Prompt string `json:"prompt"` CheckUpdate bool `json:"checkUpdate"` QuestionTemplate string `json:"questionTemplate"` + CrawlTimeOut int64 `json:"crawlTimeOut"` } func (receiver Settings) TableName() string { @@ -63,6 +64,7 @@ func (s SettingsApi) UpdateConfig() string { "check_update": s.Config.CheckUpdate, "open_ai_api_time_out": s.Config.OpenAiApiTimeOut, "question_template": s.Config.QuestionTemplate, + "crawl_time_out": s.Config.CrawlTimeOut, }) } else { logger.SugaredLogger.Infof("未找到配置,创建默认配置:%+v", s.Config) @@ -83,6 +85,7 @@ func (s SettingsApi) UpdateConfig() string { CheckUpdate: s.Config.CheckUpdate, OpenAiApiTimeOut: s.Config.OpenAiApiTimeOut, QuestionTemplate: s.Config.QuestionTemplate, + CrawlTimeOut: s.Config.CrawlTimeOut, }) } return "保存成功!" diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go index 3be37c1..f126458 100644 --- a/backend/data/stock_data_api.go +++ b/backend/data/stock_data_api.go @@ -516,15 +516,15 @@ func (IndexBasic) TableName() string { return "tushare_index_basic" } -func SearchStockPriceInfo(stockCode string) *[]string { +func SearchStockPriceInfo(stockCode string, crawlTimeOut int64) *[]string { url := "https://www.cls.cn/stock?code=" + stockCode // 创建一个 chromedp 上下文 - timeoutCtx, timeoutCtxCancel := context.WithTimeout(context.Background(), 30*time.Second) + timeoutCtx, timeoutCtxCancel := context.WithTimeout(context.Background(), time.Duration(crawlTimeOut)*time.Second) defer timeoutCtxCancel() var ctx context.Context var cancel context.CancelFunc - path, e := checkEdgeOnWindows() + path, e := checkBrowserOnWindows() logger.SugaredLogger.Infof("SearchStockPriceInfo path:%s", path) if e { pctx, pcancel := chromedp.NewExecAllocator( @@ -608,13 +608,13 @@ func FetchPrice(ctx context.Context) (string, error) { } } } -func SearchStockInfo(stock, msgType string) *[]string { +func SearchStockInfo(stock, msgType string, crawlTimeOut int64) *[]string { // 创建一个 chromedp 上下文 - timeoutCtx, timeoutCtxCancel := context.WithTimeout(context.Background(), 30*time.Second) + timeoutCtx, timeoutCtxCancel := context.WithTimeout(context.Background(), time.Duration(crawlTimeOut)*time.Second) defer timeoutCtxCancel() var ctx context.Context var cancel context.CancelFunc - path, e := checkEdgeOnWindows() + path, e := checkBrowserOnWindows() logger.SugaredLogger.Infof("SearchStockInfo path:%s", path) if e { @@ -712,8 +712,32 @@ func SearchStockInfoByCode(stock string) *[]string { return &messages } -// checkEdgeOnWindows 在 Windows 系统上检查Edge浏览器是否安装,并返回安装路径 -func checkEdgeOnWindows() (string, bool) { +// checkChromeOnWindows 在 Windows 系统上检查谷歌浏览器是否安装 +func checkChromeOnWindows() (string, bool) { + key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe`, registry.QUERY_VALUE) + if err != nil { + // 尝试在 WOW6432Node 中查找(适用于 64 位系统上的 32 位程序) + key, err = registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe`, registry.QUERY_VALUE) + if err != nil { + return "", false + } + defer key.Close() + } + defer key.Close() + path, _, err := key.GetStringValue("Path") + logger.SugaredLogger.Infof("Chrome安装路径:%s", path) + if err != nil { + return "", false + } + return path + "\\chrome.exe", true +} + +// checkBrowserOnWindows 在 Windows 系统上检查Edge浏览器是否安装,并返回安装路径 +func checkBrowserOnWindows() (string, bool) { + if path, ok := checkChromeOnWindows(); ok { + return path, true + } + key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe`, registry.QUERY_VALUE) if err != nil { // 尝试在 WOW6432Node 中查找(适用于 64 位系统上的 32 位程序) diff --git a/frontend/src/components/settings.vue b/frontend/src/components/settings.vue index d767090..10320a3 100644 --- a/frontend/src/components/settings.vue +++ b/frontend/src/components/settings.vue @@ -29,7 +29,8 @@ const formValue = ref({ maxTokens: 1024, prompt:"", timeout: 5, - questionTemplate: "{{stockName}}分析和总结" + questionTemplate: "{{stockName}}分析和总结", + crawlTimeOut:30, } }) @@ -56,6 +57,7 @@ onMounted(()=>{ prompt:res.prompt, timeout:res.openAiApiTimeOut, questionTemplate:res.questionTemplate?res.questionTemplate:'{{stockName}}分析和总结', + crawlTimeOut:res.crawlTimeOut, } console.log(res) }) @@ -80,7 +82,8 @@ function saveConfig(){ tushareToken:formValue.value.tushareToken, prompt:formValue.value.openAI.prompt, openAiApiTimeOut:formValue.value.openAI.timeout, - questionTemplate:formValue.value.openAI.questionTemplate + questionTemplate:formValue.value.openAI.questionTemplate, + crawlTimeOut:formValue.value.openAI.crawlTimeOut, }) //console.log("Settings",config) @@ -148,6 +151,7 @@ function importConfig(){ prompt:config.prompt, timeout:config.openAiApiTimeOut, questionTemplate:config.questionTemplate, + crawlTimeOut:config.crawlTimeOut, } // formRef.value.resetFields() }; @@ -215,14 +219,17 @@ window.onerror = function (event, source, lineno, colno, error) { OpenAI设置 - + - + - - + + + + + @@ -253,15 +260,14 @@ window.onerror = function (event, source, lineno, colno, error) { :show-count="true" placeholder="请输入用户prompt:例如{{stockName}}[{{stockCode}}]分析和总结" :autosize="{ - minRows: 5, - maxRows: 8 + minRows: 2, + maxRows: 5 }" /> -
- + 保存 @@ -272,7 +278,6 @@ window.onerror = function (event, source, lineno, colno, error) { 导入 -
diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts index 0073ce9..41a4c2f 100644 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -77,6 +77,7 @@ export namespace data { prompt: string; checkUpdate: boolean; questionTemplate: string; + crawlTimeOut: number; static createFrom(source: any = {}) { return new Settings(source); @@ -104,6 +105,7 @@ export namespace data { this.prompt = source["prompt"]; this.checkUpdate = source["checkUpdate"]; this.questionTemplate = source["questionTemplate"]; + this.crawlTimeOut = source["crawlTimeOut"]; } convertValues(a: any, classs: any, asMap: boolean = false): any {