diff --git a/desktop/src/components/ChatArea.tsx b/desktop/src/components/ChatArea.tsx index cd1aa97..11f683b 100644 --- a/desktop/src/components/ChatArea.tsx +++ b/desktop/src/components/ChatArea.tsx @@ -72,13 +72,27 @@ export function ChatArea({ compact, onOpenDetail }: { compact?: boolean; onOpenD const saasModels = useSaaSStore((s) => s.availableModels); const isLoggedIn = useSaaSStore((s) => s.isLoggedIn); + // Track models that failed with API key errors in this session + const failedModelIds = useRef>(new Set()); + + // Scan messages for API key errors to populate failedModelIds + useEffect(() => { + for (const msg of messages) { + if (msg.error && (msg.error.includes('没有可用的 API Key') || msg.error.includes('Key Pool'))) { + failedModelIds.current.add(currentModel); + } + } + }, [messages, currentModel]); + // Merge models: SaaS available models take priority when logged in const models = useMemo(() => { + const failed = failedModelIds.current; if (isLoggedIn && saasModels.length > 0) { return saasModels.map(m => ({ id: m.alias || m.id, name: m.alias || m.id, provider: m.provider_id, + available: !failed.has(m.alias || m.id), })); } if (configModels.length > 0) { diff --git a/desktop/src/components/VikingPanel.tsx b/desktop/src/components/VikingPanel.tsx index 997d569..675a9c6 100644 --- a/desktop/src/components/VikingPanel.tsx +++ b/desktop/src/components/VikingPanel.tsx @@ -196,68 +196,89 @@ export function VikingPanel() { )} {/* Storage Info */} - {status?.available && ( -
-
-
- +
+
+
+ +
+
+
+ 本地存储
-
-
- 本地存储 -
-
- {status.version || 'Native'} · {status.dataDir || '默认路径'} -
+
+ {status?.available + ? `${status.version || 'Native'} · ${status.dataDir || '默认路径'}` + : '存储未连接'}
-
-
- - SQLite + FTS5 -
-
- - TF-IDF 语义评分 -
- {memoryCount !== null && ( -
- - {memoryCount} 条记忆 -
- )} -
+ {!status?.available && ( + + )}
- )} +
+
+ {status?.available ? ( + + ) : ( + + )} + SQLite + FTS5 +
+
+ {status?.available ? ( + + ) : ( + + )} + TF-IDF 语义评分 +
+ {memoryCount !== null && ( +
+ + {memoryCount} 条记忆 +
+ )} +
+
{/* Search Box */} - {status?.available && ( -
-

语义搜索

-
- setSearchQuery(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - placeholder="输入自然语言查询..." - className="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-900 text-gray-900 dark:text-white text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> - -
+
+

语义搜索

+ {!status?.available && ( +

+ 存储未连接,搜索功能不可用 +

+ )} +
+ setSearchQuery(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} + placeholder="输入自然语言查询..." + disabled={!status?.available} + className="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-900 text-gray-900 dark:text-white text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" + /> +
- )} +
{/* Search Results */} {searchResults.length > 0 && ( @@ -385,59 +406,64 @@ export function VikingPanel() { )} {/* Summary Generation */} - {status?.available && ( -
-

智能摘要

-

- 存储资源并自动通过 LLM 生成 L0/L1 多级摘要(需配置摘要驱动) +

+

智能摘要

+

+ 存储资源并自动通过 LLM 生成 L0/L1 多级摘要(需配置摘要驱动) +

+ {!status?.available && ( +

+ 存储未连接,摘要功能不可用

-
- setSummaryUri(e.target.value)} - placeholder="资源 URI (如: notes/project-plan)" - className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-900 text-gray-900 dark:text-white text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -