feat: persist cleaned question insights
This commit is contained in:
@@ -927,7 +927,26 @@ async function resetChatFilters() {
|
||||
|
||||
async function searchQuestionInsights() {
|
||||
pagers.questionInsights.page = 1;
|
||||
await loadRecordTab("questionInsights");
|
||||
loading.value = true;
|
||||
try {
|
||||
const refresh = await api.refreshQuestionInsights({
|
||||
dateFrom: formatRecordDateTime(questionInsightFilters.dateFrom, "start"),
|
||||
dateTo: formatRecordDateTime(questionInsightFilters.dateTo, "end"),
|
||||
maxMessages: questionInsightFilters.maxMessages,
|
||||
});
|
||||
await loadQuestionInsights(1, pagers.questionInsights.pageSize);
|
||||
if (refresh.processedMessages > 0) {
|
||||
ElMessage.success(
|
||||
`新增清洗 ${refresh.processedMessages} 条消息,得到 ${refresh.acceptedQuestions} 个有效问题${refresh.hasMore ? ";仍有历史消息待清洗" : ""}`,
|
||||
);
|
||||
} else {
|
||||
ElMessage.success("没有新增消息,已直接使用持久化清洗结果统计");
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : "问题洞察刷新失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function resetQuestionInsightFilters() {
|
||||
@@ -1555,17 +1574,17 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
<el-input-number v-model="questionInsightFilters.minCount" :min="1" :max="50" controls-position="right" />
|
||||
</label>
|
||||
<label class="insight-number-field">
|
||||
<span>最多扫描</span>
|
||||
<span>单次清洗上限</span>
|
||||
<el-input-number v-model="questionInsightFilters.maxMessages" :min="100" :max="20000" :step="500" controls-position="right" />
|
||||
</label>
|
||||
<div class="record-filter-actions">
|
||||
<el-button type="primary" @click="searchQuestionInsights">统计问题</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="searchQuestionInsights">刷新并统计</el-button>
|
||||
<el-button @click="resetQuestionInsightFilters">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="question-insight-help">一期先对用户消息做去噪、拆问、同义词归一和相似问法合并;后续可把清洗后的结果交给大模型做更细的主题命名。</p>
|
||||
<p class="question-insight-help">清洗结果会持久化保存;点击“刷新并统计”只处理尚未清洗的用户消息,再按当前时间范围聚合,翻页不会重新扫描聊天原文。</p>
|
||||
<section v-if="questionInsights" class="question-insight-summary">
|
||||
<div><span>扫描用户消息</span><strong>{{ questionInsights.summary.scannedMessages }}</strong></div>
|
||||
<div><span>纳入清洗消息</span><strong>{{ questionInsights.summary.scannedMessages }}</strong></div>
|
||||
<div><span>有效问题</span><strong>{{ questionInsights.summary.cleanedQuestions }}</strong></div>
|
||||
<div><span>过滤低价值</span><strong>{{ questionInsights.summary.filteredMessages }}</strong></div>
|
||||
<div><span>高频问题组</span><strong>{{ questionInsights.summary.visibleClusterCount }}</strong></div>
|
||||
|
||||
@@ -32,6 +32,7 @@ import type {
|
||||
PeriodicReportRecord,
|
||||
PromptDetail,
|
||||
PromptHistoryItem,
|
||||
QuestionInsightRefreshResult,
|
||||
QuestionInsightSummary,
|
||||
} from "../types/api";
|
||||
|
||||
@@ -230,6 +231,10 @@ export const api = {
|
||||
operationLogs: (query: { module?: string; page?: number; pageSize?: number } = {}) => request<PageResult<Record<string, unknown>>>(`/admin/log/list${queryString(query)}`),
|
||||
questionInsights: (query: { dateFrom?: string; dateTo?: string; minCount?: number; maxMessages?: number; page?: number; pageSize?: number } = {}) =>
|
||||
request<QuestionInsightSummary>(`/admin/question-insights/summary${queryString(query)}`),
|
||||
refreshQuestionInsights: (query: { dateFrom?: string; dateTo?: string; maxMessages?: number } = {}) =>
|
||||
request<QuestionInsightRefreshResult>(`/admin/question-insights/refresh${queryString(query)}`, {
|
||||
method: "POST",
|
||||
}),
|
||||
retrievalLogs: (query: { page?: number; pageSize?: number } = {}) => request<PageResult<RetrievalLogItem>>(`/admin/retrieval-log/list${queryString(query)}`),
|
||||
estimateRetrievalCleanup: (before: string) => request<{ before: string; estimatedCount: number }>("/admin/retrieval-log/cleanup/estimate", { method: "POST", body: JSON.stringify({ before }) }),
|
||||
cleanupRetrievalLogs: (before: string) => request<{ before: string; deleted: number }>("/admin/retrieval-log/cleanup", { method: "POST", body: JSON.stringify({ before }) }),
|
||||
|
||||
@@ -556,6 +556,7 @@ export interface QuestionInsightSummary {
|
||||
clusterCount: number;
|
||||
visibleClusterCount: number;
|
||||
minCount: number;
|
||||
cleanerVersion: string;
|
||||
};
|
||||
items: QuestionInsightCluster[];
|
||||
total: number;
|
||||
@@ -563,6 +564,15 @@ export interface QuestionInsightSummary {
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
export interface QuestionInsightRefreshResult {
|
||||
processedMessages: number;
|
||||
acceptedQuestions: number;
|
||||
filteredMessages: number;
|
||||
concurrentSkips: number;
|
||||
hasMore: boolean;
|
||||
cleanerVersion: string;
|
||||
}
|
||||
|
||||
export interface QuestionInsightCluster {
|
||||
rank: number;
|
||||
title: string;
|
||||
|
||||
Reference in New Issue
Block a user