mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-04-27 15:29:49 +08:00
feat: 移除自定义筛选的AI功能
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 自定义筛选 Tab
|
||||
* 用于精准提取聊天记录上下文,供 AI 分析使用
|
||||
* 用于精准提取聊天记录上下文
|
||||
*
|
||||
* 支持两种互斥的筛选模式:
|
||||
* 1. 条件筛选:按关键词、时间、发送者筛选,并自动扩展上下文
|
||||
@@ -18,7 +18,6 @@ import ConditionPanel from './ConditionPanel.vue'
|
||||
import SessionPanel from './SessionPanel.vue'
|
||||
import PreviewPanel from './PreviewPanel.vue'
|
||||
import FilterHistory from './FilterHistory.vue'
|
||||
import LocalAnalysisModal from './LocalAnalysisModal.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -88,28 +87,10 @@ const filterResult = ref<{
|
||||
const isFiltering = ref(false)
|
||||
const isLoadingMore = ref(false)
|
||||
const showHistory = ref(false)
|
||||
const showAnalysisModal = ref(false)
|
||||
|
||||
// 每页块数
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
// 估算 Token 数
|
||||
// 中文:1 字符 ≈ 1.5 token(因为中文分词后每个字符可能产生 1-2 个 token)
|
||||
// 考虑到消息格式(时间、发送人等),使用 1.5 作为估算系数
|
||||
const estimatedTokens = computed(() => {
|
||||
if (!filterResult.value) return 0
|
||||
return Math.ceil(filterResult.value.stats.totalChars * 1.5)
|
||||
})
|
||||
|
||||
// Token 状态:green < 50000, yellow 50000-100000, red > 100000
|
||||
// (基于大多数模型的上下文窗口大小)
|
||||
const tokenStatus = computed(() => {
|
||||
const tokens = estimatedTokens.value
|
||||
if (tokens < 50000) return 'green'
|
||||
if (tokens < 100000) return 'yellow'
|
||||
return 'red'
|
||||
})
|
||||
|
||||
// 是否可以执行筛选
|
||||
const canExecuteFilter = computed(() => {
|
||||
if (isFiltering.value) return false
|
||||
@@ -324,12 +305,6 @@ async function exportFeedPack() {
|
||||
}
|
||||
}
|
||||
|
||||
// 打开本地 AI 分析
|
||||
function openLocalAnalysis() {
|
||||
if (!filterResult.value || filterResult.value.blocks.length === 0) return
|
||||
showAnalysisModal.value = true
|
||||
}
|
||||
|
||||
// 切换模式时清空结果
|
||||
watch(filterMode, () => {
|
||||
filterResult.value = null
|
||||
@@ -423,8 +398,6 @@ function loadHistoryCondition(condition: {
|
||||
:result="filterResult"
|
||||
:is-loading="isFiltering"
|
||||
:is-loading-more="isLoadingMore"
|
||||
:estimated-tokens="estimatedTokens"
|
||||
:token-status="tokenStatus"
|
||||
@load-more="loadMoreBlocks"
|
||||
/>
|
||||
|
||||
@@ -457,9 +430,6 @@ function loadHistoryCondition(condition: {
|
||||
>
|
||||
{{ t('analysis.filter.export') }}
|
||||
</UButton>
|
||||
<UButton color="primary" icon="i-heroicons-sparkles" @click="openLocalAnalysis">
|
||||
{{ t('analysis.filter.localAnalysis') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -467,8 +437,5 @@ function loadHistoryCondition(condition: {
|
||||
|
||||
<!-- 历史记录弹窗 -->
|
||||
<FilterHistory v-model:open="showHistory" @load="loadHistoryCondition" />
|
||||
|
||||
<!-- 本地 AI 分析弹窗 -->
|
||||
<LocalAnalysisModal v-model:open="showAnalysisModal" :filter-result="filterResult" :filter-mode="filterMode" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 本地 AI 分析弹窗
|
||||
* 支持预设分析和自定义提问
|
||||
*/
|
||||
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
// 创建 markdown-it 实例
|
||||
const md = new MarkdownIt({
|
||||
html: false,
|
||||
breaks: true,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const sessionStore = useSessionStore()
|
||||
|
||||
// 筛选结果消息类型
|
||||
interface FilterMessage {
|
||||
id: number
|
||||
senderName: string
|
||||
senderPlatformId: string
|
||||
senderAliases: string[]
|
||||
senderAvatar: string | null
|
||||
content: string
|
||||
timestamp: number
|
||||
type: number
|
||||
replyToMessageId: string | null
|
||||
replyToContent: string | null
|
||||
replyToSenderName: string | null
|
||||
isHit: boolean
|
||||
}
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
filterResult: {
|
||||
blocks: Array<{
|
||||
startTs: number
|
||||
endTs: number
|
||||
messages: FilterMessage[]
|
||||
hitCount: number
|
||||
}>
|
||||
stats: {
|
||||
totalMessages: number
|
||||
hitMessages: number
|
||||
totalChars: number
|
||||
}
|
||||
} | null
|
||||
filterMode: 'condition' | 'session'
|
||||
}>()
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false })
|
||||
|
||||
// 数据量阈值(超过此数量时提示数据量过大)
|
||||
const DATA_TOO_LARGE_THRESHOLD = 5000
|
||||
|
||||
// 检查数据量是否过大
|
||||
const isDataTooLarge = computed(() => {
|
||||
if (!props.filterResult) return false
|
||||
return props.filterResult.stats.totalMessages > DATA_TOO_LARGE_THRESHOLD
|
||||
})
|
||||
|
||||
// 分析模式:'preset' | 'custom'
|
||||
const analysisMode = ref<'preset' | 'custom'>('preset')
|
||||
|
||||
// 预设分析选项
|
||||
const presetOptions = [
|
||||
{ id: 'summary', label: '总结对话要点', prompt: '请总结这段对话的主要内容和关键要点。' },
|
||||
{ id: 'sentiment', label: '情感分析', prompt: '请分析这段对话中参与者的情感变化和整体氛围。' },
|
||||
{ id: 'topics', label: '话题提取', prompt: '请提取这段对话中讨论的主要话题,并简要说明每个话题的内容。' },
|
||||
{ id: 'insights', label: '洞察分析', prompt: '请对这段对话进行深度分析,包括参与者的关系、互动模式、潜在问题等。' },
|
||||
]
|
||||
|
||||
const selectedPreset = ref(presetOptions[0].id)
|
||||
const customPrompt = ref('')
|
||||
|
||||
// 可编辑的预设提示词(允许用户临时修改)
|
||||
const editablePresetPrompt = ref(presetOptions[0].prompt)
|
||||
|
||||
// 分析状态
|
||||
const isAnalyzing = ref(false)
|
||||
const analysisResult = ref('')
|
||||
const analysisError = ref('')
|
||||
|
||||
// 当前请求 ID(用于中止)
|
||||
let currentRequestId: string | null = null
|
||||
|
||||
// 构建上下文内容
|
||||
const contextContent = computed(() => {
|
||||
if (!props.filterResult) return ''
|
||||
|
||||
let content = ''
|
||||
for (const block of props.filterResult.blocks) {
|
||||
const startTime = new Date(block.startTs * 1000).toLocaleString()
|
||||
content += `\n--- 对话段落 (${startTime}) ---\n`
|
||||
|
||||
for (const msg of block.messages) {
|
||||
const time = new Date(msg.timestamp * 1000).toLocaleTimeString()
|
||||
content += `[${time}] ${msg.senderName}: ${msg.content || '[非文本消息]'}\n`
|
||||
}
|
||||
}
|
||||
return content
|
||||
})
|
||||
|
||||
// 获取用户提问
|
||||
const userQuestion = computed(() => {
|
||||
if (analysisMode.value === 'preset') {
|
||||
return editablePresetPrompt.value
|
||||
}
|
||||
return customPrompt.value
|
||||
})
|
||||
|
||||
// 执行分析
|
||||
async function executeAnalysis() {
|
||||
if (!props.filterResult || !userQuestion.value) return
|
||||
|
||||
isAnalyzing.value = true
|
||||
analysisResult.value = ''
|
||||
analysisError.value = ''
|
||||
|
||||
try {
|
||||
// 构建完整的消息
|
||||
const fullMessage = `以下是一段聊天记录,请根据用户的问题进行分析:
|
||||
|
||||
${contextContent.value}
|
||||
|
||||
---
|
||||
用户问题:${userQuestion.value}`
|
||||
|
||||
// 调用 Agent API
|
||||
const context = {
|
||||
sessionId: sessionStore.currentSessionId || '',
|
||||
}
|
||||
|
||||
const { requestId, promise } = window.agentApi.runStream(
|
||||
fullMessage,
|
||||
context,
|
||||
(chunk) => {
|
||||
if (chunk.type === 'content' && chunk.content) {
|
||||
analysisResult.value += chunk.content
|
||||
} else if (chunk.type === 'error') {
|
||||
analysisError.value = chunk.error || '分析出错'
|
||||
}
|
||||
},
|
||||
[], // 不需要历史消息
|
||||
sessionStore.currentSession?.type === 'group' ? 'group' : 'private'
|
||||
)
|
||||
|
||||
currentRequestId = requestId
|
||||
|
||||
const result = await promise
|
||||
|
||||
if (!result.success && result.error) {
|
||||
analysisError.value = result.error
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('分析失败:', error)
|
||||
analysisError.value = String(error)
|
||||
} finally {
|
||||
isAnalyzing.value = false
|
||||
currentRequestId = null
|
||||
}
|
||||
}
|
||||
|
||||
// 中止分析
|
||||
async function abortAnalysis() {
|
||||
if (currentRequestId) {
|
||||
try {
|
||||
await window.agentApi.abort(currentRequestId)
|
||||
} catch (error) {
|
||||
console.error('中止失败:', error)
|
||||
}
|
||||
isAnalyzing.value = false
|
||||
currentRequestId = null
|
||||
}
|
||||
}
|
||||
|
||||
// 复制结果
|
||||
async function copyResult() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(analysisResult.value)
|
||||
} catch (error) {
|
||||
console.error('复制失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 监听预设选择变化,更新可编辑的提示词
|
||||
watch(selectedPreset, (newPresetId) => {
|
||||
const preset = presetOptions.find((p) => p.id === newPresetId)
|
||||
if (preset) {
|
||||
editablePresetPrompt.value = preset.prompt
|
||||
}
|
||||
})
|
||||
|
||||
// 关闭时重置状态
|
||||
watch(open, (val) => {
|
||||
if (!val) {
|
||||
analysisResult.value = ''
|
||||
analysisError.value = ''
|
||||
if (isAnalyzing.value) {
|
||||
abortAnalysis()
|
||||
}
|
||||
} else {
|
||||
// 打开时重置为默认预设
|
||||
editablePresetPrompt.value = presetOptions.find((p) => p.id === selectedPreset.value)?.prompt || ''
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal v-model:open="open" :ui="{ width: 'max-w-3xl' }">
|
||||
<template #content>
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-lg font-semibold">{{ t('analysis.filter.localAnalysisTitle') }}</h3>
|
||||
<UButton variant="ghost" icon="i-heroicons-x-mark" size="sm" @click="open = false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- 上下文摘要 -->
|
||||
<div class="p-3 bg-gray-50 dark:bg-gray-800 rounded-lg text-sm">
|
||||
<div class="flex items-center gap-4 text-gray-600 dark:text-gray-400">
|
||||
<span>{{ filterResult?.blocks.length || 0 }} 个对话块</span>
|
||||
<span>{{ filterResult?.stats.totalMessages || 0 }} 条消息</span>
|
||||
<span>{{ filterResult?.stats.totalChars.toLocaleString() || 0 }} 字符</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据量过大警告 -->
|
||||
<div
|
||||
v-if="isDataTooLarge"
|
||||
class="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg"
|
||||
>
|
||||
<div class="flex items-start gap-2">
|
||||
<UIcon name="i-heroicons-exclamation-triangle" class="w-5 h-5 text-red-500 shrink-0 mt-0.5" />
|
||||
<div class="text-sm">
|
||||
<p class="font-medium text-red-700 dark:text-red-400">
|
||||
{{ t('analysis.filter.dataTooLarge') }}
|
||||
</p>
|
||||
<p class="text-red-600 dark:text-red-500 mt-1">
|
||||
{{ t('analysis.filter.dataTooLargeThreshold', { count: DATA_TOO_LARGE_THRESHOLD }) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分析模式切换 -->
|
||||
<div class="flex items-center gap-1 p-1 bg-gray-100 dark:bg-gray-800 rounded-lg w-fit">
|
||||
<button
|
||||
class="px-3 py-1.5 text-sm font-medium rounded-md transition-colors"
|
||||
:class="
|
||||
analysisMode === 'preset'
|
||||
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm'
|
||||
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
|
||||
"
|
||||
@click="analysisMode = 'preset'"
|
||||
>
|
||||
{{ t('analysis.filter.presetAnalysis') }}
|
||||
</button>
|
||||
<button
|
||||
class="px-3 py-1.5 text-sm font-medium rounded-md transition-colors"
|
||||
:class="
|
||||
analysisMode === 'custom'
|
||||
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm'
|
||||
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
|
||||
"
|
||||
@click="analysisMode = 'custom'"
|
||||
>
|
||||
{{ t('analysis.filter.customAnalysis') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 预设分析选项 -->
|
||||
<div v-if="analysisMode === 'preset'" class="space-y-3">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<label
|
||||
v-for="option in presetOptions"
|
||||
:key="option.id"
|
||||
class="flex items-center gap-2 p-3 border rounded-lg cursor-pointer transition-colors"
|
||||
:class="
|
||||
selectedPreset === option.id
|
||||
? 'border-primary-500 bg-primary-50 dark:bg-primary-900/20'
|
||||
: 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'
|
||||
"
|
||||
>
|
||||
<input v-model="selectedPreset" type="radio" :value="option.id" class="text-primary-500" />
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">{{ option.label }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- 可编辑的提示词 -->
|
||||
<div class="space-y-1">
|
||||
<label class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('analysis.filter.editablePromptLabel') }}
|
||||
</label>
|
||||
<UTextarea v-model="editablePresetPrompt" :rows="2" class="w-full text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自定义提问 -->
|
||||
<div v-else>
|
||||
<UTextarea
|
||||
v-model="customPrompt"
|
||||
:placeholder="t('analysis.filter.customPromptPlaceholder')"
|
||||
:rows="3"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 分析按钮 -->
|
||||
<div class="flex justify-end gap-2">
|
||||
<UButton v-if="isAnalyzing" color="red" variant="outline" @click="abortAnalysis">
|
||||
{{ t('common.cancel') }}
|
||||
</UButton>
|
||||
<UButton
|
||||
color="primary"
|
||||
:loading="isAnalyzing"
|
||||
:disabled="isAnalyzing || isDataTooLarge || (analysisMode === 'custom' && !customPrompt.trim())"
|
||||
@click="executeAnalysis"
|
||||
>
|
||||
<UIcon name="i-heroicons-sparkles" class="w-4 h-4 mr-1" />
|
||||
{{ isAnalyzing ? t('analysis.filter.analyzing') : t('analysis.filter.startAnalysis') }}
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<!-- 分析结果 -->
|
||||
<div v-if="analysisResult || analysisError" class="border-t border-gray-200 dark:border-gray-700 pt-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('analysis.filter.analysisResult') }}
|
||||
</h4>
|
||||
<UButton v-if="analysisResult" size="xs" variant="ghost" @click="copyResult">
|
||||
<UIcon name="i-heroicons-clipboard" class="w-4 h-4 mr-1" />
|
||||
{{ t('common.copy') }}
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<div
|
||||
v-if="analysisError"
|
||||
class="p-3 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-lg text-sm"
|
||||
>
|
||||
{{ analysisError }}
|
||||
</div>
|
||||
|
||||
<!-- 结果内容 -->
|
||||
<div
|
||||
v-else-if="analysisResult"
|
||||
class="prose prose-sm dark:prose-invert max-w-none p-4 bg-gray-50 dark:bg-gray-800 rounded-lg max-h-80 overflow-y-auto"
|
||||
v-html="md.render(analysisResult)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
@@ -55,8 +55,6 @@ const props = defineProps<{
|
||||
} | null
|
||||
isLoading: boolean
|
||||
isLoadingMore?: boolean
|
||||
estimatedTokens: number
|
||||
tokenStatus: 'green' | 'yellow' | 'red'
|
||||
}>()
|
||||
|
||||
// Emits
|
||||
@@ -101,25 +99,6 @@ const blockVirtualizer = useVirtualizer(
|
||||
|
||||
const virtualBlocks = computed(() => blockVirtualizer.value.getVirtualItems())
|
||||
|
||||
// Token 进度条颜色
|
||||
const tokenProgressColor = computed(() => {
|
||||
switch (props.tokenStatus) {
|
||||
case 'green':
|
||||
return 'bg-green-500'
|
||||
case 'yellow':
|
||||
return 'bg-yellow-500'
|
||||
case 'red':
|
||||
return 'bg-red-500'
|
||||
default:
|
||||
return 'bg-gray-400'
|
||||
}
|
||||
})
|
||||
|
||||
// Token 进度百分比(最大 100000)
|
||||
const tokenProgressPercent = computed(() => {
|
||||
return Math.min((props.estimatedTokens / 100000) * 100, 100)
|
||||
})
|
||||
|
||||
// 当前块的消息列表(使用反转后的索引)
|
||||
const currentBlockMessages = computed<ChatRecordMessage[]>(() => {
|
||||
if (blockCount.value === 0) return []
|
||||
@@ -299,39 +278,6 @@ function handleBlockListScroll(event: Event) {
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Token 预估进度条 -->
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap">
|
||||
{{ t('analysis.filter.stats.tokens') }}:
|
||||
<span
|
||||
class="font-medium"
|
||||
:class="{
|
||||
'text-green-600': tokenStatus === 'green',
|
||||
'text-yellow-600': tokenStatus === 'yellow',
|
||||
'text-red-600': tokenStatus === 'red',
|
||||
}"
|
||||
>
|
||||
~{{ estimatedTokens.toLocaleString() }}
|
||||
</span>
|
||||
</span>
|
||||
<div class="flex-1 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
|
||||
<div
|
||||
class="h-full rounded-full transition-all duration-300"
|
||||
:class="tokenProgressColor"
|
||||
:style="{ width: `${tokenProgressPercent}%` }"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-xs text-gray-500 whitespace-nowrap">10K</span>
|
||||
</div>
|
||||
|
||||
<!-- Token 状态提示 -->
|
||||
<div v-if="tokenStatus === 'yellow'" class="mt-2 text-xs text-yellow-600 dark:text-yellow-400">
|
||||
{{ t('analysis.filter.tokenWarning.yellow') }}
|
||||
</div>
|
||||
<div v-if="tokenStatus === 'red'" class="mt-2 text-xs text-red-600 dark:text-red-400">
|
||||
{{ t('analysis.filter.tokenWarning.red') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主内容区:左右结构 -->
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"chatExplorer": "Chat Explorer",
|
||||
"sqlLab": "SQL Lab",
|
||||
"filterAnalysis": "Filter Analysis",
|
||||
"filterAnalysisDesc": "Advanced filtering feature is planned. You can filter by person, time, or search content before AI analysis",
|
||||
"filterAnalysisDesc": "Filter chat records by person, time, or search content, and export filter results",
|
||||
"featureInDev": "{name} is in development",
|
||||
"comingSoon": "Coming soon...",
|
||||
"followNotice": "Follow me on X for updates"
|
||||
|
||||
@@ -111,7 +111,6 @@
|
||||
"history": "History",
|
||||
"execute": "Execute Filter",
|
||||
"export": "Export Feed Pack",
|
||||
"localAnalysis": "AI Analysis",
|
||||
"keywords": "Keywords",
|
||||
"keywordsHint": "Multiple keywords supported, OR logic",
|
||||
"keywordPlaceholder": "Enter keyword, press Enter to add",
|
||||
@@ -141,27 +140,12 @@
|
||||
"blocks": "Blocks",
|
||||
"messages": "Messages",
|
||||
"hits": "Hits",
|
||||
"chars": "Characters",
|
||||
"tokens": "Est. Tokens"
|
||||
},
|
||||
"tokenWarning": {
|
||||
"yellow": "Token count is high, may affect AI analysis",
|
||||
"red": "Token count too high, consider narrowing filter"
|
||||
"chars": "Characters"
|
||||
},
|
||||
"historyTitle": "Filter History",
|
||||
"noHistory": "No history records",
|
||||
"localAnalysisTitle": "AI Analysis",
|
||||
"presetAnalysis": "Preset Analysis",
|
||||
"customAnalysis": "Custom Question",
|
||||
"customPromptPlaceholder": "Enter your question...",
|
||||
"editablePromptLabel": "Prompt (editable)",
|
||||
"analyzing": "Analyzing...",
|
||||
"startAnalysis": "Start Analysis",
|
||||
"analysisResult": "Analysis Result",
|
||||
"loadMore": "Load More",
|
||||
"allLoaded": "All loaded",
|
||||
"dataTooLarge": "Data too large for AI analysis. Please narrow your filter.",
|
||||
"dataTooLargeThreshold": "Current data exceeds {count} messages",
|
||||
"exportSuccess": "Export successful",
|
||||
"exportFailed": "Export failed",
|
||||
"exportPreparing": "Preparing export..."
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"chatExplorer": "对话式探索",
|
||||
"sqlLab": "SQL实验室",
|
||||
"filterAnalysis": "自定义筛选",
|
||||
"filterAnalysisDesc": "计划实现高级筛选功能,可以先按人/按时间/按搜索内容手动筛选,然后再进行AI分析",
|
||||
"filterAnalysisDesc": "支持按人/按时间/按搜索内容手动筛选聊天记录,并导出筛选结果",
|
||||
"featureInDev": "{name}功能开发中",
|
||||
"comingSoon": "敬请期待...",
|
||||
"followNotice": "功能上线通知,欢迎关注我的小红书"
|
||||
|
||||
@@ -111,7 +111,6 @@
|
||||
"history": "历史记录",
|
||||
"execute": "开始筛选",
|
||||
"export": "导出筛选结果",
|
||||
"localAnalysis": "AI 分析",
|
||||
"keywords": "关键词",
|
||||
"keywordsHint": "支持多个关键词,OR 逻辑匹配",
|
||||
"keywordPlaceholder": "输入关键词,回车添加",
|
||||
@@ -141,27 +140,12 @@
|
||||
"blocks": "对话块",
|
||||
"messages": "消息数",
|
||||
"hits": "命中数",
|
||||
"chars": "字符数",
|
||||
"tokens": "预估 Token"
|
||||
},
|
||||
"tokenWarning": {
|
||||
"yellow": "Token 数量较多,可能影响 AI 分析效果",
|
||||
"red": "Token 数量过多,建议缩小筛选范围"
|
||||
"chars": "字符数"
|
||||
},
|
||||
"historyTitle": "筛选历史",
|
||||
"noHistory": "暂无历史记录",
|
||||
"localAnalysisTitle": "AI 分析",
|
||||
"presetAnalysis": "预设分析",
|
||||
"customAnalysis": "自定义提问",
|
||||
"customPromptPlaceholder": "输入你想问的问题...",
|
||||
"editablePromptLabel": "提示词(可临时修改)",
|
||||
"analyzing": "分析中...",
|
||||
"startAnalysis": "开始分析",
|
||||
"analysisResult": "分析结果",
|
||||
"loadMore": "加载更多",
|
||||
"allLoaded": "已加载全部",
|
||||
"dataTooLarge": "数据量过大,无法进行 AI 分析。请缩小筛选范围。",
|
||||
"dataTooLargeThreshold": "当前数据超过 {count} 条消息",
|
||||
"exportSuccess": "导出成功",
|
||||
"exportFailed": "导出失败",
|
||||
"exportPreparing": "正在准备导出..."
|
||||
|
||||
Reference in New Issue
Block a user