From 0737300ee4b0314eff751dc38e2efefc8370f3bc Mon Sep 17 00:00:00 2001 From: Innei Date: Mon, 11 Aug 2025 23:26:32 +0800 Subject: [PATCH] feat(ai): implement auto-scroll feature and initialize settings - Updated the AI chat settings to include an auto-scroll feature when streaming messages. - Introduced a new settings initialization function to set default values for various AI settings. - Enhanced the ChatInterface component to utilize the new auto-scroll setting for improved user experience. - Added localization support for the new auto-scroll setting in the English language file. These changes collectively enhance the functionality and usability of the AI chat interface. Signed-off-by: Innei --- .../desktop/layer/renderer/src/atoms/settings/ai.ts | 2 +- apps/desktop/layer/renderer/src/initialize/index.ts | 4 ++-- .../src/initialize/{hydrate.ts => settings.ts} | 4 +++- .../ai-chat/components/layouts/ChatInterface.tsx | 8 +++++++- .../layer/renderer/src/modules/settings/tabs/ai.tsx | 13 +++++++++++++ .../layer/renderer/src/providers/setting-sync.tsx | 1 + locales/ai/en.json | 3 +++ packages/internal/shared/src/settings/defaults.ts | 3 +++ packages/internal/shared/src/settings/interface.ts | 3 +++ 9 files changed, 36 insertions(+), 5 deletions(-) rename apps/desktop/layer/renderer/src/initialize/{hydrate.ts => settings.ts} (70%) diff --git a/apps/desktop/layer/renderer/src/atoms/settings/ai.ts b/apps/desktop/layer/renderer/src/atoms/settings/ai.ts index dad9bdc24..3a10f80ed 100644 --- a/apps/desktop/layer/renderer/src/atoms/settings/ai.ts +++ b/apps/desktop/layer/renderer/src/atoms/settings/ai.ts @@ -19,7 +19,7 @@ export const { export const aiServerSyncWhiteListKeys = [] // Local Setting for ai -const aiChatPinnedAtom = atom(false) +const aiChatPinnedAtom = atom(true) export const useAIChatPinned = () => useAtomValue(aiChatPinnedAtom) export const setAIChatPinned = (pinned: boolean) => { jotaiStore.set(aiChatPinnedAtom, pinned) diff --git a/apps/desktop/layer/renderer/src/initialize/index.ts b/apps/desktop/layer/renderer/src/initialize/index.ts index cdad3c140..5490b53af 100644 --- a/apps/desktop/layer/renderer/src/initialize/index.ts +++ b/apps/desktop/layer/renderer/src/initialize/index.ts @@ -14,9 +14,9 @@ import { subscribeNetworkStatus } from "../atoms/network" import { appLog } from "../lib/log" import { initAnalytics } from "./analytics" import { registerHistoryStack } from "./history" -import { hydrateSettings } from "./hydrate" import { doMigration } from "./migrates" import { initSentry } from "./sentry" +import { initializeSettings } from "./settings" declare global { interface Window { @@ -80,7 +80,7 @@ export const initializeApp = async () => { subscribeNetworkStatus() - apm("hydrateSettings", hydrateSettings) + apm("initializeSettings", initializeSettings) initSentry() await apm("i18n", initI18n) diff --git a/apps/desktop/layer/renderer/src/initialize/hydrate.ts b/apps/desktop/layer/renderer/src/initialize/settings.ts similarity index 70% rename from apps/desktop/layer/renderer/src/initialize/hydrate.ts rename to apps/desktop/layer/renderer/src/initialize/settings.ts index 5e3a150c4..ef75d72c4 100644 --- a/apps/desktop/layer/renderer/src/initialize/hydrate.ts +++ b/apps/desktop/layer/renderer/src/initialize/settings.ts @@ -1,9 +1,11 @@ +import { initializeDefaultAISettings } from "~/atoms/settings/ai" import { initializeDefaultGeneralSettings } from "~/atoms/settings/general" import { initializeDefaultIntegrationSettings } from "~/atoms/settings/integration" import { initializeDefaultUISettings } from "~/atoms/settings/ui" -export const hydrateSettings = () => { +export const initializeSettings = () => { initializeDefaultUISettings() initializeDefaultGeneralSettings() initializeDefaultIntegrationSettings() + initializeDefaultAISettings() } diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx index 411db4fc9..f4c1c8fbb 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx @@ -10,6 +10,7 @@ import type { FC } from "react" import { Suspense, useEffect, useState } from "react" import { useEventCallback } from "usehooks-ts" +import { useAISettingKey } from "~/atoms/settings/ai" import { AIChatMessage, AIChatWaitingIndicator, @@ -73,7 +74,12 @@ const ChatInterfaceContent = () => { }, }) - const { resetScrollState } = useAutoScroll(scrollAreaRef, status === "streaming") + const autoScrollWhenStreaming = useAISettingKey("autoScrollWhenStreaming") + + const { resetScrollState } = useAutoScroll( + scrollAreaRef, + autoScrollWhenStreaming && status === "streaming", + ) useEffect(() => { const scrollElement = scrollAreaRef diff --git a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx index a8f881ed7..3c10ce130 100644 --- a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx +++ b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx @@ -11,9 +11,11 @@ import { toast } from "sonner" import { setAISetting, useAISettingValue } from "~/atoms/settings/ai" import { SettingActionItem, SettingDescription } from "../control" +import { createDefineSettingItem } from "../helper/builder" import { createSettingBuilder } from "../helper/setting-builder" const SettingBuilder = createSettingBuilder(useAISettingValue) +const defineSettingItem = createDefineSettingItem(useAISettingValue, setAISetting) export const SettingAI = () => { const { t } = useTranslation("ai") @@ -22,11 +24,22 @@ export const SettingAI = () => {
{ useUXSettingSync() useLanguageSync() useGeneralSettingSync() + return null } diff --git a/locales/ai/en.json b/locales/ai/en.json index de1fc40ac..ff70c3a0f 100644 --- a/locales/ai/en.json +++ b/locales/ai/en.json @@ -1,4 +1,6 @@ { + "autoScrollWhenStreaming.description": "Automatically scroll to the bottom of the chat when streaming", + "autoScrollWhenStreaming.label": "Auto scroll when streaming", "clear_chat": "Clear Chat", "clear_chat_message": "Are you sure you want to clear all history? This action will permanently delete all content, including all chat logs and data, and cannot be undone.", "delete_chat": "Delete Chat", @@ -8,6 +10,7 @@ "export_empty_chat": "Cannot export an empty chat", "export_error": "Failed to export chat", "export_success": "Chat exported successfully", + "features.title": "Features", "personalize.description": "Tell me about yourself to get personalized AI responses", "personalize.prompt.help": "This helps AI provide personalized responses based on your preferences.", "personalize.prompt.label": "Personal Prompt", diff --git a/packages/internal/shared/src/settings/defaults.ts b/packages/internal/shared/src/settings/defaults.ts index 54033c9fb..be2158999 100644 --- a/packages/internal/shared/src/settings/defaults.ts +++ b/packages/internal/shared/src/settings/defaults.ts @@ -155,6 +155,9 @@ export const defaultIntegrationSettings: IntegrationSettings = { export const defaultAISettings: AISettings = { personalizePrompt: "", shortcuts: [], + + // Features + autoScrollWhenStreaming: true, } export const defaultSettings = { diff --git a/packages/internal/shared/src/settings/interface.ts b/packages/internal/shared/src/settings/interface.ts index 75025cd1b..c827740b6 100644 --- a/packages/internal/shared/src/settings/interface.ts +++ b/packages/internal/shared/src/settings/interface.ts @@ -181,4 +181,7 @@ export interface AIShortcut { export interface AISettings { personalizePrompt: string shortcuts: AIShortcut[] + + // Features + autoScrollWhenStreaming: boolean }