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
2 changes: 1 addition & 1 deletion ui/src/api/API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ Workspace 共享 Paragraph API 仅 getParagraphPage、getParagraphDetail,不
Workspace、System 资源管理、System 共享提供完整问题 API:
`postProblems` 直接提交内容字符串数组,`putProblem` 提交 `{ content }`,单项 DELETE 使用问题 ID,
`putBatchDeleteProblems` 直接提交问题 ID 数组;单个问题内容最多 256 字符。
`getProblemParagraphs` 返回 `ProblemParagraph[]`,包含分段字段及 knowledge_id、document_name。
`getProblemDetail` 返回 `ProblemParagraph[]`,包含分段字段及 knowledge_id、document_name。
取消关联复用 Paragraph API 的 `putUnassociateParagraphProblem`,不调用问题或分段删除接口。
Workspace 共享仅有 `getProblemsPage`,不补造详情或写接口,不回退其他范围。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const putProblem = (knowledgeId: string, problemId: string, content: string) =>
/** 删除单个知识库问题。 */
const deleteProblem = (knowledgeId: string, problemId: string) => del<undefined, boolean>(`${getPrefix(knowledgeId)}/${problemId}`)

/** 获取问题当前关联的文档分段。 */
const getProblemParagraphs = (knowledgeId: string, problemId: string) => get<ProblemParagraph[]>(`${getPrefix(knowledgeId)}/${problemId}/paragraph`)
/** 获取问题详情,返回当前关联的文档分段。 */
const getProblemDetail = (knowledgeId: string, problemId: string) => get<ProblemParagraph[]>(`${getPrefix(knowledgeId)}/${problemId}/paragraph`)

/** 批量将问题关联到指定文档分段。 */
const putBatchAssociateProblems = (knowledgeId: string, payload: ProblemBatchAssociationPayload) =>
Expand All @@ -34,7 +34,7 @@ export default {
getProblemsPage,
putProblem,
deleteProblem,
getProblemParagraphs,
getProblemDetail,
putBatchAssociateProblems,
putBatchDeleteProblems,
}
6 changes: 3 additions & 3 deletions ui/src/api/admin/system/shared-resources/knowledge/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const putProblem = (knowledgeId: string, problemId: string, content: string) =>
/** 删除单个知识库问题。 */
const deleteProblem = (knowledgeId: string, problemId: string) => del<undefined, boolean>(`${getPrefix(knowledgeId)}/${problemId}`)

/** 获取问题当前关联的文档分段。 */
const getProblemParagraphs = (knowledgeId: string, problemId: string) => get<ProblemParagraph[]>(`${getPrefix(knowledgeId)}/${problemId}/paragraph`)
/** 获取问题详情,返回当前关联的文档分段。 */
const getProblemDetail = (knowledgeId: string, problemId: string) => get<ProblemParagraph[]>(`${getPrefix(knowledgeId)}/${problemId}/paragraph`)

/** 批量将问题关联到指定文档分段。 */
const putBatchAssociateProblems = (knowledgeId: string, payload: ProblemBatchAssociationPayload) =>
Expand All @@ -34,7 +34,7 @@ export default {
getProblemsPage,
putProblem,
deleteProblem,
getProblemParagraphs,
getProblemDetail,
putBatchAssociateProblems,
putBatchDeleteProblems,
}
6 changes: 3 additions & 3 deletions ui/src/api/admin/workspace/knowledge/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const putProblem = (knowledgeId: string, problemId: string, content: string) =>
/** 删除单个知识库问题。 */
const deleteProblem = (knowledgeId: string, problemId: string) => del<undefined, boolean>(`${getPrefix(knowledgeId)}/${problemId}`)

/** 获取问题当前关联的文档分段。 */
const getProblemParagraphs = (knowledgeId: string, problemId: string) => get<ProblemParagraph[]>(`${getPrefix(knowledgeId)}/${problemId}/paragraph`)
/** 获取问题详情,返回当前关联的文档分段。 */
const getProblemDetail = (knowledgeId: string, problemId: string) => get<ProblemParagraph[]>(`${getPrefix(knowledgeId)}/${problemId}/paragraph`)

