feat: govern knowledge assets and source citations
This commit is contained in:
@@ -217,7 +217,14 @@
|
||||
</view>
|
||||
|
||||
<view v-if="msg.citationsOpen && msg.result.snippets?.length" class="bubble-citations">
|
||||
<view v-for="(snippet, index) in msg.result.snippets" :key="`${snippet.docTitle}-${index}`" class="citation">
|
||||
<component
|
||||
:is="snippet.detailRef && snippet.sourceType === 'DOCUMENT' ? 'button' : 'view'"
|
||||
v-for="(snippet, index) in msg.result.snippets"
|
||||
:key="`${snippet.docTitle}-${index}`"
|
||||
class="citation"
|
||||
:class="{ 'citation-action': Boolean(snippet.detailRef && snippet.sourceType === 'DOCUMENT') }"
|
||||
@click="openCitationDetail(snippet)"
|
||||
>
|
||||
<text class="citation-domain" :class="{ project: snippet.domain === 'PROJECT_SERVICE' }">
|
||||
{{ citationDomainLabel(snippet) }}
|
||||
</text>
|
||||
@@ -227,8 +234,11 @@
|
||||
</text>
|
||||
<text v-else-if="snippet.spaceCode" class="citation-meta">知识空间:{{ snippet.spaceCode }}</text>
|
||||
<text class="citation-content">{{ snippetExcerpt(snippet.content) }}</text>
|
||||
<text v-if="snippet.fragmentId" class="citation-meta">片段 #{{ snippet.fragmentId }}</text>
|
||||
</view>
|
||||
<view v-if="snippet.detailRef && snippet.sourceType === 'DOCUMENT'" class="citation-open-row">
|
||||
<text class="citation-location">{{ citationLocationLabel(snippet) }}</text>
|
||||
<text class="citation-open">查看出处 ›</text>
|
||||
</view>
|
||||
</component>
|
||||
</view>
|
||||
|
||||
<view v-if="msg.voiceStatus !== 'unavailable'" class="transcript-collapse" @click="collapseTranscript(msg)">
|
||||
@@ -1304,6 +1314,28 @@ const serviceMemoryStatusLabel = (status?: string | null) => ({
|
||||
|
||||
const displayCitationDate = (value?: string | null) => value ? value.replace('T', ' ').slice(0, 16) : '未记录';
|
||||
|
||||
const formatCitationTime = (milliseconds?: number | null) => {
|
||||
if (typeof milliseconds !== 'number' || milliseconds < 0) return '';
|
||||
const seconds = Math.floor(milliseconds / 1000);
|
||||
return `${String(Math.floor(seconds / 60)).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
const citationLocationLabel = (snippet: KnowledgeSearchResponse['snippets'][number]) => {
|
||||
const locator = snippet.locatorSummary;
|
||||
const at = locator?.frameMs ?? locator?.startMs;
|
||||
if (snippet.mediaType === 'VIDEO' && typeof at === 'number') return `视频 ${formatCitationTime(at)}`;
|
||||
if (locator?.pageNumber) return `第 ${locator.pageNumber} 页`;
|
||||
if (locator?.slideNumber) return `第 ${locator.slideNumber} 页`;
|
||||
if (locator?.sheetName && locator?.rowStart) return `${locator.sheetName} · 第 ${locator.rowStart} 行`;
|
||||
if (locator?.paragraphStart) return `第 ${locator.paragraphStart} 段`;
|
||||
return snippet.mediaType === 'IMAGE' ? '原图' : '来源全文';
|
||||
};
|
||||
|
||||
const openCitationDetail = (snippet: KnowledgeSearchResponse['snippets'][number]) => {
|
||||
if (!snippet.detailRef || snippet.sourceType !== 'DOCUMENT') return;
|
||||
uni.navigateTo({ url: `/pages/user/sop/citation-detail?ref=${encodeURIComponent(snippet.detailRef)}` });
|
||||
};
|
||||
|
||||
const noEvidenceText = (result: KnowledgeSearchResponse) => {
|
||||
if (result.agentIntent === 'WEB_RESEARCH') return '公开网络中没有找到可核验来源。';
|
||||
if (result.agentIntent === 'MEDIA_UNDERSTANDING') return '已分析附件,但当前资料中没有补充依据。';
|
||||
@@ -1354,6 +1386,7 @@ const feedback = async (verdict: AnswerFeedbackVerdict, msg: MasterMsg) => {
|
||||
try {
|
||||
await submitAnswerFeedback({
|
||||
queryText: msg.result.queryText || '',
|
||||
requestId: msg.result.requestId,
|
||||
fragmentIds,
|
||||
verdict,
|
||||
reviewId: msg.result.reviewId,
|
||||
@@ -3253,6 +3286,31 @@ onUnload(() => {
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.citation-action {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-left: 3px solid #d3132a;
|
||||
text-align: left;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.citation-action::after { border: 0; }
|
||||
|
||||
.citation-open-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-top: 8px;
|
||||
padding-top: 7px;
|
||||
border-top: 1px solid #e8ebef;
|
||||
}
|
||||
|
||||
.citation-location { color: #697586; font-size: 12px; }
|
||||
.citation-open { color: #c90018; font-size: 12px; font-weight: 700; }
|
||||
|
||||
.citation-title {
|
||||
display: block;
|
||||
color: #232a33;
|
||||
|
||||
Reference in New Issue
Block a user