|
|
@ -5,8 +5,12 @@ import { |
|
|
|
getReplyStreamAPI, |
|
|
|
getReplyAPI, |
|
|
|
TTSAPI, |
|
|
|
getQuestionAPI, |
|
|
|
qsArpAamClickAPI, |
|
|
|
dbqbFirstAPI, |
|
|
|
dbqbSecondOneAPI, |
|
|
|
dbqbSecondTwoAPI, |
|
|
|
dbqbSecondThreeAPI, |
|
|
|
dbqbSecondFourAPI, |
|
|
|
} from "../api/AIxiaocaishen"; |
|
|
|
import { useUserStore } from "../store/userPessionCode"; |
|
|
|
import { useChatStore } from "../store/chat"; |
|
|
@ -17,6 +21,7 @@ import katex from "katex"; // 引入 KaTeX 库 |
|
|
|
import { htmlToText } from "html-to-text"; |
|
|
|
import { Howl, Howler } from "howler"; |
|
|
|
import * as echarts from "echarts"; |
|
|
|
import moment from "moment"; |
|
|
|
|
|
|
|
import AIgif1 from "@/assets/img/AIchat/AIgif1.gif"; |
|
|
|
import AIgif2 from "@/assets/img/AIchat/AIgif2.gif"; |
|
|
@ -31,92 +36,15 @@ import title3 from "@/assets/img/AIchat/攻防三维.png"; |
|
|
|
import title4 from "@/assets/img/AIchat/综合作战.png"; |
|
|
|
|
|
|
|
const gifList = [AIgif1, AIgif2, AIgif3, AIgif4, AIgif5, AIgif6, AIgif7]; |
|
|
|
|
|
|
|
const chatStore = useChatStore(); |
|
|
|
const audioStore = useAudioStore(); |
|
|
|
const dataStore = useDataStore(); |
|
|
|
// 随机GIF |
|
|
|
const currentGif = ref(""); |
|
|
|
|
|
|
|
// 推荐问题飘屏数据 |
|
|
|
const questionsList = ref([]); |
|
|
|
const getQuestionsList = async () => { |
|
|
|
const result = await getQuestionAPI(); |
|
|
|
questionsList.value = result.data; |
|
|
|
}; |
|
|
|
|
|
|
|
// 定义自定义事件 |
|
|
|
const emit = defineEmits(["updateMessage", "sendMessage"]); |
|
|
|
|
|
|
|
// 弹窗控制 |
|
|
|
// const currentQuestions = ref(""); |
|
|
|
// const showQuestions = async (questions) => { |
|
|
|
// const click = await qsArpAamClickAPI({ |
|
|
|
// token: localStorage.getItem("localToken"), |
|
|
|
// id: questions.id, |
|
|
|
// }); |
|
|
|
// console.log(click); |
|
|
|
|
|
|
|
// currentQuestions.value = questions; |
|
|
|
// // 触发自定义事件 |
|
|
|
// emit("updateMessage", questions.title); |
|
|
|
// // emit("sendMessage"); |
|
|
|
// }; |
|
|
|
|
|
|
|
// 飘屏控制 |
|
|
|
// const floatingTopMouseEnter = function () { |
|
|
|
// const userAgent = navigator.userAgent.toLowerCase(); |
|
|
|
// const mobileKeywords = ["mobile", "android", "iphone", "ipad", "ipod"]; |
|
|
|
// const isMobile = mobileKeywords.some((keyword) => |
|
|
|
// userAgent.includes(keyword) |
|
|
|
// ); |
|
|
|
// if (isMobile) { |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// console.log("鼠标指上去"); |
|
|
|
// const floatTop = document.getElementById("top"); |
|
|
|
// floatTop.style.animationPlayState = "paused"; |
|
|
|
// }; |
|
|
|
// const floatingTopMouseLeave = function () { |
|
|
|
// const userAgent = navigator.userAgent.toLowerCase(); |
|
|
|
// const mobileKeywords = ["mobile", "android", "iphone", "ipad", "ipod"]; |
|
|
|
// const isMobile = mobileKeywords.some((keyword) => |
|
|
|
// userAgent.includes(keyword) |
|
|
|
// ); |
|
|
|
// if (isMobile) { |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// console.log("鼠标指下去"); |
|
|
|
// const floatTop = document.getElementById("top"); |
|
|
|
// floatTop.style.animationPlayState = "running"; |
|
|
|
// }; |
|
|
|
// const floatingBottomMouseEnter = function () { |
|
|
|
// const userAgent = navigator.userAgent.toLowerCase(); |
|
|
|
// const mobileKeywords = ["mobile", "android", "iphone", "ipad", "ipod"]; |
|
|
|
// const isMobile = mobileKeywords.some((keyword) => |
|
|
|
// userAgent.includes(keyword) |
|
|
|
// ); |
|
|
|
// if (isMobile) { |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// console.log("鼠标指上去"); |
|
|
|
// const floatBottom = document.getElementById("bottom"); |
|
|
|
// floatBottom.style.animationPlayState = "paused"; |
|
|
|
// }; |
|
|
|
// const floatingBottomMouseLeave = function () { |
|
|
|
// const userAgent = navigator.userAgent.toLowerCase(); |
|
|
|
// const mobileKeywords = ["mobile", "android", "iphone", "ipad", "ipod"]; |
|
|
|
// const isMobile = mobileKeywords.some((keyword) => |
|
|
|
// userAgent.includes(keyword) |
|
|
|
// ); |
|
|
|
// if (isMobile) { |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// console.log("鼠标指下去"); |
|
|
|
// const floatBottom = document.getElementById("bottom"); |
|
|
|
// floatBottom.style.animationPlayState = "running"; |
|
|
|
// }; |
|
|
|
|
|
|
|
// 音频播放方法 |
|
|
|
const playAudio = (url) => { |
|
|
|
// 添加空值校验 |
|
|
@ -276,123 +204,45 @@ watch( |
|
|
|
// 获取权限 |
|
|
|
const userStore = useUserStore(); |
|
|
|
|
|
|
|
const params = { |
|
|
|
content: newVal[newVal.length - 1].content, |
|
|
|
userData: { |
|
|
|
token: localStorage.getItem("localToken"), |
|
|
|
// language: "cn", |
|
|
|
// brainPrivilegeState: userStore.brainPerssion, |
|
|
|
// swordPrivilegeState: userStore.swordPerssion, |
|
|
|
// stockForecastPrivile: userStore.pricePerssion, |
|
|
|
// spaceForecastPrivile: userStore.timePerssion, |
|
|
|
// aibullPrivilegeState: userStore.aibullPerssion, |
|
|
|
// aigoldBullPrivilegeS: userStore.aiGnbullPerssion, |
|
|
|
// airadarPrivilegeStat: userStore.airadarPerssion, |
|
|
|
// marketList: "hk,cn,usa,my,sg,vi,in,gb" |
|
|
|
// token: "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w", |
|
|
|
language: "cn", |
|
|
|
brainPrivilegeState: "1", |
|
|
|
swordPrivilegeState: "1", |
|
|
|
stockForecastPrivile: "1", |
|
|
|
spaceForecastPrivile: "1", |
|
|
|
aibullPrivilegeState: "1", |
|
|
|
aigoldBullPrivilegeS: "1", |
|
|
|
airadarPrivilegeStat: "1", |
|
|
|
marketList: "hk,cn,usa,my,sg,vi,in,gb", |
|
|
|
const params1 = { |
|
|
|
workflow_id: "7514939889071718438", |
|
|
|
parameters: { |
|
|
|
content: newVal[newVal.length - 1].content, |
|
|
|
userData: { |
|
|
|
language: "cn", |
|
|
|
marketList: "hk,cn,usa,my,sg,vi,in,gb", |
|
|
|
token: localStorage.getItem("localToken"), |
|
|
|
// language: "cn", |
|
|
|
// marketList: "hk,cn,usa,my,sg,vi,in,gb" |
|
|
|
// token: "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w", |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
// 标志 |
|
|
|
let flag = true; |
|
|
|
const codeData = ref(); |
|
|
|
// 第一阶段,意图识别 |
|
|
|
try { |
|
|
|
chatStore.messages.push({ |
|
|
|
class: "ing", |
|
|
|
type: "ing", |
|
|
|
content: "正在为您生成特斯拉全景作战报告", |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title1", |
|
|
|
type: "title1", |
|
|
|
content: "特斯拉全景作战报告", |
|
|
|
date: "05/06/2025", |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title2", |
|
|
|
type: "title2", |
|
|
|
content: "", |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title3", |
|
|
|
type: "title3", |
|
|
|
content: title2, |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title3", |
|
|
|
type: "title3", |
|
|
|
content: title3, |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title3", |
|
|
|
type: "title3", |
|
|
|
content: title4, |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content1", |
|
|
|
type: "content1", |
|
|
|
content: "股票名称:tesla", |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content2", |
|
|
|
type: "content2", |
|
|
|
content: "K线图", |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content3", |
|
|
|
type: "content3", |
|
|
|
content: "(1)牛股评级:⭐⭐⭐⭐⭐", |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "mianze", |
|
|
|
type: "mianze", |
|
|
|
content: "内容由AI生成,请注意甄别", |
|
|
|
}); |
|
|
|
|
|
|
|
// 调用工作流获取回复 |
|
|
|
const result = (await getReplyAPI(params)).json(); |
|
|
|
// 获取结果 |
|
|
|
const ans = ref(); |
|
|
|
await result.then((res) => { |
|
|
|
// 解析 data 字段中的 JSON |
|
|
|
ans.value = JSON.parse(res.data); |
|
|
|
}); |
|
|
|
const AIcontent = ref(""); |
|
|
|
// 处理不同的 answer 字段 |
|
|
|
|
|
|
|
if (ans.value.resp !== "" && ans.value.resp !== null) { |
|
|
|
const result = await dbqbFirstAPI(params1); |
|
|
|
codeData.value = result.data; |
|
|
|
console.log(codeData.value, "codeData"); |
|
|
|
// 根据意图识别结果判断 |
|
|
|
if (result.code == 200) { |
|
|
|
chatStore.messages.push({ |
|
|
|
class: "ing", |
|
|
|
type: "ing", |
|
|
|
flag: flag, |
|
|
|
content: result.data.kaishi, |
|
|
|
}); |
|
|
|
} else { |
|
|
|
flag = false; |
|
|
|
console.log("执行回绝话术"); |
|
|
|
AIcontent.value = ans.value.resp; |
|
|
|
|
|
|
|
const AIcontent = ref(result.msg); |
|
|
|
// 修改后的消息处理逻辑 |
|
|
|
|
|
|
|
const processedContent = marked(AIcontent.value); |
|
|
|
const katexRegex = /\$\$(.*?)\$\$/g; |
|
|
|
// const plainTextContent = htmlToText(processedContent); |
|
|
|
|
|
|
|
const aiContent = processedContent.replace( |
|
|
|
katexRegex, |
|
|
|
(match, formula) => { |
|
|
@ -404,193 +254,416 @@ watch( |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
console.log(aiContent, "aiContent"); |
|
|
|
|
|
|
|
// chatStore.messages.pop(); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "ing", |
|
|
|
type: "ing", |
|
|
|
flag: flag, |
|
|
|
content: aiContent, |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.setLoading(false); |
|
|
|
} else { |
|
|
|
// 判断是否是股票问题 |
|
|
|
if (ans.value.answer !== "") { |
|
|
|
AIcontent.value = ans.value.answer; |
|
|
|
const type = ans.value.type; |
|
|
|
const data = JSON.parse(ans.value.data); |
|
|
|
|
|
|
|
console.log("处理 K 线数据 - 开始"); |
|
|
|
console.log(data, "data"); |
|
|
|
|
|
|
|
const Kline20 = { |
|
|
|
name: data.data.HomePage.StockInformation.Name, |
|
|
|
Kline: data.data, |
|
|
|
type: type, |
|
|
|
}; |
|
|
|
|
|
|
|
// 打印K线数据结构 |
|
|
|
console.log("K线数据结构:", Kline20); |
|
|
|
console.log("K线数据名称:", Kline20.name); |
|
|
|
console.log("K线数据类型:", Kline20.type); |
|
|
|
console.log("K线数据:", Kline20.Kline ? Kline20.Kline : null); |
|
|
|
|
|
|
|
// 设置数据有效标志 |
|
|
|
hasValidData.value = true; |
|
|
|
console.log("hasValidData设置为:", hasValidData.value); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.log(e, "意图识别失败"); |
|
|
|
} |
|
|
|
|
|
|
|
// chatStore.messages.pop(); |
|
|
|
if (flag) { |
|
|
|
const params2 = { |
|
|
|
content: newVal[newVal.length - 1].content, |
|
|
|
userData: { |
|
|
|
aibullPrivilegeState: 1, |
|
|
|
aigoldBullPrivilegeS: 1, |
|
|
|
airadarPrivilegeStat: 1, |
|
|
|
brainPrivilegeState: 1, |
|
|
|
spaceForecastPrivile: 1, |
|
|
|
stockForecastPrivile: 1, |
|
|
|
swordPrivilegeState: 1, |
|
|
|
language: "cn", |
|
|
|
marketList: "hk,cn,usa,my,sg,vi,in,gb", |
|
|
|
token: localStorage.getItem("localToken"), |
|
|
|
// aibullPrivilegeState: userStore.aibullPrivilegeState, |
|
|
|
// aigoldBullPrivilegeState: userStore.aigoldBullPrivilegeState, |
|
|
|
// airadarPrivilegeState: userStore.airadarPrivilegeState, |
|
|
|
// brainPrivilegeState: userStore.brainPrivilegeState, |
|
|
|
// spaceForecastPrivilegeState: userStore.spaceForecastPrivilegeState, |
|
|
|
// stockForecastPrivilegeState: userStore.stockForecastPrivilegeState, |
|
|
|
// swordPrivilegeState: userStore.swordPrivilegeState, |
|
|
|
// language: "cn", |
|
|
|
// marketList: "hk,cn,usa,my,sg,vi,in,gb" |
|
|
|
// token: "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w", |
|
|
|
}, |
|
|
|
name: codeData.value.name, |
|
|
|
code: codeData.value.code, |
|
|
|
market: codeData.value.market, |
|
|
|
}; |
|
|
|
|
|
|
|
try { |
|
|
|
const result21 = await dbqbSecondOneAPI({ |
|
|
|
workflow_id: "7514945685688025127", |
|
|
|
parameters: params2, |
|
|
|
}); |
|
|
|
const result22 = await dbqbSecondTwoAPI({ |
|
|
|
workflow_id: "7514945728733888575", |
|
|
|
parameters: params2, |
|
|
|
}); |
|
|
|
const result23 = await dbqbSecondThreeAPI({ |
|
|
|
workflow_id: "7514945758421811254", |
|
|
|
parameters: params2, |
|
|
|
}); |
|
|
|
const result24 = await dbqbSecondFourAPI({ |
|
|
|
workflow_id: "7514945791469223955", |
|
|
|
parameters: params2, |
|
|
|
}); |
|
|
|
|
|
|
|
// 先推送K线图消息 |
|
|
|
const klineMessageId = `kline-${Date.now()}`; |
|
|
|
console.log("生成K线消息ID:", klineMessageId); |
|
|
|
const katexRegex = /\$\$(.*?)\$\$/g; |
|
|
|
// 删除正在为您生成信息 |
|
|
|
chatStore.messages.pop(); |
|
|
|
// 添加报告头和时间 |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title1", |
|
|
|
type: "title1", |
|
|
|
content: codeData.value.name + "全景作战报告", |
|
|
|
date: moment().format("MM/DD/YYYY"), |
|
|
|
}); |
|
|
|
// 添加股票信息框 |
|
|
|
|
|
|
|
const pc1 = marked( |
|
|
|
result21.data.name + |
|
|
|
"\n" + |
|
|
|
result21.data.price + |
|
|
|
"\n" + |
|
|
|
result21.data.data |
|
|
|
); |
|
|
|
const ac1 = pc1.replace(katexRegex, (match, formula) => { |
|
|
|
try { |
|
|
|
return katex.renderToString(formula, { throwOnError: false }); |
|
|
|
} catch (error) { |
|
|
|
console.error("KaTeX 渲染错误:", error); |
|
|
|
return match; |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
type: "kline", |
|
|
|
chartData: Kline20, |
|
|
|
messageId: klineMessageId, |
|
|
|
hasValidData: true, // 添加hasValidData标志 |
|
|
|
}); |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content1", |
|
|
|
type: "content1", |
|
|
|
content: ac1, |
|
|
|
}); |
|
|
|
// 添加六色罗盘 |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content2", |
|
|
|
type: "content2", |
|
|
|
content: "K线图", |
|
|
|
}); |
|
|
|
// 度牛尺K线图 |
|
|
|
// 添加标题2 |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title2", |
|
|
|
type: "title2", |
|
|
|
content: "", |
|
|
|
}); |
|
|
|
// 添加内容框1 |
|
|
|
const pc2 = marked(result22.data.hxjzpg); |
|
|
|
console.log(pc2, "pc2"); |
|
|
|
const ac2 = pc2.replace(katexRegex, (match, formula) => { |
|
|
|
try { |
|
|
|
return katex.renderToString(formula, { throwOnError: false }); |
|
|
|
} catch (error) { |
|
|
|
console.error("KaTeX 渲染错误:", error); |
|
|
|
return match; |
|
|
|
} |
|
|
|
}); |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content3", |
|
|
|
type: "content3", |
|
|
|
content: ac2, |
|
|
|
}); |
|
|
|
// 添加标题3-2 |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title3", |
|
|
|
type: "title3", |
|
|
|
content: title2, |
|
|
|
}); |
|
|
|
// 添加内容框2 |
|
|
|
// const pc3 = marked(result23.data.zhuli1+'\n'+result23.data.zhuli2+'\n'+result23.data.zhuli3); |
|
|
|
// const ac3 = pc3.replace( |
|
|
|
// katexRegex, |
|
|
|
// (match, formula) => { |
|
|
|
// try { |
|
|
|
// return katex.renderToString(formula, { throwOnError: false }); |
|
|
|
// } catch (error) { |
|
|
|
// console.error("KaTeX 渲染错误:", error); |
|
|
|
// return match; |
|
|
|
// } |
|
|
|
// } |
|
|
|
// ); |
|
|
|
const ac3 = `<p style="margin:0;color:#FADC0C;display:flex;justify-content:center;font-size:28px">【主力行为】</p><p>${result23.data.zhuli1}</p><p>${result23.data.zhuli2}</p><p>${result23.data.zhuli3}</p>`; |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content3", |
|
|
|
type: "content3", |
|
|
|
content: ac3, |
|
|
|
}); |
|
|
|
// 添加标题3-3 |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title3", |
|
|
|
type: "title3", |
|
|
|
content: title3, |
|
|
|
}); |
|
|
|
// 添加内容框3 |
|
|
|
const arr = result23.data.kongjian.split(","); |
|
|
|
const kongjian = `<p style="margin:0;color:#FADC0C;display:flex;justify-content:center;font-size:28px">【空间维度】</p><p style="display:flex;justify-content:center;">${arr[0]},${arr[1]}</p><p style="display:flex;justify-content:center;">${arr[2]},${arr[3]}</p>`; |
|
|
|
const shijian = `<p style="margin:0;color:#FADC0C;display:flex;justify-content:center;font-size:28px">【时间维度】</p><p style="display:flex;justify-content:center;">${result23.data.shijian}</p>`; |
|
|
|
const nengliang = `<p style="margin:0;color:#FADC0C;display:flex;justify-content:center;font-size:28px">【能量维度】</p><p>${result23.data.nengliang}</p>`; |
|
|
|
const ac4 = kongjian + shijian + nengliang; |
|
|
|
|
|
|
|
// const pc4 = marked( |
|
|
|
// kongjian + |
|
|
|
// "\n" + |
|
|
|
// result23.data.shijian + |
|
|
|
// "\n" + |
|
|
|
// result23.data.nengliang |
|
|
|
// ); |
|
|
|
// const ac4 = pc4.replace(katexRegex, (match, formula) => { |
|
|
|
// try { |
|
|
|
// return katex.renderToString(formula, { throwOnError: false }); |
|
|
|
// } catch (error) { |
|
|
|
// console.error("KaTeX 渲染错误:", error); |
|
|
|
// return match; |
|
|
|
// } |
|
|
|
// }); |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content3", |
|
|
|
type: "content3", |
|
|
|
content: ac4, |
|
|
|
}); |
|
|
|
// 添加标题3-4 |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "title3", |
|
|
|
type: "title3", |
|
|
|
content: title4, |
|
|
|
}); |
|
|
|
// 添加内容框4 |
|
|
|
const cftj = `<p style="margin:0;color:#FADC0C;display:flex;justify-content:center;font-size:28px">【触发条件】</p><p>${result24.data.cftl}</p>`; |
|
|
|
const gfzl = `<p style="margin:0;color:#FADC0C;display:flex;justify-content:center;font-size:28px">【攻防指令】</p><p>${result24.data.gfzl}</p>`; |
|
|
|
const ac5 = cftj + gfzl; |
|
|
|
|
|
|
|
// const pc5 = marked(result24.data.cftl + "/n" + result24.data.gfzl); |
|
|
|
// const ac5 = pc5.replace(katexRegex, (match, formula) => { |
|
|
|
// try { |
|
|
|
// return katex.renderToString(formula, { throwOnError: false }); |
|
|
|
// } catch (error) { |
|
|
|
// console.error("KaTeX 渲染错误:", error); |
|
|
|
// return match; |
|
|
|
// } |
|
|
|
// }); |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "content3", |
|
|
|
type: "content3", |
|
|
|
content: ac5, |
|
|
|
}); |
|
|
|
|
|
|
|
console.log("K线消息已添加到聊天列表"); |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
class: "mianze", |
|
|
|
type: "mianze", |
|
|
|
content: "内容由AI生成,请注意甄别", |
|
|
|
}); |
|
|
|
|
|
|
|
// 再推送文字分析内容的消息 |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
content: "AI正在思考中...", |
|
|
|
}); |
|
|
|
// 调用工作流获取回复 |
|
|
|
const result = await getReplyAPI(params1); |
|
|
|
// 获取结果 |
|
|
|
const ans = ref(); |
|
|
|
await result.then((res) => { |
|
|
|
// 解析 data 字段中的 JSON |
|
|
|
ans.value = JSON.parse(res.data); |
|
|
|
}); |
|
|
|
const AIcontent = ref(""); |
|
|
|
// 处理不同的 answer 字段 |
|
|
|
|
|
|
|
// 在渲染完成后初始化图表 |
|
|
|
nextTick(() => { |
|
|
|
console.log("nextTick开始 - 准备渲染图表"); |
|
|
|
console.log("消息列表:", chatStore.messages); |
|
|
|
|
|
|
|
// 寻找最新添加的K线消息索引 |
|
|
|
let klineIndex = -1; |
|
|
|
for (let i = 0; i < chatStore.messages.length; i++) { |
|
|
|
if (chatStore.messages[i].messageId === klineMessageId) { |
|
|
|
klineIndex = i; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (ans.value.resp !== "" && ans.value.resp !== null) { |
|
|
|
} else { |
|
|
|
// 判断是否是股票问题 |
|
|
|
if (ans.value.answer !== "") { |
|
|
|
AIcontent.value = ans.value.answer; |
|
|
|
const type = ans.value.type; |
|
|
|
const data = JSON.parse(ans.value.data); |
|
|
|
|
|
|
|
console.log("处理 K 线数据 - 开始"); |
|
|
|
console.log(data, "data"); |
|
|
|
|
|
|
|
const Kline20 = { |
|
|
|
name: data.data.HomePage.StockInformation.Name, |
|
|
|
Kline: data.data, |
|
|
|
type: type, |
|
|
|
}; |
|
|
|
|
|
|
|
// 打印K线数据结构 |
|
|
|
console.log("K线数据结构:", Kline20); |
|
|
|
console.log("K线数据名称:", Kline20.name); |
|
|
|
console.log("K线数据类型:", Kline20.type); |
|
|
|
console.log("K线数据:", Kline20.Kline ? Kline20.Kline : null); |
|
|
|
|
|
|
|
// 设置数据有效标志 |
|
|
|
hasValidData.value = true; |
|
|
|
console.log("hasValidData设置为:", hasValidData.value); |
|
|
|
|
|
|
|
// chatStore.messages.pop(); |
|
|
|
|
|
|
|
// 先推送K线图消息 |
|
|
|
const klineMessageId = `kline-${Date.now()}`; |
|
|
|
console.log("生成K线消息ID:", klineMessageId); |
|
|
|
|
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
type: "kline", |
|
|
|
chartData: Kline20, |
|
|
|
messageId: klineMessageId, |
|
|
|
hasValidData: true, // 添加hasValidData标志 |
|
|
|
}); |
|
|
|
|
|
|
|
console.log("找到的K线消息索引:", klineIndex); |
|
|
|
console.log("K线消息已添加到聊天列表"); |
|
|
|
|
|
|
|
if (klineIndex !== -1) { |
|
|
|
const containerId = `kline-container-${klineIndex}`; |
|
|
|
console.log("图表容器ID:", containerId); |
|
|
|
// 在渲染完成后初始化图表 |
|
|
|
nextTick(() => { |
|
|
|
console.log("nextTick开始 - 准备渲染图表"); |
|
|
|
console.log("消息列表:", chatStore.messages); |
|
|
|
|
|
|
|
// 寻找最新添加的K线消息索引 |
|
|
|
let klineIndex = -1; |
|
|
|
for (let i = 0; i < chatStore.messages.length; i++) { |
|
|
|
if (chatStore.messages[i].messageId === klineMessageId) { |
|
|
|
klineIndex = i; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 确保DOM已经渲染完成 |
|
|
|
setTimeout(() => { |
|
|
|
console.log("延时执行,确保DOM已渲染"); |
|
|
|
KlineCanvsEcharts(containerId); |
|
|
|
}, 100); // 短暂延时确保DOM已渲染 |
|
|
|
} else { |
|
|
|
console.warn("未找到K线消息"); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
console.log("找到的K线消息索引:", klineIndex); |
|
|
|
|
|
|
|
// 修改后的消息处理逻辑 |
|
|
|
const processedContent = marked(AIcontent.value); |
|
|
|
const katexRegex = /\$\$(.*?)\$\$/g; |
|
|
|
const plainTextContent = htmlToText(processedContent); |
|
|
|
|
|
|
|
// 获取音频数据 |
|
|
|
const TTSResult = ( |
|
|
|
await TTSAPI({ |
|
|
|
language: "cn", |
|
|
|
content: plainTextContent, |
|
|
|
}) |
|
|
|
).json(); |
|
|
|
|
|
|
|
const tts = ref(); |
|
|
|
await TTSResult.then((res) => { |
|
|
|
tts.value = JSON.parse(res.data); |
|
|
|
}); |
|
|
|
if (klineIndex !== -1) { |
|
|
|
const containerId = `kline-container-${klineIndex}`; |
|
|
|
console.log("图表容器ID:", containerId); |
|
|
|
|
|
|
|
const ttsUrl = ref(); |
|
|
|
if (tts.value.tts_cn !== null) { |
|
|
|
audioStore.ttsUrl = tts.value.tts_cn.url; |
|
|
|
ttsUrl.value = tts.value.tts_cn.url; |
|
|
|
audioStore.isNewInstance = true; |
|
|
|
} else if (tts.value.tts_en !== null) { |
|
|
|
audioStore.ttsUrl = tts.value.tts_en.url; |
|
|
|
ttsUrl.value = tts.value.tts_en.url; |
|
|
|
audioStore.isNewInstance = true; |
|
|
|
} |
|
|
|
// 确保DOM已经渲染完成 |
|
|
|
setTimeout(() => { |
|
|
|
console.log("延时执行,确保DOM已渲染"); |
|
|
|
KlineCanvsEcharts(containerId); |
|
|
|
}, 100); // 短暂延时确保DOM已渲染 |
|
|
|
} else { |
|
|
|
console.warn("未找到K线消息"); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
if (ttsUrl.value) { |
|
|
|
nextTick(() => { |
|
|
|
if (audioStore.isVoiceEnabled) { |
|
|
|
console.log("ttsUrl.value", ttsUrl.value); |
|
|
|
// 播放音频 |
|
|
|
playAudio(ttsUrl.value); |
|
|
|
} |
|
|
|
// 修改后的消息处理逻辑 |
|
|
|
const processedContent = marked(AIcontent.value); |
|
|
|
const katexRegex = /\$\$(.*?)\$\$/g; |
|
|
|
const plainTextContent = htmlToText(processedContent); |
|
|
|
|
|
|
|
// 获取音频数据 |
|
|
|
const TTSResult = ( |
|
|
|
await TTSAPI({ |
|
|
|
language: "cn", |
|
|
|
content: plainTextContent, |
|
|
|
}) |
|
|
|
).json(); |
|
|
|
|
|
|
|
const tts = ref(); |
|
|
|
await TTSResult.then((res) => { |
|
|
|
tts.value = JSON.parse(res.data); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// chatStore.messages.pop(); |
|
|
|
// 先推送初始消息 |
|
|
|
const aiMessage = reactive({ |
|
|
|
sender: "ai", |
|
|
|
content: "", |
|
|
|
isTyping: true, |
|
|
|
}); |
|
|
|
chatStore.messages.push(aiMessage); |
|
|
|
|
|
|
|
let index = 0; |
|
|
|
const typingInterval = setInterval(() => { |
|
|
|
if (index < processedContent.length) { |
|
|
|
aiMessage.content += processedContent.charAt(index); |
|
|
|
index++; |
|
|
|
} else { |
|
|
|
clearInterval(typingInterval); |
|
|
|
aiMessage.isTyping = false; |
|
|
|
const ttsUrl = ref(); |
|
|
|
if (tts.value.tts_cn !== null) { |
|
|
|
audioStore.ttsUrl = tts.value.tts_cn.url; |
|
|
|
ttsUrl.value = tts.value.tts_cn.url; |
|
|
|
audioStore.isNewInstance = true; |
|
|
|
} else if (tts.value.tts_en !== null) { |
|
|
|
audioStore.ttsUrl = tts.value.tts_en.url; |
|
|
|
ttsUrl.value = tts.value.tts_en.url; |
|
|
|
audioStore.isNewInstance = true; |
|
|
|
} |
|
|
|
|
|
|
|
// 延迟处理KaTeX确保DOM已更新 |
|
|
|
if (ttsUrl.value) { |
|
|
|
nextTick(() => { |
|
|
|
aiMessage.content = aiMessage.content.replace( |
|
|
|
katexRegex, |
|
|
|
(match, formula) => { |
|
|
|
try { |
|
|
|
return katex.renderToString(formula, { |
|
|
|
throwOnError: false, |
|
|
|
}); |
|
|
|
} catch (error) { |
|
|
|
console.error("KaTeX 渲染错误:", error); |
|
|
|
return match; |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
chatStore.setLoading(false); |
|
|
|
if (audioStore.isVoiceEnabled) { |
|
|
|
console.log("ttsUrl.value", ttsUrl.value); |
|
|
|
// 播放音频 |
|
|
|
playAudio(ttsUrl.value); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
}, 50); // 调整速度为50ms/字符 |
|
|
|
// } else { |
|
|
|
// chatStore.messages.pop(); |
|
|
|
// chatStore.messages.push({ |
|
|
|
// sender: "ai", |
|
|
|
// content: status.msg |
|
|
|
// }); |
|
|
|
|
|
|
|
// chatStore.setLoading(false); |
|
|
|
// } |
|
|
|
|
|
|
|
// chatStore.messages.pop(); |
|
|
|
// 先推送初始消息 |
|
|
|
const aiMessage = reactive({ |
|
|
|
sender: "ai", |
|
|
|
content: "", |
|
|
|
isTyping: true, |
|
|
|
}); |
|
|
|
chatStore.messages.push(aiMessage); |
|
|
|
|
|
|
|
let index = 0; |
|
|
|
const typingInterval = setInterval(() => { |
|
|
|
if (index < processedContent.length) { |
|
|
|
aiMessage.content += processedContent.charAt(index); |
|
|
|
index++; |
|
|
|
} else { |
|
|
|
clearInterval(typingInterval); |
|
|
|
aiMessage.isTyping = false; |
|
|
|
|
|
|
|
// 延迟处理KaTeX确保DOM已更新 |
|
|
|
nextTick(() => { |
|
|
|
aiMessage.content = aiMessage.content.replace( |
|
|
|
katexRegex, |
|
|
|
(match, formula) => { |
|
|
|
try { |
|
|
|
return katex.renderToString(formula, { |
|
|
|
throwOnError: false, |
|
|
|
}); |
|
|
|
} catch (error) { |
|
|
|
console.error("KaTeX 渲染错误:", error); |
|
|
|
return match; |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
chatStore.setLoading(false); |
|
|
|
}); |
|
|
|
} |
|
|
|
}, 50); // 调整速度为50ms/字符 |
|
|
|
// } else { |
|
|
|
// chatStore.messages.pop(); |
|
|
|
// chatStore.messages.push({ |
|
|
|
// sender: "ai", |
|
|
|
// content: status.msg |
|
|
|
// }); |
|
|
|
|
|
|
|
// chatStore.setLoading(false); |
|
|
|
// } |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.error("请求失败:", e); |
|
|
|
hasValidData.value = false; // 请求失败时设置数据无效 |
|
|
|
// chatStore.messages.pop(); |
|
|
|
// chatStore.messages.push({ |
|
|
|
// sender: "ai", |
|
|
|
// content: "AI思考失败,请稍后再试... ", |
|
|
|
// }); |
|
|
|
chatStore.setLoading(false); |
|
|
|
} finally { |
|
|
|
await chatStore.getUserCount(); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.error("请求失败:", e); |
|
|
|
hasValidData.value = false; // 请求失败时设置数据无效 |
|
|
|
// chatStore.messages.pop(); |
|
|
|
chatStore.messages.push({ |
|
|
|
sender: "ai", |
|
|
|
content: "AI思考失败,请稍后再试... ", |
|
|
|
}); |
|
|
|
chatStore.setLoading(false); |
|
|
|
} finally { |
|
|
|
await chatStore.getUserCount(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
@ -5145,11 +5218,19 @@ function renderAllKlineCharts() { |
|
|
|
|
|
|
|
// 初始化随机GIF |
|
|
|
onMounted(() => { |
|
|
|
// 初始化marked组件 |
|
|
|
marked.setOptions({ |
|
|
|
breaks: true, // 支持换行符转换为 <br> |
|
|
|
gfm: true, // 启用 GitHub Flavored Markdown |
|
|
|
sanitize: false, // 不清理 HTML(谨慎使用) |
|
|
|
smartLists: true, // 智能列表 |
|
|
|
smartypants: true, // 智能标点符号 |
|
|
|
xhtml: false, // 不使用 XHTML 输出 |
|
|
|
}); |
|
|
|
|
|
|
|
const random = Math.floor(Math.random() * 6) + 1; |
|
|
|
currentGif.value = gifList[random]; |
|
|
|
|
|
|
|
getQuestionsList(); |
|
|
|
|
|
|
|
console.log("组件挂载完成"); |
|
|
|
|
|
|
|
// 添加DOM变化监听器 |
|
|
@ -5195,22 +5276,6 @@ onUnmounted(() => { |
|
|
|
<!-- GIF区域 --> |
|
|
|
<div class="gif-area"> |
|
|
|
<img :src="currentGif" alt="AI动画" /> |
|
|
|
|
|
|
|
<!-- <div class="marquee-container"> |
|
|
|
<div id="top" class="marquee-row top" @mouseenter="floatingTopMouseEnter" @mouseleave="floatingTopMouseLeave"> |
|
|
|
<div v-for="(questions, index) in questionsList.slice(0, 5)" :key="'top' + index" class="marquee-item" |
|
|
|
@click="showQuestions(questions)"> |
|
|
|
{{ questions.title }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div id="bottom" class="marquee-row bottom" @mouseenter="floatingBottomMouseEnter" |
|
|
|
@mouseleave="floatingBottomMouseLeave"> |
|
|
|
<div v-for="(questions, index) in questionsList.slice(5, 10)" :key="'bottom' + index" class="marquee-item" |
|
|
|
@click="showQuestions(questions)"> |
|
|
|
{{ questions.title }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> --> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div |
|
|
@ -5230,15 +5295,18 @@ onUnmounted(() => { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div v-else-if="msg.type == 'ing'"> |
|
|
|
<span>{{ msg.content }}</span> |
|
|
|
<span class="loading-dots"> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
</span> |
|
|
|
<div v-if="msg.flag"> |
|
|
|
<span>{{ msg.content }}</span> |
|
|
|
<span class="loading-dots"> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
<div v-else v-html="msg.content"></div> |
|
|
|
</div> |
|
|
|
<div v-else-if="msg.type == 'title1'" style="display: flex; width: 100%"> |
|
|
|
<div class="mainTitle"> |
|
|
|