Compare commits

...

29 Commits

Author SHA1 Message Date
ArvinLovegood
e8f063fd9b feat(news):添加新闻情绪标签显示功能(情绪标签仅供参考)
- 在新闻列表项中新增情绪标签展示
- 根据情绪结果动态设置标签颜色和文本
- 支持看涨、看跌和其他情绪状态的可视化呈现
2025-11-20 19:25:00 +08:00
ArvinLovegood
8b0b53fae7 refactor(data):重构股票数据获取与新闻电报处理逻辑
- 修改 TelegraphList 方法返回类型为 *[]models.Telegraph
- 更新获取新闻电报的调用方式,替换原有接口方法
- 新增 Telegraph 数据创建及标签关联逻辑
- 调整股票基础信息更新策略,采用批量删除后插入
- 移除旧有的增量更新逻辑,提高数据同步效率
- 增加对 Telegraph 标签(subjects)的解析与存储支持
- 修正模型字段注解,移除无效的 gorm 标签配置
- 添加测试函数用于验证股票基础信息同步功能
2025-11-20 18:55:12 +08:00
ArvinLovegood
b29c380055 feat(backend):更新财联社电报爬取功能
- 实现 TelegraphList 方法用于获取财联社电报数据
- 添加 GetLevel 函数判断电报等级是否为重要
- 修改去重逻辑,使用 content 和 time作为唯一标识- 在模型中增加 DataTime 字段以支持时间查询
- 更新测试文件,新增对 TelegraphList 的测试用例- 调整 GetNewsList2 方法,触发 TelegraphList 爬取任务
2025-11-18 17:46:00 +08:00
ArvinLovegood
cf58a707c7 refactor(stock):重构股票数据接口并新增历史资金流向功能
- 调整 import 包顺序,优化代码结构
- 新增 GetStockHistoryMoneyData 方法用于获取历史资金流向
- 移除无用空行,提升代码可读性- 更新 README 文档中的大模型平台链接信息
- 删除测试文件中冗余的日志调试代码行
2025-11-16 11:17:45 +08:00
ArvinLovegood
1ae1bb0116 feat(vip):移除水印内容显示
- 更新窗口标题以包含授权声明
- 移除水印内容显示为空字符串
2025-10-31 18:37:26 +08:00
ArvinLovegood
d8971935ee feat(settings):添加AI智能体功能开关(建议关闭,使用体验不理想)
- 在设置界面新增AI智能体启用开关
- 支持保存和读取AI智能体启用状态
- 更新配置模型以支持新的启用选项
- 动态控制菜单项显示状态
- 同步前后端配置结构以支持新功能
2025-10-31 17:11:17 +08:00
ArvinLovegood
9c68458b81 feat(stockhotmap):添加财联社行情数据标签页
- 在 stockhotmap 组件中新增财联社-行情数据标签页
- 配置嵌入链接指向 https://www.cls.cn/quotation
- 设置高度为 calc(100vh - 252px) 以适配页面布局
2025-10-31 16:54:05 +08:00
ArvinLovegood
b367d1eb40 feat(stockhotmap):启用百度股市通和摸鱼网页标签页
- 取消注释百度股市通标签页,恢复其功能
- 取消注释摸鱼标签页,恢复其功能
-保持其他标签页配置不变
2025-10-29 16:18:29 +08:00
ArvinLovegood
8fe79adbb1 feat(stock):增加股票搜索结果数量并优化搜索条件
- 将随机返回的股票数量从5-10支增加到5-20支
- 更新测试用例中的搜索关键词,提高筛选条件准确性
- 调整搜索逻辑以适应新的数据范围和质量要求
2025-10-29 16:13:30 +08:00
ArvinLovegood
1d81fdba87 chore(deps):指标选股问题
- 将 User-Agent 中的 Firefox 版本从 140.0 更新为 145.0
2025-10-27 18:16:25 +08:00
ArvinLovegood
6aca0e15cc fix(backend): 指标选股问题
- 修改fingerprint和requestId为新的固定值
- 将timestamp设置为动态生成的时间戳
- 更新xcId为新的标识符
- 在测试中增加返回结果的日志输出
2025-10-27 18:15:02 +08:00
ArvinLovegood
173ce6f243 fix(backend):修复新闻列表排序逻辑
- 将新闻列表按ID降序排列,确保最新新闻优先显示
- 保持is_red字段的降序排序,确保重要新闻优先显示
- 修复了查询条件中缺少的排序字段逗号问题
2025-09-29 18:10:55 +08:00
ArvinLovegood
e7875e73d3 feat(backend):新增并使用GetNewsList2方法以支持标签功能
- 在MarketNewsApi中添加GetNewsList2方法,支持根据source和limit获取新闻列表
- GetNewsList2方法中预加载TelegraphTags并关联标签名称
- 修改openai_api.go中调用GetNewsList的地方为GetNewsList2- 调整获取新闻列表的参数,使用固定source和随机limit值
2025-09-29 17:34:31 +08:00
ArvinLovegood
ca4727db80 fix(app):更新股票研究报告工具描述
- 修改了GetStockResearchReport函数的描述信息
- 简化了描述文本,去除冗余的"机构的"前缀
- 保持了原有功能和参数结构不变
2025-09-27 19:12:51 +08:00
ArvinLovegood
84ffe7c5fd refactor(openai_api):移除行业板块相关工具调用逻辑
- 注释掉QueryBKDictInfo工具的调用实现
- 注释掉GetIndustryResearchReport工具的调用实现
- 移除对freecache包的依赖引用- 保留GetStockResearchReport工具的调用逻辑
- 简化工具调用处理流程
2025-09-27 18:55:28 +08:00
ArvinLovegood
da02d1bd1c feat(stock):更新股票研究报接口参数并完善行业研究描述
- 修改行业研究工具函数描述,增加调用前需查询行业代码的提示
- 更新股票研究报接口测试用例中的股票代码参数值
- 完善行业研究报相关功能的使用说明和参数校验逻辑- 优化研究报数据获取流程,提升接口稳定性与准确性
2025-09-27 16:59:05 +08:00
ArvinLovegood
bae2bf9c5c docs(readme): 更新AI智能选股功能描述
- 在功能说明中添加AI智能体功能的描述
- 保持其他功能状态和备注信息不变
2025-09-27 15:46:33 +08:00
ArvinLovegood
6568b5949a docs(readme): 更新AI智能选股功能状态
- 将AI智能选股功能状态从开发中更新为已完成
- 修改功能描述为"市场行情-》AI总结"
- 调整了功能备注信息的表述方式
2025-09-27 15:44:03 +08:00
ArvinLovegood
c4287f9b78 feat(ai):新增了机构/券商的研究报告AI工具函数
- 添加 QueryBKDictInfo 工具用于获取板块/行业字典信息
- 实现 GetIndustryResearchReport 工具用于获取行业研究报告
- 实现 GetStockResearchReport 工具用于获取股票研究报告
- 在数据库中新增 BKDict 模型并自动迁移
- 更新 MarketNewsApi 测试用例以支持新工具调用
- 在 OpenAI API 中集成新工具的调用逻辑与响应处理
2025-09-27 15:39:37 +08:00
ArvinLovegood
87441d8923 feat(ai):新增了机构/券商的研究报告AI工具函数
- 添加 QueryBKDictInfo 工具用于获取板块/行业字典信息
- 实现 GetIndustryResearchReport 工具用于获取行业研究报告
- 实现 GetStockResearchReport 工具用于获取股票研究报告
- 在数据库中新增 BKDict 模型并自动迁移
- 更新 MarketNewsApi 测试用例以支持新工具调用
- 在 OpenAI API 中集成新工具的调用逻辑与响应处理
2025-09-27 15:39:25 +08:00
ArvinLovegood
ebd166e72b fix(agent):调整代理最大步骤数并修复前端显示逻辑
- 减少代理工具调用的最大步骤数计算方式
- 启用并修复前端聊天组件中的推理内容显示
- 修复删除分组时传递正确参数类型
- 更新依赖项,移除旧版本的 chromedp 和 golang.org/x/sys
2025-09-27 10:59:45 +08:00
ArvinLovegood
494a60debe refactor(backend):注释掉获取股势通资讯的代码
- 在 openai_api.go 中注释掉了获取股势通资讯的相关代码
- 在 openai_api_test.go 中添加了对 SearchGuShiTongStockInfo 函数的测试用例
2025-09-16 15:14:38 +08:00
ArvinLovegood
b3e2565a02 build: 更新多个依赖至最新版本 2025-09-16 14:19:11 +08:00
ArvinLovegood
c0a87d5d2e perf(app):优化股票基础信息更新逻辑
- 移除了定时任务中重复的股票基础信息检查逻辑
- 在获取股票基础信息前增加数据库记录数量检查,避免重复更新
2025-08-26 18:28:10 +08:00
ArvinLovegood
d74ad3c03d refactor(frontend):升级go到1.25版本(性能更强劲!)
- 从 components.d.ts 文件中删除了未使用的 TChat、TChatAction、TChatContent、TChatLoading 和 TChatSender导入
- 更新 go.mod 文件,移除 toolchain go1.24.5 并将 Go 版本升级到 1.25.0
2025-08-26 11:45:03 +08:00
ArvinLovegood
6dff9d95c4 build:更新Go依赖并升级到Go1.25
- 更新 golang.org/x/sys从 v0.33.0 到 v0.35.0
- 更新 sonic、sonic/loader、base64x、cpuid、arch 等多个依赖库
- 将 Go 版本从 1.24升级到 1.25
2025-08-26 11:28:49 +08:00
ArvinLovegood
06967420f8 feat(app):添加股票基础信息自动检查功能
- 在应用启动时检查股票基础信息是否为空
- 如果为空,则自动调用 CheckStockBaseInfo 方法获取数据
-每天凌晨 2 点定时检查股票基础信息
2025-08-26 10:45:17 +08:00
ArvinLovegood
6f4eb0ac86 refactor(backend): 移除未使用的导入语句
- 删除了 "C" 的导入语句,该语句在代码中未被使用
- 优化代码结构,提高代码的可读性和维护性
2025-08-24 20:11:57 +08:00
ArvinLovegood
f59255cc6c style:调整 Windows特定代码的构建标签
- 在 alert_windows_api.go 和 alert_windows_api_test.go 文件中添加额外的 +build windows 标签
- 优化代码结构,提高代码的可读性和可维护性
2025-08-24 16:29:57 +08:00
29 changed files with 583 additions and 152 deletions

