upload project source code
This commit is contained in:
904
后端源码/yifan.action-ai.cn/index/js/index.Cn8BFTsV.js
Normal file
904
后端源码/yifan.action-ai.cn/index/js/index.Cn8BFTsV.js
Normal file
@@ -0,0 +1,904 @@
|
||||
import { Z as ElRadioButton, P as ElRadioGroup, ao as vLoading, x as ElFormItem, aq as ElSelect, ar as ElOption, y as ElInput, as as ElSlider, h as ElButton, at as aim_default, aa as delete_default, ad as chat_dot_round_default, i as ElIcon, ae as user_default, ai as promotion_default, au as video_pause_default, w as ElForm, v as ElDialog, E as ElMessage, D as ElMessageBox } from "./element-plus.CkEW9frc.js";
|
||||
import { J as defineComponent, ej as MarkdownIt, t as onMounted, S as openBlock, _ as createElementBlock, a1 as createBaseVNode, $ as createVNode, a0 as withCtx, H as Fragment, ay as renderList, o as unref, T as createBlock, a9 as createTextVNode, aa as toDisplayString, a6 as withDirectives, a8 as createCommentVNode, a3 as normalizeClass, a_ as withKeys, aw as withModifiers, r as ref, j as computed, ak as reactive, n as nextTick, el as HighlightJS } from "./.pnpm.BW3P1y8f.js";
|
||||
import { l as httpRequest, A as Auth } from "./index.CMd5bD1r.js";
|
||||
import { A as AIProviderAPI } from "./ai_config.BnEV7HHL.js";
|
||||
import { K as KnowledgeBaseAPI } from "./knowledge_base.CHSLq1jf.js";
|
||||
import { _ as _export_sfc } from "./_plugin-vue_export-helper.1tPrXgE0.js";
|
||||
import "./codemirror.CvJAcn2d.js";
|
||||
const API_PATH = "/application/ai/model";
|
||||
const AI_MODEL_TYPES = {
|
||||
enterprise_naming: "企业起名",
|
||||
enterprise_renaming: "企业改名",
|
||||
enterprise_scoring: "企业测名",
|
||||
enterprise_scoring_trial: "企业测名试用",
|
||||
personal_naming: "个人起名",
|
||||
personal_renaming: "个人改名",
|
||||
personal_scoring: "个人测名",
|
||||
personal_scoring_trial: "个人测名试用"
|
||||
};
|
||||
const AI_MODEL_TYPE_GROUPS = {
|
||||
enterprise: {
|
||||
label: "企业服务",
|
||||
types: ["enterprise_naming", "enterprise_renaming", "enterprise_scoring", "enterprise_scoring_trial"]
|
||||
},
|
||||
personal: {
|
||||
label: "个人服务",
|
||||
types: ["personal_naming", "personal_renaming", "personal_scoring", "personal_scoring_trial"]
|
||||
}
|
||||
};
|
||||
const AIModelConfigAPI = {
|
||||
// 获取模型配置详情(如果不存在会自动创建默认配置)
|
||||
detail(modelType) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/detail/${modelType}`,
|
||||
method: "get"
|
||||
});
|
||||
},
|
||||
// 列表查询
|
||||
list(query) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/list`,
|
||||
method: "get",
|
||||
params: query
|
||||
});
|
||||
},
|
||||
// 更新配置
|
||||
update(modelType, body) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/update/${modelType}`,
|
||||
method: "put",
|
||||
data: body
|
||||
});
|
||||
},
|
||||
// 获取可用模型列表
|
||||
getAvailableModels(providerId) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/available-models/${providerId}`,
|
||||
method: "get"
|
||||
});
|
||||
},
|
||||
// 获取训练对话记录
|
||||
getMessages(modelType) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/messages/${modelType}`,
|
||||
method: "get"
|
||||
});
|
||||
},
|
||||
// 删除单条训练对话记录
|
||||
deleteMessage(messageId) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/message/${messageId}`,
|
||||
method: "delete"
|
||||
});
|
||||
},
|
||||
// 清空训练对话记录
|
||||
clearMessages(modelType) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/messages/${modelType}`,
|
||||
method: "delete"
|
||||
});
|
||||
},
|
||||
// 训练对话(流式输出)
|
||||
async chat(data, signal) {
|
||||
const baseURL = void 0;
|
||||
const token = Auth.getAccessToken();
|
||||
return fetch(`${baseURL}${API_PATH}/chat`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": token ? `Bearer ${token}` : ""
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
signal
|
||||
});
|
||||
},
|
||||
// 起名测试(非流式,一次性返回)
|
||||
test(data) {
|
||||
return httpRequest({
|
||||
url: `${API_PATH}/test`,
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
}
|
||||
};
|
||||
const _hoisted_1 = { class: "ai-model-container" };
|
||||
const _hoisted_2 = { class: "config-panel" };
|
||||
const _hoisted_3 = { class: "model-type-selector" };
|
||||
const _hoisted_4 = { class: "category-tabs" };
|
||||
const _hoisted_5 = { class: "type-tabs" };
|
||||
const _hoisted_6 = { class: "chat-panel" };
|
||||
const _hoisted_7 = { class: "panel-header" };
|
||||
const _hoisted_8 = { class: "header-actions" };
|
||||
const _hoisted_9 = {
|
||||
key: 0,
|
||||
class: "welcome-screen"
|
||||
};
|
||||
const _hoisted_10 = { class: "welcome-content" };
|
||||
const _hoisted_11 = {
|
||||
key: 1,
|
||||
class: "messages-list"
|
||||
};
|
||||
const _hoisted_12 = { class: "message-content" };
|
||||
const _hoisted_13 = { class: "message-header" };
|
||||
const _hoisted_14 = ["innerHTML"];
|
||||
const _hoisted_15 = { class: "message-avatar" };
|
||||
const _hoisted_16 = { class: "message-avatar" };
|
||||
const _hoisted_17 = { class: "message-content" };
|
||||
const _hoisted_18 = { class: "message-header" };
|
||||
const _hoisted_19 = ["innerHTML"];
|
||||
const _hoisted_20 = {
|
||||
key: 0,
|
||||
class: "message-item assistant"
|
||||
};
|
||||
const _hoisted_21 = { class: "message-avatar" };
|
||||
const _hoisted_22 = { class: "message-content" };
|
||||
const _hoisted_23 = { class: "message-body" };
|
||||
const _hoisted_24 = ["innerHTML"];
|
||||
const _hoisted_25 = {
|
||||
key: 1,
|
||||
class: "typing-indicator"
|
||||
};
|
||||
const _hoisted_26 = { class: "chat-input" };
|
||||
const _hoisted_27 = { class: "input-wrapper" };
|
||||
const _hoisted_28 = { class: "test-dialog-content" };
|
||||
const _hoisted_29 = {
|
||||
key: 0,
|
||||
class: "test-result"
|
||||
};
|
||||
const _hoisted_30 = ["innerHTML"];
|
||||
const _sfc_main = /* @__PURE__ */ defineComponent({
|
||||
...{
|
||||
name: "AIModel",
|
||||
inheritAttrs: false
|
||||
},
|
||||
__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>`;
|
||||
}
|
||||
});
|
||||
const currentCategory = ref("enterprise");
|
||||
const currentModelType = ref("enterprise_naming");
|
||||
const currentGroupTypes = computed(() => {
|
||||
return AI_MODEL_TYPE_GROUPS[currentCategory.value].types;
|
||||
});
|
||||
function getShortLabel(typeKey) {
|
||||
const label = AI_MODEL_TYPES[typeKey];
|
||||
return label.replace(/^企业|个人/, "");
|
||||
}
|
||||
function handleCategoryChange() {
|
||||
const firstType = AI_MODEL_TYPE_GROUPS[currentCategory.value].types[0];
|
||||
currentModelType.value = firstType;
|
||||
handleModelTypeChange();
|
||||
}
|
||||
const configFormRef = ref();
|
||||
const configForm = reactive({
|
||||
provider_id: void 0,
|
||||
model_name: void 0,
|
||||
system_prompt: "",
|
||||
temperature: 1,
|
||||
knowledge_base_ids: []
|
||||
});
|
||||
const originalConfig = ref({});
|
||||
const configLoading = ref(false);
|
||||
const saveLoading = ref(false);
|
||||
const messagesLoading = ref(false);
|
||||
const providerList = ref([]);
|
||||
const availableModels = ref([]);
|
||||
const knowledgeBaseList = ref([]);
|
||||
const messages = ref([]);
|
||||
const inputMessage = ref("");
|
||||
const currentResponse = ref("");
|
||||
const isGenerating = ref(false);
|
||||
const messagesContainer = ref();
|
||||
const abortController = ref(null);
|
||||
const showTestDialog = ref(false);
|
||||
const testInput = ref("");
|
||||
const testResult = ref("");
|
||||
const testLoading = ref(false);
|
||||
async function loadProviderList() {
|
||||
try {
|
||||
const res = await AIProviderAPI.list({ page_no: 1, page_size: 100 });
|
||||
providerList.value = res.data.data.items;
|
||||
} catch (error) {
|
||||
console.error("加载供应商列表失败", error);
|
||||
}
|
||||
}
|
||||
async function loadKnowledgeBaseList() {
|
||||
try {
|
||||
const res = await KnowledgeBaseAPI.list({ page_no: 1, page_size: 100, kb_status: 2 });
|
||||
knowledgeBaseList.value = res.data.data.items;
|
||||
} catch (error) {
|
||||
console.error("加载知识库列表失败", error);
|
||||
}
|
||||
}
|
||||
async function loadModelConfig() {
|
||||
configLoading.value = true;
|
||||
try {
|
||||
const res = await AIModelConfigAPI.detail(currentModelType.value);
|
||||
const data = res.data.data;
|
||||
Object.assign(configForm, {
|
||||
provider_id: data.provider_id,
|
||||
model_name: data.model_name,
|
||||
system_prompt: data.system_prompt || "",
|
||||
temperature: data.temperature ?? 1,
|
||||
knowledge_base_ids: data.knowledge_base_ids || []
|
||||
});
|
||||
originalConfig.value = { ...configForm };
|
||||
if (data.provider_id) {
|
||||
await loadAvailableModels(data.provider_id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载模型配置失败", error);
|
||||
} finally {
|
||||
configLoading.value = false;
|
||||
}
|
||||
}
|
||||
async function loadAvailableModels(providerId) {
|
||||
try {
|
||||
console.log("[DEBUG] 加载模型列表,供应商ID:", providerId);
|
||||
const res = await AIModelConfigAPI.getAvailableModels(providerId);
|
||||
console.log("[DEBUG] API 响应:", res.data);
|
||||
availableModels.value = res.data.data || [];
|
||||
console.log("[DEBUG] 更新后的模型列表:", availableModels.value);
|
||||
} catch (error) {
|
||||
console.error("加载可用模型列表失败", error);
|
||||
availableModels.value = [];
|
||||
}
|
||||
}
|
||||
async function loadMessages() {
|
||||
messagesLoading.value = true;
|
||||
try {
|
||||
const res = await AIModelConfigAPI.getMessages(currentModelType.value);
|
||||
messages.value = res.data.data;
|
||||
scrollToBottom();
|
||||
} catch (error) {
|
||||
console.error("加载训练对话记录失败", error);
|
||||
} finally {
|
||||
messagesLoading.value = false;
|
||||
}
|
||||
}
|
||||
async function handleProviderChange(providerId) {
|
||||
console.log("[DEBUG] 供应商变化,新ID:", providerId);
|
||||
configForm.model_name = void 0;
|
||||
availableModels.value = [];
|
||||
if (providerId) {
|
||||
await loadAvailableModels(providerId);
|
||||
}
|
||||
}
|
||||
async function handleModelTypeChange() {
|
||||
await Promise.all([loadModelConfig(), loadMessages()]);
|
||||
}
|
||||
async function handleSaveConfig() {
|
||||
saveLoading.value = true;
|
||||
try {
|
||||
await AIModelConfigAPI.update(currentModelType.value, configForm);
|
||||
originalConfig.value = { ...configForm };
|
||||
ElMessage.success("配置保存成功");
|
||||
} catch (error) {
|
||||
console.error("保存配置失败", error);
|
||||
ElMessage.error("保存配置失败");
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
}
|
||||
}
|
||||
function isConfigChanged() {
|
||||
return JSON.stringify(configForm) !== JSON.stringify(originalConfig.value);
|
||||
}
|
||||
async function handleSendMessage() {
|
||||
var _a;
|
||||
const message = inputMessage.value.trim();
|
||||
if (!message || isGenerating.value) return;
|
||||
const configChanged = isConfigChanged();
|
||||
inputMessage.value = "";
|
||||
isGenerating.value = true;
|
||||
currentResponse.value = "";
|
||||
const tempUserMessageId = -Date.now();
|
||||
const userMessage = {
|
||||
id: tempUserMessageId,
|
||||
model_config_id: 0,
|
||||
role: "user",
|
||||
content: message,
|
||||
created_time: (/* @__PURE__ */ new Date()).toISOString(),
|
||||
updated_time: (/* @__PURE__ */ new Date()).toISOString()
|
||||
};
|
||||
messages.value.push(userMessage);
|
||||
scrollToBottom();
|
||||
try {
|
||||
const chatData = {
|
||||
model_type: currentModelType.value,
|
||||
message,
|
||||
config_changed: configChanged,
|
||||
config_data: configChanged ? configForm : void 0
|
||||
};
|
||||
abortController.value = new AbortController();
|
||||
const response = await AIModelConfigAPI.chat(chatData, abortController.value.signal);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const reader = (_a = response.body) == null ? void 0 : _a.getReader();
|
||||
if (!reader) {
|
||||
throw new Error("无法获取响应流");
|
||||
}
|
||||
const decoder = new TextDecoder();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
const chunk = decoder.decode(value, { stream: true });
|
||||
currentResponse.value += chunk;
|
||||
scrollToBottom();
|
||||
}
|
||||
if (configChanged) {
|
||||
originalConfig.value = { ...configForm };
|
||||
}
|
||||
if (currentResponse.value) {
|
||||
const assistantMessage = {
|
||||
id: -Date.now() - 1,
|
||||
model_config_id: 0,
|
||||
role: "assistant",
|
||||
content: currentResponse.value,
|
||||
created_time: (/* @__PURE__ */ new Date()).toISOString(),
|
||||
updated_time: (/* @__PURE__ */ new Date()).toISOString()
|
||||
};
|
||||
messages.value.push(assistantMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.name === "AbortError") {
|
||||
console.log("用户中断了生成");
|
||||
if (currentResponse.value) {
|
||||
const assistantMessage = {
|
||||
id: -Date.now() - 1,
|
||||
model_config_id: 0,
|
||||
role: "assistant",
|
||||
content: currentResponse.value + "\n\n*[已停止生成]*",
|
||||
created_time: (/* @__PURE__ */ new Date()).toISOString(),
|
||||
updated_time: (/* @__PURE__ */ new Date()).toISOString()
|
||||
};
|
||||
messages.value.push(assistantMessage);
|
||||
}
|
||||
} else {
|
||||
console.error("发送消息失败", error);
|
||||
const errorMessage = {
|
||||
id: -Date.now() - 1,
|
||||
model_config_id: 0,
|
||||
role: "assistant",
|
||||
content: "发送消息失败,请检查配置和网络连接",
|
||||
created_time: (/* @__PURE__ */ new Date()).toISOString(),
|
||||
updated_time: (/* @__PURE__ */ new Date()).toISOString()
|
||||
};
|
||||
messages.value.push(errorMessage);
|
||||
}
|
||||
} finally {
|
||||
currentResponse.value = "";
|
||||
isGenerating.value = false;
|
||||
abortController.value = null;
|
||||
scrollToBottom();
|
||||
}
|
||||
}
|
||||
function handleStopGenerate() {
|
||||
if (abortController.value) {
|
||||
abortController.value.abort();
|
||||
}
|
||||
}
|
||||
async function handleTest() {
|
||||
const text = testInput.value.trim();
|
||||
if (!text || testLoading.value) return;
|
||||
testLoading.value = true;
|
||||
testResult.value = "";
|
||||
try {
|
||||
const res = await AIModelConfigAPI.test({
|
||||
model_type: currentModelType.value,
|
||||
text
|
||||
});
|
||||
testResult.value = res.data.data;
|
||||
} catch (error) {
|
||||
console.error("起名测试失败", error);
|
||||
ElMessage.error("测试失败,请检查配置和网络连接");
|
||||
} finally {
|
||||
testLoading.value = false;
|
||||
}
|
||||
}
|
||||
function handleTestDialogClosed() {
|
||||
testInput.value = "";
|
||||
testResult.value = "";
|
||||
}
|
||||
async function handleDeleteMessage(messageId) {
|
||||
try {
|
||||
await ElMessageBox.confirm("确定删除这条对话记录吗?", "提示", {
|
||||
type: "warning"
|
||||
});
|
||||
await AIModelConfigAPI.deleteMessage(messageId);
|
||||
messages.value = messages.value.filter((m) => m.id !== messageId);
|
||||
ElMessage.success("删除成功");
|
||||
} catch (error) {
|
||||
if (error !== "cancel") {
|
||||
console.error("删除消息失败", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function handleClearMessages() {
|
||||
try {
|
||||
await ElMessageBox.confirm("确定清空所有对话记录吗?此操作不可恢复。", "提示", {
|
||||
type: "warning"
|
||||
});
|
||||
await AIModelConfigAPI.clearMessages(currentModelType.value);
|
||||
messages.value = [];
|
||||
ElMessage.success("对话已清空");
|
||||
} catch (error) {
|
||||
if (error !== "cancel") {
|
||||
console.error("清空对话失败", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
function processThinkTags(content) {
|
||||
if (!content) return "";
|
||||
const thinkRegex = /<think>([\s\S]*?)<\/think>/g;
|
||||
return content.replace(thinkRegex, (_, thinkContent) => {
|
||||
const escapedContent = md.render(thinkContent.trim());
|
||||
return `<details class="think-block"><summary><span class="think-icon">💭</span> 思考过程</summary><div class="think-content">${escapedContent}</div></details>`;
|
||||
});
|
||||
}
|
||||
function formatMessage(content) {
|
||||
if (!content) return "";
|
||||
const processedContent = processThinkTags(content);
|
||||
if (processedContent !== content) {
|
||||
const parts = content.split(/<think>[\s\S]*?<\/think>/g);
|
||||
const thinkMatches = content.match(/<think>[\s\S]*?<\/think>/g) || [];
|
||||
let result = "";
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
result += md.render(parts[i]);
|
||||
if (thinkMatches[i]) {
|
||||
const thinkContent = thinkMatches[i].replace(/<\/?think>/g, "").trim();
|
||||
result += `<details class="think-block"><summary><span class="think-icon">💭</span> 思考过程</summary><div class="think-content">${md.render(thinkContent)}</div></details>`;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return md.render(content);
|
||||
}
|
||||
function scrollToBottom() {
|
||||
nextTick(() => {
|
||||
if (messagesContainer.value) {
|
||||
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
|
||||
}
|
||||
});
|
||||
}
|
||||
onMounted(async () => {
|
||||
await Promise.all([loadProviderList(), loadKnowledgeBaseList()]);
|
||||
await Promise.all([loadModelConfig(), loadMessages()]);
|
||||
});
|
||||
return (_ctx, _cache) => {
|
||||
const _component_el_radio_button = ElRadioButton;
|
||||
const _component_el_radio_group = ElRadioGroup;
|
||||
const _component_el_option = ElOption;
|
||||
const _component_el_select = ElSelect;
|
||||
const _component_el_form_item = ElFormItem;
|
||||
const _component_el_input = ElInput;
|
||||
const _component_el_slider = ElSlider;
|
||||
const _component_el_button = ElButton;
|
||||
const _component_el_form = ElForm;
|
||||
const _component_el_icon = ElIcon;
|
||||
const _component_el_dialog = ElDialog;
|
||||
const _directive_loading = vLoading;
|
||||
return openBlock(), createElementBlock("div", _hoisted_1, [
|
||||
createBaseVNode("div", _hoisted_2, [
|
||||
_cache[13] || (_cache[13] = createBaseVNode("div", { class: "panel-header" }, [
|
||||
createBaseVNode("h3", null, "模型配置")
|
||||
], -1)),
|
||||
createBaseVNode("div", _hoisted_3, [
|
||||
createBaseVNode("div", _hoisted_4, [
|
||||
createVNode(_component_el_radio_group, {
|
||||
modelValue: currentCategory.value,
|
||||
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => currentCategory.value = $event),
|
||||
onChange: handleCategoryChange
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(AI_MODEL_TYPE_GROUPS), (group, key) => {
|
||||
return openBlock(), createBlock(_component_el_radio_button, {
|
||||
key,
|
||||
value: key
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
createTextVNode(toDisplayString(group.label), 1)
|
||||
]),
|
||||
_: 2
|
||||
}, 1032, ["value"]);
|
||||
}), 128))
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue"])
|
||||
]),
|
||||
createBaseVNode("div", _hoisted_5, [
|
||||
createVNode(_component_el_radio_group, {
|
||||
modelValue: currentModelType.value,
|
||||
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => currentModelType.value = $event),
|
||||
onChange: handleModelTypeChange
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(currentGroupTypes), (typeKey) => {
|
||||
return openBlock(), createBlock(_component_el_radio_button, {
|
||||
key: typeKey,
|
||||
value: typeKey
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
createTextVNode(toDisplayString(getShortLabel(typeKey)), 1)
|
||||
]),
|
||||
_: 2
|
||||
}, 1032, ["value"]);
|
||||
}), 128))
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue"])
|
||||
])
|
||||
]),
|
||||
withDirectives((openBlock(), createBlock(_component_el_form, {
|
||||
ref_key: "configFormRef",
|
||||
ref: configFormRef,
|
||||
model: configForm,
|
||||
"label-position": "top",
|
||||
class: "config-form"
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_form_item, { label: "AI供应商" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_select, {
|
||||
modelValue: configForm.provider_id,
|
||||
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => configForm.provider_id = $event),
|
||||
placeholder: "请选择AI供应商",
|
||||
style: { "width": "100%" },
|
||||
onChange: handleProviderChange
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
(openBlock(true), createElementBlock(Fragment, null, renderList(providerList.value, (provider) => {
|
||||
return openBlock(), createBlock(_component_el_option, {
|
||||
key: provider.id,
|
||||
label: provider.name,
|
||||
value: provider.id || ""
|
||||
}, null, 8, ["label", "value"]);
|
||||
}), 128))
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
createVNode(_component_el_form_item, { label: "模型" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_select, {
|
||||
modelValue: configForm.model_name,
|
||||
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => configForm.model_name = $event),
|
||||
placeholder: "请选择或输入模型名称",
|
||||
style: { "width": "100%" },
|
||||
disabled: !configForm.provider_id,
|
||||
filterable: "",
|
||||
"allow-create": "",
|
||||
"default-first-option": ""
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
(openBlock(true), createElementBlock(Fragment, null, renderList(availableModels.value, (model) => {
|
||||
return openBlock(), createBlock(_component_el_option, {
|
||||
key: model.id,
|
||||
label: model.name,
|
||||
value: model.id
|
||||
}, null, 8, ["label", "value"]);
|
||||
}), 128))
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue", "disabled"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
createVNode(_component_el_form_item, { label: "系统提示词" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_input, {
|
||||
modelValue: configForm.system_prompt,
|
||||
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => configForm.system_prompt = $event),
|
||||
type: "textarea",
|
||||
rows: 6,
|
||||
placeholder: "请输入系统提示词"
|
||||
}, null, 8, ["modelValue"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
createVNode(_component_el_form_item, { label: "模型温度" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_slider, {
|
||||
modelValue: configForm.temperature,
|
||||
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => configForm.temperature = $event),
|
||||
min: 0,
|
||||
max: 2,
|
||||
step: 0.1,
|
||||
"show-input": "",
|
||||
"show-input-controls": false,
|
||||
"input-size": "small"
|
||||
}, null, 8, ["modelValue"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
createVNode(_component_el_form_item, { label: "关联知识库" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_select, {
|
||||
modelValue: configForm.knowledge_base_ids,
|
||||
"onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => configForm.knowledge_base_ids = $event),
|
||||
multiple: "",
|
||||
placeholder: "请选择关联的知识库",
|
||||
style: { "width": "100%" }
|
||||
}, {
|
||||
default: withCtx(() => [
|
||||
(openBlock(true), createElementBlock(Fragment, null, renderList(knowledgeBaseList.value, (kb) => {
|
||||
return openBlock(), createBlock(_component_el_option, {
|
||||
key: kb.id,
|
||||
label: kb.name,
|
||||
value: kb.id || ""
|
||||
}, null, 8, ["label", "value"]);
|
||||
}), 128))
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
createVNode(_component_el_form_item, null, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_button, {
|
||||
type: "primary",
|
||||
loading: saveLoading.value,
|
||||
onClick: handleSaveConfig,
|
||||
style: { "width": "100%" }
|
||||
}, {
|
||||
default: withCtx(() => [..._cache[12] || (_cache[12] = [
|
||||
createTextVNode(" 保存配置 ", -1)
|
||||
])]),
|
||||
_: 1
|
||||
}, 8, ["loading"])
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["model"])), [
|
||||
[_directive_loading, configLoading.value]
|
||||
])
|
||||
]),
|
||||
createBaseVNode("div", _hoisted_6, [
|
||||
createBaseVNode("div", _hoisted_7, [
|
||||
createBaseVNode("h3", null, "对话训练 - " + toDisplayString(unref(AI_MODEL_TYPES)[currentModelType.value]), 1),
|
||||
createBaseVNode("div", _hoisted_8, [
|
||||
createVNode(_component_el_button, {
|
||||
text: "",
|
||||
icon: unref(aim_default),
|
||||
onClick: _cache[7] || (_cache[7] = ($event) => showTestDialog.value = true)
|
||||
}, {
|
||||
default: withCtx(() => [..._cache[14] || (_cache[14] = [
|
||||
createTextVNode(" 起名测试 ", -1)
|
||||
])]),
|
||||
_: 1
|
||||
}, 8, ["icon"]),
|
||||
messages.value.length > 0 ? (openBlock(), createBlock(_component_el_button, {
|
||||
key: 0,
|
||||
text: "",
|
||||
icon: unref(delete_default),
|
||||
onClick: handleClearMessages
|
||||
}, {
|
||||
default: withCtx(() => [..._cache[15] || (_cache[15] = [
|
||||
createTextVNode(" 清空对话 ", -1)
|
||||
])]),
|
||||
_: 1
|
||||
}, 8, ["icon"])) : createCommentVNode("", true)
|
||||
])
|
||||
]),
|
||||
createBaseVNode("div", {
|
||||
ref_key: "messagesContainer",
|
||||
ref: messagesContainer,
|
||||
class: "chat-messages"
|
||||
}, [
|
||||
messages.value.length === 0 && !messagesLoading.value ? (openBlock(), createElementBlock("div", _hoisted_9, [
|
||||
createBaseVNode("div", _hoisted_10, [
|
||||
createVNode(_component_el_icon, { size: "48" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(unref(chat_dot_round_default))
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
createBaseVNode("h2", null, toDisplayString(unref(AI_MODEL_TYPES)[currentModelType.value]) + "训练", 1),
|
||||
_cache[16] || (_cache[16] = createBaseVNode("p", null, "通过与AI对话来训练和优化模型效果", -1))
|
||||
])
|
||||
])) : withDirectives((openBlock(), createElementBlock("div", _hoisted_11, [
|
||||
(openBlock(true), createElementBlock(Fragment, null, renderList(messages.value, (message) => {
|
||||
return openBlock(), createElementBlock("div", {
|
||||
key: message.id,
|
||||
class: normalizeClass(["message-item", message.role])
|
||||
}, [
|
||||
message.role === "user" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
|
||||
createBaseVNode("div", _hoisted_12, [
|
||||
createBaseVNode("div", _hoisted_13, [
|
||||
createVNode(_component_el_button, {
|
||||
text: "",
|
||||
size: "small",
|
||||
icon: unref(delete_default),
|
||||
class: "delete-btn",
|
||||
onClick: ($event) => handleDeleteMessage(message.id)
|
||||
}, null, 8, ["icon", "onClick"]),
|
||||
_cache[17] || (_cache[17] = createBaseVNode("span", { class: "sender-name" }, "用户", -1))
|
||||
]),
|
||||
createBaseVNode("div", {
|
||||
class: "message-body",
|
||||
innerHTML: formatMessage(message.content)
|
||||
}, null, 8, _hoisted_14)
|
||||
]),
|
||||
createBaseVNode("div", _hoisted_15, [
|
||||
createVNode(_component_el_icon, null, {
|
||||
default: withCtx(() => [
|
||||
createVNode(unref(user_default))
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
])
|
||||
], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
||||
createBaseVNode("div", _hoisted_16, [
|
||||
createVNode(_component_el_icon, null, {
|
||||
default: withCtx(() => [
|
||||
createVNode(unref(chat_dot_round_default))
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
createBaseVNode("div", _hoisted_17, [
|
||||
createBaseVNode("div", _hoisted_18, [
|
||||
_cache[18] || (_cache[18] = createBaseVNode("span", { class: "sender-name" }, "AI", -1)),
|
||||
createVNode(_component_el_button, {
|
||||
text: "",
|
||||
size: "small",
|
||||
icon: unref(delete_default),
|
||||
class: "delete-btn",
|
||||
onClick: ($event) => handleDeleteMessage(message.id)
|
||||
}, null, 8, ["icon", "onClick"])
|
||||
]),
|
||||
createBaseVNode("div", {
|
||||
class: "message-body",
|
||||
innerHTML: formatMessage(message.content)
|
||||
}, null, 8, _hoisted_19)
|
||||
])
|
||||
], 64))
|
||||
], 2);
|
||||
}), 128)),
|
||||
isGenerating.value ? (openBlock(), createElementBlock("div", _hoisted_20, [
|
||||
createBaseVNode("div", _hoisted_21, [
|
||||
createVNode(_component_el_icon, null, {
|
||||
default: withCtx(() => [
|
||||
createVNode(unref(chat_dot_round_default))
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
createBaseVNode("div", _hoisted_22, [
|
||||
_cache[20] || (_cache[20] = createBaseVNode("div", { class: "message-header" }, [
|
||||
createBaseVNode("span", { class: "sender-name" }, "AI")
|
||||
], -1)),
|
||||
createBaseVNode("div", _hoisted_23, [
|
||||
currentResponse.value ? (openBlock(), createElementBlock("span", {
|
||||
key: 0,
|
||||
innerHTML: formatMessage(currentResponse.value)
|
||||
}, null, 8, _hoisted_24)) : (openBlock(), createElementBlock("span", _hoisted_25, [..._cache[19] || (_cache[19] = [
|
||||
createBaseVNode("span", null, null, -1),
|
||||
createBaseVNode("span", null, null, -1),
|
||||
createBaseVNode("span", null, null, -1)
|
||||
])]))
|
||||
])
|
||||
])
|
||||
])) : createCommentVNode("", true)
|
||||
])), [
|
||||
[_directive_loading, messagesLoading.value]
|
||||
])
|
||||
], 512),
|
||||
createBaseVNode("div", _hoisted_26, [
|
||||
createBaseVNode("div", _hoisted_27, [
|
||||
createVNode(_component_el_input, {
|
||||
modelValue: inputMessage.value,
|
||||
"onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => inputMessage.value = $event),
|
||||
type: "textarea",
|
||||
rows: 1,
|
||||
autosize: { minRows: 1, maxRows: 4 },
|
||||
placeholder: "输入消息进行训练...",
|
||||
disabled: isGenerating.value,
|
||||
onKeydown: withKeys(withModifiers(handleSendMessage, ["exact", "prevent"]), ["enter"])
|
||||
}, null, 8, ["modelValue", "disabled", "onKeydown"]),
|
||||
!isGenerating.value ? (openBlock(), createBlock(_component_el_button, {
|
||||
key: 0,
|
||||
type: "primary",
|
||||
icon: unref(promotion_default),
|
||||
disabled: !inputMessage.value.trim(),
|
||||
circle: "",
|
||||
onClick: handleSendMessage
|
||||
}, null, 8, ["icon", "disabled"])) : (openBlock(), createBlock(_component_el_button, {
|
||||
key: 1,
|
||||
type: "danger",
|
||||
icon: unref(video_pause_default),
|
||||
circle: "",
|
||||
onClick: handleStopGenerate
|
||||
}, null, 8, ["icon"]))
|
||||
]),
|
||||
_cache[21] || (_cache[21] = createBaseVNode("div", { class: "input-hint" }, " 按 Enter 发送消息,Shift + Enter 换行 ", -1))
|
||||
])
|
||||
]),
|
||||
createVNode(_component_el_dialog, {
|
||||
modelValue: showTestDialog.value,
|
||||
"onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => showTestDialog.value = $event),
|
||||
title: "起名测试",
|
||||
width: "600px",
|
||||
"close-on-click-modal": false,
|
||||
onClosed: handleTestDialogClosed
|
||||
}, {
|
||||
footer: withCtx(() => [
|
||||
createVNode(_component_el_button, {
|
||||
onClick: _cache[10] || (_cache[10] = ($event) => showTestDialog.value = false)
|
||||
}, {
|
||||
default: withCtx(() => [..._cache[23] || (_cache[23] = [
|
||||
createTextVNode("关闭", -1)
|
||||
])]),
|
||||
_: 1
|
||||
}),
|
||||
createVNode(_component_el_button, {
|
||||
type: "primary",
|
||||
loading: testLoading.value,
|
||||
disabled: !testInput.value.trim(),
|
||||
onClick: handleTest
|
||||
}, {
|
||||
default: withCtx(() => [..._cache[24] || (_cache[24] = [
|
||||
createTextVNode(" 提交测试 ", -1)
|
||||
])]),
|
||||
_: 1
|
||||
}, 8, ["loading", "disabled"])
|
||||
]),
|
||||
default: withCtx(() => [
|
||||
createBaseVNode("div", _hoisted_28, [
|
||||
createVNode(_component_el_form, { "label-position": "top" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_form_item, { label: "测试内容" }, {
|
||||
default: withCtx(() => [
|
||||
createVNode(_component_el_input, {
|
||||
modelValue: testInput.value,
|
||||
"onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => testInput.value = $event),
|
||||
type: "textarea",
|
||||
rows: 4,
|
||||
placeholder: "请输入要测试的内容...",
|
||||
disabled: testLoading.value
|
||||
}, null, 8, ["modelValue", "disabled"])
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
testResult.value ? (openBlock(), createElementBlock("div", _hoisted_29, [
|
||||
_cache[22] || (_cache[22] = createBaseVNode("div", { class: "result-header" }, [
|
||||
createBaseVNode("span", null, "测试结果")
|
||||
], -1)),
|
||||
createBaseVNode("div", {
|
||||
class: "result-content",
|
||||
innerHTML: formatMessage(testResult.value)
|
||||
}, null, 8, _hoisted_30)
|
||||
])) : createCommentVNode("", true)
|
||||
])
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue"])
|
||||
]);
|
||||
};
|
||||
}
|
||||
});
|
||||
const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-b7d6e58d"]]);
|
||||
export {
|
||||
index as default
|
||||
};
|
||||
Reference in New Issue
Block a user