feat:知识库精细化管理 (#96)
* feat(知识库管理): 新增知识库创建人选择功能 (#96) * "feat(知识库管理): 新增知识库权限修改功能并扩展操作列宽度 (#97)" * feat(文档解析): 添加embedding向量维度校验,确保维度为1024并提示使用bge-m3模型
This commit is contained in:
parent
98f3547521
commit
d0d7a24297
|
@ -576,6 +576,12 @@ def perform_parse(doc_id, doc_info, file_info, embedding_config):
|
|||
embedding_data = embedding_resp.json()
|
||||
q_1024_vec = embedding_data["data"][0]["embedding"]
|
||||
print(f"[Parser-INFO] 获取embedding成功,长度: {len(q_1024_vec)}")
|
||||
# 检查向量维度是否为1024
|
||||
if len(q_1024_vec) != 1024:
|
||||
error_msg = f"[Parser-ERROR] Embedding向量维度不是1024,实际维度: {len(q_1024_vec)}, 建议使用bge-m3模型"
|
||||
print(error_msg)
|
||||
update_progress(-1, error_msg)
|
||||
raise ValueError(error_msg)
|
||||
except Exception as e:
|
||||
print(f"[Parser-ERROR] 获取embedding失败: {e}")
|
||||
raise Exception(f"[Parser-ERROR] 获取embedding失败: {e}")
|
||||
|
|
|
@ -154,6 +154,7 @@ class KnowledgebaseService:
|
|||
@classmethod
|
||||
def create_knowledgebase(cls, **data):
|
||||
"""创建知识库"""
|
||||
|
||||
try:
|
||||
# 检查知识库名称是否已存在
|
||||
exists = cls._check_name_exists(data['name'])
|
||||
|
@ -163,36 +164,42 @@ class KnowledgebaseService:
|
|||
conn = cls._get_db_connection()
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
# 获取最早的用户ID作为tenant_id和created_by
|
||||
tenant_id = None
|
||||
created_by = None
|
||||
try:
|
||||
query_earliest_user = """
|
||||
SELECT id FROM user
|
||||
WHERE create_time = (SELECT MIN(create_time) FROM user)
|
||||
LIMIT 1
|
||||
"""
|
||||
cursor.execute(query_earliest_user)
|
||||
earliest_user = cursor.fetchone()
|
||||
|
||||
if earliest_user:
|
||||
tenant_id = earliest_user['id']
|
||||
created_by = earliest_user['id'] # 使用最早用户ID作为created_by
|
||||
print(f"使用创建时间最早的用户ID作为tenant_id和created_by: {tenant_id}")
|
||||
else:
|
||||
# 如果找不到用户,使用默认值
|
||||
# 使用传入的 creator_id 作为 tenant_id 和 created_by
|
||||
tenant_id = data.get('creator_id')
|
||||
created_by = data.get('creator_id')
|
||||
|
||||
if not tenant_id:
|
||||
# 如果没有提供 creator_id,则使用默认值
|
||||
print("未提供 creator_id,尝试获取最早用户 ID")
|
||||
try:
|
||||
query_earliest_user = """
|
||||
SELECT id FROM user
|
||||
WHERE create_time = (SELECT MIN(create_time) FROM user)
|
||||
LIMIT 1
|
||||
"""
|
||||
cursor.execute(query_earliest_user)
|
||||
earliest_user = cursor.fetchone()
|
||||
|
||||
if earliest_user:
|
||||
tenant_id = earliest_user['id']
|
||||
created_by = earliest_user['id']
|
||||
print(f"使用创建时间最早的用户ID作为tenant_id和created_by: {tenant_id}")
|
||||
else:
|
||||
# 如果找不到用户,使用默认值
|
||||
tenant_id = "system"
|
||||
created_by = "system"
|
||||
print(f"未找到用户, 使用默认值作为tenant_id和created_by: {tenant_id}")
|
||||
except Exception as e:
|
||||
print(f"获取用户ID失败: {str(e)},使用默认值")
|
||||
tenant_id = "system"
|
||||
created_by = "system"
|
||||
print(f"未找到用户, 使用默认值作为tenant_id和created_by: {tenant_id}")
|
||||
except Exception as e:
|
||||
print(f"获取用户ID失败: {str(e)},使用默认值")
|
||||
tenant_id = "system"
|
||||
created_by = "system"
|
||||
else:
|
||||
print(f"使用传入的 creator_id 作为 tenant_id 和 created_by: {tenant_id}")
|
||||
|
||||
|
||||
# --- 获取动态 embd_id ---
|
||||
dynamic_embd_id = None
|
||||
default_embd_id = 'bge-m3___VLLM@VLLM' # Fallback default
|
||||
default_embd_id = 'bge-m3' # Fallback default
|
||||
try:
|
||||
query_embedding_model = """
|
||||
SELECT llm_name
|
||||
|
@ -316,6 +323,10 @@ class KnowledgebaseService:
|
|||
if 'description' in data:
|
||||
update_fields.append("description = %s")
|
||||
params.append(data['description'])
|
||||
|
||||
if 'permission' in data:
|
||||
update_fields.append("permission = %s")
|
||||
params.append(data['permission'])
|
||||
|
||||
# 更新时间
|
||||
current_time = datetime.now()
|
||||
|
|
|
@ -29,6 +29,7 @@ export function createKnowledgeBaseApi(data: {
|
|||
description?: string
|
||||
language?: string
|
||||
permission?: string
|
||||
creator_id: string
|
||||
}) {
|
||||
return request({
|
||||
url: "/api/v1/knowledgebases",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts" setup>
|
||||
import type { FormInstance, UploadUserFile } from "element-plus"
|
||||
import { batchDeleteFilesApi, deleteFileApi, getFileListApi, uploadFileApi } from "@@/apis/files"
|
||||
import { getTableDataApi } from "@@/apis/tables"
|
||||
import { usePagination } from "@@/composables/usePagination"
|
||||
import { Delete, Download, Refresh, Search, Upload } from "@element-plus/icons-vue"
|
||||
import { ElLoading, ElMessage, ElMessageBox } from "element-plus"
|
||||
|
@ -393,7 +394,7 @@ onActivated(() => {
|
|||
{{ (paginationData.currentPage - 1) * paginationData.pageSize + scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="文档名" align="center" sortable="custom"/>
|
||||
<el-table-column prop="name" label="文档名" align="center" sortable="custom" />
|
||||
<el-table-column label="大小" align="center" width="120" sortable="custom">
|
||||
<template #default="scope">
|
||||
{{ formatFileSize(scope.row.size) }}
|
||||
|
|
|
@ -18,13 +18,16 @@ import {
|
|||
getSystemEmbeddingConfigApi,
|
||||
setSystemEmbeddingConfigApi
|
||||
} from "@@/apis/kbs/knowledgebase"
|
||||
import { getTableDataApi } from "@@/apis/tables"
|
||||
import { usePagination } from "@@/composables/usePagination"
|
||||
import { CaretRight, Delete, Loading, Plus, Refresh, Search, Setting, View } from "@element-plus/icons-vue"
|
||||
import { CaretRight, Delete, Edit, Loading, Plus, Refresh, Search, Setting, View } from "@element-plus/icons-vue"
|
||||
|
||||
import axios from "axios"
|
||||
import { ElMessage, ElMessageBox } from "element-plus"
|
||||
import { nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, reactive, ref, watch } from "vue"
|
||||
import "element-plus/dist/index.css"
|
||||
import "element-plus/theme-chalk/el-message-box.css"
|
||||
|
||||
import "element-plus/theme-chalk/el-message.css"
|
||||
|
||||
defineOptions({
|
||||
|
@ -88,7 +91,8 @@ const knowledgeBaseForm = reactive({
|
|||
name: "",
|
||||
description: "",
|
||||
language: "Chinese",
|
||||
permission: "me"
|
||||
permission: "me",
|
||||
creator_id: ""
|
||||
})
|
||||
|
||||
// 定义API返回数据的接口
|
||||
|
@ -116,6 +120,9 @@ const knowledgeBaseFormRules = {
|
|||
],
|
||||
description: [
|
||||
{ max: 200, message: "描述不能超过200个字符", trigger: "blur" }
|
||||
],
|
||||
creator_id: [
|
||||
{ required: true, message: "请选择创建人", trigger: "change" }
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -146,6 +153,43 @@ const fileSortData = reactive({
|
|||
sortOrder: "desc" // 默认排序顺序
|
||||
})
|
||||
|
||||
const editDialogVisible = ref(false)
|
||||
const editForm = reactive({
|
||||
id: "",
|
||||
name: "",
|
||||
permission: "me"
|
||||
})
|
||||
const editLoading = ref(false)
|
||||
|
||||
// 处理修改知识库
|
||||
function handleEdit(row: KnowledgeBaseData) {
|
||||
editDialogVisible.value = true
|
||||
editForm.id = row.id
|
||||
editForm.name = row.name
|
||||
editForm.permission = row.permission
|
||||
}
|
||||
|
||||
// 提交修改
|
||||
function submitEdit() {
|
||||
editLoading.value = true
|
||||
// 调用修改知识库API
|
||||
axios.put(`/api/v1/knowledgebases/${editForm.id}`, {
|
||||
permission: editForm.permission
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success("知识库权限修改成功")
|
||||
editDialogVisible.value = false
|
||||
// 刷新知识库列表
|
||||
getTableData()
|
||||
})
|
||||
.catch((error) => {
|
||||
ElMessage.error(`修改知识库权限失败: ${error?.message || "未知错误"}`)
|
||||
})
|
||||
.finally(() => {
|
||||
editLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
// 存储多选的表格数据
|
||||
const multipleSelection = ref<KnowledgeBaseData[]>([])
|
||||
|
||||
|
@ -186,6 +230,31 @@ function resetSearch() {
|
|||
// 打开新建知识库对话框
|
||||
function handleCreate() {
|
||||
createDialogVisible.value = true
|
||||
getUserList() // 获取用户列表
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
function getUserList() {
|
||||
userLoading.value = true
|
||||
// 复用用户管理页面的API
|
||||
getTableDataApi({
|
||||
currentPage: 1,
|
||||
size: 1000, // 获取足够多的用户
|
||||
username: "",
|
||||
email: "",
|
||||
sort_by: "create_date",
|
||||
sort_order: "desc"
|
||||
}).then(({ data }) => {
|
||||
userList.value = data.list.map((user: any) => ({
|
||||
id: user.id,
|
||||
username: user.username
|
||||
}))
|
||||
}).catch(() => {
|
||||
userList.value = []
|
||||
ElMessage.error("获取用户列表失败")
|
||||
}).finally(() => {
|
||||
userLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
// 提交新建知识库
|
||||
|
@ -982,6 +1051,10 @@ function isLoadingStatus(status: string) {
|
|||
function shouldShowProgressCount(status: string) {
|
||||
return !["starting", "not_found"].includes(status)
|
||||
}
|
||||
|
||||
// 用户列表相关状态
|
||||
const userList = ref<{ id: number, username: string }[]>([])
|
||||
const userLoading = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1037,8 +1110,8 @@ function shouldShowProgressCount(status: string) {
|
|||
{{ (paginationData.currentPage - 1) * paginationData.pageSize + scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="知识库名称" align="center" min-width="120" sortable="custom"/>
|
||||
<el-table-column prop="description" label="描述" align="center" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="name" label="知识库名称" align="center" min-width="120" sortable="custom" />
|
||||
<el-table-column prop="description" label="描述" align="center" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="doc_num" label="文档数量" align="center" width="120" />
|
||||
<el-table-column label="语言" align="center" width="100">
|
||||
<template #default="scope">
|
||||
|
@ -1060,7 +1133,7 @@ function shouldShowProgressCount(status: string) {
|
|||
{{ scope.row.create_date }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" label="操作" width="180" align="center">
|
||||
<el-table-column fixed="right" label="操作" width="300" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
|
@ -1072,6 +1145,16 @@ function shouldShowProgressCount(status: string) {
|
|||
>
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
text
|
||||
bg
|
||||
size="small"
|
||||
:icon="Edit"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
text
|
||||
|
@ -1268,6 +1351,22 @@ function shouldShowProgressCount(status: string) {
|
|||
<el-option label="英文" value="English" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建人" prop="creator_id">
|
||||
<el-select
|
||||
v-model="knowledgeBaseForm.creator_id"
|
||||
placeholder="请选择创建人"
|
||||
style="width: 100%"
|
||||
filterable
|
||||
:loading="userLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="user in userList"
|
||||
:key="user.id"
|
||||
:label="user.username"
|
||||
:value="user.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限" prop="permission">
|
||||
<el-select v-model="knowledgeBaseForm.permission" placeholder="请选择权限">
|
||||
<el-option label="个人" value="me" />
|
||||
|
@ -1289,6 +1388,45 @@ function shouldShowProgressCount(status: string) {
|
|||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 修改知识库对话框 -->
|
||||
<el-dialog
|
||||
v-model="editDialogVisible"
|
||||
title="修改知识库权限"
|
||||
width="40%"
|
||||
>
|
||||
<el-form
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="知识库名称">
|
||||
<span>{{ editForm.name }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限设置">
|
||||
<el-select v-model="editForm.permission" placeholder="请选择权限">
|
||||
<el-option label="个人" value="me" />
|
||||
<el-option label="团队" value="team" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="color: #909399; font-size: 12px; line-height: 1.5;">
|
||||
个人权限:仅自己可见和使用<br>
|
||||
团队权限:团队成员可见和使用
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="editDialogVisible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="editLoading"
|
||||
@click="submitEdit"
|
||||
>
|
||||
确认修改
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 文档对话框 -->
|
||||
<el-dialog
|
||||
v-model="addDocumentDialogVisible"
|
||||
|
@ -1314,11 +1452,11 @@ function shouldShowProgressCount(status: string) {
|
|||
{{ formatFileType(scope.row.type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_date" label="创建时间" align="center" width="180" sortable="custom">
|
||||
<template #default="scope">
|
||||
{{ scope.row.create_date }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_date" label="创建时间" align="center" width="180" sortable="custom">
|
||||
<template #default="scope">
|
||||
{{ scope.row.create_date }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页控件 -->
|
||||
|
@ -1554,4 +1692,4 @@ function shouldShowProgressCount(status: string) {
|
|||
vertical-align: middle;
|
||||
animation: rotating 2s linear infinite;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue