Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ui/src/api/API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,16 @@ System 接口由资源管理服务提供;本地开源后端没有对应扩展

### 知识库文档

`workspace/knowledge/document.ts` 同时维护文档启停、删除、召回设置、向量化、分词索引、
任务取消、生成问题、迁移、同步、导出、原文件下载/替换及标签关联。
批量任务沿用 v2 的 `id_list` / `state_list`;生成问题使用 `document_id_list`,
添加标签使用 `document_ids` / `tag_ids`,迁移和批量导出直接提交文档 ID 数组。
向量化、生成问题默认排除成功分段,也可选择全部分段。任务类型使用 `DOCUMENT_TASK_TYPE`。
文档设置的共享载荷为 `DocumentSettingPayload`,生成问题使用 `DocumentGeneratePayload`;
单项设置通过 `meta` 保留来源数据,批量设置将 `allow_download` 放在顶层。
飞书同步沿用 v2 扩展接口 `/knowledge/lark/<knowledgeId>/_batch`,需部署环境支持。
共享文档 API 继续仅提供查询,不增加写入方法。

`workspace/knowledge/document.ts` 维护文档分页查询,路径为
`/workspace/<workspaceId>/knowledge/<knowledgeId>/document/<currentPage>/<pageSize>`。
`putQuickCreateDocuments(knowledgeId, documents)` 通过 PUT `document/batch_create` 创建空白文档,
Expand Down
108 changes: 105 additions & 3 deletions ui/src/api/admin/workspace/knowledge/document.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { get, put } from '../../core/request'
import { del, downloadRequest, get, getExportFile, post, put } from '../../core/request'
import type { ParamsPage, ResponsePage } from '../../core/types'
import type { Dict, DocumentItem, DocumentQuickCreatePayload } from '@/api/types'
import type {
Dict,
DocumentGeneratePayload,
DocumentItem,
DocumentQuickCreatePayload,
DocumentSettingPayload,
DocumentTaskState,
DocumentTaskType,
KnowledgeTagGroup,
} from '@/api/types'
import { getWorkspaceId } from '@/utils/resource-context'

