feat(backend): 添加股票价格信息查询功能

- 新增 SearchStockPriceInfo 函数,用于查询股票价格信息
- 更新 NewChatStream 函数,增加股票代码参数- 在前端添加股票代码参数传递
- 优化后端接口测试用例
This commit is contained in:
spark 2025-01-22 17:00:14 +08:00
parent 16e187b96c
commit e3e06d342b
8 changed files with 83 additions and 21 deletions

4
app.go
View File

@ -377,8 +377,8 @@ func (a *App) NewChat(stock string) string {
return data.NewDeepSeekOpenAi().NewChat(stock)
}
func (a *App) NewChatStream(stock string) {
msgs := data.NewDeepSeekOpenAi().NewChatStream(stock)
func (a *App) NewChatStream(stock, stockCode string) {
msgs := data.NewDeepSeekOpenAi().NewChatStream(stock, stockCode)
for msg := range msgs {
runtime.EventsEmit(a.ctx, "newChatStream", msg)
}

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"github.com/go-resty/resty/v2"
"strings"
"sync"
)
// @Author spark
@ -108,7 +109,7 @@ func (o OpenAi) NewChat(stock string) string {
//logger.SugaredLogger.Infof("%v", res.Choices[0].Message.Content)
return res.Choices[0].Message.Content
}
func (o OpenAi) NewChatStream(stock string) <-chan string {
func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string {
ch := make(chan string)
go func() {
defer close(ch)
@ -124,21 +125,42 @@ func (o OpenAi) NewChatStream(stock string) <-chan string {
},
}
messages := SearchStockInfo(stock, "depth")
for _, message := range *messages {
msg = append(msg, map[string]interface{}{
"role": "assistant",
"content": message,
})
}
wg := &sync.WaitGroup{}
messages = SearchStockInfo(stock, "telegram")
for _, message := range *messages {
wg.Add(3)
go func() {
defer wg.Done()
messages := SearchStockPriceInfo(stockCode)
price := ""
for _, message := range *messages {
price += message + ";"
}
msg = append(msg, map[string]interface{}{
"role": "assistant",
"content": message,
"content": stock + "当前价格:" + price,
})
}
}()
go func() {
defer wg.Done()
messages := SearchStockInfo(stock, "depth")
for _, message := range *messages {
msg = append(msg, map[string]interface{}{
"role": "assistant",
"content": message,
})
}
}()
go func() {
defer wg.Done()
messages := SearchStockInfo(stock, "telegram")
for _, message := range *messages {
msg = append(msg, map[string]interface{}{
"role": "assistant",
"content": message,
})
}
}()
wg.Wait()
msg = append(msg, map[string]interface{}{
"role": "user",
@ -157,6 +179,7 @@ func (o OpenAi) NewChatStream(stock string) <-chan string {
Post("/chat/completions")
if err != nil {
ch <- err.Error()
return
}
defer resp.RawBody().Close()
@ -164,6 +187,7 @@ func (o OpenAi) NewChatStream(stock string) <-chan string {
scanner := bufio.NewScanner(resp.RawBody())
for scanner.Scan() {
line := scanner.Text()
//logger.SugaredLogger.Infof("Received data: %s", line)
if strings.HasPrefix(line, "data: ") {
data := strings.TrimPrefix(line, "data: ")
if data == "[DONE]" {

View File

@ -8,7 +8,7 @@ import (
func TestNewDeepSeekOpenAiConfig(t *testing.T) {
db.Init("../../data/stock.db")
ai := NewDeepSeekOpenAi()
res := ai.NewChatStream("闻泰科技")
res := ai.NewChatStream("闻泰科技", "sh600745")
for {
select {
case msg := <-res:

View File

@ -510,6 +510,38 @@ func (IndexBasic) TableName() string {
return "tushare_index_basic"
}
func SearchStockPriceInfo(stockCode string) *[]string {
url := "https://www.cls.cn/stock?code=" + stockCode
// 创建一个 chromedp 上下文
ctx, cancel := chromedp.NewContext(
context.Background(),
)
defer cancel()
var htmlContent string
err := chromedp.Run(ctx,
chromedp.Navigate(url),
// 等待页面加载完成,可以根据需要调整等待时间
chromedp.Sleep(3*time.Second),
chromedp.OuterHTML("html", &htmlContent, chromedp.ByQuery),
)
if err != nil {
logger.SugaredLogger.Error(err.Error())
return &[]string{}
}
document, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))
if err != nil {
logger.SugaredLogger.Error(err.Error())
return &[]string{}
}
var messages []string
document.Find("div.quote-text-border,span.quote-price").Each(func(i int, selection *goquery.Selection) {
text := strutil.RemoveNonPrintable(selection.Text())
logger.SugaredLogger.Info(text)
messages = append(messages, text)
})
return &messages
}
func SearchStockInfo(stock, msgType string) *[]string {
// 创建一个 chromedp 上下文
ctx, cancel := chromedp.NewContext(

View File

@ -49,6 +49,11 @@ func TestGetTelegraphSearch(t *testing.T) {
logger.SugaredLogger.Info(message)
}
//https://www.cls.cn/stock?code=sh600745
}
func TestGetTelegraphSearch2(t *testing.T) {
SearchStockPriceInfo("sh600745")
}
func TestParseFullSingleStockData(t *testing.T) {

View File

@ -378,12 +378,13 @@ function SendMessage(result,type){
SendDingDingMessageByType(msg,result["股票代码"],type)
}
function aiCheckStock(stock){
function aiCheckStock(stock,stockCode){
data.airesult=""
data.name=stock
data.code=stockCode
modalShow4.value=true
message.loading("ai检测中...")
NewChatStream(stock)
NewChatStream(stock,stockCode)
}
function getTypeName(type){
@ -443,7 +444,7 @@ function getHeight() {
<n-button size="tiny" secondary type="primary" @click="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
取消关注
</n-button>&nbsp;
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning" @click="aiCheckStock(result['股票名称'])"> AI分析 </n-button>
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning" @click="aiCheckStock(result['股票名称'],result['股票代码'])"> AI分析 </n-button>
</template>
<template #footer>

View File

@ -14,7 +14,7 @@ export function Greet(arg1:string):Promise<data.StockInfo>;
export function NewChat(arg1:string):Promise<string>;
export function NewChatStream(arg1:string):Promise<void>;
export function NewChatStream(arg1:string,arg2:string):Promise<void>;
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;

View File

@ -26,8 +26,8 @@ export function NewChat(arg1) {
return window['go']['main']['App']['NewChat'](arg1);
}
export function NewChatStream(arg1) {
return window['go']['main']['App']['NewChatStream'](arg1);
export function NewChatStream(arg1, arg2) {
return window['go']['main']['App']['NewChatStream'](arg1, arg2);
}
export function SendDingDingMessage(arg1, arg2) {