mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(data): 添加 AIResponseResult模型并实现相关功能
感谢 @gnim2600 的建议! - 新增 AIResponseResult 模型用于保存 AI 分析结果 - 实现 SaveAIResponseResult 和 GetAIResponseResult 函数 - 在前端添加 AI 分析功能,包括保存和获取分析结果 -优化 AI 分析界面,增加分析时间显示和再次分析按钮
This commit is contained in:
parent
3e13ef007b
commit
7b93d4d8ca
7
app.go
7
app.go
@ -424,6 +424,13 @@ func (a *App) NewChatStream(stock, stockCode string) {
|
||||
runtime.EventsEmit(a.ctx, "newChatStream", "DONE")
|
||||
}
|
||||
|
||||
func (a *App) SaveAIResponseResult(stockCode, stockName, result string) {
|
||||
data.NewDeepSeekOpenAi().SaveAIResponseResult(stockCode, stockName, result)
|
||||
}
|
||||
func (a *App) GetAIResponseResult(stock string) *models.AIResponseResult {
|
||||
return data.NewDeepSeekOpenAi().GetAIResponseResult(stock)
|
||||
}
|
||||
|
||||
func GenNotificationMsg(stockInfo *data.StockInfo) string {
|
||||
Price, err := convertor.ToFloat(stockInfo.Price)
|
||||
if err != nil {
|
||||
|
@ -9,7 +9,9 @@ import (
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/logger"
|
||||
"go-stock/backend/models"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -208,6 +210,9 @@ func (o OpenAi) NewChatStream(stock, stockCode string) <-chan string {
|
||||
client.SetHeader("Authorization", "Bearer "+o.ApiKey)
|
||||
client.SetHeader("Content-Type", "application/json")
|
||||
client.SetRetryCount(3)
|
||||
if o.TimeOut <= 0 {
|
||||
o.TimeOut = 300
|
||||
}
|
||||
client.SetTimeout(time.Duration(o.TimeOut) * time.Second)
|
||||
resp, err := client.R().
|
||||
SetDoNotParseResponse(true).
|
||||
@ -446,3 +451,17 @@ func GetTelegraphList() *[]string {
|
||||
})
|
||||
return &telegraph
|
||||
}
|
||||
|
||||
func (o OpenAi) SaveAIResponseResult(stockCode, stockName, result string) {
|
||||
db.Dao.Create(&models.AIResponseResult{
|
||||
StockCode: stockCode,
|
||||
StockName: stockName,
|
||||
Content: result,
|
||||
})
|
||||
}
|
||||
|
||||
func (o OpenAi) GetAIResponseResult(stock string) *models.AIResponseResult {
|
||||
var result models.AIResponseResult
|
||||
db.Dao.Where("stock_code = ?", stock).Order("id desc").First(&result)
|
||||
return &result
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/plugin/soft_delete"
|
||||
"time"
|
||||
)
|
||||
|
||||
// @Author spark
|
||||
// @Date 2025/2/6 15:25
|
||||
@ -128,3 +132,15 @@ type Commit struct {
|
||||
VerifiedAt interface{} `json:"verified_at"`
|
||||
} `json:"verification"`
|
||||
}
|
||||
|
||||
type AIResponseResult struct {
|
||||
gorm.Model
|
||||
StockCode string `json:"stockCode"`
|
||||
StockName string `json:"stockName"`
|
||||
Content string `json:"content"`
|
||||
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
|
||||
}
|
||||
|
||||
func (receiver AIResponseResult) TableName() string {
|
||||
return "ai_response_result"
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ import {
|
||||
Follow, GetConfig,
|
||||
GetFollowList,
|
||||
GetStockList,
|
||||
Greet, NewChat, NewChatStream,
|
||||
Greet, SaveAIResponseResult, NewChatStream,
|
||||
SendDingDingMessage, SendDingDingMessageByType,
|
||||
SetAlarmChangePercent,
|
||||
SetCostPriceAndVolume, SetStockSort,
|
||||
UnFollow
|
||||
UnFollow, GetAIResponseResult
|
||||
} from '../../wailsjs/go/main/App'
|
||||
import {
|
||||
NAvatar,
|
||||
@ -152,6 +152,7 @@ EventsOn("newChatStream",async (msg) => {
|
||||
//console.log("newChatStream:->",data.airesult)
|
||||
data.loading = false
|
||||
if (msg === "DONE") {
|
||||
SaveAIResponseResult(data.code, data.name, data.airesult)
|
||||
message.info("AI分析完成!")
|
||||
message.destroyAll()
|
||||
} else {
|
||||
@ -448,9 +449,9 @@ function SendMessage(result,type){
|
||||
// SendDingDingMessage(msg,result["股票代码"])
|
||||
SendDingDingMessageByType(msg,result["股票代码"],type)
|
||||
}
|
||||
|
||||
function aiCheckStock(stock,stockCode){
|
||||
function aiReCheckStock(stock,stockCode) {
|
||||
data.airesult=""
|
||||
data.time=""
|
||||
data.name=stock
|
||||
data.code=stockCode
|
||||
data.loading=true
|
||||
@ -461,6 +462,38 @@ function aiCheckStock(stock,stockCode){
|
||||
NewChatStream(stock,stockCode)
|
||||
}
|
||||
|
||||
function aiCheckStock(stock,stockCode){
|
||||
GetAIResponseResult(stockCode).then(result => {
|
||||
if(result.content){
|
||||
data.name=stock
|
||||
data.code=stockCode
|
||||
data.loading=false
|
||||
modalShow4.value=true
|
||||
data.airesult=result.content
|
||||
const date = new Date(result.CreatedAt);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
data.time=formattedDate
|
||||
}else{
|
||||
data.airesult=""
|
||||
data.time=""
|
||||
data.name=stock
|
||||
data.code=stockCode
|
||||
data.loading=true
|
||||
modalShow4.value=true
|
||||
message.loading("ai检测中...",{
|
||||
duration: 0,
|
||||
})
|
||||
NewChatStream(stock,stockCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getTypeName(type){
|
||||
switch (type)
|
||||
{
|
||||
@ -518,7 +551,9 @@ function getHeight() {
|
||||
<n-button size="tiny" secondary type="primary" @click="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
|
||||
取消关注
|
||||
</n-button>
|
||||
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning" @click="aiCheckStock(result['股票名称'],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>
|
||||
@ -609,18 +644,28 @@ function getHeight() {
|
||||
<n-image :src="data.kURL" />
|
||||
</n-modal>
|
||||
|
||||
<n-modal transform-origin="center" v-model:show="modalShow4" preset="card" style="width: 800px;height: 480px" :title="'['+data.name+']AI分析结果'" >
|
||||
<n-modal transform-origin="center" v-model:show="modalShow4" preset="card" style="width: 800px;height: 500px" :title="'['+data.name+']AI分析结果'" >
|
||||
<n-spin size="small" :show="data.loading">
|
||||
<MdPreview ref="mdPreviewRef" style="height: 380px;text-align: left" :modelValue="data.airesult" :theme="'dark'"/>
|
||||
</n-spin>
|
||||
<template #header-extra>
|
||||
|
||||
</template>
|
||||
<template #footer>
|
||||
<n-flex justify="space-between">
|
||||
<n-text type="error" v-if="data.time" >分析时间:{{data.time}}</n-text>
|
||||
<n-button size="tiny" type="warning" @click="aiReCheckStock(data.name,data.code)">再次分析</n-button>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
#总结 {
|
||||
text-align: center;
|
||||
}
|
||||
.md-editor-preview h3{
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.md-editor-preview p{
|
||||
text-align: left !important;
|
||||
}
|
||||
</style>
|
||||
|
5
frontend/wailsjs/go/main/App.d.ts
vendored
5
frontend/wailsjs/go/main/App.d.ts
vendored
@ -1,9 +1,12 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
import {models} from '../models';
|
||||
import {data} from '../models';
|
||||
|
||||
export function Follow(arg1:string):Promise<string>;
|
||||
|
||||
export function GetAIResponseResult(arg1:string):Promise<models.AIResponseResult>;
|
||||
|
||||
export function GetConfig():Promise<data.Settings>;
|
||||
|
||||
export function GetFollowList():Promise<Array<data.FollowedStock>>;
|
||||
@ -16,6 +19,8 @@ export function NewChat(arg1:string):Promise<string>;
|
||||
|
||||
export function NewChatStream(arg1:string,arg2:string):Promise<void>;
|
||||
|
||||
export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string):Promise<void>;
|
||||
|
||||
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;
|
||||
|
||||
export function SendDingDingMessageByType(arg1:string,arg2:string,arg3:number):Promise<string>;
|
||||
|
@ -6,6 +6,10 @@ export function Follow(arg1) {
|
||||
return window['go']['main']['App']['Follow'](arg1);
|
||||
}
|
||||
|
||||
export function GetAIResponseResult(arg1) {
|
||||
return window['go']['main']['App']['GetAIResponseResult'](arg1);
|
||||
}
|
||||
|
||||
export function GetConfig() {
|
||||
return window['go']['main']['App']['GetConfig']();
|
||||
}
|
||||
@ -30,6 +34,10 @@ export function NewChatStream(arg1, arg2) {
|
||||
return window['go']['main']['App']['NewChatStream'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function SaveAIResponseResult(arg1, arg2, arg3) {
|
||||
return window['go']['main']['App']['SaveAIResponseResult'](arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function SendDingDingMessage(arg1, arg2) {
|
||||
return window['go']['main']['App']['SendDingDingMessage'](arg1, arg2);
|
||||
}
|
||||
|
@ -329,3 +329,55 @@ export namespace data {
|
||||
|
||||
}
|
||||
|
||||
export namespace models {
|
||||
|
||||
export class AIResponseResult {
|
||||
ID: number;
|
||||
// Go type: time
|
||||
CreatedAt: any;
|
||||
// Go type: time
|
||||
UpdatedAt: any;
|
||||
// Go type: gorm
|
||||
DeletedAt: any;
|
||||
stockCode: string;
|
||||
stockName: string;
|
||||
content: string;
|
||||
IsDel: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new AIResponseResult(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.ID = source["ID"];
|
||||
this.CreatedAt = this.convertValues(source["CreatedAt"], null);
|
||||
this.UpdatedAt = this.convertValues(source["UpdatedAt"], null);
|
||||
this.DeletedAt = this.convertValues(source["DeletedAt"], null);
|
||||
this.stockCode = source["stockCode"];
|
||||
this.stockName = source["stockName"];
|
||||
this.content = source["content"];
|
||||
this.IsDel = source["IsDel"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
2
main.go
2
main.go
@ -14,6 +14,7 @@ import (
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
"go-stock/backend/data"
|
||||
"go-stock/backend/db"
|
||||
"go-stock/backend/models"
|
||||
"log"
|
||||
"os"
|
||||
goruntime "runtime"
|
||||
@ -44,6 +45,7 @@ func main() {
|
||||
db.Dao.AutoMigrate(&data.FollowedStock{})
|
||||
db.Dao.AutoMigrate(&data.IndexBasic{})
|
||||
db.Dao.AutoMigrate(&data.Settings{})
|
||||
db.Dao.AutoMigrate(&models.AIResponseResult{})
|
||||
|
||||
if stocksBin != nil && len(stocksBin) > 0 {
|
||||
go initStockData()
|
||||
|
Loading…
x
Reference in New Issue
Block a user