diff --git a/components/DeepResearch.vue b/components/DeepResearch.vue index 61e6de2..69df586 100644 --- a/components/DeepResearch.vue +++ b/components/DeepResearch.vue @@ -8,12 +8,14 @@ import type { TreeNode } from './Tree.vue' import { marked } from 'marked' - const { t, locale } = useI18n() - const { config } = storeToRefs(useConfigStore()) const emit = defineEmits<{ (e: 'complete', results: ResearchResult): void }>() + const toast = useToast() + const { t, locale } = useI18n() + const { config } = storeToRefs(useConfigStore()) + const tree = ref({ id: '0', label: t('webBrowsing.startNode.label'), @@ -41,8 +43,8 @@ // 创建新节点 node = { id: nodeId, - label: t('webBrowsing.generating'), - researchGoal: t('webBrowsing.generating'), + label: '', + researchGoal: '', learnings: [], children: [], } @@ -63,7 +65,7 @@ } // 更新节点的查询内容 if (step.result) { - node.label = step.result.query ?? t('webBrowsing.generating') + node.label = step.result.query ?? '' node.researchGoal = step.result.researchGoal } break @@ -102,6 +104,15 @@ case 'error': 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 case 'complete': @@ -186,8 +197,19 @@
- -

{{ selectedNode.label }}

+ + +

+ {{ selectedNode.label ?? $t('webBrowsing.generating') }} +

diff --git a/components/Tree.vue b/components/Tree.vue index 9b8e780..de3ce95 100644 --- a/components/Tree.vue +++ b/components/Tree.vue @@ -14,6 +14,7 @@ visitedUrls?: string[] status?: TreeNodeStatus children: TreeNode[] + error?: string } const props = defineProps<{ diff --git a/i18n/en.json b/i18n/en.json index 08760bc..370302b 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -64,7 +64,9 @@ "researchGoal": "Research Goal", "visitedUrls": "Visited URLs", "learnings": "Learnings", - "generating": "Generating..." + "generating": "Generating...", + "nodeFailed": "Search failed", + "nodeFailedToast": "Search node \"{label}\" failed" }, "researchReport": { "title": "4. Research Report", diff --git a/i18n/zh.json b/i18n/zh.json index f95db5e..260e1e6 100644 --- a/i18n/zh.json +++ b/i18n/zh.json @@ -29,7 +29,9 @@ "providerHelp": "目前仅支持 Tavily,每个月可以免费搜索 1000 次。\n请在 {0} 生成一个 API 密钥。", "apiKey": "API 密钥", "queryLanguage": "使用语言", - "queryLanguageHelp": "修改搜索词的语言。如果你想获取不同的搜索结果(比如查询高质量的英文资料),可以在这里修改。\nAI 模型在总结的时候仍然会使用当前网页的语言。" + "queryLanguageHelp": "修改搜索词的语言。如果你想获取不同的搜索结果(比如查询高质量的英文资料),可以在这里修改。\nAI 模型在总结的时候仍然会使用当前网页的语言。", + "nodeFailed": "搜索失败", + "nodeFailedToast": "搜索步骤 “{label}” 失败" } }, "researchTopic": { diff --git a/lib/deep-research.ts b/lib/deep-research.ts index 741dc18..ca13c8d 100644 --- a/lib/deep-research.ts +++ b/lib/deep-research.ts @@ -381,9 +381,20 @@ export async function deepResearch({ } } } catch (e: any) { - throw new Error( - `Error searching for ${searchQuery.query}, depth ${currentDepth}\nMessage: ${e.message}`, + const id = childNodeId(nodeId, i) + console.error( + `Error in node ${id} for query ${searchQuery.query}`, + e, ) + onProgress({ + type: 'error', + message: e.message, + nodeId: id, + }) + return { + learnings: [], + visitedUrls: [], + } } }), ),