feat: 添加知识库配置功能,支持会话管理中的知识库选择与设置
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
"ttsProvider": "TTS Provider",
|
||||
"llmStatus": "LLM Status",
|
||||
"ttsStatus": "TTS Status",
|
||||
"knowledgeBase": "Knowledge Base",
|
||||
"pluginManagement": "Plugin Management",
|
||||
"actions": "Actions"
|
||||
}
|
||||
@@ -67,6 +68,31 @@
|
||||
"fullSessionId": "Full Session ID",
|
||||
"hint": "Custom names help you easily identify sessions. The small information icon (!) will show the actual UMO when hovering."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"title": "Knowledge Base Configuration",
|
||||
"configure": "Configure",
|
||||
"selectKB": "Select Knowledge Bases",
|
||||
"selectMultiple": "You can select multiple knowledge bases",
|
||||
"noKBAvailable": "No knowledge bases available",
|
||||
"noKBDesc": "No knowledge bases have been created yet",
|
||||
"createKB": "Create Knowledge Base",
|
||||
"advancedSettings": "Advanced Settings",
|
||||
"topK": "Result Count",
|
||||
"topKHint": "Number of results to retrieve from knowledge base",
|
||||
"enableRerank": "Enable Reranking",
|
||||
"enableRerankHint": "Use reranking model to improve retrieval quality",
|
||||
"clearConfig": "Clear Configuration",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"loading": "Loading knowledge base configuration...",
|
||||
"description": "Configure knowledge bases for this session. The session will use configured knowledge bases to enhance conversation context.",
|
||||
"saveSuccess": "Knowledge base configuration saved successfully",
|
||||
"saveFailed": "Failed to save knowledge base configuration",
|
||||
"loadFailed": "Failed to load knowledge base configuration",
|
||||
"clearSuccess": "Knowledge base configuration cleared",
|
||||
"clearFailed": "Failed to clear knowledge base configuration",
|
||||
"clearConfirm": "Are you sure you want to clear the knowledge base configuration for this session?"
|
||||
},
|
||||
"deleteConfirm": {
|
||||
"message": "Are you sure you want to delete session {sessionName}?",
|
||||
"warning": "This action will permanently delete all chat history and preference settings for this session (except for data linked via plugins), and this cannot be undone. Continue?"
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"ttsProvider": "语音合成模型",
|
||||
"llmStatus": "启用 LLM",
|
||||
"ttsStatus": "启用 TTS",
|
||||
"knowledgeBase": "知识库配置",
|
||||
"pluginManagement": "插件管理",
|
||||
"actions": "操作"
|
||||
}
|
||||
@@ -67,6 +68,31 @@
|
||||
"fullSessionId": "完整会话ID",
|
||||
"hint": "自定义名称帮助您轻松识别会话。当设置了自定义名称时,会显示一个小感叹号标识(!),鼠标悬停时会显示实际的UMO。"
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"title": "知识库配置",
|
||||
"configure": "配置",
|
||||
"selectKB": "选择知识库",
|
||||
"selectMultiple": "可以选择多个知识库",
|
||||
"noKBAvailable": "暂无可用的知识库",
|
||||
"noKBDesc": "目前没有创建任何知识库",
|
||||
"createKB": "创建知识库",
|
||||
"advancedSettings": "高级配置",
|
||||
"topK": "返回结果数量",
|
||||
"topKHint": "从知识库检索的结果数量",
|
||||
"enableRerank": "启用重排序",
|
||||
"enableRerankHint": "使用重排序模型提高检索质量",
|
||||
"clearConfig": "清除配置",
|
||||
"save": "保存",
|
||||
"cancel": "取消",
|
||||
"loading": "加载知识库配置中...",
|
||||
"description": "为此会话配置使用的知识库。会话将使用配置的知识库来增强对话上下文。",
|
||||
"saveSuccess": "知识库配置保存成功",
|
||||
"saveFailed": "保存知识库配置失败",
|
||||
"loadFailed": "加载知识库配置失败",
|
||||
"clearSuccess": "知识库配置已清除",
|
||||
"clearFailed": "清除知识库配置失败",
|
||||
"clearConfirm": "确定要清除此会话的知识库配置吗?"
|
||||
},
|
||||
"deleteConfirm": {
|
||||
"message": "确定要删除会话 {sessionName} 吗?",
|
||||
"warning": "此操作将永久删除本次会话的「全部对话记录」与「偏好设置」(插件对会话的关联数据除外),且无法恢复。确认继续?"
|
||||
|
||||
@@ -142,6 +142,14 @@
|
||||
</v-checkbox>
|
||||
</template>
|
||||
|
||||
<!-- 知识库配置 -->
|
||||
<template v-slot:item.knowledge_base="{ item }">
|
||||
<v-btn size="x-small" variant="tonal" color="info" @click="openKBManager(item)"
|
||||
:loading="item.loadingKB" :disabled="!item.session_enabled">
|
||||
{{ tm('knowledgeBase.configure') }}
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<!-- 插件管理 -->
|
||||
<template v-slot:item.plugins="{ item }">
|
||||
<v-btn size="x-small" variant="tonal" color="primary" @click="openPluginManager(item)"
|
||||
@@ -335,6 +343,123 @@
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 知识库配置对话框 -->
|
||||
<v-dialog v-model="kbDialog" max-width="800" min-height="60%">
|
||||
<v-card v-if="selectedSessionForKB">
|
||||
<v-card-title class="bg-primary text-white py-3 px-4" style="display: flex; align-items: center;">
|
||||
<span>{{ tm('knowledgeBase.title') }} - {{ selectedSessionForKB.session_name }}</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon variant="text" color="white" @click="kbDialog = false">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text v-if="!loadingKBConfig">
|
||||
<div style="padding: 16px;">
|
||||
<v-alert type="info" variant="tonal" class="mb-4">
|
||||
{{ tm('knowledgeBase.description') }}
|
||||
</v-alert>
|
||||
|
||||
<!-- 知识库选择 -->
|
||||
<v-select
|
||||
v-model="sessionKBConfig.kb_ids"
|
||||
:items="availableKBs"
|
||||
item-title="kb_name"
|
||||
item-value="kb_id"
|
||||
:label="tm('knowledgeBase.selectKB')"
|
||||
multiple
|
||||
chips
|
||||
closable-chips
|
||||
variant="outlined"
|
||||
class="mb-4"
|
||||
:hint="tm('knowledgeBase.selectMultiple')"
|
||||
persistent-hint
|
||||
>
|
||||
<template v-slot:chip="{ item }">
|
||||
<v-chip>
|
||||
<span class="mr-1">{{ item.raw.emoji }}</span>
|
||||
{{ item.raw.kb_name }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<template v-slot:item="{ item, props }">
|
||||
<v-list-item v-bind="props">
|
||||
<template v-slot:prepend>
|
||||
<span style="font-size: 20px; margin-right: 8px;">{{ item.raw.emoji }}</span>
|
||||
</template>
|
||||
<v-list-item-title>{{ item.raw.kb_name }}</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
{{ item.raw.description || tm('knowledgeBase.noKBDesc') }} - {{ item.raw.doc_count }} {{ tm('list.documents', { count: item.raw.doc_count }) }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<!-- 高级配置 -->
|
||||
<v-expansion-panels class="mb-4">
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title>
|
||||
<v-icon class="mr-2">mdi-cog</v-icon>
|
||||
{{ tm('knowledgeBase.advancedSettings') }}
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
v-model.number="sessionKBConfig.top_k"
|
||||
:label="tm('knowledgeBase.topK')"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:hint="tm('knowledgeBase.topKHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox
|
||||
v-model="sessionKBConfig.enable_rerank"
|
||||
:label="tm('knowledgeBase.enableRerank')"
|
||||
color="primary"
|
||||
:hint="tm('knowledgeBase.enableRerankHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
|
||||
<div v-if="availableKBs.length === 0" class="text-center py-8">
|
||||
<v-icon size="64" color="grey-lighten-2">mdi-database-off</v-icon>
|
||||
<p class="mt-4 text-medium-emphasis">{{ tm('knowledgeBase.noKBAvailable') }}</p>
|
||||
<v-btn color="primary" variant="tonal" class="mt-2" @click="goToKBPage">
|
||||
{{ tm('knowledgeBase.createKB') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text v-else class="text-center py-8">
|
||||
<v-progress-circular indeterminate color="primary" size="48"></v-progress-circular>
|
||||
<div class="text-body-1 mt-4">{{ tm('knowledgeBase.loading') }}</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-actions class="pa-4">
|
||||
<v-btn variant="text" @click="clearKBConfig" :disabled="savingKBConfig || loadingKBConfig">
|
||||
{{ tm('knowledgeBase.clearConfig') }}
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn variant="text" @click="kbDialog = false" :disabled="savingKBConfig">
|
||||
{{ tm('knowledgeBase.cancel') }}
|
||||
</v-btn>
|
||||
<v-btn color="primary" variant="tonal" @click="saveKBConfig" :loading="savingKBConfig">
|
||||
{{ tm('knowledgeBase.save') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<v-snackbar v-model="snackbar" :timeout="3000" elevation="24" :color="snackbarColor" location="top">
|
||||
{{ snackbarText }}
|
||||
@@ -399,6 +524,18 @@ export default {
|
||||
newSessionName: '',
|
||||
nameEditLoading: false,
|
||||
|
||||
// 知识库管理
|
||||
kbDialog: false,
|
||||
selectedSessionForKB: null,
|
||||
sessionKBConfig: {
|
||||
kb_ids: [],
|
||||
top_k: 5,
|
||||
enable_rerank: true
|
||||
},
|
||||
availableKBs: [],
|
||||
loadingKBConfig: false,
|
||||
savingKBConfig: false,
|
||||
|
||||
// 提示信息
|
||||
snackbar: false,
|
||||
snackbarText: '',
|
||||
@@ -432,6 +569,7 @@ export default {
|
||||
{ title: this.tm('table.headers.ttsProvider'), key: 'tts_provider', sortable: false, minWidth: '200px' },
|
||||
{ title: this.tm('table.headers.llmStatus'), key: 'llm_enabled', sortable: false, minWidth: '120px' },
|
||||
{ title: this.tm('table.headers.ttsStatus'), key: 'tts_enabled', sortable: false, minWidth: '120px' },
|
||||
{ title: this.tm('table.headers.knowledgeBase'), key: 'knowledge_base', sortable: false, minWidth: '150px' },
|
||||
{ title: this.tm('table.headers.pluginManagement'), key: 'plugins', sortable: false, minWidth: '120px' },
|
||||
{ title: this.tm('table.headers.actions'), key: 'actions', sortable: false, minWidth: '100px' },
|
||||
]
|
||||
@@ -503,7 +641,8 @@ export default {
|
||||
...session,
|
||||
updating: false, // 添加更新状态标志
|
||||
loadingPlugins: false, // 添加插件加载状态标志
|
||||
deleting: false // 添加删除状态标志
|
||||
deleting: false, // 添加删除状态标志
|
||||
loadingKB: false // 添加知识库加载状态标志
|
||||
}));
|
||||
this.availablePersonas = data.available_personas;
|
||||
this.availableChatProviders = data.available_chat_providers;
|
||||
@@ -964,6 +1103,110 @@ export default {
|
||||
this.currentPage = 1; // 重置到第一页
|
||||
this.loadSessions();
|
||||
},
|
||||
|
||||
// 知识库配置相关方法
|
||||
async openKBManager(session) {
|
||||
this.selectedSessionForKB = session;
|
||||
this.kbDialog = true;
|
||||
this.loadingKBConfig = true;
|
||||
|
||||
try {
|
||||
// 加载可用的知识库列表
|
||||
const kbListResponse = await axios.get('/api/kb/list');
|
||||
if (kbListResponse.data.status === 'ok') {
|
||||
this.availableKBs = kbListResponse.data.data.items;
|
||||
}
|
||||
|
||||
// 加载当前会话的知识库配置
|
||||
const configResponse = await axios.get('/api/kb/session/config/get', {
|
||||
params: { session_id: session.session_id }
|
||||
});
|
||||
|
||||
if (configResponse.data.status === 'ok') {
|
||||
const config = configResponse.data.data;
|
||||
this.sessionKBConfig = {
|
||||
kb_ids: config.kb_ids || [],
|
||||
top_k: config.top_k || 5,
|
||||
enable_rerank: config.enable_rerank !== false
|
||||
};
|
||||
} else {
|
||||
// 如果没有配置,使用默认值
|
||||
this.sessionKBConfig = {
|
||||
kb_ids: [],
|
||||
top_k: 5,
|
||||
enable_rerank: true
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载知识库配置失败:', error);
|
||||
this.showError(this.tm('knowledgeBase.loadFailed'));
|
||||
} finally {
|
||||
this.loadingKBConfig = false;
|
||||
}
|
||||
},
|
||||
|
||||
async saveKBConfig() {
|
||||
if (!this.selectedSessionForKB) return;
|
||||
|
||||
this.savingKBConfig = true;
|
||||
try {
|
||||
const response = await axios.post('/api/kb/session/config/set', {
|
||||
scope: 'session',
|
||||
scope_id: this.selectedSessionForKB.session_id,
|
||||
kb_ids: this.sessionKBConfig.kb_ids,
|
||||
top_k: this.sessionKBConfig.top_k,
|
||||
enable_rerank: this.sessionKBConfig.enable_rerank
|
||||
});
|
||||
|
||||
if (response.data.status === 'ok') {
|
||||
this.showSuccess(this.tm('knowledgeBase.saveSuccess'));
|
||||
this.kbDialog = false;
|
||||
} else {
|
||||
this.showError(response.data.message || this.tm('knowledgeBase.saveFailed'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存知识库配置失败:', error);
|
||||
this.showError(error.response?.data?.message || this.tm('knowledgeBase.saveFailed'));
|
||||
} finally {
|
||||
this.savingKBConfig = false;
|
||||
}
|
||||
},
|
||||
|
||||
async clearKBConfig() {
|
||||
if (!this.selectedSessionForKB) return;
|
||||
|
||||
if (!confirm(this.tm('knowledgeBase.clearConfirm'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.savingKBConfig = true;
|
||||
try {
|
||||
const response = await axios.post('/api/kb/session/config/delete', {
|
||||
scope: 'session',
|
||||
scope_id: this.selectedSessionForKB.session_id
|
||||
});
|
||||
|
||||
if (response.data.status === 'ok') {
|
||||
this.showSuccess(this.tm('knowledgeBase.clearSuccess'));
|
||||
this.sessionKBConfig = {
|
||||
kb_ids: [],
|
||||
top_k: 5,
|
||||
enable_rerank: true
|
||||
};
|
||||
} else {
|
||||
this.showError(response.data.message || this.tm('knowledgeBase.clearFailed'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('清除知识库配置失败:', error);
|
||||
this.showError(error.response?.data?.message || this.tm('knowledgeBase.clearFailed'));
|
||||
} finally {
|
||||
this.savingKBConfig = false;
|
||||
}
|
||||
},
|
||||
|
||||
goToKBPage() {
|
||||
this.$router.push('/knowledge-base');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -152,6 +152,7 @@
|
||||
:label="t('create.embeddingModelLabel')"
|
||||
variant="outlined"
|
||||
class="mb-4"
|
||||
@update:model-value="handleEmbeddingProviderChange"
|
||||
>
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item v-bind="props">
|
||||
@@ -165,6 +166,10 @@
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<v-alert type="warning" variant="tonal" density="compact" class="mb-4" v-if="editingKB && showEmbeddingWarning">
|
||||
<strong>注意:</strong> 修改嵌入模型会导致现有的向量数据失效,建议重新上传文档。不同的嵌入模型生成的向量不兼容,可能导致检索结果不准确。
|
||||
</v-alert>
|
||||
|
||||
<v-select
|
||||
v-model="formData.rerank_provider_id"
|
||||
:items="rerankProviders"
|
||||
@@ -272,6 +277,39 @@
|
||||
<v-snackbar v-model="snackbar.show" :color="snackbar.color">
|
||||
{{ snackbar.text }}
|
||||
</v-snackbar>
|
||||
|
||||
<!-- Embedding Provider 修改确认对话框 -->
|
||||
<v-dialog v-model="embeddingChangeDialog" max-width="500px" persistent>
|
||||
<v-card>
|
||||
<v-card-title class="bg-warning text-white">
|
||||
<v-icon class="mr-2">mdi-alert</v-icon>
|
||||
确认修改嵌入模型
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-6">
|
||||
<v-alert type="warning" variant="tonal" class="mb-4">
|
||||
<strong>警告:</strong> 修改嵌入模型将导致以下影响:
|
||||
</v-alert>
|
||||
<ul class="text-body-2">
|
||||
<li>现有的向量数据将失效</li>
|
||||
<li>检索功能可能无法正常工作</li>
|
||||
<li>建议删除现有文档后重新上传</li>
|
||||
<li>不同嵌入模型生成的向量不兼容</li>
|
||||
</ul>
|
||||
<div class="mt-4 text-body-2">
|
||||
您确定要将嵌入模型从 <strong>{{ originalEmbeddingProvider }}</strong> 修改为 <strong>{{ pendingEmbeddingProvider }}</strong> 吗?
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer />
|
||||
<v-btn variant="text" @click="cancelEmbeddingChange">
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn color="warning" variant="elevated" @click="confirmEmbeddingChange">
|
||||
确认修改
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -291,6 +329,10 @@ const deleting = ref(false)
|
||||
const kbList = ref<any[]>([])
|
||||
const embeddingProviders = ref<any[]>([])
|
||||
const rerankProviders = ref<any[]>([])
|
||||
const originalEmbeddingProvider = ref<string | null>(null)
|
||||
const showEmbeddingWarning = ref(false)
|
||||
const embeddingChangeDialog = ref(false)
|
||||
const pendingEmbeddingProvider = ref<string | null>(null)
|
||||
|
||||
// 对话框
|
||||
const showCreateDialog = ref(false)
|
||||
@@ -386,6 +428,7 @@ const navigateToDetail = (kbId: string) => {
|
||||
// 编辑知识库
|
||||
const editKB = (kb: any) => {
|
||||
editingKB.value = kb
|
||||
originalEmbeddingProvider.value = kb.embedding_provider_id
|
||||
formData.value = {
|
||||
kb_name: kb.kb_name,
|
||||
description: kb.description || '',
|
||||
@@ -396,6 +439,39 @@ const editKB = (kb: any) => {
|
||||
showCreateDialog.value = true
|
||||
}
|
||||
|
||||
// 处理 embedding provider 变更
|
||||
const handleEmbeddingProviderChange = (newValue: string | null) => {
|
||||
// 检测是否修改了embedding provider
|
||||
if (newValue && originalEmbeddingProvider.value && newValue !== originalEmbeddingProvider.value) {
|
||||
// 显示二次确认对话框
|
||||
showEmbeddingWarning.value = true
|
||||
pendingEmbeddingProvider.value = newValue
|
||||
embeddingChangeDialog.value = true
|
||||
} else {
|
||||
showEmbeddingWarning.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 确认修改 embedding provider
|
||||
const confirmEmbeddingChange = () => {
|
||||
if (pendingEmbeddingProvider.value) {
|
||||
formData.value.embedding_provider_id = pendingEmbeddingProvider.value
|
||||
// 更新原始值,这样下次比较时不会重复弹窗
|
||||
originalEmbeddingProvider.value = pendingEmbeddingProvider.value
|
||||
}
|
||||
embeddingChangeDialog.value = false
|
||||
showEmbeddingWarning.value = true
|
||||
}
|
||||
|
||||
// 取消修改 embedding provider
|
||||
const cancelEmbeddingChange = () => {
|
||||
// 恢复到原始值
|
||||
formData.value.embedding_provider_id = originalEmbeddingProvider.value
|
||||
embeddingChangeDialog.value = false
|
||||
showEmbeddingWarning.value = false
|
||||
pendingEmbeddingProvider.value = null
|
||||
}
|
||||
|
||||
// 确认删除
|
||||
const confirmDelete = (kb: any) => {
|
||||
deleteTarget.value = kb
|
||||
@@ -481,6 +557,9 @@ const submitForm = async () => {
|
||||
const closeCreateDialog = () => {
|
||||
showCreateDialog.value = false
|
||||
editingKB.value = null
|
||||
originalEmbeddingProvider.value = null
|
||||
showEmbeddingWarning.value = false
|
||||
pendingEmbeddingProvider.value = null
|
||||
formData.value = {
|
||||
kb_name: '',
|
||||
description: '',
|
||||
|
||||
@@ -86,9 +86,7 @@
|
||||
:label="t('settings.embeddingProvider')"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
disabled
|
||||
hint="嵌入模型创建后不可修改"
|
||||
persistent-hint
|
||||
@update:model-value="handleEmbeddingProviderChange"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
@@ -108,6 +106,10 @@
|
||||
<v-alert type="info" variant="tonal" class="mt-4">
|
||||
{{ t('settings.tips') }}
|
||||
</v-alert>
|
||||
|
||||
<v-alert type="warning" variant="tonal" class="mt-4" v-if="showEmbeddingWarning">
|
||||
<strong>注意:</strong> 修改嵌入模型会导致现有的向量数据失效,建议重新上传文档。不同的嵌入模型生成的向量不兼容,可能导致检索结果不准确。
|
||||
</v-alert>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
||||
@@ -131,6 +133,39 @@
|
||||
<v-snackbar v-model="snackbar.show" :color="snackbar.color">
|
||||
{{ snackbar.text }}
|
||||
</v-snackbar>
|
||||
|
||||
<!-- Embedding Provider修改确认对话框 -->
|
||||
<v-dialog v-model="embeddingChangeDialog" max-width="500px" persistent>
|
||||
<v-card>
|
||||
<v-card-title class="bg-warning text-white">
|
||||
<v-icon class="mr-2">mdi-alert</v-icon>
|
||||
确认修改嵌入模型
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-6">
|
||||
<v-alert type="warning" variant="tonal" class="mb-4">
|
||||
<strong>警告:</strong> 修改嵌入模型将导致以下影响:
|
||||
</v-alert>
|
||||
<ul class="text-body-2">
|
||||
<li>现有的向量数据将失效</li>
|
||||
<li>检索功能可能无法正常工作</li>
|
||||
<li>建议删除现有文档后重新上传</li>
|
||||
<li>不同嵌入模型生成的向量不兼容</li>
|
||||
</ul>
|
||||
<div class="mt-4 text-body-2">
|
||||
您确定要将嵌入模型从 <strong>{{ originalEmbeddingProvider }}</strong> 修改为 <strong>{{ pendingEmbeddingProvider }}</strong> 吗?
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer />
|
||||
<v-btn variant="text" @click="cancelEmbeddingChange">
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn color="warning" variant="elevated" @click="confirmEmbeddingChange">
|
||||
确认修改
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -152,6 +187,10 @@ const saving = ref(false)
|
||||
const formRef = ref()
|
||||
const embeddingProviders = ref<any[]>([])
|
||||
const rerankProviders = ref<any[]>([])
|
||||
const originalEmbeddingProvider = ref('')
|
||||
const showEmbeddingWarning = ref(false)
|
||||
const embeddingChangeDialog = ref(false)
|
||||
const pendingEmbeddingProvider = ref('')
|
||||
|
||||
const snackbar = ref({
|
||||
show: false,
|
||||
@@ -190,6 +229,8 @@ watch(() => props.kb, (kb) => {
|
||||
embedding_provider_id: kb.embedding_provider_id || '',
|
||||
rerank_provider_id: kb.rerank_provider_id || ''
|
||||
}
|
||||
// 保存原始的embedding provider
|
||||
originalEmbeddingProvider.value = kb.embedding_provider_id || ''
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
@@ -212,6 +253,33 @@ const loadProviders = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理embedding provider变更
|
||||
const handleEmbeddingProviderChange = (newValue: string) => {
|
||||
if (newValue && newValue !== originalEmbeddingProvider.value) {
|
||||
// 显示警告并需要确认
|
||||
showEmbeddingWarning.value = true
|
||||
pendingEmbeddingProvider.value = newValue
|
||||
embeddingChangeDialog.value = true
|
||||
} else {
|
||||
showEmbeddingWarning.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 确认修改embedding provider
|
||||
const confirmEmbeddingChange = () => {
|
||||
formData.value.embedding_provider_id = pendingEmbeddingProvider.value
|
||||
embeddingChangeDialog.value = false
|
||||
showEmbeddingWarning.value = true
|
||||
}
|
||||
|
||||
// 取消修改embedding provider
|
||||
const cancelEmbeddingChange = () => {
|
||||
formData.value.embedding_provider_id = originalEmbeddingProvider.value
|
||||
embeddingChangeDialog.value = false
|
||||
showEmbeddingWarning.value = false
|
||||
pendingEmbeddingProvider.value = ''
|
||||
}
|
||||
|
||||
// 保存设置
|
||||
const saveSettings = async () => {
|
||||
const { valid } = await formRef.value.validate()
|
||||
|
||||
Reference in New Issue
Block a user