const getPrefix = (knowledgeId: string) => `/workspace/${getWorkspaceId()}/knowledge/${knowledgeId}/document`
Expand All @@ -13,4 +22,97 @@ const getDocumentPage = (knowledgeId: string, page: ParamsPage, query?: Dict<unk
const putQuickCreateDocuments = (knowledgeId: string, documents: DocumentQuickCreatePayload[]) =>
put<DocumentQuickCreatePayload[], DocumentItem[]>(`${getPrefix(knowledgeId)}/batch_create`, documents)

export default { getDocumentPage, putQuickCreateDocuments }
/** 更新文档启用状态。 */
const putDocumentActive = (knowledgeId: string, documentId: string, isActive: boolean) =>
put(`${getPrefix(knowledgeId)}/${documentId}`, { is_active: isActive })

/** 删除单个文档。 */
const deleteDocument = (knowledgeId: string, documentId: string) => del(`${getPrefix(knowledgeId)}/${documentId}`)

/** 批量删除文档。 */
const putBatchDeleteDocuments = (knowledgeId: string, documentIds: string[]) =>
put(`${getPrefix(knowledgeId)}/batch_delete`, { id_list: documentIds })

/** 批量提交文档向量化。 */
const putBatchRefreshDocuments = (knowledgeId: string, documentIds: string[], stateList: DocumentTaskState[]) =>
put(`${getPrefix(knowledgeId)}/batch_refresh`, { id_list: documentIds, state_list: stateList })

/** 批量提交文档分词索引。 */
const putBatchTokenizeDocuments = (knowledgeId: string, documentIds: string[], stateList: DocumentTaskState[]) =>
put(`${getPrefix(knowledgeId)}/batch_tokenize`, { id_list: documentIds, state_list: stateList })

/** 批量取消指定文档任务。 */
const putBatchCancelDocumentTask = (knowledgeId: string, documentIds: string[], taskType: DocumentTaskType) =>
put(`${getPrefix(knowledgeId)}/batch_cancel_task`, { id_list: documentIds, type: taskType })

/** 保存单个文档的召回及来源设置。 */
const putDocumentSetting = (knowledgeId: string, documentId: string, data: DocumentSettingPayload) =>
put(`${getPrefix(knowledgeId)}/${documentId}`, data)

/** 批量保存文档召回设置。 */
const putBatchDocumentSetting = (knowledgeId: string, documentIds: string[], data: DocumentSettingPayload) =>
put(`${getPrefix(knowledgeId)}/batch_hit_handling`, { ...data, id_list: documentIds })

/** 根据文档内容生成关联问题。 */
const putGenerateDocumentQuestions = (knowledgeId: string, data: DocumentGeneratePayload) =>
put(`${getPrefix(knowledgeId)}/batch_generate_related`, data)

/** 将选中文档迁移至目标知识库。 */
const putMigrateDocuments = (knowledgeId: string, targetKnowledgeId: string, documentIds: string[]) =>
put(`${getPrefix(knowledgeId)}/migrate/${targetKnowledgeId}`, documentIds)

/** 同步 Web 文档。 */
const putSyncDocuments = (knowledgeId: string, documentIds: string[]) => put(`${getPrefix(knowledgeId)}/batch_sync`, { id_list: documentIds })

/** 同步飞书文档。 */
const putSyncLarkDocuments = (knowledgeId: string, documentIds: string[]) =>
put(`/workspace/${getWorkspaceId()}/knowledge/lark/${knowledgeId}/_batch`, { id_list: documentIds })

/** 导出所选文档为 Excel 或 ZIP。 */
const exportDocuments = (knowledgeId: string, documentIds: string[], format: 'excel' | 'zip') =>
downloadRequest(`${getPrefix(knowledgeId)}/${format === 'excel' ? 'batch_export' : 'batch_export_zip'}`, 'POST', documentIds)

/** 下载文档原文件。 */
const downloadDocumentSource = (knowledgeId: string, document: DocumentItem) =>
getExportFile(document.name, `${getPrefix(knowledgeId)}/${document.id}/download_source_file`)

/** 替换文档原文件。 */
const postReplaceDocumentSource = (knowledgeId: string, documentId: string, file: File) => {
const data = new FormData()
data.append('file', file)
return post(`${getPrefix(knowledgeId)}/${documentId}/replace_source_file`, data)
}

/** 查询文档当前标签。 */
const getDocumentTags = (knowledgeId: string, documentId: string) => get<KnowledgeTagGroup[]>(`${getPrefix(knowledgeId)}/${documentId}/tags`)

/** 批量添加文档标签。 */
const postAddDocumentTags = (knowledgeId: string, documentIds: string[], tagIds: string[]) =>
post(`${getPrefix(knowledgeId)}/batch_add_tag`, { document_ids: documentIds, tag_ids: tagIds })

/** 移除文档标签关联。 */
const putDeleteDocumentTags = (knowledgeId: string, documentId: string, tagIds: string[]) =>
put(`${getPrefix(knowledgeId)}/${documentId}/tags/batch_delete`, tagIds)

export default {
getDocumentPage,
putQuickCreateDocuments,
putDocumentActive,
deleteDocument,
putBatchDeleteDocuments,
putBatchRefreshDocuments,
putBatchTokenizeDocuments,
putBatchCancelDocumentTask,
putDocumentSetting,
putBatchDocumentSetting,
putGenerateDocumentQuestions,
putMigrateDocuments,
putSyncDocuments,
putSyncLarkDocuments,
exportDocuments,
downloadDocumentSource,
postReplaceDocumentSource,
getDocumentTags,
postAddDocumentTags,
putDeleteDocumentTags,
}
17 changes: 17 additions & 0 deletions ui/src/api/types/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ export interface DocumentQuickCreatePayload {
name: string
}

/** 文档召回及来源设置。 */
export interface DocumentSettingPayload {
hit_handling_method: DocumentHitHandling
directly_return_similarity: number
meta?: Record<string, unknown>
allow_download?: boolean
}

/** 根据文档分段生成问题。 */
export interface DocumentGeneratePayload {
document_id_list: string[]
model_id: string
model_params_setting: Record<string, unknown>
prompt: string
state_list: DocumentTaskState[]
}

/** 文件各任务的分段计数及状态发生时间。 */
export interface DocumentStatusMeta {
aggs?: { status: string | null; count: number }[]
Expand Down
15 changes: 13 additions & 2 deletions ui/src/views/VIEW_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -666,14 +666,25 @@ Workspace API 内部通过 `getWorkspaceId()` 读取当前路由工作空间。
设置页中。当前设置页仅接入 Workspace 路由和 API,暂不增加前端权限判断。
更换向量模型需确认,先保存再重新向量化,整条流程禁止重复提交;向量化失败时保留原模型比较基准,
允许再次保存重试。Web、飞书设置保留未编辑的 `meta` 字段,上传限制使用详情顶层值。
`knowledge-detail/document/index.vue` 仅维护文档列表查询,使用 `MkComplexSearch`、`MkTable`。
`knowledge-detail/document/index.vue` 维护文档列表查询、多选和文档操作,使用 `MkComplexSearch`、`MkTable`。
搜索只提供名称 `name` 和创建者 `create_user`;创建者通过 Workspace `CommonApi.getAllUsers`
加载,支持按 `nick_name` 远程搜索。列表使用 `documentData`、`paginationConfig`、`documentQuery`,
查询方法为 `loadDocuments`,搜索处理为 `handleSearchChange`,搜索变化后回到第一页。
文档页通过 `onMounted` 加载文档列表,创建者选项在展开下拉或输入关键词时通过 `remoteMethod`
按需加载,不在进入页面时预加载;其他列表页的同类创建者筛选遵循相同方式。不额外监听路由重置状态。切换工作空间
整页加载并返回知识库列表;当前知识库与共享资源入口均从其他页面进入,挂载时初始化筛选和分页。
无轮询、排序入口、选择列和文档操作。
无轮询和排序入口。非共享文档显示选择列,按文档 ID 跨页保留选择,搜索或筛选变化时清空;
选中后通过 `footer-batch-actions` 展示批量操作。右侧固定操作列提供启停、向量化、分词索引和更多菜单,
运行或排队中的任务切换为取消入口。Web、飞书提供同步,普通与工作流文档提供原文下载和替换。
单项与批量操作共用页面请求状态,删除和同步先确认,成功后清空选择并刷新,导出和下载保留选择。
文档操作入口与专属弹窗合并放在 `document/components/`:`ButtonDocumentTask` 负责向量化分段范围与生成问题配置,
`ButtonDocumentSetting` 负责召回及来源设置,`ButtonMigrateDocument` 选择目标知识库,
`ButtonDocumentTags` 添加已有标签和移除文档标签关联。组件接收知识库 ID、文档 ID 或文档数组及禁用状态,
点击时快照本次操作对象,内部管理弹窗和请求,成功后通过 `refresh` 通知页面刷新,失败保留输入。
任务组件通过 `action` 区分向量化与生成问题,通过 `batch` 切换批量按钮;行内入口使用 `display` 区分菜单与图标按钮。
设置组件通过 `batch` 区分单项与批量,标签组件通过 `manageTags` 区分标签管理与批量添加。
页面不再维护这些弹窗 Ref 和打开方法;承载入口的 `MkTableMoreDropdown` 使用 `persistent`,避免菜单收起时卸载弹窗。
不新增前端权限判断;共享文档不展示选择列及操作入口。
文档分页接口维护在 `workspace/knowledge/document.ts`,页面管理 loading。文件状态表头使用
`MkDropdown` 单选筛选全部、成功、失败、索引中、分词索引中、排队中和生成中;查询组合
`status` 与可选的 `task_type`,切换选项清除旧任务类型并回到第一页,保留名称和创建者条件。
Expand Down
92 changes: 45 additions & 47 deletions ui/src/views/home/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,54 +41,52 @@ watch(
)
</script>
<template>
<el-scrollbar class="h-full">
<div class="px-6 py-4">
<!-- 快捷创建 -->
<h4 class="mb-4">快捷创建</h4>
<HomeQuickCreate :workspace-id="workspaceId" />
<!-- 资源 -->
<h4 class="mb-4 mt-4">资源</h4>
<HomeResourceOverview :api="HomepageApi" :workspace-id="workspaceId" />
<!-- 监控 -->
<HomeStatistics class="mt-4" :workspace-id="workspaceId" :application-id="applicationId" :api="HomepageApi">
<template #application="{ loading }">
<el-select
v-model="applicationId"
filterable
remote
fit-input-width
class="w-55!"
:remote-method="loadApplications"
:loading="applicationsLoading"
:disabled="loading"
@change="handleApplicationChange"
>
<el-option label="全部智能体" value="all">
<MkViewLayout title="">
<!-- 快捷创建 -->
<h4 class="mb-4 mt-4">快捷创建</h4>
<HomeQuickCreate :workspace-id="workspaceId" />
<!-- 资源 -->
<h4 class="mb-4 mt-4">资源</h4>
<HomeResourceOverview :api="HomepageApi" :workspace-id="workspaceId" />
<!-- 监控 -->
<HomeStatistics class="mt-4" :workspace-id="workspaceId" :application-id="applicationId" :api="HomepageApi">
<template #application="{ loading }">
<el-select
v-model="applicationId"
filterable
remote
fit-input-width
class="w-55!"
:remote-method="loadApplications"
:loading="applicationsLoading"
:disabled="loading"
@change="handleApplicationChange"
>
<el-option label="全部智能体" value="all">
<div class="flex-align-center gap-2">
<MkIcon name="icon_card_outlined" :size="20" class="shrink-0 text-N600" />
<span>全部智能体</span>
</div>
</el-option>
<template v-for="application in applications" :key="application.id">
<el-option :label="application.name" :value="application.id">
<div class="flex-align-center gap-2">
<MkIcon name="icon_card_outlined" :size="20" class="shrink-0 text-N600" />
<span>全部智能体</span>
<ApplicationIcon :icon="application.icon" :size="20" class="shrink-0" />
<span class="truncate" :title="application.name">{{ application.name }}</span>
</div>
</el-option>
<template v-for="application in applications" :key="application.id">
<el-option :label="application.name" :value="application.id">
<div class="flex-align-center gap-2">
<ApplicationIcon :icon="application.icon" :size="20" class="shrink-0" />
<span class="truncate" :title="application.name">{{ application.name }}</span>
</div>
</el-option>
</template>
<template #label="{ label, value }">
<div class="flex-align-center gap-2">
<MkIcon v-if="value === 'all'" name="icon_card_outlined" :size="18" class="shrink-0" />
<ApplicationIcon v-else :icon="selectedApplication?.icon" :size="18" class="shrink-0" />
<span class="truncate" :title="label">{{ label }}</span>
</div>
</template>
</el-select>
</template>
</HomeStatistics>
<!-- 排行榜 TOP5 -->
<HomeRankings class="mt-4" :workspace-id="workspaceId" :api="HomepageApi" />
</div>
</el-scrollbar>
</template>
<template #label="{ label, value }">
<div class="flex-align-center gap-2">
<MkIcon v-if="value === 'all'" name="icon_card_outlined" :size="18" class="shrink-0" />
<ApplicationIcon v-else :icon="selectedApplication?.icon" :size="18" class="shrink-0" />
<span class="truncate" :title="label">{{ label }}</span>
</div>
</template>
</el-select>
</template>
</HomeStatistics>
<!-- 排行榜 TOP5 -->
<HomeRankings class="mt-4" :workspace-id="workspaceId" :api="HomepageApi" />
</MkViewLayout>
</template>
Loading
Loading