/** 批量将问题关联到指定文档分段。 */
const putBatchAssociateProblems = (knowledgeId: string, payload: ProblemBatchAssociationPayload) =>
Expand All @@ -35,7 +35,7 @@ export default {
getProblemsPage,
putProblem,
deleteProblem,
getProblemParagraphs,
getProblemDetail,
putBatchAssociateProblems,
putBatchDeleteProblems,
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ export const systemResourceKnowledgeRoutes: RouteRecordRaw[] = [
meta: { title: '召回测试', order: 10 },
},
{
path: 'question',
name: 'system-resource-knowledge-question',
component: () => import('@/views/knowledge-detail/question/index.vue'),
path: 'problem',
name: 'system-resource-knowledge-problem',
component: () => import('@/views/knowledge-detail/problem/index.vue'),
meta: { title: '问题', order: 20 },
},
{
Expand Down
6 changes: 3 additions & 3 deletions ui/src/router/admin/system/modules/knowledge-system-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ export const systemSharedKnowledgeRoutes: RouteRecordRaw[] = [
meta: { title: '召回测试', order: 10 },
},
{
path: 'question',
name: 'system-shared-knowledge-question',
component: () => import('@/views/knowledge-detail/question/index.vue'),
path: 'problem',
name: 'system-shared-knowledge-problem',
component: () => import('@/views/knowledge-detail/problem/index.vue'),
meta: { title: '问题', order: 20 },
},
{
Expand Down
6 changes: 3 additions & 3 deletions ui/src/router/admin/workspace/modules/knowledge-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ export const sharedKnowledgeRoutes: RouteRecordRaw[] = [
meta: { title: '召回测试', order: 10 },
},
{
path: 'question',
name: 'workspace-shared-knowledge-question',
component: () => import('@/views/knowledge-detail/question/index.vue'),
path: 'problem',
name: 'workspace-shared-knowledge-problem',
component: () => import('@/views/knowledge-detail/problem/index.vue'),
meta: { title: '问题', order: 20 },
},
{
Expand Down
10 changes: 5 additions & 5 deletions ui/src/router/admin/workspace/modules/knowledge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const knowledgeRoutes: RouteRecordRaw[] = [
meta: { title: '工作流', icon: 'icon_ticket-flow_outlined', order: 20 },
},
{
path: 'retrieval',
path: '',
name: 'workspace-knowledge-retrieval',
redirect: { name: 'workspace-knowledge-hit-test' },
meta: { title: '检索优化', icon: 'icon_trace_outlined', order: 30 },
Expand All @@ -77,9 +77,9 @@ export const knowledgeRoutes: RouteRecordRaw[] = [
meta: { title: '召回测试', order: 10 },
},
{
path: 'question',
name: 'workspace-knowledge-question',
component: () => import('@/views/knowledge-detail/question/index.vue'),
path: 'problem',
name: 'workspace-knowledge-problem',
component: () => import('@/views/knowledge-detail/problem/index.vue'),
meta: { title: '问题', order: 20 },
},
{
Expand All @@ -91,7 +91,7 @@ export const knowledgeRoutes: RouteRecordRaw[] = [
],
},
{
path: 'integration',
path: '',
name: 'workspace-knowledge-integration',
redirect: { name: 'workspace-knowledge-chat-user' },
meta: { title: '授权与集成', icon: 'icon_personal-privacy_outlined', order: 40 },
Expand Down
3 changes: 1 addition & 2 deletions ui/src/views/document-detail/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,6 @@ onMounted(() => {
</div>
</el-card>
</div>
<h4 class="mb-2 pr-44">{{ paragraph.title || '-' }}</h4>

<!-- 选择批量操作的分段 -->
<el-checkbox
v-if="batchMode"
Expand All @@ -431,6 +429,7 @@ onMounted(() => {
@change="(selected: boolean | string | number) => handleSelectBatchParagraph(paragraph.id, Boolean(selected))"
/>

<h4 class="mb-2 pr-44">{{ paragraph.title || '-' }}</h4>
<MdPreview :model-value="paragraph.content" />
<p class="mt-2 text-sm text-N600">{{ paragraph.content.length }} 字符</p>
</el-card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import type MkViewLayout from '@/components/global/mk-view-layout/index.vue'
import MkSearchList from '@/components/mk-search-list/index.vue'
import type { ParamsPage } from '@/api/admin/core/types'
import { DOCUMENT_RESOURCE_TYPE } from '@/api/enums'
import type { DocumentItem, DocumentResourceType, ParagraphItem, ProblemParagraph, ProblemParagraphReference } from '@/api/types'
import type { DocumentItem, DocumentResourceType, ParagraphItem, ProblemParagraphReference } from '@/api/types'
import { getFileUrl } from '@/utils/common'
import { getFileIconUrl } from '@/utils/icon'
import { MsgSuccess } from '@/utils/message'
import { useKnowledgeDetailContext } from '@/views/knowledge-detail/context'
import ParagraphDialog from '@/views/document-detail/paragraph-dialog/ParagraphDialog.vue'

defineOptions({ name: 'AssociateProblemParagraphDialog' })
defineOptions({ name: 'AssociateParagraphDialog' })
const emit = defineEmits<{ success: [] }>()
const { knowledgeId, resourceApi } = useKnowledgeDetailContext({ resourceScopes: ['workspace', 'system-resource', 'system-shared'] as const })

const visible = ref(false)
const documentLoading = ref(false)
const operationLoading = ref(false)
const problemIds = ref<string[]>([])
const documents = ref<DocumentItem[]>([])
const documentData = ref<DocumentItem[]>([])
const resourceType = ref<DocumentResourceType>(DOCUMENT_RESOURCE_TYPE.DOCUMENT)
const documentSearchText = ref('')
const selectedDocumentId = ref('')
Expand All @@ -32,7 +32,7 @@ const paragraphLayoutRef = useTemplateRef<InstanceType<typeof MkViewLayout>>('pa
const paragraphDialogRef = useTemplateRef<InstanceType<typeof ParagraphDialog>>('paragraphDialogRef')

const isBatchAssociation = computed(() => problemIds.value.length > 1)
const selectedDocument = computed(() => documents.value.find(({ id }) => id === selectedDocumentId.value))
const selectedDocument = computed(() => documentData.value.find(({ id }) => id === selectedDocumentId.value))
const selectedParagraphIds = computed(() => new Set(selectedParagraphs.value.map(({ paragraph_id }) => paragraph_id)))

function getSelectedCount(documentId: string) {
Expand All @@ -45,14 +45,14 @@ function isSelected(paragraphId: string) {

function loadDocuments() {
paragraphLayoutRef.value?.setScrollTop(0)
documents.value = []
documentData.value = []
selectedDocumentId.value = ''
documentSearchText.value = ''
paragraphSearchText.value = ''
paragraphs.value = []
return resourceApi.document.getAllDocuments(knowledgeId.value, { resource_type: resourceType.value }).then((documentList) => {
documents.value = documentList
selectedDocumentId.value = documentList[0]?.id ?? ''
return resourceApi.document.getAllDocuments(knowledgeId.value, { resource_type: resourceType.value }).then((documentRecords) => {
documentData.value = documentRecords
selectedDocumentId.value = documentRecords[0]?.id ?? ''
})
}

Expand Down Expand Up @@ -152,34 +152,21 @@ function handleParagraphDialogClosed() {
const problemId = problemIds.value[0]
if (isBatchAssociation.value || !problemId) return
// 分段详情可修改问题关联,关闭后重新读取当前问题的关联状态。
void resourceApi.problem.getProblemParagraphs(knowledgeId.value, problemId).then((associatedParagraphs) => {
void resourceApi.problem.getProblemDetail(knowledgeId.value, problemId).then((associatedParagraphs) => {
selectedParagraphs.value = associatedParagraphs.map(({ id, document_id }) => ({ paragraph_id: id, document_id }))
})
}

function handleClosed() {
problemIds.value = []
documents.value = []
documentSearchText.value = ''
selectedDocumentId.value = ''
paragraphSearchText.value = ''
paragraphs.value = []
selectedParagraphs.value = []
detailParagraph.value = undefined
}

function open(targetProblemIds: string[]) {
if (visible.value || operationLoading.value || !targetProblemIds.length) return
const problemId = targetProblemIds[0]
if (!problemId) return
if (visible.value || operationLoading.value || !targetProblemIds[0]) return
problemIds.value = [...targetProblemIds]
resourceType.value = DOCUMENT_RESOURCE_TYPE.DOCUMENT
visible.value = true
documentLoading.value = true
// TODO(图片联调):确认已关联分段查询包含图片分段,并返回 id、document_id,供选中态和关联数量回显。
const associatedParagraphs =
targetProblemIds.length === 1 ? resourceApi.problem.getProblemParagraphs(knowledgeId.value, problemId) : Promise.resolve<ProblemParagraph[]>([])
return Promise.all([loadDocuments(), associatedParagraphs])
return Promise.all([
loadDocuments(),
// TODO(图片联调):确认已关联分段查询包含图片分段,并返回 id、document_id,供选中态和关联数量回显。
targetProblemIds.length === 1 ? resourceApi.problem.getProblemDetail(knowledgeId.value, targetProblemIds[0]) : [],
])
.then(([, problemParagraphs]) => {
selectedParagraphs.value = problemParagraphs.map(({ id, document_id }) => ({ paragraph_id: id, document_id }))
})
Expand All @@ -191,6 +178,18 @@ function open(targetProblemIds: string[]) {
})
}

function handleClosed() {
problemIds.value = []
documentData.value = []
documentSearchText.value = ''
selectedDocumentId.value = ''
paragraphSearchText.value = ''
paragraphs.value = []
selectedParagraphs.value = []
detailParagraph.value = undefined
resourceType.value = DOCUMENT_RESOURCE_TYPE.DOCUMENT
}

defineExpose({ open })
</script>

Expand All @@ -215,7 +214,7 @@ defineExpose({ open })
<!-- 搜索并切换候选分段所在资源 -->
<MkSearchList
v-model="documentSearchText"
:data="documents"
:data="documentData"
:default-active="selectedDocumentId"
:empty-text="resourceType === DOCUMENT_RESOURCE_TYPE.IMAGE ? '暂无图片' : '暂无文档'"
@click="handleSelectDocument"
Expand Down Expand Up @@ -261,11 +260,8 @@ defineExpose({ open })
:class="{ active: isSelected(paragraph.id), disabled: operationLoading }"
@click="handleOpenParagraphDetail(paragraph)"
>
<h4 class="mb-2 truncate" :title="paragraph.title || '-'">{{ paragraph.title || '-' }}</h4>
<p class="mb-3 line-clamp-2 break-words">{{ paragraph.content }}</p>
<span class="text-sm text-N500">{{ paragraph.content.length }} 字符</span>
<!-- 关联当前问题与分段 -->
<MkTooltip v-if="!isSelected(paragraph.id)" content="关联" placement="top">
<!-- 关联当前问题与分段 -->
<el-button
circle
class="group-hover-visible absolute top-2 right-2 shadow-md"
Expand All @@ -275,8 +271,8 @@ defineExpose({ open })
<MkIcon name="icon_link-record_outlined" />
</el-button>
</MkTooltip>
<!-- 取消当前问题与分段的关联 -->
<MkTooltip v-else-if="!isBatchAssociation" content="取消关联" placement="top">
<!-- 取消当前问题与分段的关联 -->
<el-button
circle
class="group-hover-visible absolute top-2 right-2 shadow-md"
Expand All @@ -286,6 +282,10 @@ defineExpose({ open })
<MkIcon name="icon_unlink_outlined" />
</el-button>
</MkTooltip>
<h4 class="mb-2">{{ paragraph.title || '-' }}</h4>

<MdPreview :model-value="paragraph.content" />
<p class="mt-2 text-sm text-N600">{{ paragraph.content.length }} 字符</p>
</el-card>
</template>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const paragraphDialogRef = ref<InstanceType<typeof ParagraphDialog>>()
function loadParagraphs() {
loadFailed.value = false
return (
resourceApi.problem.getProblemParagraphs?.(knowledgeId.value, problem.value.id).then((records) => {
resourceApi.problem.getProblemDetail?.(knowledgeId.value, problem.value.id).then((records) => {
paragraphs.value = records
problem.value.paragraph_count = records.length
}) ?? Promise.resolve()
Expand Down Expand Up @@ -114,14 +114,6 @@ watch(
<template v-for="paragraph in paragraphs" :key="paragraph.id">
<!-- 查看关联分段详情 -->
<el-card class="mk-paragraph-card group relative cursor-pointer" shadow="never" @click="handleOpenParagraph(paragraph)">
<h4 class="mb-2 truncate pr-8" :title="paragraph.title || '-'">{{ paragraph.title || '-' }}</h4>
<p class="mb-3 line-clamp-2 break-words" :title="paragraph.content">{{ paragraph.content }}</p>
<div class="flex-align-center gap-2 text-sm text-N500">
<span class="shrink-0">{{ paragraph.content.length }} 字符</span>
<el-divider direction="vertical" />
<img :src="getFileIconUrl(paragraph.document_name)" class="size-4 shrink-0" alt="" />
<span class="truncate" :title="paragraph.document_name">{{ paragraph.document_name }}</span>
</div>
<!-- 取消当前问题与分段的关联,不删除分段 -->
<MkTooltip content="取消关联" placement="top">
<el-button
Expand All @@ -133,6 +125,15 @@ watch(
<MkIcon name="icon_unlink_outlined" />
</el-button>
</MkTooltip>

<h4 class="mb-2">{{ paragraph.title || '-' }}</h4>
<MdPreview :model-value="paragraph.content" />
<div class="flex-align-center gap-2 text-sm text-N600">
<span class="shrink-0">{{ paragraph.content.length }} 字符</span>
<el-divider direction="vertical" />
<img :src="getFileIconUrl(paragraph.document_name)" class="size-4 shrink-0" alt="" />
<span class="truncate" :title="paragraph.document_name">{{ paragraph.document_name }}</span>
</div>
</el-card>
</template>
</div>
Expand Down
Loading
Loading