feat: improve error handling in web search
This commit is contained in:
@ -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'">
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
visitedUrls?: string[]
|
visitedUrls?: string[]
|
||||||
status?: TreeNodeStatus
|
status?: TreeNodeStatus
|
||||||
children: TreeNode[]
|
children: TreeNode[]
|
||||||
|
error?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -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",
|
||||||
|
@ -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": {
|
||||||
|
@ -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: [],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
Reference in New Issue
Block a user