View File

@@ -50,7 +50,7 @@ jobs:
build-name: ${{ matrix.build.name }}
build-platform: ${{ matrix.build.platform }}
package: true
go-version: '1.24'
go-version: '1.25'
build-tags: ${{ github.ref_name }}
build-commit-message: ${{ steps.get_commit_message.outputs.commit_message }}
build-statement: ${{ env.OFFICIAL_STATEMENT }}

View File

@@ -37,11 +37,9 @@
| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
| [DeepSeek](https://www.deepseek.com/) | ✅ | deepseek-reasoner,deepseek-chat |
| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[302.AI](https://share.302.ai/1KUpfG)[硅基流动](https://cloud.siliconflow.cn/i/foufCerk)[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) |
| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[硅基流动](https://cloud.siliconflow.cn/i/foufCerk)[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) |
### <span style="color: #568DF4;">各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个<i style="color: #EA2626;">star</i>吧,谢谢!</span>💕
- 302.AI新用户使用邀请码注册即可领取 $1 测试额度![注册链接](https://share.302.ai/1KUpfG)
[//]: # (- 优云智算by UCloud万卡规模4090免费用10小时新人注册另增50万tokens海量热门源项目镜像一键部署[注册链接]&#40;https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock&#41;)
- 火山方舟新用户每个模型注册即送50万tokens[注册链接](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ)
- 硅基流动(siliconflow)注册即送2000万Tokens[注册链接](https://cloud.siliconflow.cn/i/foufCerk)
@@ -62,7 +60,7 @@
| 功能说明 | 状态 | 备注 |
|-----------------|----|----------------------------------------------------------------------------------------------------------|
| 股票分析知识库 | 🚧 | 未来计划 |
| Ai智能选股 | 🚧 | Ai智能选股功能开发中(下半年重点开发计划) |
| Ai智能选股 | | Ai智能选股功能(市场行情-》AI总结/AI智能体功能) |
| ETF支持 | 🚧 | ETF数据支持 (目前可以查看净值和估值) |
| 美股支持 | ✅ | 美股数据支持 |
| 港股支持 | ✅ | 港股数据支持 |

156
app.go
View File

@@ -131,6 +131,50 @@ func AddTools(tools []data.Tool) []data.Tool {
},
})
//tools = append(tools, data.Tool{
// Type: "function",
// Function: data.ToolFunction{
// Name: "QueryBKDictInfo",
// Description: "获取所有板块/行业名称或者代码(bkCode,bkName)",
// },
//})
//tools = append(tools, data.Tool{
// Type: "function",
// Function: data.ToolFunction{
// Name: "GetIndustryResearchReport",
// Description: "获取行业/板块研究报告,请先使用QueryBKDictInfo工具获取行业代码然后输入行业代码调用",
// Parameters: data.FunctionParameters{
// Type: "object",
// Properties: map[string]any{
// "bkCode": map[string]any{
// "type": "string",
// "description": "板块/行业代码",
// },
// },
// Required: []string{"bkCode"},
// },
// },
//})
tools = append(tools, data.Tool{
Type: "function",
Function: data.ToolFunction{
Name: "GetStockResearchReport",
Description: "获取股票的分析/研究报告",
Parameters: data.FunctionParameters{
Type: "object",
Properties: map[string]any{
"stockCode": map[string]any{
"type": "string",
"description": "股票代码",
},
},
Required: []string{"stockCode"},
},
},
})
return tools
}
@@ -384,7 +428,8 @@ func (a *App) domReady(ctx context.Context) {
a.cronEntrys["MonitorStockPrices"] = id
}
entryID, err := a.cron.AddFunc(fmt.Sprintf("@every %ds", interval+10), func() {
news := data.NewMarketNewsApi().GetNewTelegraph(30)
//news := data.NewMarketNewsApi().GetNewTelegraph(30)
news := data.NewMarketNewsApi().TelegraphList(30)
if config.EnablePushNews {
go a.NewsPush(news)
}
@@ -465,6 +510,8 @@ func (a *App) domReady(ctx context.Context) {
//检查新版本
go func() {
a.CheckUpdate(0)
go a.CheckStockBaseInfo(a.ctx)
a.cron.AddFunc("0 0 2 * * *", func() {
logger.SugaredLogger.Errorf("Checking for updates...")
a.CheckStockBaseInfo(a.ctx)
@@ -518,60 +565,84 @@ func (a *App) CheckStockBaseInfo(ctx context.Context) {
SetResult(stockBasics).
Get("http://8.134.249.145:18080/go-stock/stock_basic.json")
for _, stock := range *stockBasics {
stockInfo := &data.StockBasic{
TsCode: stock.TsCode,
Name: stock.Name,
Symbol: stock.Symbol,
BKCode: stock.BKCode,
BKName: stock.BKName,
}
db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).First(stockInfo)
if stockInfo.ID == 0 {
db.Dao.Model(&data.StockBasic{}).Create(stockInfo)
} else {
db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).Updates(stockInfo)
}
db.Dao.Unscoped().Model(&data.StockBasic{}).Where("1=1").Delete(&data.StockBasic{})
err := db.Dao.CreateInBatches(stockBasics, 400).Error
if err != nil {
logger.SugaredLogger.Errorf("保存StockBasic股票基础信息失败:%s", err.Error())
}
//count := int64(0)
//db.Dao.Model(&data.StockBasic{}).Count(&count)
//if count == int64(len(*stockBasics)) {
// return
//}
//for _, stock := range *stockBasics {
// stockInfo := &data.StockBasic{
// TsCode: stock.TsCode,
// Name: stock.Name,
// Symbol: stock.Symbol,
// BKCode: stock.BKCode,
// BKName: stock.BKName,
// }
// db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).First(stockInfo)
// if stockInfo.ID == 0 {
// db.Dao.Model(&data.StockBasic{}).Create(stockInfo)
// } else {
// db.Dao.Model(&data.StockBasic{}).Where("ts_code = ?", stock.TsCode).Updates(stockInfo)
// }
//}
stockHKBasics := &[]models.StockInfoHK{}
resty.New().R().
SetHeader("user", "go-stock").
SetResult(stockHKBasics).
Get("http://8.134.249.145:18080/go-stock/stock_base_info_hk.json")
for _, stock := range *stockHKBasics {
stockInfo := &models.StockInfoHK{
Code: stock.Code,
Name: stock.Name,
BKName: stock.BKName,
BKCode: stock.BKCode,
}
db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).First(stockInfo)
if stockInfo.ID == 0 {
db.Dao.Model(&models.StockInfoHK{}).Create(stockInfo)
} else {
db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).Updates(stockInfo)
}
db.Dao.Unscoped().Model(&models.StockInfoHK{}).Where("1=1").Delete(&models.StockInfoHK{})
err = db.Dao.CreateInBatches(stockHKBasics, 400).Error
if err != nil {
logger.SugaredLogger.Errorf("保存StockInfoHK股票基础信息失败:%s", err.Error())
}
//for _, stock := range *stockHKBasics {
// stockInfo := &models.StockInfoHK{
// Code: stock.Code,
// Name: stock.Name,
// BKName: stock.BKName,
// BKCode: stock.BKCode,
// }
// db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).First(stockInfo)
// if stockInfo.ID == 0 {
// db.Dao.Model(&models.StockInfoHK{}).Create(stockInfo)
// } else {
// db.Dao.Model(&models.StockInfoHK{}).Where("code = ?", stock.Code).Updates(stockInfo)
// }
//}
stockUSBasics := &[]models.StockInfoUS{}
resty.New().R().
SetHeader("user", "go-stock").
SetResult(stockUSBasics).
Get("http://8.134.249.145:18080/go-stock/stock_base_info_us.json")
for _, stock := range *stockUSBasics {
stockInfo := &models.StockInfoUS{
Code: stock.Code,
Name: stock.Name,
BKName: stock.BKName,
BKCode: stock.BKCode,
}
db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).First(stockInfo)
if stockInfo.ID == 0 {
db.Dao.Model(&models.StockInfoUS{}).Create(stockInfo)
} else {
db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).Updates(stockInfo)
}
db.Dao.Unscoped().Model(&models.StockInfoUS{}).Where("1=1").Delete(&models.StockInfoUS{})
err = db.Dao.CreateInBatches(stockUSBasics, 400).Error
if err != nil {
logger.SugaredLogger.Errorf("保存StockInfoUS股票基础信息失败:%s", err.Error())
}
//for _, stock := range *stockUSBasics {
// stockInfo := &models.StockInfoUS{
// Code: stock.Code,
// Name: stock.Name,
// BKName: stock.BKName,
// BKCode: stock.BKCode,
// }
// db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).First(stockInfo)
// if stockInfo.ID == 0 {
// db.Dao.Model(&models.StockInfoUS{}).Create(stockInfo)
// } else {
// db.Dao.Model(&models.StockInfoUS{}).Where("code = ?", stock.Code).Updates(stockInfo)
// }
//}
}
func (a *App) NewsPush(news *[]models.Telegraph) {
@@ -1286,7 +1357,8 @@ func (a *App) GetTelegraphList(source string) *[]*models.Telegraph {
}
func (a *App) ReFleshTelegraphList(source string) *[]*models.Telegraph {
data.NewMarketNewsApi().GetNewTelegraph(30)
//data.NewMarketNewsApi().GetNewTelegraph(30)
data.NewMarketNewsApi().TelegraphList(30)
data.NewMarketNewsApi().GetSinaNews(30)
telegraphs := data.NewMarketNewsApi().GetTelegraphList(source)
return telegraphs

View File

@@ -73,13 +73,14 @@ func GetStockAiAgent(ctx *context.Context, aiConfig data.AIConfig) *react.Agent
tools.GetFinancialReportTool(),
tools.GetQueryStockNewsTool(),
tools.GetIndustryResearchReportTool(),
tools.GetQueryBKDictTool(),
},
}
// 创建 agent
agent, err := react.NewAgent(*ctx, &react.AgentConfig{
ToolCallingModel: toolableChatModel,
ToolsConfig: aiTools,
MaxStep: len(aiTools.Tools)*3 + 2,
MaxStep: len(aiTools.Tools)*1 + 3,
MessageModifier: func(ctx context.Context, input []*schema.Message) []*schema.Message {
return input
},

View File

@@ -0,0 +1,34 @@
package tools
import (
"context"
"encoding/json"
"go-stock/backend/data"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/schema"
"github.com/coocood/freecache"
)
// @Author spark
// @Date 2025/9/27 14:09
// @Desc
// -----------------------------------------------------------------------------------
type ToolQueryBKDict struct{}
func (t ToolQueryBKDict) Info(ctx context.Context) (*schema.ToolInfo, error) {
return &schema.ToolInfo{
Name: "QueryBKDictInfo",
Desc: "获取所有板块/行业名称或者代码(bkCode,bkName)",
}, nil
}
func (t ToolQueryBKDict) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) {
resp := data.NewMarketNewsApi().EMDictCode("016", freecache.NewCache(100))
bytes, err := json.Marshal(resp)
return string(bytes), err
}
func GetQueryBKDictTool() tool.InvokableTool {
return &ToolQueryBKDict{}
}

View File

@@ -4,11 +4,12 @@ import (
"context"
"encoding/json"
"fmt"
"go-stock/backend/data"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/schema"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/random"
"go-stock/backend/data"
)
// @Author spark
@@ -55,7 +56,7 @@ func (c ChoiceStockByIndicators) InvokableRun(ctx context.Context, argumentsInJS
}
content := "无符合条件的数据"
words := parms["words"].(string)
res := data.NewSearchStockApi(words).SearchStock(random.RandInt(5, 10))
res := data.NewSearchStockApi(words).SearchStock(random.RandInt(5, 20))
if convertor.ToString(res["code"]) == "100" {
resData := res["data"].(map[string]any)
result := resData["result"].(map[string]any)

View File

@@ -1,11 +1,12 @@
//go:build windows
// +build windows
package data
import "C"
import (
"github.com/go-toast/toast"
"go-stock/backend/logger"
"github.com/go-toast/toast"
)
// AlertWindowsApi @Author spark

View File

@@ -1,11 +1,13 @@
//go:build windows
// +build windows
package data
import (
"github.com/go-toast/toast"
"go-stock/backend/logger"
"testing"
"github.com/go-toast/toast"
)
// @Author spark

View File

@@ -33,6 +33,70 @@ func NewMarketNewsApi() *MarketNewsApi {
return &MarketNewsApi{}
}
func (m MarketNewsApi) TelegraphList(crawlTimeOut int64) *[]models.Telegraph {
//https://www.cls.cn/nodeapi/telegraphList
url := "https://www.cls.cn/nodeapi/telegraphList"
res := map[string]any{}
_, _ = 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").
SetResult(&res).
Get(url)
var telegraphs []models.Telegraph
if v, _ := convertor.ToInt(res["error"]); v == 0 {
data := res["data"].(map[string]any)
rollData := data["roll_data"].([]any)
for _, v := range rollData {
news := v.(map[string]any)
ctime, _ := convertor.ToInt(news["ctime"])
dataTime := time.Unix(ctime, 0)
logger.SugaredLogger.Debugf("dataTime: %s", dataTime)
telegraph := models.Telegraph{
Content: news["content"].(string),
Time: dataTime.Format("15:04:05"),
DataTime: &dataTime,
Url: news["shareurl"].(string),
Source: "财联社电报",
IsRed: GetLevel(news["level"].(string)),
SentimentResult: AnalyzeSentiment(news["content"].(string)).Description,
}
cnt := int64(0)
db.Dao.Model(telegraph).Where("time=? and content=?", telegraph.Time, telegraph.Content).Count(&cnt)
if cnt > 0 {
continue
}
telegraphs = append(telegraphs, telegraph)
db.Dao.Model(&models.Telegraph{}).Create(&telegraph)
logger.SugaredLogger.Debugf("telegraph: %+v", &telegraph)
if news["subjects"] == nil {
continue
}
subjects := news["subjects"].([]any)
for _, subject := range subjects {
name := subject.(map[string]any)["subject_name"].(string)
tag := &models.Tags{
Name: name,
Type: "subject",
}
db.Dao.Model(tag).Where("name=? and type=?", name, "subject").FirstOrCreate(&tag)
db.Dao.Model(models.TelegraphTags{}).Where("telegraph_id=? and tag_id=?", telegraph.ID, tag.ID).FirstOrCreate(&models.TelegraphTags{
TelegraphId: telegraph.ID,
TagId: tag.ID,
})
}
}
//db.Dao.Model(&models.Telegraph{}).Create(&telegraphs)
//logger.SugaredLogger.Debugf("telegraphs: %+v", &telegraphs)
}
return &telegraphs
}
func GetLevel(s string) bool {
return s >= "C"
}
func (m MarketNewsApi) GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
url := "https://www.cls.cn/telegraph"
response, _ := resty.New().SetTimeout(time.Duration(crawlTimeOut)*time.Second).R().
@@ -77,7 +141,7 @@ func (m MarketNewsApi) GetNewTelegraph(crawlTimeOut int64) *[]models.Telegraph {
if telegraph.Content != "" {
telegraph.SentimentResult = AnalyzeSentiment(telegraph.Content).Description
cnt := int64(0)
db.Dao.Model(telegraph).Where("time=? and source=?", telegraph.Time, telegraph.Source).Count(&cnt)
db.Dao.Model(telegraph).Where("time=? and content=?", telegraph.Time, telegraph.Content).Count(&cnt)
if cnt == 0 {
db.Dao.Create(&telegraph)
telegraphs = append(telegraphs, telegraph)
@@ -117,6 +181,28 @@ func (m MarketNewsApi) GetNewsList(source string, limit int) *[]*models.Telegrap
}
return news
}
func (m MarketNewsApi) GetNewsList2(source string, limit int) *[]*models.Telegraph {
NewMarketNewsApi().TelegraphList(30)
news := &[]*models.Telegraph{}
if source != "" {
db.Dao.Model(news).Preload("TelegraphTags").Where("source=?", source).Order("id desc,is_red desc").Limit(limit).Find(news)
} else {
db.Dao.Model(news).Preload("TelegraphTags").Order("id desc,is_red desc").Limit(limit).Find(news)
}
for _, item := range *news {
tags := &[]models.Tags{}
db.Dao.Model(&models.Tags{}).Where("id in ?", lo.Map(item.TelegraphTags, func(item models.TelegraphTags, index int) uint {
return item.TagId
})).Find(&tags)
tagNames := lo.Map(*tags, func(item models.Tags, index int) string {
return item.Name
})
item.SubjectTags = tagNames
logger.SugaredLogger.Infof("tagNames %v SubjectTags%s", tagNames, item.SubjectTags)
}
return news
}
func (m MarketNewsApi) GetTelegraphList(source string) *[]*models.Telegraph {
news := &[]*models.Telegraph{}
if source != "" {

View File

@@ -4,11 +4,13 @@ import (
"encoding/json"
"go-stock/backend/db"
"go-stock/backend/logger"
"go-stock/backend/models"
"go-stock/backend/util"
"strings"
"testing"
"github.com/coocood/freecache"
"github.com/duke-git/lancet/v2/random"
"github.com/tidwall/gjson"
)
@@ -37,7 +39,6 @@ func TestGetIndustryRank(t *testing.T) {
res := NewMarketNewsApi().GetIndustryRank("0", 10)
for s, a := range res["data"].([]any) {
logger.SugaredLogger.Debugf("key: %+v, value: %+v", s, a)
}
}
func TestGetIndustryMoneyRankSina(t *testing.T) {
@@ -72,9 +73,12 @@ func TestLongTiger(t *testing.T) {
func TestStockResearchReport(t *testing.T) {
db.Init("../../data/stock.db")
resp := NewMarketNewsApi().StockResearchReport("600584.sh", 7)
resp := NewMarketNewsApi().StockResearchReport("688082", 7)
for _, a := range resp {
logger.SugaredLogger.Debugf("value: %+v", a)
data := a.(map[string]any)
logger.SugaredLogger.Debugf("value: %s infoCode:%s", data["title"], data["infoCode"])
NewMarketNewsApi().GetIndustryReportInfo(data["infoCode"].(string))
}
}
@@ -108,7 +112,11 @@ func TestEMDictCode(t *testing.T) {
if err != nil {
return
}
dict := &[]models.BKDict{}
json.Unmarshal(bytes, dict)
logger.SugaredLogger.Debugf("value: %s", string(bytes))
md := util.MarkdownTableWithTitle("行业/板块代码", dict)
logger.SugaredLogger.Debugf(md)
}
@@ -226,3 +234,18 @@ func TestInteractiveAnswer(t *testing.T) {
logger.SugaredLogger.Debugf(md)
}
func TestGetNewsList2(t *testing.T) {
db.Init("../../data/stock.db")
news := NewMarketNewsApi().GetNewsList2("财联社电报", random.RandInt(100, 500))
messageText := strings.Builder{}
for _, telegraph := range *news {
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
messageText.WriteString("### " + telegraph.Content + "\n")
}
logger.SugaredLogger.Debugf("value: %s", messageText.String())
}
func TestTelegraphList(t *testing.T) {
db.Init("../../data/stock.db")
NewMarketNewsApi().TelegraphList(30)
}

View File

@@ -323,8 +323,7 @@ func (o *OpenAi) NewSummaryStockNewsStreamWithTools(userQuestion string, sysProm
})
}()
wg.Wait()
news := NewMarketNewsApi().GetNewsList("财联社电报", random.RandInt(100, 500))
news := NewMarketNewsApi().GetNewsList2("财联社电报", random.RandInt(100, 500))
messageText := strings.Builder{}
for _, telegraph := range *news {
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
@@ -473,7 +472,7 @@ func (o *OpenAi) NewSummaryStockNewsStream(userQuestion string, sysPromptId *int
wg.Wait()
news := NewMarketNewsApi().GetNewsList("", 100)
news := NewMarketNewsApi().GetNewsList2("财联社电报", random.RandInt(100, 500))
messageText := strings.Builder{}
for _, telegraph := range *news {
messageText.WriteString("## " + telegraph.Time + ":" + "\n")
@@ -808,25 +807,25 @@ func (o *OpenAi) NewChatStream(stock, stockCode, userQuestion string, sysPromptI
return
}
messages := SearchGuShiTongStockInfo(stockCode, o.CrawlTimeOut)
if messages == nil || len(*messages) == 0 {
logger.SugaredLogger.Error("获取股势通资讯失败")
//ch <- "***❗获取股势通资讯失败,分析结果可能不准确***<hr>"
//go runtime.EventsEmit(o.ctx, "warnMsg", "❗获取股势通资讯失败,分析结果可能不准确")
return
}
var newsText strings.Builder
for _, message := range *messages {
newsText.WriteString(message + "\n")
}
msg = append(msg, map[string]interface{}{
"role": "user",
"content": stock + "相关新闻资讯",
})
msg = append(msg, map[string]interface{}{
"role": "assistant",
"content": newsText.String(),
})
//messages := SearchGuShiTongStockInfo(stockCode, o.CrawlTimeOut)
//if messages == nil || len(*messages) == 0 {
// logger.SugaredLogger.Error("获取股势通资讯失败")
// //ch <- "***❗获取股势通资讯失败,分析结果可能不准确***<hr>"
// //go runtime.EventsEmit(o.ctx, "warnMsg", "❗获取股势通资讯失败,分析结果可能不准确")
// return
//}
//var newsText strings.Builder
//for _, message := range *messages {
// newsText.WriteString(message + "\n")
//}
//msg = append(msg, map[string]interface{}{
// "role": "user",
// "content": stock + "相关新闻资讯",
//})
//msg = append(msg, map[string]interface{}{
// "role": "assistant",
// "content": newsText.String(),
//})
}()
go func() {
@@ -1155,7 +1154,7 @@ func AskAiWithTools(o *OpenAi, err error, messages []map[string]interface{}, ch
}
content := "无符合条件的数据"
res := NewSearchStockApi(words).SearchStock(random.RandInt(5, 10))
res := NewSearchStockApi(words).SearchStock(random.RandInt(5, 20))
if convertor.ToString(res["code"]) == "100" {
resData := res["data"].(map[string]any)
result := resData["result"].(map[string]any)
@@ -1366,6 +1365,140 @@ func AskAiWithTools(o *OpenAi, err error, messages []map[string]interface{}, ch
"tool_call_id": currentCallId,
})
}
//
//if funcName == "QueryBKDictInfo" {
// ch <- map[string]any{
// "code": 1,
// "question": question,
// "chatId": streamResponse.Id,
// "model": streamResponse.Model,
// "content": "\r\n```\r\n开始调用工具QueryBKDictInfo\n参数" + funcArguments + "\r\n```\r\n",
// "time": time.Now().Format(time.DateTime),
// }
// res := NewMarketNewsApi().EMDictCode("016", freecache.NewCache(100))
// bytes, err := json.Marshal(res)
// if err != nil {
// return
// }
// dict := &[]models.BKDict{}
// json.Unmarshal(bytes, dict)
// md := util.MarkdownTableWithTitle("行业/板块代码", dict)
// logger.SugaredLogger.Infof("行业/板块代码=\n%s", md)
// messages = append(messages, map[string]interface{}{
// "role": "assistant",
// "content": currentAIContent.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,
// })
//}
//if funcName == "GetIndustryResearchReport" {
// bkCode := gjson.Get(funcArguments, "bkCode").String()
// ch <- map[string]any{
// "code": 1,
// "question": question,
// "chatId": streamResponse.Id,
// "model": streamResponse.Model,
// "content": "\r\n```\r\n开始调用工具GetIndustryResearchReport\n参数" + bkCode + "\r\n```\r\n",
// "time": time.Now().Format(time.DateTime),
// }
// bkCode = strutil.ReplaceWithMap(bkCode, map[string]string{
// "-": "",
// "_": "",
// "bk": "",
// "BK": "",
// "bk0": "",
// "BK0": "",
// })
//
// logger.SugaredLogger.Debugf("code:%s", bkCode)
// codeStr := convertor.ToString(bkCode)
// res := NewMarketNewsApi().IndustryResearchReport(codeStr, 7)
// md := strings.Builder{}
// for _, a := range res {
// d := a.(map[string]any)
// md.WriteString(NewMarketNewsApi().GetIndustryReportInfo(d["infoCode"].(string)))
// }
// logger.SugaredLogger.Infof("bkCode:%s IndustryResearchReport:\n %s", bkCode, md.String())
// messages = append(messages, map[string]interface{}{
// "role": "assistant",
// "content": currentAIContent.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.String(),
// "tool_call_id": currentCallId,
// })
//}
if funcName == "GetStockResearchReport" {
stockCode := gjson.Get(funcArguments, "stockCode").String()
ch <- map[string]any{
"code": 1,
"question": question,
"chatId": streamResponse.Id,
"model": streamResponse.Model,
"content": "\r\n```\r\n开始调用工具GetStockResearchReport\n参数" + stockCode + "\r\n```\r\n",
"time": time.Now().Format(time.DateTime),
}
res := NewMarketNewsApi().StockResearchReport(stockCode, 7)
md := strings.Builder{}
for _, a := range res {
logger.SugaredLogger.Debugf("value: %+v", a)
d := a.(map[string]any)
logger.SugaredLogger.Debugf("value: %s infoCode:%s", d["title"], d["infoCode"])
md.WriteString(NewMarketNewsApi().GetIndustryReportInfo(d["infoCode"].(string)))
}
logger.SugaredLogger.Infof("stockCode:%s StockResearchReport:\n %s", stockCode, md.String())
messages = append(messages, map[string]interface{}{
"role": "assistant",
"content": currentAIContent.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.String(),
"tool_call_id": currentCallId,
})
}
}
AskAiWithTools(o, err, messages, ch, question, tools)

View File

@@ -3,6 +3,7 @@ package data
import (
"context"
"go-stock/backend/db"
log "go-stock/backend/logger"
"testing"
)
@@ -52,9 +53,12 @@ func TestGetTopNewsList(t *testing.T) {
func TestSearchGuShiTongStockInfo(t *testing.T) {
db.Init("../../data/stock.db")
SearchGuShiTongStockInfo("hk01810", 60)
SearchGuShiTongStockInfo("sh600745", 60)
SearchGuShiTongStockInfo("gb_goog", 60)
//SearchGuShiTongStockInfo("hk01810", 60)
msgs := SearchGuShiTongStockInfo("sh600745", 60)
for _, msg := range *msgs {
log.SugaredLogger.Infof("%s", msg)
}
//SearchGuShiTongStockInfo("gb_goog", 60)
}

View File

@@ -3,9 +3,10 @@ package data
import (
"encoding/json"
"fmt"
"github.com/go-resty/resty/v2"
"go-stock/backend/logger"
"time"
"github.com/go-resty/resty/v2"
)
// @Author spark
@@ -25,25 +26,25 @@ func (s SearchStockApi) SearchStock(pageSize int) map[string]any {
SetHeader("Host", "np-tjxg-g.eastmoney.com").
SetHeader("Origin", "https://xuangu.eastmoney.com").
SetHeader("Referer", "https://xuangu.eastmoney.com/").
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0").
SetHeader("Content-Type", "application/json").
SetBody(fmt.Sprintf(`{
"keyWord": "%s",
"pageSize": %d,
"pageNo": 1,
"fingerprint": "e38b5faabf9378c8238e57219f0ebc9b",
"fingerprint": "02efa8944b1f90fbfe050e1e695a480d",
"gids": [],
"matchWord": "",
"timestamp": "1751113883290349",
"timestamp": "%d",
"shareToGuba": false,
"requestId": "8xTWgCDAjvQ5lmvz5mDA3Ydk2AE4yoiJ1751113883290",
"requestId": "RMd3Y76AJI98axPvdhdbKvbBDVwLlUK61761559950168",
"needCorrect": true,
"removedConditionIdList": [],
"xcId": "xc0af28549ab330013ed",
"xcId": "xc0d61279aad33008260",
"ownSelectAll": false,
"dxInfo": [],
"extraCondition": ""
}`, s.words, pageSize)).Post(url)
}`, s.words, pageSize, time.Now().Unix())).Post(url)
if err != nil {
logger.SugaredLogger.Errorf("SearchStock-err:%+v", err)
return map[string]any{}

View File

@@ -2,16 +2,18 @@ package data
import (
"encoding/json"
"github.com/duke-git/lancet/v2/convertor"
"go-stock/backend/db"
"go-stock/backend/logger"
"testing"
"github.com/duke-git/lancet/v2/convertor"
)
func TestSearchStock(t *testing.T) {
db.Init("../../data/stock.db")
res := NewSearchStockApi("算力股;净利润连续3年增长").SearchStock(10)
res := NewSearchStockApi("量比大于2基本面优秀2025年三季报已披露主力连续3日净流入非创业板非科创板非ST").SearchStock(20)
logger.SugaredLogger.Infof("res:%+v", res)
data := res["data"].(map[string]any)
result := data["result"].(map[string]any)
dataList := result["dataList"].([]any)

View File

@@ -3,11 +3,12 @@ package data
import (
"encoding/json"
"errors"
"github.com/samber/lo"
"go-stock/backend/db"
"go-stock/backend/logger"
"gorm.io/gorm"
"time"
"github.com/samber/lo"
"gorm.io/gorm"
)
type Settings struct {
@@ -35,6 +36,7 @@ type Settings struct {
SponsorCode string `json:"sponsorCode"`
HttpProxy string `json:"httpProxy"`
HttpProxyEnabled bool `json:"httpProxyEnabled"`
EnableAgent bool `json:"enableAgent"`
}
func (receiver Settings) TableName() string {
@@ -105,6 +107,7 @@ func UpdateConfig(s *SettingConfig) string {
"sponsor_code": s.SponsorCode,
"http_proxy": s.HttpProxy,
"http_proxy_enabled": s.HttpProxyEnabled,
"enable_agent": s.EnableAgent,
})
//更新AiConfig

View File

@@ -9,6 +9,14 @@ import (
"context"
"encoding/json"
"fmt"
"go-stock/backend/db"
"go-stock/backend/logger"
"go-stock/backend/models"
"io"
"io/ioutil"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
"github.com/chromedp/chromedp"
"github.com/duke-git/lancet/v2/convertor"
@@ -17,17 +25,10 @@ import (
"github.com/go-resty/resty/v2"
"github.com/robertkrimen/otto"
"github.com/samber/lo"
"go-stock/backend/db"
"go-stock/backend/logger"
"go-stock/backend/models"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
"io"
"io/ioutil"
"strings"
"time"
)
const sinaStockUrl = "http://hq.sinajs.cn/rn=%d&list=%s"
@@ -1744,6 +1745,11 @@ func (receiver StockDataApi) GetCommonKLineData(stockCode string, kLineType stri
return K
}
// GetStockHistoryMoneyData 获取股票历史资金流向数据
func (receiver StockDataApi) GetStockHistoryMoneyData() {
}
// JSONToMarkdownTable 将JSON数据转换为Markdown表格
func JSONToMarkdownTable(jsonData []byte) (string, error) {
var data []map[string]interface{}

View File

@@ -265,3 +265,20 @@ func TestStockDataApi_GetIndexBasic(t *testing.T) {
stockDataApi := NewStockDataApi()
stockDataApi.GetIndexBasic()
}
func TestName(t *testing.T) {
db.Init("../../data/stock.db")
stockBasics := &[]StockBasic{}
resty.New().R().
SetHeader("user", "go-stock").
SetResult(stockBasics).
Get("http://8.134.249.145:18080/go-stock/stock_basic.json")
db.Dao.Unscoped().Model(&StockBasic{}).Where("1=1").Delete(&StockBasic{})
err := db.Dao.CreateInBatches(stockBasics, 400).Error
if err != nil {
t.Log(err.Error())
}
}

View File

@@ -1,9 +1,10 @@
package models
import (
"time"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
"time"
)
// @Author spark
@@ -231,6 +232,7 @@ type Prompt struct {
type Telegraph struct {
gorm.Model
Time string `json:"time"`
DataTime *time.Time `json:"dataTime"`
Content string `json:"content"`
SubjectTags []string `json:"subjects" gorm:"-:all"`
StocksTags []string `json:"stocks" gorm:"-:all"`
@@ -238,7 +240,7 @@ type Telegraph struct {
Url string `json:"url"`
Source string `json:"source"`
TelegraphTags []TelegraphTags `json:"tags" gorm:"-:migration;foreignKey:TelegraphId"`
SentimentResult string `json:"sentimentResult" gorm:"-:all"`
SentimentResult string `json:"sentimentResult"`
}
type TelegraphTags struct {
gorm.Model
@@ -687,3 +689,16 @@ type CailianpressWeb struct {
Author string `json:"author" md:"资讯发布者"`
} `json:"list"`
}
type BKDict struct {
gorm.Model `md:"-"`
BkCode string `json:"bkCode" md:"行业/板块代码"`
BkName string `json:"bkName" md:"行业/板块名称"`
FirstLetter string `json:"firstLetter" md:"first_letter"`
FubkCode string `json:"fubkCode" md:"fubk_code"`
PublishCode string `json:"publishCode" md:"publish_code"`
}
func (b BKDict) TableName() string {
return "bk_dict"
}

View File

@@ -6,7 +6,8 @@ import {
Quit,
WindowFullscreen,
WindowHide,
WindowUnfullscreen
WindowUnfullscreen,
WindowSetTitle
} from '../wailsjs/runtime'
import {h, onBeforeMount, onBeforeUnmount, onMounted, ref} from "vue";
import {RouterLink, useRouter} from 'vue-router'
@@ -43,6 +44,7 @@ const loadingMsg = ref("加载数据中...")
const enableNews = ref(false)
const contentStyle = ref("")
const enableFund = ref(false)
const enableAgent = ref(false)
const enableDarkTheme = ref(null)
const content = ref('未经授权,禁止商业目的!\n\n数据来源于网络,仅供参考;投资有风险,入市需谨慎')
const isFullscreen = ref(false)
@@ -440,6 +442,7 @@ const menuOptions = ref([
{default: () => 'Ai智能体'}
),
key: 'agent',
show:enableAgent.value,
icon: renderIcon(Robot),
},
{
@@ -646,11 +649,15 @@ onBeforeMount(() => {
GetConfig().then((res) => {
//console.log(res)
enableFund.value = res.enableFund
enableAgent.value = res.enableAgent
menuOptions.value.filter((item) => {
if (item.key === 'fund') {
item.show = res.enableFund
}
if (item.key === 'agent') {
item.show = res.enableAgent
}
})
if (res.darkTheme) {
@@ -662,12 +669,14 @@ onBeforeMount(() => {
})
onMounted(() => {
WindowSetTitle("go-stockAI赋能股票分析✨ 未经授权,禁止商业目的! [数据来源于网络,仅供参考;投资有风险,入市需谨慎]")
contentStyle.value = "max-height: calc(92vh);overflow: hidden"
GetConfig().then((res) => {
if (res.enableNews) {
enableNews.value = true
}
enableFund.value = res.enableFund
enableAgent.value = res.enableAgent
const {notification } =createDiscreteApi(["notification"], {
configProviderProps: {
theme: enableDarkTheme.value ? darkTheme : lightTheme ,
@@ -714,7 +723,7 @@ onMounted(() => {
<n-modal-provider>
<n-dialog-provider>
<n-watermark
:content="content"
:content="''"
cross
selectable
:font-size="16"

View File

@@ -5,7 +5,9 @@ import 'md-editor-v3/lib/preview.css';
import {h, onBeforeUnmount, onMounted, ref} from 'vue';
import {CheckUpdate, GetVersionInfo,GetSponsorInfo,OpenURL} from "../../wailsjs/go/main/App";
import {EventsOff, EventsOn,Environment} from "../../wailsjs/runtime";
import {NAvatar, NButton, useNotification} from "naive-ui";
import {NAvatar, NButton, useNotification,NText} from "naive-ui";
import { addMonths, format ,parse} from 'date-fns';
import { zhCN } from 'date-fns/locale';
const updateLog = ref('');
const versionInfo = ref('');
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
@@ -16,6 +18,7 @@ const notify = useNotification()
const vipLevel=ref("");
const vipStartTime=ref("");
const vipEndTime=ref("");
const expired=ref(false)
onMounted(() => {
document.title = '关于软件';
@@ -31,6 +34,13 @@ onMounted(() => {
vipLevel.value = res.vipLevel;
vipStartTime.value = res.vipStartTime;
vipEndTime.value = res.vipEndTime;
//判断时间是否到期
if (res.vipLevel) {
if (res.vipEndTime < format(new Date(), 'yyyy-MM-dd HH:mm:ss')) {
notify.warning({content: 'VIP已到期'})
expired.value = true;
}
}
})
});
@@ -115,10 +125,10 @@ EventsOn("updateVersion",async (msg) => {
<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-gradient-text type="warning" :size="50" >go-stock</n-gradient-text><n-tag :bordered="false" size="small" type="warning">VIP{{vipLevel}}</n-tag>
<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>
<n-gradient-text type="warning" v-if="vipLevel" >vip到期时间{{vipEndTime}}</n-gradient-text>
<n-gradient-text :type="expired?'error':'warning'" v-if="vipLevel" >vip到期时间{{vipEndTime}}</n-gradient-text>
<n-button size="tiny" @click="CheckUpdate(1)" type="info" tertiary >检查更新</n-button>
<div style="justify-self: center;text-align: left" >
<p>自选股行情实时监控基于Wails和NaiveUI构建的AI赋能股票分析工具</p>

View File

@@ -14,7 +14,7 @@
<template #content="{ item, index }">
<t-chat-reasoning v-if="item.role === 'assistant'" expand-icon-placement="right">
<t-chat-loading v-if="isStreamLoad" text="思考中..." />
<!-- <t-chat-content v-if="item.reasoning.length > 0" :content="item.reasoning" />-->
<t-chat-content v-if="item.reasoning.length > 0" :content="item.reasoning" />
</t-chat-reasoning>
<t-chat-content v-if="item.content.length > 0" :content="item.content" />
</template>
@@ -97,9 +97,9 @@ EventsOn("agent-message", (data) => {
if(data['role']==="assistant"){
loading.value = false;
const lastItem = chatList.value[0];
// if (data['reasoning_content']){
// lastItem.reasoning = data['reasoning_content'];
// }
if (data['reasoning_content']){
lastItem.reasoning += data['reasoning_content'];
}
if (data['content']){
lastItem.content +=data['content'];
}

View File

@@ -49,6 +49,9 @@ const updateMessage = () => {
<n-text type="warning">查看原文</n-text>
</a>
</n-tag>
<n-tag v-if="item.sentimentResult" :bordered="false" :type="item.sentimentResult==='看涨'?'error':item.sentimentResult==='看跌'?'success':'info'" size="small">
{{ item.sentimentResult }}
</n-tag>
</n-space>
</n-list-item>
</n-list>

View File

@@ -45,6 +45,7 @@ const formValue = ref({
sponsorCode: "",
httpProxy:"",
httpProxyEnabled:false,
enableAgent: false,
})
// 添加一个新的AI配置到列表
@@ -103,6 +104,7 @@ onMounted(() => {
formValue.value.sponsorCode = res.sponsorCode
formValue.value.httpProxy=res.httpProxy;
formValue.value.httpProxyEnabled=res.httpProxyEnabled;
formValue.value.enableAgent = res.enableAgent;
})
@@ -142,6 +144,7 @@ function saveConfig() {
sponsorCode: formValue.value.sponsorCode,
httpProxy:formValue.value.httpProxy,
httpProxyEnabled:formValue.value.httpProxyEnabled,
enableAgent: formValue.value.enableAgent,
})
if (config.sponsorCode) {
@@ -231,6 +234,7 @@ function importConfig() {
formValue.value.sponsorCode = config.sponsorCode
formValue.value.httpProxy=config.httpProxy
formValue.value.httpProxyEnabled=config.httpProxyEnabled
formValue.value.enableAgent = config.enableAgent
};
reader.readAsText(file);
};
@@ -321,6 +325,10 @@ function deletePrompt(ID) {
<n-form-item-gi :span="3" label="指数基金:" path="enableFund">
<n-switch v-model:value="formValue.enableFund"/>
</n-form-item-gi>
<n-form-item-gi :span="3" label="AI智能体" path="enableAgent">
<n-switch v-model:value="formValue.enableAgent"/>
</n-form-item-gi>
<n-form-item-gi :span="11" label="赞助码:" path="sponsorCode">
<n-input-group>
<n-input :show-count="true" placeholder="赞助码" v-model:value="formValue.sponsorCode"/>

View File

@@ -1853,8 +1853,8 @@ function updateTab(name) {
})
}
function delTab(name) {
let infos = groupList.value = groupList.value.filter(item => item.ID === Number(name))
function delTab(groupId) {
let infos = groupList.value = groupList.value.filter(item => item.ID === Number(groupId))
dialog.create({
title: '删除分组',
type: 'warning',
@@ -1862,7 +1862,7 @@ function delTab(name) {
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
RemoveGroup(name).then(result => {
RemoveGroup(Number(groupId)).then(result => {
message.info(result)
GetGroupList().then(result => {
groupList.value = result

View File

@@ -9,18 +9,21 @@ import EmbeddedUrl from "./EmbeddedUrl.vue";
<n-tab-pane name="选股通" tab="选股通">
<embedded-url url="https://xuangutong.com.cn" :height="'calc(100vh - 252px)'"/>
</n-tab-pane>
<!-- <n-tab-pane name="百度股市通" tab="百度股市通">-->
<!-- <embedded-url url="https://gushitong.baidu.com" :height="'calc(100vh - 252px)'"/>-->
<!-- </n-tab-pane>-->
<n-tab-pane name="百度股市通" tab="百度股市通">
<embedded-url url="https://gushitong.baidu.com" :height="'calc(100vh - 252px)'"/>
</n-tab-pane>
<n-tab-pane name="东财大盘星图" tab="东财大盘星图">
<embedded-url url="https://quote.eastmoney.com/stockhotmap/" :height="'calc(100vh - 252px)'"/>
</n-tab-pane>
<n-tab-pane name="TopHub" tab="TopHub(今日热榜)">
<embedded-url url="https://tophub.today/c/finance" :height="'calc(100vh - 252px)'"/>
</n-tab-pane>
<!-- <n-tab-pane name="摸鱼" tab="摸鱼">-->
<!-- <embedded-url url="https://996.ninja/" :height="'calc(100vh - 252px)'"/>-->
<!-- </n-tab-pane>-->
<n-tab-pane name="摸鱼" tab="摸鱼">
<embedded-url url="https://996.ninja/" :height="'calc(100vh - 252px)'"/>
</n-tab-pane>
<n-tab-pane name="财联社-行情数据" tab="财联社-行情数据">
<embedded-url url="https://www.cls.cn/quotation" :height="'calc(100vh - 252px)'"/>
</n-tab-pane>
<n-tab-pane name="欢迎推荐更多有趣的财经网页" tab="欢迎推荐更多有趣的财经网页">

View File

@@ -393,6 +393,7 @@ export namespace data {
sponsorCode: string;
httpProxy: string;
httpProxyEnabled: boolean;
enableAgent: boolean;
aiConfigs: AIConfig[];
static createFrom(source: any = {}) {
@@ -428,6 +429,7 @@ export namespace data {
this.sponsorCode = source["sponsorCode"];
this.httpProxy = source["httpProxy"];
this.httpProxyEnabled = source["httpProxyEnabled"];
this.enableAgent = source["enableAgent"];
this.aiConfigs = this.convertValues(source["aiConfigs"], AIConfig);
}

21
go.mod
View File

@@ -1,12 +1,10 @@
module go-stock
go 1.24.0
toolchain go1.24.5
go 1.25.0
require (
github.com/PuerkitoBio/goquery v1.10.1
github.com/chromedp/chromedp v0.11.2
github.com/chromedp/chromedp v0.14.1
github.com/cloudwego/eino v0.4.1
github.com/cloudwego/eino-ext/components/model/ark v0.1.19
github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20250804092122-8845979a2228
@@ -28,7 +26,7 @@ require (
github.com/wailsapp/wails/v2 v2.10.1
go.uber.org/zap v1.27.0
golang.org/x/net v0.38.0
golang.org/x/sys v0.33.0
golang.org/x/sys v0.36.0
golang.org/x/text v0.26.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gorm.io/gorm v1.25.12
@@ -40,12 +38,12 @@ require (
git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/bep/debounce v1.2.1 // indirect
github.com/bytedance/sonic v1.13.2 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/bytedance/sonic v1.14.0 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb // indirect
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250804062529-6e67726a4b3f // indirect
github.com/cohesion-org/deepseek-go v1.3.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -54,6 +52,7 @@ require (
github.com/evanphx/json-patch v0.5.2 // indirect
github.com/getkin/kin-openapi v0.118.0 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
@@ -72,7 +71,7 @@ require (
github.com/joho/godotenv v1.5.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/labstack/echo/v4 v4.13.3 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
@@ -119,7 +118,7 @@ require (
github.com/wailsapp/mimetype v1.4.1 // indirect
github.com/yargevad/filepathx v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/arch v0.11.0 // indirect
golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect

39
go.sum
View File

@@ -16,24 +16,23 @@ github.com/bugsnag/bugsnag-go v1.4.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqR
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bytedance/mockey v1.2.14 h1:KZaFgPdiUwW+jOWFieo3Lr7INM1P+6adO3hxZhDswY8=
github.com/bytedance/mockey v1.2.14/go.mod h1:1BPHF9sol5R1ud/+0VEHGQq/+i2lN+GTsr3O2Q9IENY=
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb h1:noKVm2SsG4v0Yd0lHNtFYc9EUxIVvrr4kJ6hM8wvIYU=
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb/go.mod h1:4XqMl3iIW08jtieURWL6Tt5924w21pxirC6th662XUM=
github.com/chromedp/chromedp v0.11.2 h1:ZRHTh7DjbNTlfIv3NFTbB7eVeu5XCNkgrpcGSpn2oX0=
github.com/chromedp/chromedp v0.11.2/go.mod h1:lr8dFRLKsdTTWb75C/Ttol2vnBKOSnt0BW8R9Xaupi8=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
github.com/chromedp/chromedp v0.14.1 h1:0uAbnxewy/Q+Bg7oafVePE/6EXEho9hnaC38f+TTENg=
github.com/chromedp/chromedp v0.14.1/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/cloudwego/eino v0.4.1 h1:Jy9KWpCvd+Z75oIynhHsT9dEECUuCW8IPZlVjHgVu9s=
github.com/cloudwego/eino v0.4.1/go.mod h1:wUjz990apdsaOraOXdh6CdhVXq8DJsOvLsVlxNTcNfY=
github.com/cloudwego/eino-ext/components/model/ark v0.1.19 h1:XYnOeszXA28T1gxYOpTIjOjLCPO2gjexK+ShSan9u/8=
@@ -44,7 +43,6 @@ github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250804092122-8845
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250804092122-8845979a2228/go.mod h1:3uBZ/GzJzh1izfY2w62282FZrQG3ISs6T/jTmmPffvE=
github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250804062529-6e67726a4b3f h1:J1tQBg6RDftrtm3vsv+ozlupdlNV+WGslpXiTDr/2xI=
github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250804062529-6e67726a4b3f/go.mod h1:4EBgz8+68n1iuKyWC37Tu9NG1WJkPm+yLxvyLik28Us=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cohesion-org/deepseek-go v1.3.2 h1:WTZ/2346KFYca+n+DL5p+Ar1RQxF2w/wGkU4jDvyXaQ=
github.com/cohesion-org/deepseek-go v1.3.2/go.mod h1:bOVyKj38r90UEYZFrmJOzJKPxuAh8sIzHOCnLOpiXeI=
github.com/coocood/freecache v1.2.4 h1:UdR6Yz/X1HW4fZOuH0Z94KwG851GWOSknua5VUbb/5M=
@@ -78,6 +76,8 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJY
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-ego/gse v0.80.3 h1:YNFkjMhlhQnUeuoFcUEd1ivh6SOB764rT8GDsEbDiEg=
github.com/go-ego/gse v0.80.3/go.mod h1:Gt3A9Ry1Eso2Kza4MRaiZ7f2DTAvActmETY46Lxg0gU=
github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3 h1:02WINGfSX5w0Mn+F28UyRoSt9uvMhKguwWMlOAh6U/0=
github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -162,10 +162,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -343,8 +341,8 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4=
golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
@@ -413,8 +411,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -512,4 +510,3 @@ modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

View File

@@ -228,6 +228,7 @@ func AutoMigrate() {
db.Dao.AutoMigrate(&models.TelegraphTags{})
db.Dao.AutoMigrate(&models.LongTigerRankData{})
db.Dao.AutoMigrate(&data.AIConfig{})
db.Dao.AutoMigrate(&models.BKDict{})
updateMultipleModel()
}