@liuyuzhao/ai-chat
Version:
A Vue 3 AI chat component with TypeScript support for Web, H5, and UniApp
1,069 lines • 51.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
import { ref, onMounted, defineComponent, watch, createElementBlock, openBlock, createCommentVNode, createElementVNode, unref, toDisplayString, Fragment, renderList, normalizeClass, createTextVNode, withDirectives, withKeys, isRef, vModelText } from "vue";
import { marked } from "marked";
import DOMPurify from "dompurify";
const detectPlatform = () => {
if (typeof uni !== "undefined") {
return "uniapp";
}
if (typeof window !== "undefined") {
return "web";
}
return "node";
};
class AIService {
constructor(config) {
__publicField(this, "config");
this.config = config;
}
connect(messages, sessionId, requestConfig, onMessage, onError, onComplete) {
return __async(this, null, function* () {
try {
const params = new URLSearchParams();
const prompt = `${messages[messages.length - 1][0].content}`;
params.append("prompt", prompt);
if (sessionId) {
params.append("sessionId", sessionId);
}
if (requestConfig.requestParams) {
Object.entries(requestConfig.requestParams).forEach(([key, value]) => {
params.append(key, String(value));
});
}
if (!params.has("lawyerName")) {
params.append("lawyerName", requestConfig.lawyerName || "");
}
if (requestConfig.lawyerAllowedPort) {
params.append("lawyerAllowedPort", requestConfig.lawyerAllowedPort || "");
}
if (!params.has("knowledgeCode")) {
params.append("knowledgeCode", requestConfig.knowledgeCode || "");
}
if (!params.has("hotIssues")) {
params.append("hotIssues", requestConfig.hotIssues || "");
}
const url = `${requestConfig.apiUrl}/chat?${params.toString()}`;
const platform = detectPlatform();
return yield this.connectWeb(url, requestConfig.headers, onMessage, onError, onComplete);
if (platform === "uniapp") {
return this.connectUniapp(url, requestConfig.headers, onMessage, onError, onComplete);
} else {
return yield this.connectWeb(url, requestConfig.headers, onMessage, onError, onComplete);
}
} catch (error) {
onError(new Error(`Failed to establish connection: ${error}`));
return {
close: () => {
}
};
}
});
}
connectWeb(url, headers, onMessage, onError, onComplete) {
return __async(this, null, function* () {
const { EventSourcePolyfill } = yield import("./eventsource-_QmQq4NR.mjs").then((n) => n.e);
const source = new EventSourcePolyfill(url, __spreadValues({
withCredentials: false
}, headers && { headers }));
source.addEventListener("message", (event) => {
try {
onMessage(event.data);
} catch (error) {
onError(new Error(`Message parsing error: ${error}`));
}
});
source.addEventListener("error", (err) => {
onError(new Error("Connection error occurred"));
source.close();
});
source.addEventListener("end", () => {
source.close();
onComplete == null ? void 0 : onComplete();
});
return source;
});
}
connectUniapp(url, headers, onMessage, onError, onComplete) {
const requestTask = uni.request({
url,
method: "GET",
header: headers || {},
responseType: "text",
enableChunked: true,
success: (res) => {
try {
onMessage(res.data);
onComplete == null ? void 0 : onComplete();
} catch (error) {
onError(new Error(`Message parsing error: ${error}`));
}
},
fail: (err) => {
onError(new Error("Connection error occurred"));
}
});
return {
close: () => requestTask.abort()
};
}
}
let chunkBuffer = "";
function useAiChat(config) {
const messages = ref([]);
const input = ref("");
const loading = ref(false);
const error = ref(null);
const currentSessionId = ref(null);
const currentConnection = ref(null);
const currentHotIssueId = ref(null);
const hotQuestions = ref([]);
const systemQuestions = ref([]);
const lawyerQuestions = ref([]);
const hotQuestionsLoading = ref(false);
const systemQuestionsLoading = ref(false);
const lawyerQuestionsLoading = ref(false);
const questions = ref(["hotQuestions", "systemQuestions", "lawyerQuestions"]);
const hotIssuesCache = /* @__PURE__ */ new Map();
const CACHE_DURATION = 5 * 60 * 1e3;
let fetchDebounceTimer = null;
const service = new AIService(config);
const getHotIssueConfig = (type) => {
const configs = {
hotQuestions: { category: "0", ref: hotQuestions, loading: hotQuestionsLoading },
systemQuestions: { category: "1", ref: systemQuestions, loading: systemQuestionsLoading },
lawyerQuestions: { category: "2", ref: lawyerQuestions, loading: lawyerQuestionsLoading }
};
return configs[type] || configs.lawyerQuestions;
};
const setLoadingState = (type, isLoading) => {
const config2 = getHotIssueConfig(type);
config2.loading.value = isLoading;
};
const setHotIssuesData = (type, data) => {
const config2 = getHotIssueConfig(type);
config2.ref.value = data;
};
const fetchHotIssues = (..._0) => __async(this, [..._0], function* (excludeIds = [], type = "lawyerQuestions", immediate = false) {
if (immediate) {
return yield fetchHotIssuesInternal(excludeIds, type);
}
if (fetchDebounceTimer) {
clearTimeout(fetchDebounceTimer);
}
return new Promise((resolve) => {
fetchDebounceTimer = setTimeout(() => __async(this, null, function* () {
yield fetchHotIssuesInternal(excludeIds, type);
resolve();
}), 300);
});
});
const fetchHotIssuesInternal = (..._0) => __async(this, [..._0], function* (excludeIds = [], type = "lawyerQuestions") {
const cacheKey = `${type}-${excludeIds.join(",")}`;
const cached = hotIssuesCache.get(cacheKey);
const now = Date.now();
if (cached && now - cached.timestamp < CACHE_DURATION) {
setHotIssuesData(type, cached.data);
return;
}
setLoadingState(type, true);
try {
const typeConfig = getHotIssueConfig(type);
const url = `${config.apiUrl}/hot-issues?category=${typeConfig.category}`;
const response = yield fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(excludeIds)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = yield response.json();
const hotIssues = data.data || [];
setHotIssuesData(type, hotIssues);
hotIssuesCache.set(cacheKey, { data: hotIssues, timestamp: now });
} catch (err) {
console.error(`获取${type}热点问题失败:`, err);
setHotIssuesData(type, []);
error.value = err instanceof Error ? err : new Error("获取热点问题失败");
} finally {
setLoadingState(type, false);
}
});
const refreshHotIssues = (type = "lawyerQuestions") => __async(this, null, function* () {
console.log("刷新热点问题", type);
const keysToDelete = Array.from(hotIssuesCache.keys()).filter((key) => key.startsWith(type));
keysToDelete.forEach((key) => hotIssuesCache.delete(key));
const getCurrentIds = () => {
switch (type) {
case "hotQuestions":
return hotQuestions.value.map((item) => item.id);
case "systemQuestions":
return systemQuestions.value.map((item) => item.id);
case "lawyerQuestions":
return lawyerQuestions.value.map((item) => item.id);
default:
return [];
}
};
try {
yield fetchHotIssues(getCurrentIds(), type);
} catch (err) {
console.error("刷新热点问题失败:", err);
error.value = err instanceof Error ? err : new Error("刷新热点问题失败");
}
});
const selectHotIssue = (hotIssue) => {
if (!hotIssue || !hotIssue.question.trim()) {
console.warn("无效的热点问题:", hotIssue);
return;
}
if (loading.value) {
console.warn("正在发送消息,请稍后再试");
return;
}
currentHotIssueId.value = hotIssue.id;
input.value = hotIssue.question;
sendMessage();
};
onMounted(() => __async(this, null, function* () {
if (config.knowledgeCode === "lsyy") {
const fetchPromises = questions.value.map(
(item) => fetchHotIssues([], item, true).catch((err) => {
console.error(`初始化${item}失败:`, err);
})
);
yield Promise.allSettled(fetchPromises);
}
}));
let contentBuffer = "";
let isProcessingJson = false;
let currentMessageId = "";
let activeJsonContainers = /* @__PURE__ */ new Map();
let buttonBuffers = /* @__PURE__ */ new Map();
const sendMessage = () => __async(this, null, function* () {
if (!input.value.trim() || loading.value) return;
const userMsg = { role: "user", content: input.value };
const assistantMsg = { role: "assistant", content: "" };
messages.value.push([userMsg, assistantMsg]);
input.value = "";
loading.value = true;
chunkBuffer = "";
contentBuffer = "";
isProcessingJson = false;
currentMessageId = "";
activeJsonContainers.clear();
const requestConfig = __spreadValues({}, config);
if (currentHotIssueId.value) {
requestConfig.requestParams = __spreadProps(__spreadValues({}, config.requestParams), {
hotIssues: currentHotIssueId.value
});
currentHotIssueId.value = null;
}
try {
const connection = yield service.connect(
messages.value,
currentSessionId.value,
requestConfig,
(chunk) => {
var _a, _b;
chunkBuffer += chunk;
let remainingBuffer = chunkBuffer;
while (remainingBuffer.length > 0) {
try {
let braceCount = 0;
let inString = false;
let escapeNext = false;
let jsonEnd = -1;
for (let i = 0; i < remainingBuffer.length; i++) {
const char = remainingBuffer[i];
if (escapeNext) {
escapeNext = false;
continue;
}
if (char === "\\") {
escapeNext = true;
continue;
}
if (char === '"') {
inString = !inString;
continue;
}
if (!inString) {
if (char === "{") {
braceCount++;
} else if (char === "}") {
braceCount--;
if (braceCount === 0) {
jsonEnd = i + 1;
break;
}
}
}
}
if (jsonEnd > 0) {
const jsonStr = remainingBuffer.substring(0, jsonEnd);
const tempData = JSON.parse(jsonStr);
const data = tempData.choices[0].delta;
let content = data.content;
if (content === "[DONE]") {
loading.value = false;
currentConnection.value = null;
chunkBuffer = "";
contentBuffer = "";
activeJsonContainers.clear();
return;
}
currentSessionId.value = (_a = tempData.id) != null ? _a : "";
if (content) {
const messageId = (_b = tempData.id) != null ? _b : "";
if (currentMessageId !== messageId) {
contentBuffer = "";
isProcessingJson = false;
currentMessageId = messageId;
activeJsonContainers.clear();
buttonBuffers.clear();
}
const generateId = () => "json_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
const createButtonContainer = (containerId) => {
return `<div id="${containerId}" class="button-group" style="margin: 10px 0; display: flex; flex-wrap: wrap; gap: 8px; min-height: 40px; border: 1px dashed #ccc; padding: 8px; border-radius: 4px;"><span class="loading-text" style="color: #666; font-size: 12px;">正在加载按钮...</span></div>`;
};
const createTableContainer = (containerId) => {
return `<div id="${containerId}" style="margin: 10px 0;"><table class="json-table" style="border-collapse: collapse; width: 100%; border: 1px solid #ddd;"><thead><tr><th style="border: 1px solid #ddd; padding: 12px; background: #f5f5f5;">正在加载表格...</th></tr></thead><tbody></tbody></table></div>`;
};
const fillButtonGroup = (containerId, data2) => {
if (!Array.isArray(data2)) {
console.error("按钮数据格式错误:", data2);
return;
}
let html = "";
data2.forEach((item) => {
html += `<button class="msgButton" onclick="selectPerson('${item}')">${item}</button>`;
});
setTimeout(() => {
const container = document.getElementById(containerId);
if (container) {
container.innerHTML = html;
container.style.border = "none";
}
}, 0);
};
const fillTable = (containerId, data2) => {
let html = "";
if (Array.isArray(data2)) {
if (data2.length === 0) return;
const headers = Object.keys(data2[0]);
html = '<table class="json-table" style="border-collapse: collapse; width: 100%; border: 1px solid #ddd;">';
html += "<thead><tr>";
headers.forEach((header) => {
html += `<th style="border: 1px solid #ddd; padding: 12px; background: #f5f5f5; font-weight: bold; text-align: left;">${header}</th>`;
});
html += "</tr></thead>";
html += "<tbody>";
data2.forEach((row, rowIndex) => {
const bgColor = rowIndex % 2 === 0 ? "#ffffff" : "#f9f9f9";
html += `<tr style="background-color: ${bgColor};">`;
headers.forEach((header) => {
html += `<td style="border: 1px solid #ddd; padding: 12px;">${row[header] || ""}</td>`;
});
html += "</tr>";
});
html += "</tbody></table>";
} else if (data2.headers && data2.rows) {
html = '<table class="json-table" style="border-collapse: collapse; width: 100%; border: 1px solid #ddd;">';
html += "<thead><tr>";
data2.headers.forEach((header) => {
html += `<th style="border: 1px solid #ddd; padding: 12px; background: #f5f5f5; font-weight: bold; text-align: left;">${header}</th>`;
});
html += "</tr></thead>";
html += "<tbody>";
data2.rows.forEach((row, rowIndex) => {
const bgColor = rowIndex % 2 === 0 ? "#ffffff" : "#f9f9f9";
html += `<tr style="background-color: ${bgColor};">`;
row.forEach((cell) => {
html += `<td style="border: 1px solid #ddd; padding: 12px;">${cell}</td>`;
});
html += "</tr>";
});
html += "</tbody></table>";
}
setTimeout(() => {
const container = document.getElementById(containerId);
if (container) {
container.innerHTML = html;
}
}, 0);
};
const progressiveButtonDisplay = (containerId, newButtons) => {
const container = document.getElementById(containerId);
if (!container) return;
const existingButtons = container.querySelectorAll("button").length;
if (existingButtons === 0) {
const loadingText = container.querySelector(".loading-text");
if (loadingText) {
loadingText.remove();
}
}
const buttonsToAdd = newButtons.slice(existingButtons);
buttonsToAdd.forEach((buttonText, index) => {
if (buttonText && buttonText.trim()) {
setTimeout(() => {
const button = document.createElement("button");
button.className = "msgButton";
button.textContent = buttonText.trim();
button.onclick = () => {
input.value = buttonText.trim();
sendMessage();
};
button.style.opacity = "0";
button.style.transform = "translateY(10px)";
button.style.transition = "all 0.3s ease";
container.appendChild(button);
setTimeout(() => {
button.style.opacity = "1";
button.style.transform = "translateY(0)";
}, 10);
}, index * 150);
}
});
};
const parsePartialButtons = (partialJson) => {
const buttons = [];
try {
const arrayMatch = partialJson.match(new RegExp('"data"\\s*:\\s*\\[(.*?)\\]', "s"));
if (arrayMatch) {
const arrayContent = arrayMatch[1];
const stringMatches = arrayContent.match(/"([^"]+)"/g);
if (stringMatches) {
stringMatches.forEach((match) => {
const buttonText = match.replace(/"/g, "").trim();
if (buttonText) {
buttons.push(buttonText);
}
});
}
}
} catch (error2) {
console.log("解析部分按钮数据失败:", error2);
}
return buttons;
};
contentBuffer += content;
const hasBeginTag = contentBuffer.includes("begin");
if (!hasBeginTag) {
const currentMessage = messages.value[messages.value.length - 1][1];
currentMessage.content += content;
contentBuffer = "";
} else {
const beginMatches = [...contentBuffer.matchAll(/begin/g)];
const endMatches = [...contentBuffer.matchAll(/end/g)];
if (beginMatches.length > endMatches.length) {
const newBeginCount = beginMatches.length - activeJsonContainers.size;
for (let i = 0; i < newBeginCount; i++) {
const containerId = generateId();
const partialRegex = /begin([\s\S]*?)$/;
const partialMatch = contentBuffer.match(partialRegex);
if (partialMatch) {
const partialJson = partialMatch[1].trim();
let containerHtml = "";
if (partialJson.includes('"type"') && partialJson.includes('"button"')) {
containerHtml = createButtonContainer(containerId);
activeJsonContainers.set(containerId, "button");
buttonBuffers.set(containerId, []);
const currentMessage = messages.value[messages.value.length - 1][1];
currentMessage.content += containerHtml;
setTimeout(() => {
const partialButtons = parsePartialButtons(partialJson);
if (partialButtons.length > 0) {
buttonBuffers.set(containerId, partialButtons);
progressiveButtonDisplay(containerId, partialButtons);
}
}, 100);
} else if (partialJson.includes('"type"') && partialJson.includes('"table"')) {
containerHtml = createTableContainer(containerId);
activeJsonContainers.set(containerId, "table");
const currentMessage = messages.value[messages.value.length - 1][1];
currentMessage.content += containerHtml;
}
}
}
}
activeJsonContainers.forEach((type, containerId) => {
if (type === "button") {
const partialRegex = /begin([\s\S]*?)(?:end|$)/;
const partialMatch = contentBuffer.match(partialRegex);
if (partialMatch) {
const partialJson = partialMatch[1].trim();
const currentButtons = parsePartialButtons(partialJson);
const existingButtons = buttonBuffers.get(containerId) || [];
if (currentButtons.length > existingButtons.length) {
buttonBuffers.set(containerId, currentButtons);
progressiveButtonDisplay(containerId, currentButtons);
}
}
}
});
const completeRegex = /begin([\s\S]*?)end/g;
const completeMatches = [...contentBuffer.matchAll(completeRegex)];
completeMatches.forEach((match, index) => {
const jsonContent = match[1].trim();
try {
const jsonData = JSON.parse(jsonContent);
if (jsonData.type && jsonData.data) {
const containerIds = Array.from(activeJsonContainers.keys());
const containerId = containerIds[index];
if (containerId) {
switch (jsonData.type) {
case "button":
const finalButtons = Array.isArray(jsonData.data) ? jsonData.data : [];
const currentButtons = buttonBuffers.get(containerId) || [];
if (finalButtons.length > currentButtons.length) {
buttonBuffers.set(containerId, finalButtons);
progressiveButtonDisplay(containerId, finalButtons);
}
setTimeout(() => {
const container = document.getElementById(containerId);
if (container) {
container.style.border = "none";
}
}, finalButtons.length * 150 + 200);
break;
case "table":
fillTable(containerId, jsonData.data);
break;
default:
console.warn("未知的JSON类型:", jsonData.type);
}
activeJsonContainers.delete(containerId);
buttonBuffers.delete(containerId);
}
}
} catch (error2) {
console.log("JSON解析失败:", error2);
}
});
if (completeMatches.length > 0) {
let cleanContent = contentBuffer;
completeMatches.forEach((match) => {
cleanContent = cleanContent.replace(match[0], "");
});
if (cleanContent.trim() && !cleanContent.includes("begin")) {
const currentMessage = messages.value[messages.value.length - 1][1];
currentMessage.content += cleanContent;
}
contentBuffer = cleanContent.includes("begin") ? cleanContent : "";
}
}
}
}
remainingBuffer = remainingBuffer.substring(jsonEnd);
chunkBuffer = remainingBuffer;
} catch (e) {
break;
}
}
},
(err) => {
error.value = err;
loading.value = false;
currentConnection.value = null;
chunkBuffer = "";
contentBuffer = "";
activeJsonContainers.clear();
}
);
currentConnection.value = connection;
} catch (err) {
error.value = err instanceof Error ? err : new Error("连接失败");
loading.value = false;
currentConnection.value = null;
}
});
const stopGeneration = () => {
if (currentConnection.value && typeof currentConnection.value.close === "function") {
try {
currentConnection.value.close();
} catch (error2) {
console.warn("关闭连接时出错:", error2);
}
currentConnection.value = null;
loading.value = false;
messages.value[messages.value.length - 1][1].stopMessage = true;
chunkBuffer = "";
contentBuffer = "";
activeJsonContainers.clear();
}
};
return {
messages,
input,
loading,
error,
sendMessage,
stopGeneration,
hotQuestions,
systemQuestions,
lawyerQuestions,
hotQuestionsLoading,
systemQuestionsLoading,
lawyerQuestionsLoading,
refreshHotIssues,
selectHotIssue
};
}
function parseStructuredData(content) {
return content;
}
function parseMarkdown(content) {
if (!content) return "";
let processedContent = parseStructuredData(content);
if (processedContent !== content) {
return DOMPurify.sanitize(processedContent, {
ALLOWED_TAGS: [
"div",
"span",
"p",
"br",
"strong",
"em",
"code",
"pre",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"ul",
"ol",
"li",
"a",
"button",
"table",
"thead",
"tbody",
"tr",
"th",
"td"
],
ALLOWED_ATTR: ["href", "class", "onclick", "data-*", "id", "colspan", "rowspan"]
});
}
const hasButton = content.includes("<button");
const hasTable = content.includes("<table") || content.includes("<tr") || content.includes("<td") || content.includes("<th");
if (hasButton || hasTable) {
const result2 = content.replace(/\n/g, "\n");
return DOMPurify.sanitize(result2, {
ALLOWED_TAGS: [
"p",
"br",
"strong",
"em",
"code",
"pre",
"blockquote",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"ul",
"ol",
"li",
"a",
"button",
"div",
"span",
"table",
"thead",
"tbody",
"tfoot",
"tr",
"th",
"td",
"caption"
],
ALLOWED_ATTR: [
"href",
"class",
"onclick",
"data-*",
"id",
"target",
"title",
"alt",
"src",
"width",
"height",
"colspan",
"rowspan",
"scope",
"style"
]
});
}
const needsMarkdownParsing = content.includes("**") || content.includes("*") || content.includes("`") || content.includes("#") || content.includes("[") || content.includes("\n- ") || content.includes("\n1. ") || content.includes("|");
let result = content;
if (needsMarkdownParsing) {
result = marked.parse(content);
} else {
result = content.replace(/\n/g, "<br>");
}
return DOMPurify.sanitize(result, {
ALLOWED_TAGS: [
"p",
"br",
"strong",
"em",
"code",
"pre",
"blockquote",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"ul",
"ol",
"li",
"a",
"button",
"div",
"span",
"table",
"thead",
"tbody",
"tfoot",
"tr",
"th",
"td",
"caption"
],
ALLOWED_ATTR: [
"href",
"class",
"onclick",
"data-*",
"id",
"target",
"title",
"alt",
"src",
"width",
"height",
"colspan",
"rowspan",
"scope",
"style"
]
});
}
const aiIcon = "data:image/png;base64,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";
const _hoisted_1 = { class: "ai-chat-container" };
const _hoisted_2 = {
key: 0,
class: "chat-header"
};
const _hoisted_3 = { class: "ai-avatar" };
const _hoisted_4 = ["src"];
const _hoisted_5 = { class: "welcome-message" };
const _hoisted_6 = {
key: 1,
class: "hot-questions-container"
};
const _hoisted_7 = { class: "hot-questions" };
const _hoisted_8 = { class: "section-title" };
const _hoisted_9 = ["disabled"];
const _hoisted_10 = { class: "questions-list" };
const _hoisted_11 = ["onClick"];
const _hoisted_12 = {
key: 0,
class: "empty-questions"
};
const _hoisted_13 = { class: "hot-questions" };
const _hoisted_14 = { class: "section-title" };
const _hoisted_15 = ["disabled"];
const _hoisted_16 = { class: "questions-list" };
const _hoisted_17 = ["onClick"];
const _hoisted_18 = {
key: 0,
class: "empty-questions"
};
const _hoisted_19 = { class: "message-content user" };
const _hoisted_20 = ["innerHTML"];
const _hoisted_21 = { class: "message-content assistant" };
const _hoisted_22 = { class: "message-label" };
const _hoisted_23 = {
key: 0,
class: "assistant-loading"
};
const _hoisted_24 = {
key: 1,
class: "assistant-stop"
};
const _hoisted_25 = ["innerHTML"];
const _hoisted_26 = { class: "chat-input" };
const _hoisted_27 = { class: "input-container" };
const _hoisted_28 = ["disabled"];
const _hoisted_29 = ["disabled"];
const inputPlaceholder = "请输入想要咨询的问题";
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "AiChat",
props: {
config: {}
},
setup(__props) {
const props = __props;
const {
messages,
input,
loading,
sendMessage,
stopGeneration,
// stopMessage,
hotQuestions,
systemQuestions,
lawyerQuestions,
hotQuestionsLoading,
systemQuestionsLoading,
lawyerQuestionsLoading,
refreshHotIssues,
selectHotIssue
} = useAiChat(props.config);
const tagList = ref(["查看被监管人", "系统问题"]);
const scrollToBottom = () => {
setTimeout(() => {
window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: "smooth"
});
}, 100);
};
watch(
() => messages.value.length,
() => {
scrollToBottom();
}
);
watch(
() => {
if (messages.value.length > 0) {
return messages.value[messages.value.length - 1][1].content;
}
return "";
},
() => {
scrollToBottom();
}
);
watch(loading, (newLoading) => {
if (newLoading) {
scrollToBottom();
}
});
const parseMessageContent = (content) => {
if (!content) return "";
const messageIndex = messages.value.findIndex(
(msgPair) => msgPair[1].content === content
);
const currentIndex = messageIndex !== -1 ? messageIndex : messages.value.length - 1;
let processedContent = content.replace(
/onclick="selectPerson\('([^']+)',\s*(true|false)\)"/g,
`onclick="selectPerson('$1', $2, ${currentIndex})"`
);
processedContent = processedContent.replace(
/onclick="selectPerson\('([^']+)'\)"/g,
`onclick="selectPerson('$1', false, ${currentIndex})"`
);
const phoneRegex = new RegExp("(?<!\\w)((?:1[3-9]\\d{9})|(?:400-?\\d{3}-?\\d{4})|(?:0\\d{2,3}-?\\d{7,8})|(?:\\d{3,4}-\\d{7,8})|(?:\\(\\d{3,4}\\)\\d{7,8})|(?:\\d{6}))(?!\\w)", "g");
processedContent = processedContent.replace(phoneRegex, (match) => {
const cleanPhone = match.replace(/[-()]/g, "");
return `<a href="tel:${cleanPhone}" style="color: #007bff; text-decoration: underline; cursor: pointer;">${match}</a>`;
});
return parseMarkdown(processedContent);
};
const selectPerson = (personId, isJoin = false, messageIndex) => {
const targetIndex = messageIndex !== void 0 ? messageIndex : messages.value.length - 1;
if (props.config.knowledgeCode === "lsyy") {
input.value = `请提供关于 ${personId} 的详细信息`;
} else {
if (targetIndex >= 0 && targetIndex < messages.value.length) {
const targetMessage = messages.value[targetIndex][0].content;
input.value = `${targetMessage}${targetMessage.includes(":") ? `-${personId}` : `:${personId}`}`;
} else {
const lastMessage = messages.value[messages.value.length - 1][0].content;
input.value = `${lastMessage}${lastMessage.includes(":") ? `-${personId}` : `:${personId}`}`;
}
return;
}
sendMessage();
};
if (typeof window !== "undefined") {
window.selectPerson = selectPerson;
}
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1, [
_ctx.config.knowledgeCode === "lsyy" ? (openBlock(), createElementBlock("div", _hoisted_2, [
createElementVNode("div", _hoisted_3, [
createElementVNode("img", {
width: "100%",
mode: "widthFix",
src: unref(aiIcon),
alt: "AI头像"
}, null, 8, _hoisted_4)
]),
createElementVNode("div", _hoisted_5, " 你好," + toDisplayString(_ctx.config.lawyerName) + "律师,我是智能客服,很高兴为您服务。请选择您想询问的问题,或输入想要咨询的内容: ", 1)
])) : createCommentVNode("", true),
_ctx.config.knowledgeCode === "lsyy" ? (openBlock(), createElementBlock("div", _hoisted_6, [
createElementVNode("div", _hoisted_7, [
createElementVNode("div", _hoisted_8, [
_cache[6] || (_cache[6] = createElementVNode("span", null, "热门问题", -1)),
createElementVNode("button", {
class: "refresh-btn",
onClick: _cache[0] || (_cache[0] = ($event) => unref(refreshHotIssues)("hotQuestions")),
disabled: unref(hotQuestionsLoading)
}, toDisplayString(unref(hotQuestionsLoading) ? "加载中..." : "换一换"), 9, _hoisted_9)
]),
createElementVNode("div", _hoisted_10, [
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(hotQuestions), (question, index) => {
return openBlock(), createElementBlock("div", {
class: "question-item",
key: question.id,
onClick: ($event) => unref(selectHotIssue)(question)
}, toDisplayString(index + 1) + ". " + toDisplayString(question.question), 9, _hoisted_11);
}), 128)),
unref(hotQuestions).length === 0 && !unref(hotQuestionsLoading) ? (openBlock(), createElementBlock("div", _hoisted_12, " 暂无热门问题 ")) : createCommentVNode("", true)
])
]),
createElementVNode("div", _hoisted_13, [
createElementVNode("div", _hoisted_14, [
_cache[7] || (_cache[7] = createElementVNode("span", null, "系统问题", -1)),
createElementVNode("button", {
class: "refresh-btn",
onClick: _cache[1] || (_cache[1] = ($event) => unref(refreshHotIssues)("systemQuestions")),
disabled: unref(systemQuestionsLoading)
}, toDisplayString(unref(systemQuestionsLoading) ? "加载中..." : "换一换"), 9, _hoisted_15)
]),
createElementVNode("div", _hoisted_16, [
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(systemQuestions), (question, index) => {
return openBlock(), createElementBlock("div", {
class: "question-item",
key: question.id,
onClick: ($event) => unref(selectHotIssue)(question)
}, toDisplayString(index + 1) + ". " + toDisplayString(question.question), 9, _hoisted_17);
}), 128)),
unref(systemQuestions).length === 0 && !unref(systemQuestionsLoading) ? (openBlock(), createElementBlock("div", _hoisted_18, " 暂无热门问题 ")) : createCommentVNode("", true)
])
])
])) : createCommentVNode("", true),
unref(messages).length > 0 ? (openBlock(), createElementBlock("div", {
key: 2,
class: normalizeClass(["chat-messages", { "tag": tagList.value.length > 0 }])
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(messages), (message, index) => {
return openBlock(), createElementBlock("div", {
class: "message-item",
key: index
}, [
createElementVNode("div", _hoisted_19, [
_cache[8] || (_cache[8] = createElementVNode("div", { class: "message-label" }, "问:", -1)),
createElementVNode("div", {
class: "user-message-text",
innerHTML: parseMessageContent(message[0].content)
}, null, 8, _hoisted_20)
]),
createElementVNode("div", _hoisted_21, [
createElementVNode("div", _hoisted_22, [
_cache[9] || (_cache[9] = createTextVNode(" 答: ", -1)),
unref(loading) && index === unref(messages).length - 1 ? (openBlock(), createElementBlock("span", _hoisted_23)) : createCommentVNode("", true),
message[1].stopMessage ? (openBlock(), createElementBlock("span", _hoisted_24, "此问题用户停止咨询")) : createCommentVNode("", true)
]),
createElementVNode("div", {
class: "message-text",
innerHTML: parseMessageContent(message[1].content)
}, null, 8, _hoisted_25)
])
]);
}), 128))
], 2)) : createCommentVNode("", true),
createElementVNode("div", _hoisted_26, [
createElementVNode("div", _hoisted_27, [
withDirectives(createElementVNode("input", {
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => isRef(input) ? input.value = $event : null),
onKeyup: _cache[3] || (_cache[3] = withKeys(
//@ts-ignore
(...args) => unref(sendMessage) && unref(sendMessage)(...args),
["enter"]
)),
placeholder: inputPlaceholder,
disabled: unref(loading),
class: "message-input"
}, null, 40, _hoisted_28), [
[vModelText, unref(input)]
]),
!unref(loading) ? (openBlock(), createElementBlock("button", {
key: 0,
onClick: _cache[4] || (_cache[4] = //@ts-ignore
(...args) => unref(sendMessage) && unref(sendMessage)(...args)),
disabled: !unref(input).trim(),
class: "send-button"
}, _cache[10] || (_cache[10] = [
createElementVNode("svg", {
width: "20",
height: "20",
viewBox: "0 0 24 24",
fill: "none"
}, [
createElementVNode("path", {
d: "M2 21L23 12L2 3V10L17 12L2 14V21Z",
fill: "currentColor"
})
], -1)
]), 8, _hoisted_29)) : createCommentVNode("", true),
unref(loading) ? (openBlock(), createElementBlock("button", {
key: 1,
onClick: _cache[5] || (_cache[5] = //@ts-ignore
(...args) => unref(stopGeneration) && unref(stopGeneration)(...args)),
class: "stop-butto