|
@@ -42,6 +42,7 @@ import { useDropZone, useFileDialog } from '@vueuse/core'
|
|
|
import download from 'downloadjs'
|
|
|
import common from '/@/api/common'
|
|
|
import { UploadFile } from '/@/api/common/type'
|
|
|
+import system from '/@/api/system'
|
|
|
|
|
|
const plugins: Array<MarkdownPlugin<any>> = [EChartsPlugin(), ToolsLoadingPlugin(), TablePlugin(), StructDataPlugin()]
|
|
|
|
|
@@ -63,7 +64,7 @@ const {
|
|
|
// 附件管理:使用本地列表以支持单个移除
|
|
|
const dropToUploadZone = ref<HTMLElement>()
|
|
|
|
|
|
-const { isOverDropZone } = useDropZone(dropToUploadZone, async (files:File[] | null)=> {
|
|
|
+const { isOverDropZone } = useDropZone(dropToUploadZone, async (files: File[] | null) => {
|
|
|
if (loadingUpload.value) {
|
|
|
ElMessage.warning('请等待上传完成')
|
|
|
return
|
|
@@ -186,43 +187,16 @@ const { loading: loadingModels, doLoading: loadModel } = useLoading(async () =>
|
|
|
modelOptions.value = data.list ?? []
|
|
|
selectedModel.value = modelOptions.value[0]?.id ?? undefined
|
|
|
})
|
|
|
-
|
|
|
-// 词嵌入模型选择
|
|
|
-const embeddingModelOptions = ref<LmConfigInfo[]>([])
|
|
|
-const selectedEmbeddingModel = ref<number | undefined>(undefined)
|
|
|
-const embeddingModelLabel = computed(() => {
|
|
|
- if (!loadingEmbeddingModels.value && selectedEmbeddingModel.value === undefined) {
|
|
|
- return '未配置词嵌入'
|
|
|
- }
|
|
|
- const select = embeddingModelOptions.value.filter((i) => i.id === selectedEmbeddingModel.value)
|
|
|
-
|
|
|
- if (select.length === 0) {
|
|
|
- return '加载中'
|
|
|
- }
|
|
|
-
|
|
|
- return select[0].modelName
|
|
|
-})
|
|
|
onMounted(loadModel)
|
|
|
|
|
|
-const { loading: loadingEmbeddingModels, doLoading: loadEmbeddingModel } = useLoading(async () => {
|
|
|
- const data: { list: LmConfigInfo[]; total: number } = await assist.model.getList({ modelType: 'embedding' }).catch(() => {
|
|
|
- return {
|
|
|
- list: [],
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- embeddingModelOptions.value = data.list ?? []
|
|
|
- if (embeddingModelOptions.value.length !== 0) {
|
|
|
- embeddingModelOptions.value.unshift({
|
|
|
- id: -1,
|
|
|
- modelName: '不启用词嵌入',
|
|
|
- status: true,
|
|
|
- })
|
|
|
- }
|
|
|
- selectedEmbeddingModel.value = embeddingModelOptions.value[0]?.id ?? undefined
|
|
|
+const selectEmbeddingId = ref<number | undefined>(undefined)
|
|
|
+const { loading: loadingEmbedding, doLoading: loadEmbedding } = useLoading(async () => {
|
|
|
+ const embedding_key = await system.getInfoByKey('assistant.embedding.default').then((res: any) => res.data.configValue)
|
|
|
+ const embedding_model = await assist.model.getList({ modelType: 'embedding',keyWord: embedding_key }) as LmConfigInfo[]
|
|
|
+ selectEmbeddingId.value = embedding_model[0]?.id
|
|
|
})
|
|
|
|
|
|
-onMounted(loadEmbeddingModel)
|
|
|
+onMounted(loadEmbedding)
|
|
|
|
|
|
// 提示词列表相关状态
|
|
|
const customPrompt = ref('')
|
|
@@ -437,7 +411,7 @@ const chatInternal = (rtn: Message, context: Message[] = messages.value) => {
|
|
|
session_id: activeConversationId.value!,
|
|
|
message: r,
|
|
|
modelClassId: selectedModel.value,
|
|
|
- modelEmbeddingId: (selectedEmbeddingModel.value ?? -1) > 0 ? selectedEmbeddingModel.value : undefined,
|
|
|
+ modelEmbeddingId: selectEmbeddingId.value,
|
|
|
},
|
|
|
onReceive: (resp: ChatResponse) => {
|
|
|
switch (resp.type) {
|
|
@@ -701,8 +675,7 @@ const startMultidelete = async () => {
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
await nextTick()
|
|
|
- // await doLoadConversations()
|
|
|
- conversations.value = conversations.value.filter((item) => item.session_id !== id)
|
|
|
+ conversations.value = conversations.value.filter((item) => !multiDeleteConversationModel.value.selectedConversations.includes(item.session_id))
|
|
|
}
|
|
|
|
|
|
// 创建新对话
|
|
@@ -776,7 +749,6 @@ const canSendMessage = computed(() => {
|
|
|
return (
|
|
|
!inputMessage.value.trim() ||
|
|
|
loadingModels.value ||
|
|
|
- loadingEmbeddingModels.value ||
|
|
|
loadingPromptList.value ||
|
|
|
loadConversations.value ||
|
|
|
loadingMessage.value ||
|
|
@@ -913,10 +885,18 @@ const formatFileSize = (bytes: number): string => {
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+const isSystemLoading = computed(()=> {
|
|
|
+ return loadConversations.value ||
|
|
|
+ loadingModels.value ||
|
|
|
+ loadingPromptList.value ||
|
|
|
+ loadingEmbedding.value
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <el-container class="chat-container" ref="dropToUploadZone">
|
|
|
+ <el-container class="chat-container" ref="dropToUploadZone" v-loading="isSystemLoading">
|
|
|
<!-- 左侧会话列表 -->
|
|
|
<el-aside width="300px" class="chat-sidebar">
|
|
|
<div class="sidebar-header">
|
|
@@ -1297,29 +1277,6 @@ const formatFileSize = (bytes: number): string => {
|
|
|
</el-dropdown>
|
|
|
|
|
|
<!-- 词嵌入模型选择按钮 -->
|
|
|
- <el-dropdown trigger="click" placement="top-start" :disabled="loadingModels || embeddingModelLabel == '未配置词嵌入'">
|
|
|
- <button class="control-btn embedding-model-btn">
|
|
|
- <el-icon>
|
|
|
- <CopyDocument v-if="!loadingEmbeddingModels" />
|
|
|
- <Loading v-else class="spin" />
|
|
|
- </el-icon>
|
|
|
- <span>{{ embeddingModelLabel }}</span>
|
|
|
- </button>
|
|
|
- <template #dropdown>
|
|
|
- <el-dropdown-menu>
|
|
|
- <el-dropdown-item
|
|
|
- v-for="item in embeddingModelOptions"
|
|
|
- :key="item.id"
|
|
|
- @click="selectedEmbeddingModel = item.id"
|
|
|
- :class="{ 'is-selected': selectedEmbeddingModel === item.id }"
|
|
|
- >
|
|
|
- {{ item.modelName }}
|
|
|
- </el-dropdown-item>
|
|
|
- </el-dropdown-menu>
|
|
|
- </template>
|
|
|
- </el-dropdown>
|
|
|
-
|
|
|
- <!-- 词嵌入模型选择按钮 -->
|
|
|
<el-dropdown trigger="click" placement="top-start" :disabled="loadingModels || promptLabel == '未配置提示词'">
|
|
|
<button class="control-btn embedding-model-btn">
|
|
|
<el-icon>
|