Compare commits

...

1 Commits

Author SHA1 Message Date
ArvinLovegood
6c31f5aa76 feat(ai):添加AI推荐股票批量创建功能
- 在后端服务中实现BatchCreateAiRecommendStocks方法支持批量插入
- 前端组件中增加bkName字段到搜索关键词匹配
- 更新API文档描述,细化止盈价区间格式说明
- 添加批量创建工具函数定义和参数校验规则
- 实现OpenAI API中的批量调用处理逻辑
- 优化板块名称描述为"板块/概念/行业名称"
- 完善风险提示和备注字段的功能说明
2026-01-27 13:17:26 +08:00
4 changed files with 144 additions and 4 deletions

88
app.go
View File

@@ -276,7 +276,7 @@ func AddTools(tools []data.Tool) []data.Tool {
},
"bkName": map[string]any{
"type": "string",
"description": "板块/行业名称",
"description": "板块/概念/行业名称",
},
"stockPrice": map[string]any{
"type": "string",
@@ -300,7 +300,7 @@ func AddTools(tools []data.Tool) []data.Tool {
},
"recommendStopProfitPrice": map[string]any{
"type": "string",
"description": "ai建议止盈价",
"description": "ai建议止盈价区间最低价和最高价之间用`-`分隔",
},
"recommendStopLossPrice": map[string]any{
"type": "string",
@@ -312,10 +312,90 @@ func AddTools(tools []data.Tool) []data.Tool {
},
"remarks": map[string]any{
"type": "string",
"description": "备注",
"description": "操作总结/备注",
},
},
Required: []string{"stockCode", "stockName"},
Required: []string{"stockCode", "stockName", "bkName"},
},
},
})
//BatchCreateAiRecommendStocks
tools = append(tools, data.Tool{
Type: "function",
Function: data.ToolFunction{
Name: "BatchCreateAiRecommendStocks",
Description: "批量创建/保存AI推荐股票记录建议每次批量保存5条记录",
Parameters: &data.FunctionParameters{
Type: "object",
Properties: map[string]any{
"stocks": map[string]any{
"type": "array",
"items": map[string]any{
"type": "object",
"properties": map[string]any{
"modelName": map[string]any{
"type": "string",
"description": "模型名称",
},
"stockCode": map[string]any{
"type": "string",
"description": "股票代码,如601138.SH。注意 上海证券交易所股票以.SH结尾深圳证券交易所股票以.SZ结尾港股股票以.HK结尾北交所股票以.BJ结尾",
},
"stockName": map[string]any{
"type": "string",
"description": "股票名称",
},
"bkCode": map[string]any{
"type": "string",
"description": "板块/行业代码",
},
"bkName": map[string]any{
"type": "string",
"description": "板块/概念/行业名称",
},
"stockPrice": map[string]any{
"type": "string",
"description": "推荐时股票价格",
},
"stockPrePrice": map[string]any{
"type": "string",
"description": "前一交易日股票价格",
},
"stockClosePrice": map[string]any{
"type": "string",
"description": "推荐时股票收盘价格",
},
"recommendReason": map[string]any{
"type": "string",
"description": "推荐理由/驱动因素/逻辑",
},
"recommendBuyPrice": map[string]any{
"type": "string",
"description": "ai建议买入价区间最低价和最高价之间用`-`分隔",
},
"recommendStopProfitPrice": map[string]any{
"type": "string",
"description": "ai建议止盈价区间最低价和最高价之间用`-`分隔",
},
"recommendStopLossPrice": map[string]any{
"type": "string",
"description": "ai建议止损价",
},
"riskRemarks": map[string]any{
"type": "string",
"description": "风险提示",
},
"remarks": map[string]any{
"type": "string",
"description": "操作总结/备注",
},
},
},
},
},
Required: []string{"stockCode", "stockName", "bkName"},
},
},
})

View File

@@ -21,6 +21,11 @@ func (s *AiRecommendStocksService) CreateAiRecommendStocks(recommend *models.AiR
return result.Error
}
func (s *AiRecommendStocksService) BatchCreateAiRecommendStocks(recommends []*models.AiRecommendStocks) error {
result := db.Dao.Create(recommends)
return result.Error
}
// GetAiRecommendStocksList 分页查询AI推荐股票记录
func (s *AiRecommendStocksService) GetAiRecommendStocksList(query *models.AiRecommendStocksQuery) (*models.AiRecommendStocksPageData, error) {
var list []models.AiRecommendStocks
@@ -41,6 +46,7 @@ func (s *AiRecommendStocksService) GetAiRecommendStocksList(query *models.AiReco
if query.BkName != "" {
q.Or("bk_name LIKE ?", "%"+query.BkName+"%")
}
if query.StartDate != "" && query.EndDate != "" {
query.StartDate = strutil.ReplaceWithMap(query.StartDate, map[string]string{
"T": " ",

View File

@@ -1870,6 +1870,59 @@ func AskAiWithTools(o *OpenAi, err error, messages []map[string]interface{}, ch
})
}
//BatchCreateAiRecommendStocks
if funcName == "BatchCreateAiRecommendStocks" {
ch <- map[string]any{
"code": 1,
"question": question,
"chatId": streamResponse.Id,
"model": streamResponse.Model,
"content": "\r\n```\r\n开始调用工具BatchCreateAiRecommendStocks\n参数" + funcArguments + "\r\n```\r\n",
"time": time.Now().Format(time.DateTime),
}
stocks := gjson.Get(funcArguments, "stocks").String()
var recommends []*models.AiRecommendStocks
err := json.Unmarshal([]byte(stocks), &recommends)
if err != nil {
logger.SugaredLogger.Infof("BatchCreateAiRecommendStocks error : %s", err.Error())
return
}
err = NewAiRecommendStocksService().BatchCreateAiRecommendStocks(recommends)
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,
},
},
},
})
if err != nil {
logger.SugaredLogger.Infof("BatchCreateAiRecommendStocks error : %s", err.Error())
ch <- map[string]any{
"code": 0,
"question": question,
"content": "批量保存股票推荐失败:" + err.Error(),
}
return
}
messages = append(messages, map[string]interface{}{
"role": "tool",
"content": "批量保存股票推荐成功",
"tool_call_id": currentCallId,
//"reasoning_content": reasoningContentText.String(),
//"tool_calls": choice.Delta.ToolCalls,
})
}
}
AskAiWithTools(o, err, messages, ch, question, tools, thinkingMode)
}

View File

@@ -268,6 +268,7 @@ function query({
"modelName":keyword,
"stockName":keyword,
"stockCode":keyword,
"bkName":keyword,
"startDate": startDate,
"endDate": endDate
}).then((res) => {