feat: improve error handling in web search

This commit is contained in:
AnotiaWang
2025-02-14 10:30:02 +08:00
parent 8d27f70c3e
commit e60890e286
5 changed files with 49 additions and 11 deletions

View File

@ -8,12 +8,14 @@
import type { TreeNode } from './Tree.vue' import type { TreeNode } from './Tree.vue'
import { marked } from 'marked' import { marked } from 'marked'
const { t, locale } = useI18n()
const { config } = storeToRefs(useConfigStore())
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'complete', results: ResearchResult): void (e: 'complete', results: ResearchResult): void
}>() }>()
const toast = useToast()
const { t, locale } = useI18n()
const { config } = storeToRefs(useConfigStore())
const tree = ref<TreeNode>({ const tree = ref<TreeNode>({
id: '0', id: '0',
label: t('webBrowsing.startNode.label'), label: t('webBrowsing.startNode.label'),
@ -41,8 +43,8 @@
// 创建新节点 // 创建新节点
node = { node = {
id: nodeId, id: nodeId,
label: t('webBrowsing.generating'), label: '',
researchGoal: t('webBrowsing.generating'), researchGoal: '',
learnings: [], learnings: [],
children: [], children: [],
} }
@ -63,7 +65,7 @@
} }
// 更新节点的查询内容 // 更新节点的查询内容
if (step.result) { if (step.result) {
node.label = step.result.query ?? t('webBrowsing.generating') node.label = step.result.query ?? ''
node.researchGoal = step.result.researchGoal node.researchGoal = step.result.researchGoal
} }
break break
@ -102,6 +104,15 @@
case 'error': case 'error':
console.error(`Research error on node ${nodeId}:`, step.message) console.error(`Research error on node ${nodeId}:`, step.message)
node!.error = step.message
toast.add({
title: t('webBrowsing.nodeFailedToast', {
label: node!.label ?? nodeId,
}),
description: step.message,
color: 'error',
duration: 8000,
})
break break
case 'complete': case 'complete':
@ -186,8 +197,19 @@
<Tree :node="tree" :selected-node="selectedNode" @select="selectNode" /> <Tree :node="tree" :selected-node="selectedNode" @select="selectNode" />
</div> </div>
<div v-if="selectedNode" class="p-4"> <div v-if="selectedNode" class="p-4">
<USeparator :label="t('webBrowsing.nodeDetails')" /> <USeparator :label="$t('webBrowsing.nodeDetails')" />
<h2 class="text-xl font-bold my-2">{{ selectedNode.label }}</h2> <UAlert
v-if="selectedNode.error"
class="my-2"
:title="$t('webBrowsing.nodeFailed')"
:description="selectedNode.error"
color="error"
variant="soft"
:duration="8000"
/>
<h2 class="text-xl font-bold my-2">
{{ selectedNode.label ?? $t('webBrowsing.generating') }}
</h2>
<!-- Root node has no additional information --> <!-- Root node has no additional information -->
<p v-if="selectedNode.id === '0'"> <p v-if="selectedNode.id === '0'">

View File

@ -14,6 +14,7 @@
visitedUrls?: string[] visitedUrls?: string[]
status?: TreeNodeStatus status?: TreeNodeStatus
children: TreeNode[] children: TreeNode[]
error?: string
} }
const props = defineProps<{ const props = defineProps<{

View File

@ -64,7 +64,9 @@
"researchGoal": "Research Goal", "researchGoal": "Research Goal",
"visitedUrls": "Visited URLs", "visitedUrls": "Visited URLs",
"learnings": "Learnings", "learnings": "Learnings",
"generating": "Generating..." "generating": "Generating...",
"nodeFailed": "Search failed",
"nodeFailedToast": "Search node \"{label}\" failed"
}, },
"researchReport": { "researchReport": {
"title": "4. Research Report", "title": "4. Research Report",

View File

@ -29,7 +29,9 @@
"providerHelp": "目前仅支持 Tavily每个月可以免费搜索 1000 次。\n请在 {0} 生成一个 API 密钥。", "providerHelp": "目前仅支持 Tavily每个月可以免费搜索 1000 次。\n请在 {0} 生成一个 API 密钥。",
"apiKey": "API 密钥", "apiKey": "API 密钥",
"queryLanguage": "使用语言", "queryLanguage": "使用语言",
"queryLanguageHelp": "修改搜索词的语言。如果你想获取不同的搜索结果(比如查询高质量的英文资料),可以在这里修改。\nAI 模型在总结的时候仍然会使用当前网页的语言。" "queryLanguageHelp": "修改搜索词的语言。如果你想获取不同的搜索结果(比如查询高质量的英文资料),可以在这里修改。\nAI 模型在总结的时候仍然会使用当前网页的语言。",
"nodeFailed": "搜索失败",
"nodeFailedToast": "搜索步骤 “{label}” 失败"
} }
}, },
"researchTopic": { "researchTopic": {

View File

@ -381,9 +381,20 @@ export async function deepResearch({
} }
} }
} catch (e: any) { } catch (e: any) {
throw new Error( const id = childNodeId(nodeId, i)
`Error searching for ${searchQuery.query}, depth ${currentDepth}\nMessage: ${e.message}`, console.error(
`Error in node ${id} for query ${searchQuery.query}`,
e,
) )
onProgress({
type: 'error',
message: e.message,
nodeId: id,
})
return {
learnings: [],
visitedUrls: [],
}
} }
}), }),
), ),