Add dependency on remove-markdown, update package.json and pnpm-lock.yaml files, optimize the search view component, enhance internationalization support, update user interaction prompts, and improve both user experience and code readability.

This commit is contained in:
duanfuxiang 2025-07-07 17:32:49 +08:00
parent c89186a40d
commit bff3e05d93
7 changed files with 181 additions and 55 deletions

View File

@ -120,6 +120,7 @@
"reconnecting-eventsource": "^1.6.4",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.0",
"remove-markdown": "^0.6.2",
"shell-env": "^4.0.1",
"simple-git": "^3.27.0",
"smart-embed-model": "^1.0.7",

24
pnpm-lock.yaml generated
View File

@ -210,6 +210,9 @@ importers:
remark-gfm:
specifier: ^4.0.0
version: 4.0.1
remove-markdown:
specifier: ^0.6.2
version: 0.6.2
shell-env:
specifier: ^4.0.1
version: 4.0.1
@ -577,8 +580,8 @@ packages:
'@codemirror/language@6.11.2':
resolution: {integrity: sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==}
'@codemirror/language@https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
resolution: {tarball: https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67}
'@codemirror/language@git+https://git@github.com:lishid/cm-language.git#6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
resolution: {commit: 6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67, repo: git@github.com:lishid/cm-language.git, type: git}
version: 6.10.8
'@codemirror/lint@0.20.3':
@ -5451,8 +5454,8 @@ packages:
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66:
resolution: {tarball: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66}
obsidian@git+https://git@github.com:obsidianmd/obsidian-api.git#103ff76a0712a02dd0da28646b5a6b0ba6686d66:
resolution: {commit: 103ff76a0712a02dd0da28646b5a6b0ba6686d66, repo: git@github.com:obsidianmd/obsidian-api.git, type: git}
version: 1.8.7
peerDependencies:
'@codemirror/state': ^6.0.0
@ -5921,6 +5924,9 @@ packages:
remove-markdown@0.5.5:
resolution: {integrity: sha512-lMR8tOtDqazFT6W2bZidoXwkptMdF3pCxpri0AEokHg0sZlC2GdoLqnoaxsEj1o7/BtXV1MKtT3YviA1t7rW7g==}
remove-markdown@0.6.2:
resolution: {integrity: sha512-EijDXJZbzpGbQBd852ViUzcqgpMujthM+SAEHiWCMcZonRbZ+xViWKLJA/vrwbDwYdxrs1aFDjpBhcGrZoJRGA==}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
@ -7083,7 +7089,7 @@ snapshots:
'@lezer/lr': 1.4.2
style-mod: 4.1.2
'@codemirror/language@https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
'@codemirror/language@git+https://git@github.com:lishid/cm-language.git#6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.0
@ -12598,7 +12604,7 @@ snapshots:
obsidian-daily-notes-interface@0.8.4(@codemirror/state@6.5.2)(@codemirror/view@6.38.0):
dependencies:
obsidian: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0)
obsidian: git+https://git@github.com:obsidianmd/obsidian-api.git#103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0)
tslib: 2.1.0
transitivePeerDependencies:
- '@codemirror/state'
@ -12606,7 +12612,7 @@ snapshots:
obsidian-dataview@0.5.68:
dependencies:
'@codemirror/language': https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67
'@codemirror/language': git+https://git@github.com:lishid/cm-language.git#6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.0
emoji-regex: 10.4.0
@ -12625,7 +12631,7 @@ snapshots:
'@types/codemirror': 5.60.8
moment: 2.29.4
obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0):
obsidian@git+https://git@github.com:obsidianmd/obsidian-api.git#103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0):
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.0
@ -13233,6 +13239,8 @@ snapshots:
remove-markdown@0.5.5: {}
remove-markdown@0.6.2: {}
require-directory@2.1.1: {}
require-from-string@2.0.2: {}

View File

