Compare commits
5 Commits
v2026.01.0
...
v2026.01.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ca0d0df32 | ||
|
|
fea9b06a27 | ||
|
|
1d1e437b47 | ||
|
|
eca2f8adee | ||
|
|
49d2109d60 |
47
app.go
47
app.go
@@ -70,9 +70,10 @@ func AddTools(tools []data.Tool) []data.Tool {
|
||||
"words": map[string]any{
|
||||
"type": "string",
|
||||
"description": "选股自然语言。" +
|
||||
"例如,查看技术指标:上海贝岭,macd,rsi,kdj,boll,5日均线,14日均线,30日均线,60日均线,成交量,OBV,EMA" +
|
||||
"例如查看近期趋势:量比连续2天>1,主力连续2日净流入且递增,主力净额>3000万元,行业,股价在20日线上" +
|
||||
"例如,查看有潜力的成交量爆发股:最近7日成交量量比大于3,出现过一次,非ST" +
|
||||
"例如:查看技术指标:上海贝岭,macd,rsi,kdj,boll,5日均线,14日均线,30日均线,60日均线,成交量,OBV,EMA" +
|
||||
"例如:查看近期趋势:量比连续2天>1,主力连续2日净流入且递增,主力净额>3000万元,行业,股价在20日线上" +
|
||||
"例如:当日成交量 ≥ 近 5 日平均成交量 ×1.5,收盘价 ≥ 20 日均线,20 日均线 ≥ 60 日均线,当日涨幅 3%-7%, 3日主力资金净流入累计≥5000 万元,当日换手率 5%-15%,筹码集中度(90% 筹码峰)≤15%,非创业板非科创板非ST非北交所,行业," +
|
||||
"例如:查看有潜力的成交量爆发股:最近7日成交量量比大于3,出现过一次,非ST" +
|
||||
"例1:创新药,半导体;PE<30;净利润增长率>50%。 " +
|
||||
"例2:上证指数,科创50。 " +
|
||||
"例3:长电科技,上海贝岭。" +
|
||||
@@ -206,6 +207,41 @@ func AddTools(tools []data.Tool) []data.Tool {
|
||||
},
|
||||
})
|
||||
|
||||
tools = append(tools, data.Tool{
|
||||
Type: "function",
|
||||
Function: data.ToolFunction{
|
||||
Name: "GetStockMoneyData",
|
||||
Description: "今日股票资金流入排名",
|
||||
Parameters: &data.FunctionParameters{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"pageSize": map[string]any{
|
||||
"type": "string",
|
||||
"description": "分页大小",
|
||||
},
|
||||
},
|
||||
Required: []string{"pageSize"},
|
||||
},
|
||||
},
|
||||
})
|
||||
tools = append(tools, data.Tool{
|
||||
Type: "function",
|
||||
Function: data.ToolFunction{
|
||||
Name: "GetStockConceptInfo",
|
||||
Description: "获取股票所属概念详细信息",
|
||||
Parameters: &data.FunctionParameters{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"code": map[string]any{
|
||||
"type": "string",
|
||||
"description": "股票代码,如:601138.SH。注意 上海证券交易所股票以.SH结尾,深圳证券交易所股票以.SZ结尾,港股股票以.HK结尾,北交所股票以.BJ结尾,",
|
||||
},
|
||||
},
|
||||
Required: []string{"code"},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return tools
|
||||
}
|
||||
|
||||
@@ -472,7 +508,10 @@ func (a *App) syncNews() {
|
||||
}
|
||||
if cnt == 0 {
|
||||
db.Dao.Model(telegraph).Create(&telegraph)
|
||||
a.NewsPush(&[]models.Telegraph{*telegraph})
|
||||
//计算时间差如果<5分钟则推送
|
||||
if time.Now().Sub(dataTime) < 5*time.Minute {
|
||||
a.NewsPush(&[]models.Telegraph{*telegraph})
|
||||
}
|
||||
tags := slice.Filter(news.Tags, func(index int, item string) bool {
|
||||
return !(item == "rotating_light" || item == "loudspeaker")
|
||||
})
|
||||
|
||||
@@ -43,6 +43,8 @@ type OpenAi struct {
|
||||
CrawlTimeOut int64 `json:"crawl_time_out"`
|
||||
KDays int64 `json:"kDays"`
|
||||
BrowserPath string `json:"browser_path"`
|
||||
HttpProxy string `json:"httpProxy"`
|
||||
HttpProxyEnabled bool `json:"httpProxyEnabled"`
|
||||
}
|
||||
|
||||
func (o OpenAi) String() string {
|
||||
@@ -67,7 +69,7 @@ func NewDeepSeekOpenAi(ctx context.Context, aiConfigId int) *OpenAi {
|
||||
settingConfig.CrawlTimeOut = 60
|
||||
}
|
||||
if settingConfig.KDays < 30 {
|
||||
settingConfig.KDays = 120
|
||||
settingConfig.KDays = 60
|
||||
}
|
||||
}
|
||||
o := &OpenAi{
|
||||
@@ -78,6 +80,8 @@ func NewDeepSeekOpenAi(ctx context.Context, aiConfigId int) *OpenAi {
|
||||
MaxTokens: aiConfig.MaxTokens,
|
||||
Temperature: aiConfig.Temperature,
|
||||
TimeOut: aiConfig.TimeOut,
|
||||
HttpProxy: aiConfig.HttpProxy,
|
||||
HttpProxyEnabled: aiConfig.HttpProxyEnabled,
|
||||
Prompt: settingConfig.Prompt,
|
||||
QuestionTemplate: settingConfig.QuestionTemplate,
|
||||
CrawlTimeOut: settingConfig.CrawlTimeOut,
|
||||
@@ -193,22 +197,22 @@ func (o *OpenAi) NewSummaryStockNewsStreamWithTools(userQuestion string, sysProm
|
||||
"content": "当前本地时间是:" + time.Now().Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(5)
|
||||
wg.Add(4)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
res := NewMarketNewsApi().XUEQIUHotStock(50, "10")
|
||||
md := util.MarkdownTableWithTitle("当前热门股票排名", res)
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "user",
|
||||
"content": "当前热门股票排名数据",
|
||||
})
|
||||
msg = append(msg, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"reasoning_content": "使用工具查询",
|
||||
"content": md,
|
||||
})
|
||||
}()
|
||||
//go func() {
|
||||
// defer wg.Done()
|
||||
// res := NewMarketNewsApi().XUEQIUHotStock(50, "10")
|
||||
// md := util.MarkdownTableWithTitle("当前热门股票排名", res)
|
||||
// msg = append(msg, map[string]interface{}{
|
||||
// "role": "user",
|
||||
// "content": "当前热门股票排名数据",
|
||||
// })
|
||||
// msg = append(msg, map[string]interface{}{
|
||||
// "role": "assistant",
|
||||
// "reasoning_content": "使用工具查询",
|
||||
// "content": md,
|
||||
// })
|
||||
//}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
datas := NewMarketNewsApi().InteractiveAnswer(1, 100, "")
|
||||
@@ -977,18 +981,27 @@ func AskAi(o *OpenAi, err error, messages []map[string]interface{}, ch chan map[
|
||||
thinking = "enabled"
|
||||
}
|
||||
client.SetTimeout(time.Duration(o.TimeOut) * time.Second)
|
||||
if o.HttpProxyEnabled && o.HttpProxy != "" {
|
||||
client.SetProxy(o.HttpProxy)
|
||||
}
|
||||
bodyMap := map[string]interface{}{
|
||||
"model": o.Model,
|
||||
"max_tokens": o.MaxTokens,
|
||||
"temperature": o.Temperature,
|
||||
"stream": true,
|
||||
"messages": messages,
|
||||
}
|
||||
if think {
|
||||
bodyMap["thinking"] = map[string]any{
|
||||
//"type": "disabled",
|
||||
//"type": "enabled",
|
||||
"type": thinking,
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := client.R().
|
||||
SetDoNotParseResponse(true).
|
||||
SetBody(map[string]interface{}{
|
||||
"model": o.Model,
|
||||
"thinking": map[string]any{
|
||||
"type": thinking,
|
||||
},
|
||||
"max_tokens": o.MaxTokens,
|
||||
"temperature": o.Temperature,
|
||||
"stream": true,
|
||||
"messages": messages,
|
||||
}).
|
||||
SetBody(bodyMap).
|
||||
Post("/chat/completions")
|
||||
|
||||
body := resp.RawBody()
|
||||
@@ -1128,21 +1141,28 @@ func AskAiWithTools(o *OpenAi, err error, messages []map[string]interface{}, ch
|
||||
thinking = "enabled"
|
||||
}
|
||||
client.SetTimeout(time.Duration(o.TimeOut) * time.Second)
|
||||
if o.HttpProxyEnabled && o.HttpProxy != "" {
|
||||
client.SetProxy(o.HttpProxy)
|
||||
}
|
||||
bodyMap := map[string]interface{}{
|
||||
"model": o.Model,
|
||||
"max_tokens": o.MaxTokens,
|
||||
"temperature": o.Temperature,
|
||||
"stream": true,
|
||||
"messages": messages,
|
||||
"tools": tools,
|
||||
}
|
||||
if thinkingMode {
|
||||
bodyMap["thinking"] = map[string]any{
|
||||
//"type": "disabled",
|
||||
//"type": "enabled",
|
||||
"type": thinking,
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := client.R().
|
||||
SetDoNotParseResponse(true).
|
||||
SetBody(map[string]interface{}{
|
||||
"model": o.Model,
|
||||
"thinking": map[string]any{
|
||||
//"type": "disabled",
|
||||
//"type": "enabled",
|
||||
"type": thinking,
|
||||
},
|
||||
"max_tokens": o.MaxTokens,
|
||||
"temperature": o.Temperature,
|
||||
"stream": true,
|
||||
"messages": messages,
|
||||
"tools": tools,
|
||||
}).
|
||||
SetBody(bodyMap).
|
||||
Post("/chat/completions")
|
||||
|
||||
body := resp.RawBody()
|
||||
@@ -1720,6 +1740,83 @@ func AskAiWithTools(o *OpenAi, err error, messages []map[string]interface{}, ch
|
||||
|
||||
}
|
||||
|
||||
if funcName == "GetStockMoneyData" {
|
||||
ch <- map[string]any{
|
||||
"code": 1,
|
||||
"question": question,
|
||||
"chatId": streamResponse.Id,
|
||||
"model": streamResponse.Model,
|
||||
"content": "\r\n```\r\n开始调用工具:GetStockMoneyData,\n参数:" + funcArguments + "\r\n```\r\n",
|
||||
"time": time.Now().Format(time.DateTime),
|
||||
}
|
||||
res := NewStockDataApi().GetStockMoneyData()
|
||||
md := util.MarkdownTableWithTitle("今日个股资金流向Top50", res.Data.Diff)
|
||||
logger.SugaredLogger.Infof("%s", md)
|
||||
messages = append(messages, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": currentAIContent.String(),
|
||||
"reasoning_content": reasoningContentText.String(),
|
||||
"tool_calls": []map[string]any{
|
||||
{
|
||||
"id": currentCallId,
|
||||
"tool_call_id": currentCallId,
|
||||
"type": "function",
|
||||
"function": map[string]string{
|
||||
"name": funcName,
|
||||
"arguments": funcArguments,
|
||||
"parameters": funcArguments,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
messages = append(messages, map[string]interface{}{
|
||||
"role": "tool",
|
||||
"content": md,
|
||||
"tool_call_id": currentCallId,
|
||||
//"reasoning_content": reasoningContentText.String(),
|
||||
//"tool_calls": choice.Delta.ToolCalls,
|
||||
})
|
||||
}
|
||||
|
||||
if funcName == "GetStockConceptInfo" {
|
||||
ch <- map[string]any{
|
||||
"code": 1,
|
||||
"question": question,
|
||||
"chatId": streamResponse.Id,
|
||||
"model": streamResponse.Model,
|
||||
"content": "\r\n```\r\n开始调用工具:GetStockConceptInfo,\n参数:" + funcArguments + "\r\n```\r\n",
|
||||
"time": time.Now().Format(time.DateTime),
|
||||
}
|
||||
code := gjson.Get(funcArguments, "code").String()
|
||||
res := NewStockDataApi().GetStockConceptInfo(code)
|
||||
md := util.MarkdownTableWithTitle(code+" 股票所属概念详细信息", res.Result.Data)
|
||||
logger.SugaredLogger.Infof("%s", md)
|
||||
messages = append(messages, map[string]interface{}{
|
||||
"role": "assistant",
|
||||
"content": currentAIContent.String(),
|
||||
"reasoning_content": reasoningContentText.String(),
|
||||
"tool_calls": []map[string]any{
|
||||
{
|
||||
"id": currentCallId,
|
||||
"tool_call_id": currentCallId,
|
||||
"type": "function",
|
||||
"function": map[string]string{
|
||||
"name": funcName,
|
||||
"arguments": funcArguments,
|
||||
"parameters": funcArguments,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
messages = append(messages, map[string]interface{}{
|
||||
"role": "tool",
|
||||
"content": md,
|
||||
"tool_call_id": currentCallId,
|
||||
//"reasoning_content": reasoningContentText.String(),
|
||||
//"tool_calls": choice.Delta.ToolCalls,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
AskAiWithTools(o, err, messages, ch, question, tools, thinkingMode)
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ func TestNewDeepSeekOpenAiConfig(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
ai := NewDeepSeekOpenAi(context.TODO(), 0)
|
||||
ai := NewDeepSeekOpenAi(context.TODO(), 11)
|
||||
//res := ai.NewChatStream("长电科技", "sh600584", "长电科技分析和总结", nil)
|
||||
res := ai.NewSummaryStockNewsStreamWithTools("总结市场资讯,发掘潜力标的/行业/板块/概念,控制风险。调用工具函数验证", nil, tools, true)
|
||||
res := ai.NewSummaryStockNewsStreamWithTools("总结市场资讯,发掘潜力标的/行业/板块/概念,控制风险。调用工具函数验证", nil, tools, false)
|
||||
|
||||
for {
|
||||
select {
|
||||
|
||||
@@ -45,16 +45,18 @@ func (receiver Settings) TableName() string {
|
||||
}
|
||||
|
||||
type AIConfig struct {
|
||||
ID uint `gorm:"primarykey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Name string `json:"name"`
|
||||
BaseUrl string `json:"baseUrl"`
|
||||
ApiKey string `json:"apiKey" `
|
||||
ModelName string `json:"modelName"`
|
||||
MaxTokens int `json:"maxTokens"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
TimeOut int `json:"timeOut"`
|
||||
ID uint `gorm:"primarykey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Name string `json:"name"`
|
||||
BaseUrl string `json:"baseUrl"`
|
||||
ApiKey string `json:"apiKey" `
|
||||
ModelName string `json:"modelName"`
|
||||
MaxTokens int `json:"maxTokens"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
TimeOut int `json:"timeOut"`
|
||||
HttpProxy string `json:"httpProxy"`
|
||||
HttpProxyEnabled bool `json:"httpProxyEnabled"`
|
||||
}
|
||||
|
||||
func (AIConfig) TableName() string {
|
||||
@@ -163,13 +165,15 @@ func updateAiConfigs(aiConfigs []*AIConfig) error {
|
||||
} else {
|
||||
notDeleteIds = append(notDeleteIds, item.ID)
|
||||
e = db.Dao.Model(&AIConfig{}).Where("id=?", item.ID).Updates(map[string]interface{}{
|
||||
"name": item.Name,
|
||||
"base_url": item.BaseUrl,
|
||||
"api_key": item.ApiKey,
|
||||
"model_name": item.ModelName,
|
||||
"max_tokens": item.MaxTokens,
|
||||
"temperature": item.Temperature,
|
||||
"time_out": item.TimeOut,
|
||||
"name": item.Name,
|
||||
"base_url": item.BaseUrl,
|
||||
"api_key": item.ApiKey,
|
||||
"model_name": item.ModelName,
|
||||
"max_tokens": item.MaxTokens,
|
||||
"temperature": item.Temperature,
|
||||
"time_out": item.TimeOut,
|
||||
"http_proxy": item.HttpProxy,
|
||||
"http_proxy_enabled": item.HttpProxyEnabled,
|
||||
}).Error
|
||||
if e != nil {
|
||||
return
|
||||
@@ -198,12 +202,6 @@ func GetSettingConfig() *SettingConfig {
|
||||
aiConfigs := make([]*AIConfig, 0)
|
||||
// 处理数据库查询可能返回的空结果
|
||||
result := db.Dao.Model(&Settings{}).First(settings)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
// 初始化默认设置并保存到数据库
|
||||
settings = &Settings{OpenAiEnable: false, CrawlTimeOut: 60}
|
||||
db.Dao.Create(settings)
|
||||
}
|
||||
|
||||
if settings.OpenAiEnable {
|
||||
// 处理AI配置查询可能出现的错误
|
||||
result = db.Dao.Model(&AIConfig{}).Find(&aiConfigs)
|
||||
@@ -220,7 +218,7 @@ func GetSettingConfig() *SettingConfig {
|
||||
settings.CrawlTimeOut = 60
|
||||
}
|
||||
if settings.KDays < 30 {
|
||||
settings.KDays = 120
|
||||
settings.KDays = 60
|
||||
}
|
||||
}
|
||||
if settings.BrowserPath == "" {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"go-stock/backend/models"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
url2 "net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -1750,6 +1751,65 @@ func (receiver StockDataApi) GetStockHistoryMoneyData() {
|
||||
|
||||
}
|
||||
|
||||
// GetStockMoneyData 获取个股资金流数据
|
||||
func (receiver StockDataApi) GetStockMoneyData() models.StockMoneyDataResp {
|
||||
var resData models.StockMoneyDataResp
|
||||
url := "https://push2.eastmoney.com/api/qt/clist/get?cb=data&fid=f62&po=1&pz=50&pn=1&np=1&fltt=2&invt=2&ut=8dec03ba335b81bf4ebdf7b29ec27d15&fs=m:0+t:6+f:!2,m:0+t:13+f:!2,m:0+t:80+f:!2,m:1+t:2+f:!2,m:1+t:23+f:!2,m:0+t:7+f:!2,m:1+t:3+f:!2&fields=f12,f14,f2,f3,f62,f184,f66,f69,f72,f75,f78,f81,f84,f87,f204,f205,f124,f1,f13,f100,f265"
|
||||
resp, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
||||
SetHeader("Host", "push2.eastmoney.com").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0").
|
||||
Get(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||
}
|
||||
body := string(resp.Body())
|
||||
logger.SugaredLogger.Infof("resp:%s", body)
|
||||
vm := otto.New()
|
||||
vm.Run("function data(res){return res};")
|
||||
val, err := vm.Run(body)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||
}
|
||||
value, err := val.Export()
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||
}
|
||||
marshal, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||
return models.StockMoneyDataResp{}
|
||||
}
|
||||
err = json.Unmarshal(marshal, &resData)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||
return models.StockMoneyDataResp{}
|
||||
}
|
||||
return resData
|
||||
}
|
||||
|
||||
// 获取股票概念题材信息
|
||||
func (receiver StockDataApi) GetStockConceptInfo(stockCode string) models.StockConceptInfoResp {
|
||||
//601138.SH
|
||||
url := "https://datacenter.eastmoney.com/securities/api/data/v1/get?reportName=RPT_F10_CORETHEME_BOARDTYPE&columns=SECUCODE%2CSECURITY_CODE%2CSECURITY_NAME_ABBR%2CNEW_BOARD_CODE%2CBOARD_NAME%2CSELECTED_BOARD_REASON%2CIS_PRECISE%2CBOARD_RANK%2CBOARD_YIELD%2CDERIVE_BOARD_CODE"eColumns=f3~05~NEW_BOARD_CODE~BOARD_YIELD&filter=(SECUCODE%3D%22" + stockCode + "%22)(IS_PRECISE%3D%221%22)&pageNumber=1&pageSize=&sortTypes=1&sortColumns=BOARD_RANK&source=HSF10&client=PC&v=005634233622011753"
|
||||
logger.SugaredLogger.Infof("url:%s", url2.QueryEscape(url))
|
||||
var data models.StockConceptInfoResp
|
||||
resp, err := receiver.client.SetTimeout(time.Duration(receiver.config.CrawlTimeOut)*time.Second).R().
|
||||
SetHeader("Host", "datacenter.eastmoney.com").
|
||||
SetHeader("Referer", "https://emweb.securities.eastmoney.com/").
|
||||
SetHeader("Origin", "https://emweb.securities.eastmoney.com").
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0").
|
||||
Get(url)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||
}
|
||||
err = json.Unmarshal(resp.Body(), &data)
|
||||
if err != nil {
|
||||
logger.SugaredLogger.Errorf("err:%s", err.Error())
|
||||
return models.StockConceptInfoResp{}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// JSONToMarkdownTable 将JSON数据转换为Markdown表格
|
||||
func JSONToMarkdownTable(jsonData []byte) (string, error) {
|
||||
var data []map[string]interface{}
|
||||
|
||||
@@ -283,3 +283,17 @@ func TestName(t *testing.T) {
|
||||
//}
|
||||
|
||||
}
|
||||
func TestGetStockMoneyData(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
stockDataApi := NewStockDataApi()
|
||||
res := stockDataApi.GetStockMoneyData()
|
||||
logger.SugaredLogger.Infof("%s", util.MarkdownTableWithTitle("今日个股资金流向Top50", res.Data.Diff))
|
||||
}
|
||||
|
||||
func TestGetStockConceptInfo(t *testing.T) {
|
||||
db.Init("../../data/stock.db")
|
||||
stockDataApi := NewStockDataApi()
|
||||
res := stockDataApi.GetStockConceptInfo("601138.SH")
|
||||
logger.SugaredLogger.Infof("%s", util.MarkdownTableWithTitle("601138.SH所属概念/板块信息", res.Result.Data))
|
||||
|
||||
}
|
||||
|
||||
@@ -812,3 +812,67 @@ type THSHotStrategy struct {
|
||||
} `json:"list"`
|
||||
} `json:"result"`
|
||||
}
|
||||
|
||||
type StockMoneyDataResp struct {
|
||||
Rc int `json:"rc"`
|
||||
Rt int `json:"rt"`
|
||||
Svr int `json:"svr"`
|
||||
Lt int `json:"lt"`
|
||||
Full int `json:"full"`
|
||||
Dlmkts string `json:"dlmkts"`
|
||||
Data StockMoneyData `json:"data"`
|
||||
}
|
||||
|
||||
type StockMoneyData struct {
|
||||
Total int `json:"total"`
|
||||
Diff []StockMoneyDataDiff `json:"diff"`
|
||||
}
|
||||
|
||||
type StockMoneyDataDiff struct {
|
||||
F1 int `json:"f1" md:"-"`
|
||||
F12 string `json:"f12" md:"股票代码"`
|
||||
F13 int `json:"f13" md:"-"`
|
||||
F14 string `json:"f14" md:"股票名称"`
|
||||
F2 float64 `json:"f2" md:"最新价"`
|
||||
F3 float64 `json:"f3" md:"今日涨跌幅(%)"`
|
||||
F62 float64 `json:"f62" md:"今日主力净额(元)"`
|
||||
F184 float64 `json:"f184" md:"今日主力净占比(%)"`
|
||||
F66 float64 `json:"f66" md:"今日超大单净额(元)"`
|
||||
F69 float64 `json:"f69" md:"今日超大单净占比(%)"`
|
||||
F72 float64 `json:"f72" md:"今日大单净额(元)"`
|
||||
F75 float64 `json:"f75" md:"今日大单净占比(%)"`
|
||||
F78 float64 `json:"f78" md:"今日中单净额(元)"`
|
||||
F81 float64 `json:"f81" md:"今日中单净占比(%)"`
|
||||
F84 float64 `json:"f84" md:"今日小单净额(元)"`
|
||||
F87 float64 `json:"f87" md:"今日小单净占比(%)"`
|
||||
F124 int `json:"f124" md:"f124"`
|
||||
F100 string `json:"f100" md:"所属板块"`
|
||||
F265 string `json:"f265" md:"板块代码"`
|
||||
}
|
||||
|
||||
type StockConceptInfoResp struct {
|
||||
Version string `json:"version"`
|
||||
Result StockConceptInfoResult `json:"result"`
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
type StockConceptInfoResult struct {
|
||||
Pages int `json:"pages"`
|
||||
Data []StockConceptInfo `json:"data"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
type StockConceptInfo struct {
|
||||
SECUCODE string `json:"SECUCODE" md:"完整股票代码"`
|
||||
SECURITYCODE string `json:"SECURITY_CODE" md:"股票代码"`
|
||||
SECURITYNAMEABBR string `json:"SECURITY_NAME_ABBR" md:"股票名称"`
|
||||
NEWBOARDCODE string `json:"NEW_BOARD_CODE" md:"板块/概念代码"`
|
||||
BOARDNAME string `json:"BOARD_NAME" md:"板块/概念名称"`
|
||||
SELECTEDBOARDREASON string `json:"SELECTED_BOARD_REASON" md:"板块/概念描述"`
|
||||
ISPRECISE string `json:"IS_PRECISE" md:"-"`
|
||||
BOARDRANK int `json:"BOARD_RANK" md:"-"`
|
||||
BOARDYIELD float64 `json:"BOARD_YIELD" md:"板块/概念涨跌幅(%)"`
|
||||
DERIVEBOARDCODE string `json:"DERIVE_BOARD_CODE" md:"-"`
|
||||
}
|
||||
|
||||
@@ -121,10 +121,10 @@ EventsOn("updateVersion",async (msg) => {
|
||||
<n-space vertical >
|
||||
<n-image width="100" :src="icon" />
|
||||
<h1>
|
||||
<n-badge v-if="!vipLevel" :value="versionInfo" :offset="[50,10]" type="success">
|
||||
<n-badge v-if="!vipLevel" :value="versionInfo" :offset="[80,10]" type="success">
|
||||
<n-gradient-text type="info" :size="50" >go-stock</n-gradient-text>
|
||||
</n-badge>
|
||||
<n-badge v-if="vipLevel" :value="versionInfo" :offset="[50,10]" type="success">
|
||||
<n-badge v-if="vipLevel" :value="versionInfo" :offset="[70,10]" type="success">
|
||||
<n-gradient-text :type="expired?'error':'warning'" :size="50" >go-stock</n-gradient-text><n-tag :bordered="false" size="small" type="warning">VIP{{vipLevel}}</n-tag>
|
||||
</n-badge>
|
||||
</h1>
|
||||
|
||||
@@ -34,6 +34,8 @@ const formValue = ref({
|
||||
questionTemplate: "{{stockName}}分析和总结",
|
||||
crawlTimeOut: 30,
|
||||
kDays: 30,
|
||||
httpProxy:"",
|
||||
httpProxyEnabled:false,
|
||||
},
|
||||
enableDanmu: false,
|
||||
browserPath: '',
|
||||
@@ -57,8 +59,10 @@ function addAiConfig() {
|
||||
apiKey: '',
|
||||
modelName: 'deepseek-chat',
|
||||
temperature: 0.1,
|
||||
maxTokens: 1024,
|
||||
maxTokens: 4096,
|
||||
timeOut: 60,
|
||||
httpProxy:"",
|
||||
httpProxyEnabled:false,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -92,6 +96,8 @@ onMounted(() => {
|
||||
questionTemplate: res.questionTemplate ? res.questionTemplate : '{{stockName}}分析和总结',
|
||||
crawlTimeOut: res.crawlTimeOut,
|
||||
kDays: res.kDays,
|
||||
httpProxy:"",
|
||||
httpProxyEnabled:false,
|
||||
}
|
||||
|
||||
|
||||
@@ -388,14 +394,14 @@ function deletePrompt(ID) {
|
||||
</n-form-item-gi>
|
||||
<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-input-number min="30" step="1" max="60" v-model:value="formValue.openAI.kDays"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="2" label="http代理" path="httpProxyEnabled">
|
||||
<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-input type="text" placeholder="爬虫http代理地址" v-model:value="formValue.httpProxy" clearable/>
|
||||
</n-form-item-gi>
|
||||
|
||||
|
||||
@@ -452,6 +458,12 @@ function deletePrompt(ID) {
|
||||
<n-form-item-gi :span="5" label="Timeout(秒)" :path="`openAI.aiConfigs[${index}].timeOut`">
|
||||
<n-input-number min="60" step="1" placeholder="超时(秒)" v-model:value="aiConfig.timeOut"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="http代理" :path="`openAI.aiConfigs[${index}].httpProxyEnabled`">
|
||||
<n-switch v-model:value="aiConfig.httpProxyEnabled"/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" v-if="aiConfig.httpProxyEnabled" title="http代理地址" :path="`openAI.aiConfigs[${index}].httpProxy`">
|
||||
<n-input type="text" placeholder="http代理地址" v-model:value="aiConfig.httpProxy" clearable/>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
<n-button type="primary" dashed @click="addAiConfig" style="width: 100%;">+ 添加AI配置</n-button>
|
||||
|
||||
@@ -13,6 +13,8 @@ export namespace data {
|
||||
maxTokens: number;
|
||||
temperature: number;
|
||||
timeOut: number;
|
||||
httpProxy: string;
|
||||
httpProxyEnabled: boolean;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new AIConfig(source);
|
||||
@@ -30,6 +32,8 @@ export namespace data {
|
||||
this.maxTokens = source["maxTokens"];
|
||||
this.temperature = source["temperature"];
|
||||
this.timeOut = source["timeOut"];
|
||||
this.httpProxy = source["httpProxy"];
|
||||
this.httpProxyEnabled = source["httpProxyEnabled"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
|
||||
Reference in New Issue
Block a user