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 {