@ -10,6 +10,7 @@ import { useTrans } from '../../contexts/TransContext'
import { Workspace } from '../../database/json/workspace/types'
import { WorkspaceManager } from '../../database/json/workspace/WorkspaceManager'
import { SelectVector } from '../../database/schema'
import { t } from '../../lang/helpers'
import { Mentionable } from '../../types/mentionable'
import { getFilesWithTag } from '../../utils/glob-utils'
import { openMarkdownFile } from '../../utils/obsidian'
@ -459,7 +460,7 @@ const SearchView = () => {
h5: ({ children }) => <h5>{children}</h5>,
h6: ({ children }) => <h5>{children}</h5>,
// 移除图片显示,避免布局问题
img: () => <span className="obsidian-image-placeholder">[]</span>,
img: () => <span className="obsidian-image-placeholder">{t('semanticSearch.imagePlaceholder')}</span>,
// 代码块样式
code: ({ children, inline }: { children: React.ReactNode; inline?: boolean;[key: string]: unknown }) => {
if (inline) {
@ -619,7 +620,7 @@ const SearchView = () => {
{/* 头部信息 */}
<div className="obsidian-search-header-wrapper">
<div className="obsidian-search-title">
<h3></h3>
<h3>{t('semanticSearch.title')}</h3>
</div>
{/* 统计信息 */}
@ -628,20 +629,20 @@ const SearchView = () => {
<div className="obsidian-search-stats-overview">
<div className="obsidian-search-stats-main">
<span className="obsidian-search-stats-number">{statisticsInfo.totalChunks}</span>
<span className="obsidian-search-stats-label"></span>
<span className="obsidian-search-stats-label">{t('semanticSearch.vectorBlocks')}</span>
</div>
<div className="obsidian-search-stats-breakdown">
<div className="obsidian-search-stats-item">
<span className="obsidian-search-stats-item-icon">📄</span>
<span className="obsidian-search-stats-item-value">{statisticsInfo.totalFiles}</span>
<span className="obsidian-search-stats-item-label"></span>
<span className="obsidian-search-stats-item-label">{t('semanticSearch.files')}</span>
</div>
</div>
</div>
)}
<div className="infio-search-model-info">
<div className="infio-search-model-row">
<span className="infio-search-model-label">:</span>
<span className="infio-search-model-label">{t('semanticSearch.embeddingModel')}</span>
<ModelSelect modelType="embedding" />
</div>
<div className="obsidian-search-actions">
@ -649,9 +650,9 @@ const SearchView = () => {
onClick={handleInitWorkspaceRAG}
disabled={isInitializingRAG || isDeleting || isSearching}
className="obsidian-search-init-btn"
title={statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? '更新索引' : '初始化索引'}
title={statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? t('semanticSearch.updateIndex') : t('semanticSearch.initializeIndex')}
>
{isInitializingRAG ? '正在初始化...' : (statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? '更新索引' : '初始化索引')}
{isInitializingRAG ? t('semanticSearch.initializing') : (statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? t('semanticSearch.updateIndex') : t('semanticSearch.initializeIndex'))}
</button>
</div>
@ -662,15 +663,15 @@ const SearchView = () => {
{isInitializingRAG && (
<div className="obsidian-rag-initializing">
<div className="obsidian-rag-init-header">
<h4> RAG </h4>
<p></p>
<h4>{t('semanticSearch.initializingWorkspace')}</h4>
<p>{t('semanticSearch.initializingDescription')}</p>
</div>
{ragInitProgress && ragInitProgress.type === 'indexing' && ragInitProgress.indexProgress && (
<div className="obsidian-rag-progress">
<div className="obsidian-rag-progress-info">
<span className="obsidian-rag-progress-stage"></span>
<span className="obsidian-rag-progress-stage">{t('semanticSearch.buildingVectorIndex')}</span>
<span className="obsidian-rag-progress-counter">
{ragInitProgress.indexProgress.completedChunks} / {ragInitProgress.indexProgress.totalChunks}
{ragInitProgress.indexProgress.completedChunks} / {ragInitProgress.indexProgress.totalChunks} {t('semanticSearch.blocks')}
</span>
</div>
<div className="obsidian-rag-progress-bar">
@ -683,7 +684,7 @@ const SearchView = () => {
</div>
<div className="obsidian-rag-progress-details">
<div className="obsidian-rag-progress-files">
{ragInitProgress.indexProgress.totalFiles}
{t('semanticSearch.totalFiles', { count: ragInitProgress.indexProgress.totalFiles })}
</div>
<div className="obsidian-rag-progress-percentage">
{Math.round((ragInitProgress.indexProgress.completedChunks / Math.max(ragInitProgress.indexProgress.totalChunks, 1)) * 100)}%
@ -700,9 +701,9 @@ const SearchView = () => {
<div className="obsidian-rag-success-content">
<span className="obsidian-rag-success-icon"></span>
<div className="obsidian-rag-success-text">
<span className="obsidian-rag-success-title">
RAG : {ragInitSuccess.workspaceName}
</span>
<span className="obsidian-rag-success-title">
{t('semanticSearch.initializationComplete', { workspaceName: ragInitSuccess.workspaceName })}
</span>
</div>
<button
className="obsidian-rag-success-close"
@ -723,7 +724,7 @@ const SearchView = () => {
onSubmit={handleSearch}
mentionables={mentionables}
setMentionables={setMentionables}
placeholder="语义搜索(按回车键搜索)..."
placeholder={t('semanticSearch.searchPlaceholder')}
autoFocus={true}
disabled={isSearching}
searchMode={searchMode}
@ -737,11 +738,11 @@ const SearchView = () => {
<div className="obsidian-search-stats">
<div className="obsidian-search-stats-line">
{searchMode === 'notes' ? (
`${totalFiles} 个文件,${totalBlocks} 个块`
t('semanticSearch.stats.filesAndBlocks', { files: totalFiles, blocks: totalBlocks })
) : searchMode === 'insights' ? (
`${insightGroupedResults.length} 个文件,${insightResults.length} 个洞察`
t('semanticSearch.stats.filesAndInsights', { files: insightGroupedResults.length, insights: insightResults.length })
) : (
`${totalAllFiles} 个文件,${totalBlocks} 个块,${insightResults.length} 个洞察`
t('semanticSearch.stats.filesBlocksAndInsights', { files: totalAllFiles, blocks: totalBlocks, insights: insightResults.length })
)}
</div>
</div>
@ -751,17 +752,17 @@ const SearchView = () => {
<div className="obsidian-confirm-dialog-overlay">
<div className="obsidian-confirm-dialog">
<div className="obsidian-confirm-dialog-header">
<h3></h3>
<h3>{t('semanticSearch.deleteConfirm.title')}</h3>
</div>
<div className="obsidian-confirm-dialog-body">
<p>
{t('semanticSearch.deleteConfirm.message')}
</p>
<p className="obsidian-confirm-dialog-warning">
{t('semanticSearch.deleteConfirm.warning')}
</p>
<div className="obsidian-confirm-dialog-scope">
<strong>:</strong> {settings.workspace === 'vault' ? '整个 Vault' : settings.workspace}
<strong>{t('semanticSearch.deleteConfirm.workspaceLabel')}</strong> {settings.workspace === 'vault' ? t('semanticSearch.deleteConfirm.entireVault') : settings.workspace}
</div>
</div>
<div className="obsidian-confirm-dialog-footer">
@ -769,13 +770,13 @@ const SearchView = () => {
onClick={cancelDeleteConfirm}
className="obsidian-confirm-dialog-cancel-btn"
>
{t('semanticSearch.deleteConfirm.cancel')}
</button>
<button
onClick={confirmDeleteWorkspaceIndex}
className="obsidian-confirm-dialog-confirm-btn"
>
{t('semanticSearch.deleteConfirm.confirm')}
</button>
</div>
</div>
@ -787,31 +788,31 @@ const SearchView = () => {
<div className="obsidian-confirm-dialog-overlay">
<div className="obsidian-confirm-dialog">
<div className="obsidian-confirm-dialog-header">
<h3>{statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? '更新工作区索引' : '初始化工作区索引'}</h3>
<h3>{statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? t('semanticSearch.initConfirm.updateTitle') : t('semanticSearch.initConfirm.initTitle')}</h3>
</div>
<div className="obsidian-confirm-dialog-body">
<p>
{statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0)
? '将更新当前工作区的向量索引,重新处理所有文件以确保索引最新。'
: '将为当前工作区的所有文件建立向量索引,这将提高语义搜索的准确性。'
? t('semanticSearch.initConfirm.updateMessage')
: t('semanticSearch.initConfirm.initMessage')
}
</p>
<div className="obsidian-confirm-dialog-info">
<div className="obsidian-confirm-dialog-info-item">
<strong>:</strong>
<strong>{t('semanticSearch.initConfirm.embeddingModelLabel')}</strong>
<span className="obsidian-confirm-dialog-model">
{settings.embeddingModelId}
</span>
</div>
<div className="obsidian-confirm-dialog-info-item">
<strong>:</strong>
<strong>{t('semanticSearch.initConfirm.workspaceLabel')}</strong>
<span className="obsidian-confirm-dialog-workspace">
{settings.workspace === 'vault' ? '整个 Vault' : settings.workspace}
{settings.workspace === 'vault' ? t('semanticSearch.initConfirm.entireVault') : settings.workspace}
</span>
</div>
</div>
<p className="obsidian-confirm-dialog-warning">
{t('semanticSearch.initConfirm.warning')}
</p>
</div>
<div className="obsidian-confirm-dialog-footer">
@ -819,13 +820,13 @@ const SearchView = () => {
onClick={cancelRAGInitConfirm}
className="obsidian-confirm-dialog-cancel-btn"
>
{t('semanticSearch.initConfirm.cancel')}
</button>
<button
onClick={confirmInitWorkspaceRAG}
className="obsidian-confirm-dialog-confirm-btn"
>
{statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? '开始更新' : '开始初始化'}
{statisticsInfo && (statisticsInfo.totalFiles > 0 || statisticsInfo.totalChunks > 0) ? t('semanticSearch.initConfirm.startUpdate') : t('semanticSearch.initConfirm.startInit')}
</button>
</div>
</div>
@ -835,7 +836,7 @@ const SearchView = () => {
{/* 搜索进度 */}
{isSearching && (
<div className="obsidian-search-loading">
...
{t('semanticSearch.searching')}
</div>
)}
@ -1044,7 +1045,7 @@ const SearchView = () => {
(searchMode === 'all' && allGroupedResults.length === 0)
) && (
<div className="obsidian-no-results">
<p></p>
<p>{t('semanticSearch.noResults')}</p>
</div>
)}
</div>

View File

@ -2,6 +2,8 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import { ChevronDown, ChevronUp, FileText, Lightbulb, Globe } from 'lucide-react'
import { useState } from 'react'
import { t } from '../../../lang/helpers'
interface SearchModeSelectProps {
searchMode: 'notes' | 'insights' | 'all'
onSearchModeChange: (mode: 'notes' | 'insights' | 'all') => void
@ -13,21 +15,21 @@ export function SearchModeSelect({ searchMode, onSearchModeChange }: SearchModeS
const searchModes = [
{
value: 'all' as const,
name: '全部',
name: t('semanticSearch.searchMode.all'),
icon: <Globe size={14} />,
description: '聚合搜索原始笔记和 AI 洞察'
description: t('semanticSearch.searchMode.allDescription')
},
{
value: 'notes' as const,
name: '原始笔记',
name: t('semanticSearch.searchMode.notes'),
icon: <FileText size={14} />,
description: '搜索原始笔记内容'
description: t('semanticSearch.searchMode.notesDescription')
},
{
value: 'insights' as const,
name: 'AI 洞察',
name: t('semanticSearch.searchMode.insights'),
icon: <Lightbulb size={14} />,
description: '搜索 AI 洞察内容'
description: t('semanticSearch.searchMode.insightsDescription')
}
]

View File

@ -1,9 +1,9 @@
import { backOff } from 'exponential-backoff';
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
import removeMarkdown from "markdown-to-text";
import { minimatch } from 'minimatch';
import { App, Notice, TFile } from 'obsidian';
import pLimit from 'p-limit';
import removeMarkdown from 'remove-markdown';
import { IndexProgress } from '../../../components/chat-view/QueryProgress';
import {
@ -14,10 +14,10 @@ import {
} from '../../../core/llm/exception';
import { InsertVector, SelectVector } from '../../../database/schema';
import { EmbeddingModel } from '../../../types/embedding';
import { openSettingsModalWithError } from '../../../utils/open-settings-modal';
import { getFilesWithTag } from '../../../utils/glob-utils';
import { Workspace } from '../../json/workspace/types';
import { openSettingsModalWithError } from '../../../utils/open-settings-modal';
import { DBManager } from '../../database-manager';
import { Workspace } from '../../json/workspace/types';
import { VectorRepository } from './vector-repository';
@ -256,7 +256,7 @@ export class VectorManager {
async () => {
// 在嵌入之前处理 markdown
const cleanedBatchData = batchChunks.map(chunk => {
const cleanContent = removeMarkdown(chunk.content).replace(/\0/g, '')
const cleanContent = removeMarkdown(chunk.content)
return { chunk, cleanContent }
}).filter(({ cleanContent }) => cleanContent && cleanContent.trim().length > 0)
@ -539,7 +539,7 @@ export class VectorManager {
async () => {
// 在嵌入之前处理 markdown只处理一次
const cleanedBatchData = batchChunks.map(chunk => {
const cleanContent = removeMarkdown(chunk.content).replace(/\0/g, '')
const cleanContent = removeMarkdown(chunk.content)
return { chunk, cleanContent }
}).filter(({ cleanContent }) => cleanContent && cleanContent.trim().length > 0)

View File

@ -497,6 +497,63 @@ export default {
toolNoDescription: "No description",
useMcpToolFrom: "Use MCP tool from",
},
semanticSearch: {
title: "Semantic Index",
embeddingModel: "Embedding model:",
vectorBlocks: "vector blocks",
files: "files",
initializeIndex: "Initialize index",
updateIndex: "Update index",
initializing: "Initializing...",
initializingWorkspace: "Initializing workspace RAG vector index",
initializingDescription: "Building vector index for files in the current workspace to improve search accuracy",
buildingVectorIndex: "Building vector index",
blocks: "blocks",
totalFiles: "Total {count} files",
initializationComplete: "Workspace RAG vector index initialization complete: {workspaceName}",
searchPlaceholder: "Semantic search (press Enter to search)...",
searching: "Searching...",
noResults: "No relevant results found",
imagePlaceholder: "[Image]",
// Search mode
searchMode: {
all: "All",
allDescription: "Search both original notes and AI insights",
notes: "Original Notes",
notesDescription: "Search original note content",
insights: "AI Insights",
insightsDescription: "Search AI insight content"
},
// Statistics
stats: {
filesAndBlocks: "{files} files, {blocks} blocks",
filesAndInsights: "{files} files, {insights} insights",
filesBlocksAndInsights: "{files} files, {blocks} blocks, {insights} insights"
},
// Confirmation dialogs
deleteConfirm: {
title: "Clear workspace index",
message: "This will clear all vector index data for the current workspace.",
warning: "This action cannot be undone. After clearing, you need to reinitialize the index to perform semantic search.",
workspaceLabel: "Workspace:",
entireVault: "Entire Vault",
cancel: "Cancel",
confirm: "Confirm Clear"
},
initConfirm: {
initTitle: "Initialize workspace index",
updateTitle: "Update workspace index",
initMessage: "This will build vector index for all files in the current workspace, which will improve semantic search accuracy.",
updateMessage: "This will update the vector index for the current workspace, reprocessing all files to ensure the index is up-to-date.",
embeddingModelLabel: "Embedding model:",
workspaceLabel: "Workspace:",
entireVault: "Entire Vault",
warning: "This operation may take several minutes, depending on the number and size of files.",
cancel: "Cancel",
startInit: "Start Initialize",
startUpdate: "Start Update"
}
},
insights: {
title: "AI Insights",
initializeInsights: "Initialize Insights",

View File

@ -499,6 +499,63 @@ export default {
useMcpToolFrom: "使用来自以下的 MCP 工具:",
}
},
semanticSearch: {
title: "语义索引",
embeddingModel: "嵌入模型:",
vectorBlocks: "个向量块",
files: "文件",
initializeIndex: "初始化索引",
updateIndex: "更新索引",
initializing: "正在初始化...",
initializingWorkspace: "正在初始化工作区 RAG 向量索引",
initializingDescription: "为当前工作区的文件建立向量索引,提高搜索精度",
buildingVectorIndex: "建立向量索引",
blocks: "块",
totalFiles: "共 {count} 个文件",
initializationComplete: "工作区 RAG 向量索引初始化完成: {workspaceName}",
searchPlaceholder: "语义搜索(按回车键搜索)...",
searching: "正在搜索...",
noResults: "未找到相关结果",
imagePlaceholder: "[图片]",
// 搜索模式
searchMode: {
all: "全部",
allDescription: "聚合搜索原始笔记和 AI 洞察",
notes: "原始笔记",
notesDescription: "搜索原始笔记内容",
insights: "AI 洞察",
insightsDescription: "搜索 AI 洞察内容"
},
// 统计信息
stats: {
filesAndBlocks: "{files} 个文件,{blocks} 个块",
filesAndInsights: "{files} 个文件,{insights} 个洞察",
filesBlocksAndInsights: "{files} 个文件,{blocks} 个块,{insights} 个洞察"
},
// 确认对话框
deleteConfirm: {
title: "清除工作区索引",
message: "将清除当前工作区的所有向量索引数据。",
warning: "此操作无法撤销,清除后需要重新初始化索引才能进行语义搜索。",
workspaceLabel: "工作区:",
entireVault: "整个 Vault",
cancel: "取消",
confirm: "确认清除"
},
initConfirm: {
initTitle: "初始化工作区索引",
updateTitle: "更新工作区索引",
initMessage: "将为当前工作区的所有文件建立向量索引,这将提高语义搜索的准确性。",
updateMessage: "将更新当前工作区的向量索引,重新处理所有文件以确保索引最新。",
embeddingModelLabel: "嵌入模型:",
workspaceLabel: "工作区:",
entireVault: "整个 Vault",
warning: "此操作可能需要几分钟时间,具体取决于文件数量和大小。",
cancel: "取消",
startInit: "开始初始化",
startUpdate: "开始更新"
}
},
insights: {
title: "AI 洞察",
initializeInsights: "初始化洞察",