Files
----/后端源码/yifan.action-ai.cn/index/js/index.oTkWBrWl.js

499 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { W as connection_default, a7 as loading_default, ab as warning_default, i as ElIcon, aa as delete_default, ac as setting_default, h as ElButton, ad as chat_dot_round_default, ae as user_default, af as arrow_down_default, ag as arrow_up_default, ah as copy_document_default, K as refresh_left_default, a0 as ElAlert, y as ElInput, ai as promotion_default, E as ElMessage, D as ElMessageBox } from "./element-plus.CkEW9frc.js";
import { J as defineComponent, ej as MarkdownIt, ek as markdownItHighlightjs, t as onMounted, ah as onUnmounted, S as openBlock, _ as createElementBlock, a1 as createBaseVNode, $ as createVNode, a0 as withCtx, T as createBlock, o as unref, a3 as normalizeClass, aa as toDisplayString, a9 as createTextVNode, a8 as createCommentVNode, H as Fragment, ay as renderList, a_ as withKeys, aw as withModifiers, r as ref, j as computed, n as nextTick, el as HighlightJS } from "./.pnpm.BW3P1y8f.js";
import { _ as _export_sfc } from "./_plugin-vue_export-helper.1tPrXgE0.js";
const _hoisted_1 = { class: "chatgpt-container" };
const _hoisted_2 = { class: "main-chat" };
const _hoisted_3 = { class: "chat-navbar" };
const _hoisted_4 = { class: "navbar-right" };
const _hoisted_5 = { class: "connection-status" };
const _hoisted_6 = { class: "status-text" };
const _hoisted_7 = {
key: 0,
class: "welcome-screen"
};
const _hoisted_8 = { class: "welcome-content" };
const _hoisted_9 = { class: "ai-logo" };
const _hoisted_10 = { class: "example-prompts" };
const _hoisted_11 = {
key: 1,
class: "messages-list"
};
const _hoisted_12 = { class: "message-avatar" };
const _hoisted_13 = {
key: 0,
class: "user-avatar"
};
const _hoisted_14 = {
key: 1,
class: "ai-avatar"
};
const _hoisted_15 = { class: "message-content" };
const _hoisted_16 = { class: "message-header" };
const _hoisted_17 = { class: "sender-name" };
const _hoisted_18 = { class: "message-body" };
const _hoisted_19 = ["innerHTML"];
const _hoisted_20 = {
key: 1,
class: "typing-indicator"
};
const _hoisted_21 = {
key: 0,
class: "message-actions"
};
const _hoisted_22 = {
key: 2,
class: "error-banner"
};
const _hoisted_23 = { class: "chat-input" };
const _hoisted_24 = { class: "input-wrapper" };
const _hoisted_25 = { class: "input-container" };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "index",
setup(__props) {
const md = new MarkdownIt({
html: true,
linkify: true,
typographer: true,
breaks: true,
highlight(str, lang) {
if (lang && HighlightJS.getLanguage(lang)) {
try {
return `<pre class="hljs"><code>${HighlightJS.highlight(str, { language: lang, ignoreIllegals: true }).value}</code></pre>`;
} catch {
}
}
return `<pre class="hljs"><code>${md.utils.escapeHtml(str)}</code></pre>`;
}
}).use(markdownItHighlightjs);
const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options, env, self);
};
md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
tokens[idx].attrPush(["target", "_blank"]);
tokens[idx].attrPush(["rel", "noopener noreferrer"]);
return defaultRender(tokens, idx, options, env, self);
};
const messages = ref([]);
const inputMessage = ref("");
const sending = ref(false);
const isConnected = ref(false);
const connectionStatus = ref("disconnected");
const error = ref("");
const messagesContainer = ref();
let ws = null;
const WS_URL = "undefined/api/v1/application/ai/ws";
const connectionStatusText = computed(() => {
switch (connectionStatus.value) {
case "connected":
return "已连接";
case "connecting":
return "连接中...";
case "disconnected":
return "未连接";
default:
return "未知状态";
}
});
const connectWebSocket = () => {
if ((ws == null ? void 0 : ws.readyState) === WebSocket.OPEN) {
return;
}
connectionStatus.value = "connecting";
error.value = "";
try {
ws = new WebSocket(WS_URL);
ws.onopen = () => {
console.log("WebSocket 连接已建立");
isConnected.value = true;
connectionStatus.value = "connected";
ElMessage.success("连接成功");
};
ws.onmessage = (event) => {
handleWebSocketMessage({ content: event.data });
};
ws.onclose = (event) => {
console.log("WebSocket 连接已关闭", event.code, event.reason);
isConnected.value = false;
connectionStatus.value = "disconnected";
messages.value.forEach((message) => {
if (message.type === "assistant" && message.loading) {
message.loading = false;
message.collapsed = message.content.length > 200;
}
});
};
ws.onerror = (error2) => {
console.error("WebSocket 错误:", error2);
isConnected.value = false;
connectionStatus.value = "disconnected";
ElMessage.error("连接失败,请检查服务器状态");
messages.value.forEach((message) => {
if (message.type === "assistant" && message.loading) {
message.loading = false;
message.collapsed = message.content.length > 200;
}
});
};
} catch (err) {
console.error("创建 WebSocket 连接失败:", err);
connectionStatus.value = "disconnected";
error.value = "无法创建连接";
}
};
const disconnectWebSocket = () => {
if (ws) {
ws.close(1e3, "用户主动断开");
ws = null;
}
isConnected.value = false;
connectionStatus.value = "disconnected";
messages.value.forEach((message) => {
if (message.type === "assistant" && message.loading) {
message.loading = false;
}
});
};
const toggleConnection = () => {
if (isConnected.value) {
disconnectWebSocket();
ElMessage.info("已断开连接");
} else {
connectWebSocket();
}
};
const handleWebSocketMessage = (data) => {
const lastMessage = messages.value[messages.value.length - 1];
if (lastMessage && lastMessage.type === "assistant" && lastMessage.loading) {
lastMessage.content += data.content || data.message || "";
} else {
addMessage("assistant", data.content || data.message || "收到回复");
}
scrollToBottom();
};
const sendMessage = async () => {
const message = inputMessage.value.trim();
if (!message || !isConnected.value || sending.value) {
return;
}
const lastMessage = messages.value[messages.value.length - 1];
if (lastMessage && lastMessage.type === "assistant" && lastMessage.loading) {
lastMessage.loading = false;
}
addMessage("user", message);
inputMessage.value = "";
const loadingMessage = {
id: generateId(),
type: "assistant",
content: "",
timestamp: Date.now(),
loading: true
};
messages.value.push(loadingMessage);
sending.value = true;
scrollToBottom();
try {
if ((ws == null ? void 0 : ws.readyState) === WebSocket.OPEN) {
ws.send(message);
} else {
throw new Error("WebSocket 连接未建立");
}
} catch (err) {
console.error("发送消息失败:", err);
messages.value.pop();
error.value = "发送消息失败,请检查连接状态";
ElMessage.error("发送失败");
} finally {
sending.value = false;
}
};
const addMessage = (type, content) => {
const message = {
id: generateId(),
type,
content,
timestamp: Date.now(),
// 长消息自动折叠
collapsed: content.length > 200
};
messages.value.push(message);
nextTick(() => scrollToBottom());
};
const clearCurrentChat = async () => {
try {
await ElMessageBox.confirm("确定要清空当前对话吗?此操作不可恢复。", "确认清空", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
});
messages.value = [];
ElMessage.success("对话已清空");
} catch {
}
};
const setPrompt = (prompt) => {
inputMessage.value = prompt;
};
const copyMessage = async (content) => {
try {
await navigator.clipboard.writeText(content);
ElMessage.success("已复制到剪贴板");
} catch {
const textArea = document.createElement("textarea");
textArea.value = content;
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
ElMessage.success("已复制到剪贴板");
}
};
const toggleMessageFold = (message) => {
message.collapsed = !message.collapsed;
};
const scrollToBottom = () => {
nextTick(() => {
if (messagesContainer.value) {
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
}
});
};
const formatMessage = (content) => {
if (!content) return "";
return md.render(content);
};
const generateId = () => {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
};
onMounted(() => {
connectWebSocket();
});
onUnmounted(() => {
disconnectWebSocket();
});
return (_ctx, _cache) => {
const _component_el_icon = ElIcon;
const _component_el_button = ElButton;
const _component_el_alert = ElAlert;
const _component_el_input = ElInput;
return openBlock(), createElementBlock("div", _hoisted_1, [
createBaseVNode("div", _hoisted_2, [
createBaseVNode("div", _hoisted_3, [
_cache[8] || (_cache[8] = createBaseVNode("div", { class: "navbar-left" }, [
createBaseVNode("h2", null, "FA智能助手")
], -1)),
createBaseVNode("div", _hoisted_4, [
createBaseVNode("div", _hoisted_5, [
createVNode(_component_el_icon, {
class: normalizeClass(["status-icon", connectionStatus.value])
}, {
default: withCtx(() => [
connectionStatus.value === "connected" ? (openBlock(), createBlock(unref(connection_default), { key: 0 })) : connectionStatus.value === "connecting" ? (openBlock(), createBlock(unref(loading_default), { key: 1 })) : (openBlock(), createBlock(unref(warning_default), { key: 2 }))
]),
_: 1
}, 8, ["class"]),
createBaseVNode("span", _hoisted_6, toDisplayString(connectionStatusText.value), 1)
]),
messages.value.length > 0 ? (openBlock(), createBlock(_component_el_button, {
key: 0,
text: "",
icon: unref(delete_default),
onClick: clearCurrentChat
}, {
default: withCtx(() => [..._cache[7] || (_cache[7] = [
createTextVNode(" 清空对话 ", -1)
])]),
_: 1
}, 8, ["icon"])) : createCommentVNode("", true),
createVNode(_component_el_button, {
text: "",
icon: unref(setting_default),
onClick: toggleConnection
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(isConnected.value ? "断开连接" : "重新连接"), 1)
]),
_: 1
}, 8, ["icon"])
])
]),
createBaseVNode("div", {
ref_key: "messagesContainer",
ref: messagesContainer,
class: "chat-messages"
}, [
messages.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_7, [
createBaseVNode("div", _hoisted_8, [
createBaseVNode("div", _hoisted_9, [
createVNode(_component_el_icon, { size: "64" }, {
default: withCtx(() => [
createVNode(unref(chat_dot_round_default))
]),
_: 1
})
]),
_cache[13] || (_cache[13] = createBaseVNode("h1", null, "FA智能助手", -1)),
_cache[14] || (_cache[14] = createBaseVNode("p", { class: "welcome-subtitle" }, " 我是您的专属AI助手可以帮您回答问题、处理任务和进行智能对话 ", -1)),
createBaseVNode("div", _hoisted_10, [
createBaseVNode("div", {
class: "prompt-card",
onClick: _cache[0] || (_cache[0] = ($event) => setPrompt("请介绍一下FastApiAdmin系统"))
}, [..._cache[9] || (_cache[9] = [
createBaseVNode("h4", null, "系统介绍", -1),
createBaseVNode("p", null, "请介绍一下FastApiAdmin系统", -1)
])]),
createBaseVNode("div", {
class: "prompt-card",
onClick: _cache[1] || (_cache[1] = ($event) => setPrompt("如何在系统中创建新的模块?"))
}, [..._cache[10] || (_cache[10] = [
createBaseVNode("h4", null, "开发指导", -1),
createBaseVNode("p", null, "如何在系统中创建新的模块?", -1)
])]),
createBaseVNode("div", {
class: "prompt-card",
onClick: _cache[2] || (_cache[2] = ($event) => setPrompt("系统的权限管理是如何工作的?"))
}, [..._cache[11] || (_cache[11] = [
createBaseVNode("h4", null, "权限管理", -1),
createBaseVNode("p", null, "FA系统的权限管理是如何工作的", -1)
])]),
createBaseVNode("div", {
class: "prompt-card",
onClick: _cache[3] || (_cache[3] = ($event) => setPrompt("如何优化FA系统的性能"))
}, [..._cache[12] || (_cache[12] = [
createBaseVNode("h4", null, "性能优化", -1),
createBaseVNode("p", null, "如何优化系统的性能?", -1)
])])
])
])
])) : (openBlock(), createElementBlock("div", _hoisted_11, [
(openBlock(true), createElementBlock(Fragment, null, renderList(messages.value, (message) => {
return openBlock(), createElementBlock("div", {
key: message.id,
class: normalizeClass(["message-group", message.type])
}, [
createBaseVNode("div", _hoisted_12, [
message.type === "user" ? (openBlock(), createElementBlock("div", _hoisted_13, [
createVNode(_component_el_icon, null, {
default: withCtx(() => [
createVNode(unref(user_default))
]),
_: 1
})
])) : (openBlock(), createElementBlock("div", _hoisted_14, [
createVNode(_component_el_icon, null, {
default: withCtx(() => [
createVNode(unref(chat_dot_round_default))
]),
_: 1
})
]))
]),
createBaseVNode("div", _hoisted_15, [
createBaseVNode("div", _hoisted_16, [
createBaseVNode("strong", _hoisted_17, toDisplayString(message.type === "user" ? "You" : "FA助手"), 1)
]),
createBaseVNode("div", _hoisted_18, [
message.content.length > 200 ? (openBlock(), createBlock(_component_el_button, {
key: 0,
text: "",
size: "small",
icon: message.collapsed ? unref(arrow_down_default) : unref(arrow_up_default),
class: "fold-button",
onClick: ($event) => toggleMessageFold(message)
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(message.collapsed ? "展开" : "收起"), 1)
]),
_: 2
}, 1032, ["icon", "onClick"])) : createCommentVNode("", true),
createBaseVNode("div", {
class: normalizeClass(["message-text", { collapsed: message.collapsed }]),
innerHTML: formatMessage(message.content)
}, null, 10, _hoisted_19),
message.type === "assistant" && message.loading && !message.content ? (openBlock(), createElementBlock("div", _hoisted_20, [..._cache[15] || (_cache[15] = [
createBaseVNode("div", { class: "typing-dots" }, [
createBaseVNode("span"),
createBaseVNode("span"),
createBaseVNode("span")
], -1)
])])) : createCommentVNode("", true)
]),
!message.loading ? (openBlock(), createElementBlock("div", _hoisted_21, [
createVNode(_component_el_button, {
text: "",
size: "small",
icon: unref(copy_document_default),
onClick: ($event) => copyMessage(message.content)
}, null, 8, ["icon", "onClick"]),
message.type === "assistant" ? (openBlock(), createBlock(_component_el_button, {
key: 0,
text: "",
size: "small",
icon: unref(refresh_left_default)
}, null, 8, ["icon"])) : createCommentVNode("", true)
])) : createCommentVNode("", true)
])
], 2);
}), 128))
])),
error.value ? (openBlock(), createElementBlock("div", _hoisted_22, [
createVNode(_component_el_alert, {
title: error.value,
type: "error",
closable: true,
"show-icon": "",
onClose: _cache[4] || (_cache[4] = ($event) => error.value = "")
}, null, 8, ["title"])
])) : createCommentVNode("", true)
], 512),
createBaseVNode("div", _hoisted_23, [
createBaseVNode("div", _hoisted_24, [
createBaseVNode("div", _hoisted_25, [
createVNode(_component_el_input, {
modelValue: inputMessage.value,
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => inputMessage.value = $event),
placeholder: isConnected.value ? "向FA助手发送消息..." : "请先连接到服务器",
disabled: !isConnected.value || sending.value,
type: "textarea",
rows: 1,
autosize: { minRows: 1, maxRows: 6 },
resize: "none",
class: "message-input",
onKeydown: [
withKeys(withModifiers(sendMessage, ["exact", "prevent"]), ["enter"]),
_cache[6] || (_cache[6] = withKeys(withModifiers(($event) => inputMessage.value += "\n", ["shift", "exact"]), ["enter"]))
]
}, null, 8, ["modelValue", "placeholder", "disabled", "onKeydown"]),
createVNode(_component_el_button, {
disabled: !inputMessage.value.trim() || !isConnected.value || sending.value,
loading: sending.value,
class: "send-button",
type: "primary",
circle: "",
onClick: sendMessage
}, {
default: withCtx(() => [
createVNode(_component_el_icon, null, {
default: withCtx(() => [
createVNode(unref(promotion_default))
]),
_: 1
})
]),
_: 1
}, 8, ["disabled", "loading"])
]),
_cache[16] || (_cache[16] = createBaseVNode("div", { class: "input-footer" }, [
createBaseVNode("span", { class: "input-hint" }, "按 Enter 发送消息Shift + Enter 换行")
], -1))
])
])
])
]);
};
}
});
const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9253047d"]]);
export {
index as default
};