feat: 添加知识库检索功能和改进模型路由错误处理
- 在ChatRequest中添加Citation事件类型,支持引用来源展示 - 实现聊天上下文准备服务,构建带源元数据的受限聊天上下文 - 添加ThreadedProcess类以支持Windows平台的子进程操作 - 改进检索引擎中的错误处理和向量搜索逻辑 - 实现严格的嵌入模型验证和索引重建机制 - 添加前端聊天界面的知识库检索开关 - 实现搜索历史记录功能和错误降级处理 - 更新模型路由设置提示信息以反映索引重建需求
This commit is contained in:
@@ -66,7 +66,8 @@ async function openCitation(citation: Citation) {
|
||||
<option v-for="provider in providerStore.enabledProviders" :key="provider.provider_id" :value="provider.provider_id">{{ provider.name }}</option>
|
||||
</select></div>
|
||||
<div class="field compact"><label>模型 ID</label><input v-model="chatStore.selectedModel" class="input" list="chat-models" placeholder="填写模型 ID" /><datalist id="chat-models"><option v-for="model in availableModels" :key="model.model_id" :value="model.model_id">{{ model.name }}</option></datalist></div>
|
||||
<span class="subtle">知识库问答与技能请使用智能体;普通聊天尚未接入这些能力。</span>
|
||||
<label class="rag-toggle"><input v-model="chatStore.useRag" type="checkbox" :disabled="chatStore.isStreaming" />检索知识库</label>
|
||||
<span class="subtle">开启后,将相关笔记片段发送给所选模型,并显示来源。技能调用请使用智能体。</span>
|
||||
</header>
|
||||
<div v-if="loadError || providerStore.error" class="error-banner chat-error">{{ loadError || providerStore.error }}</div>
|
||||
<main class="message-timeline">
|
||||
|
||||
@@ -46,6 +46,12 @@ async function openResult(result: SearchResult) {
|
||||
</div>
|
||||
</form>
|
||||
<div v-if="searchStore.error" class="error-banner">{{ searchStore.error }}</div>
|
||||
<div v-if="searchStore.historyError" class="notice-banner">{{ searchStore.historyError }}</div>
|
||||
<div v-if="searchStore.recentQueries.length" class="search-history">
|
||||
<span class="subtle">最近搜索(保存在当前浏览器)</span>
|
||||
<button v-for="item in searchStore.recentQueries" :key="item" class="button-secondary" @click="searchStore.query = item; submitSearch()">{{ item }}</button>
|
||||
<button class="button-secondary" @click="searchStore.clearHistory">清空记录</button>
|
||||
</div>
|
||||
<div v-if="searchStore.vectorUnavailable" class="notice-banner">向量索引不可用,已保留全文检索能力。</div>
|
||||
<div v-if="searchStore.results.length" class="results-header">
|
||||
<span>找到 {{ searchStore.total }} 条结果</span><span class="badge info">{{ searchStore.mode }}</span>
|
||||
@@ -69,6 +75,7 @@ async function openResult(result: SearchResult) {
|
||||
.search-page > * { width: min(100%, 1040px); margin-inline: auto; }
|
||||
.search-form { display: grid; grid-template-columns: 1fr auto; gap: var(--space-md); margin-bottom: var(--space-lg); }
|
||||
.search-input { height: 44px; font-size: var(--font-size-lg); }
|
||||
.search-history { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-bottom: var(--space-md); }
|
||||
.advanced { grid-column: 1 / -1; }
|
||||
.results-header, .result-title, .result-meta { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md); }
|
||||
.results-header { margin: var(--space-xl) 0 var(--space-md); color: var(--color-text-secondary); }
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('ModelRoutingSettings', () => {
|
||||
expect(wrapper.text()).toContain('本地采用 Qwen3-ASR')
|
||||
expect(wrapper.text()).toContain('本地采用 ERes2NetV2')
|
||||
expect(wrapper.text()).toContain('重建全部')
|
||||
expect(wrapper.text()).toContain('重建完成前继续使用本地检索')
|
||||
expect(wrapper.text()).toContain('重建完成前可使用全文检索')
|
||||
expect(wrapper.text()).toContain('不是 OpenAI 标准接口')
|
||||
for (const id of ['responses', 'anthropic', 'ollama', 'disabled']) expect(wrapper.get(`option[value="${id}"]`).attributes()).toHaveProperty('disabled')
|
||||
expect(wrapper.get('option[value="p1"]').attributes()).not.toHaveProperty('disabled')
|
||||
|
||||
@@ -116,7 +116,7 @@ async function save() {
|
||||
<fieldset :disabled="loading || saving || conflict">
|
||||
<article v-for="capability in capabilities" :key="capability.id" class="routing-card" :data-capability="capability.id">
|
||||
<h3>{{ capability.name }}</h3>
|
||||
<p v-if="capability.id === 'embedding'" class="embedding-notice">更换模型或接口后,请重建全部索引。重建完成前继续使用本地检索。</p>
|
||||
<p v-if="capability.id === 'embedding'" class="embedding-notice">保存配置或更换模型、接口后,请重建全部索引。配置成功不代表已有笔记的向量索引已更新;重建完成前可使用全文检索,混合检索会回退到全文检索。</p>
|
||||
<div class="protocols" aria-label="协议可用性">
|
||||
<span v-for="protocol in protocols" :key="protocol.id" class="badge" :class="{ 'protocol-unavailable': !['openai_chat', 'openai_compatible'].includes(protocol.id) }">{{ protocol.label }}{{ ['openai_chat', 'openai_compatible'].includes(protocol.id) ? ' · 可用' : ' · 不可用' }}</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user