mirror of
https://github.com/readest/readest
synced 2026-04-21 13:37:44 +00:00
* feat(ai): add dependencies * chore: bump zod version to default version * feat(ai): define types and model constants * feat(ai): ollama provider for local LLM * feat(ai): implement openrouter provider for cloud models * feat(settings): register ai settings panel in global dialog * refactor(ai): expose provider factory and service layer entry point * test(ai): add unit tests for the providers * test(ai): add unit tests for the providers * feat(ai): settings panel for ai configurations * refactor(ai): rewrite aipanel with autosave and greyed out disabled state * fix: remove unused onClose prop from aipanel * test(ai): update mock data * refactor(ai): remove models * refactor: use centralised defaults in system defaults * chore(ai): remove comments * fix(ai): merge default ai settings on load to prevent undefined values * refactor(ai): rewrite settings panel with autosave and model input * feat(ai): add ai tab with simplified highlighting * feat(sidebar): render AIAssistant for ai tab * feat(ai): add chat UI * feat(ai); add chat service with RAG context * feat(ai): temp debug logger * feat(ai): add RAG service * feat(ai): add text chunking utility * feat(ai): add structured method * feat(ai): add chatstructured method * feat(ai): add rag types nd structured output schema * feat(ai): add aistore, indexdb, bm25 * fix: update lock file * feat(ai): update types for AI SDK v5 * feat(ai): add placeholder gateway model constants * refactor(ai): update OllamaProvider for AI SDK * feat(ai): add native gateway provider * refactor(ai): update provider exports * refactor(ai): use streamText from AI SDK * refactor(ai): use embed from AI sdk * refactor(ai): update provider factory exports * feat(ai): add AI Elements and shadcn components * config: add shadcn component config * deps: add AI SDK and AI Elements dependencies * config: add ai packages to transpilePackages * refactor(ai): remove OpenRouterProvider and old tests * feat(ai):add assistant-ui components * feat(ai): add TauriChatAdapter for assistant-ui runtime * refactor(ai): remove ai-elements components * dep(ai): install assistant-ui and update next config * chore(ai): export adapters from service index * feat(ui): enhance ui components for assistant integration * feat(settings): migrate ai settings to gateway * feat(sidebar): integrate assistant-ui * feat: add ai settings toggle to sidebar content * feat: conditionally show ai tab in sidebar navigation * feat: update ai model constants for cheaper options * feat: add gateway provider with proxied embedding * feat: add timeouts to ollama provider health checks * feat: add retry logic to rag service embeddings * feat: add error recovery to ai store * feat: add ai feature tests * feat: add ai api endpoints * feat: add proxied gateway embedding provider * feat: add ai runtime utilities * feat: add ai retry utilities * feat: add tauri env example template * feat: add web env example template * chore: add env * feat(ai): update models and pricing, remove GLM-4.7-FlashX * feat(ai): improve system prompt with official headings and no numeric citations * feat(ai): optimize system prompt for tauri chat * feat(ui): refine ai chat UI and relocate sources * feat(ui): update ai settings panel with model pricing and custom model support * feat(ai): add custom model support to ai settings * test(ai): update constants tests for removed model * feat(api): implement ai chat proxy route * feat(api): implement ai embedding proxy route * feat(ai): implement ai gateway health check and proxy logic * feat(ai): simplify proxied embedding provider * feat(ui): improve markdown text rendering * feat(ui): add input group component * test(ai): update ai provider tests * feat(ai): add pageNumber to text chunk schema * feat(ai): implement page-based chunking with 1500 char formula * feat(ai): bump db to v2 and add store reset migration * feat(ai): transition rag pipeline to page level spoiler filtering * feat(ai): overhaul readest persona and antijailbreak prompt * feat(ai): update tauri adapter for page tracking and persona * chore(ai): export aiStore and logger from core index * feat(reader): integrate page tracking and manual index reset * feat(ui): add re-index action and reset logic to chat * chore: sync pnpm lockfile with ai dependencies * feat(utils): add browser-safe file utilities for web builds * refactor(utils): use dynamic tauri fs import to prevent web crashes * refactor(services): defer osType call to init() for web compatibility * refactor(services): import RemoteFile from file.web * refactor(services): import ClosableFile from file.web * fix(libs): cast Entry to any for getData access * fix(annotator): cast Overlayer to any for bubble access * refactor(ai): replace SparklesIcon with BookOpenIcon for index prompt * test(ai): add pageNumber to TextChunk mocks * test(ai): fix chunkSection signature in tests * chore: update files * fix(ai): prevent useLocalRuntime crash when adapter is null * refactor: optimize annotator overlay drawing * feat: stabilize AI assistant runtime and adapter * refactor: improve document zip loader type safety * feat: update tauri chat adapter for dynamic options * fix: restore architecture comments and refine platform properties * build: update lockfile with assistant-ui patch * fix(library): patch @assistant-ui/react for runtime initialization * build: update dependencies in readest-app * build: update root dependencies and patch configuration * fix(ai): patch @assistant-ui/react for thread deletion and runtime init * fix(ai): update assistant-ui patch with dist guards and deletion fallback * build: sync lockfile with assistant-ui patch updates * chore(env): update .gitignore by removing .env files from it * chore(env): update .gitignore by adding .env.local * chore(env): update .gitignore by adding .env*.local * fix: restore static osType import * chore: sync submodules with upstream/main * refactor: remove redundant file.web module and revert import * chore: update pnpm-lock.yaml * refactor: revert guards * refactor; remove deprecated codes and extract prompts.ts * refactor(ai): remove unused ragservice exports * refactor: remove unused ollama and embedding models * refactor: remove unused type * test: remove test for the now deleted constants * refactor: remove unused export * style: fix ui component formatting * style: fix core and style file formatting * test: fix broken ai provider import * fix: typescript error * fix: add eslint disable command * fix(deps): remove unused ai sdk provider util after v6 ai sdk migration * fix(patch): add lookbehind regex patch * feat(dep): upgrade vercel ai sdk to v6 and ai-sdk-ollama to v3 * chore: update lockfile for vercel ai sdk v6 * refactor(ai): remove EmbeddingModel generic for ai sdk v6 * refactor(ai): remove EmbeddingModel generic for ai sdk v6 * test(ai): update mock to use embeddingModel * fix(patch): add lookbehind regex patch for email autolinks in markdown * refactor(ai): use ai sdk v6 syntax * fix: prettier formatting * chore: revert cargo.lock * fix(ai): update proxied embedding model to v3 spec * feat(ai): add aiconversation types for chat persistence * feat(ai): add conversation/message indexeddb and crud operations * feat(ai): create aiChatStore zustand store for chat state management * feat(notebook): add notebookactivetab state for Notes/AI * refactor(ai): refine conversation and message types for persistence * feat(types): add notebookActiveTab to ReadSettings type * chore: update deps * feat: add notebookactive tab default value * feat: add hook for ai chat * feat: update left side panel with history/chat icon * feat: integrate ChatHistoryView into sidebar content * feat: create UI for managing AI chat history * feat: implement persistent history with assistant-ui adapter * feat: create tab navigation component for notes and AI * feat: add tab navigation and AI assistant view * feat: update header to display active tab title * fix: formatting * feat: remove title and update new chat button * fix: formatting * fix: revert tooltip and styling * feat: implement cross-platform ask dialog bridge * feat(ai): preserve history during ui clear & use native dialogs * fix: align notebook navigation height with sidebar tabs * fix(ai): add missing dependency to handleDeleteConversation hook * docs: update PROJECT.md with session highlights * chore: delete projectmd * chore: update package.json and lock file * chore: update package.json * chore: remove patch * chore: upgrade react types to 19 and show ai features only in development mode for now --------- Co-authored-by: Huang Xin <chrox.huang@gmail.com>
121 lines
4.1 KiB
TypeScript
121 lines
4.1 KiB
TypeScript
import clsx from 'clsx';
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
import { BookDoc } from '@/libs/document';
|
|
import { useThemeStore } from '@/store/themeStore';
|
|
import { useReaderStore } from '@/store/readerStore';
|
|
import { useSidebarStore } from '@/store/sidebarStore';
|
|
import { useBookDataStore } from '@/store/bookDataStore';
|
|
import { useSettingsStore } from '@/store/settingsStore';
|
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
|
import 'overlayscrollbars/overlayscrollbars.css';
|
|
|
|
import TOCView from './TOCView';
|
|
import BooknoteView from './BooknoteView';
|
|
import TabNavigation from './TabNavigation';
|
|
import ChatHistoryView from './ChatHistoryView';
|
|
|
|
const SidebarContent: React.FC<{
|
|
bookDoc: BookDoc;
|
|
sideBarBookKey: string;
|
|
}> = ({ bookDoc, sideBarBookKey }) => {
|
|
const { safeAreaInsets } = useThemeStore();
|
|
const { setHoveredBookKey } = useReaderStore();
|
|
const { setSideBarVisible } = useSidebarStore();
|
|
const { getConfig, setConfig } = useBookDataStore();
|
|
const { settings } = useSettingsStore();
|
|
const config = getConfig(sideBarBookKey);
|
|
const [activeTab, setActiveTab] = useState(config?.viewSettings?.sideBarTab || 'toc');
|
|
const [fade, setFade] = useState(false);
|
|
const [targetTab, setTargetTab] = useState(activeTab);
|
|
const isMobile = window.innerWidth < 640 || window.innerHeight < 640;
|
|
const aiEnabled = settings?.aiSettings?.enabled ?? false;
|
|
|
|
useEffect(() => {
|
|
if (!sideBarBookKey) return;
|
|
const config = getConfig(sideBarBookKey!)!;
|
|
setActiveTab(config.viewSettings!.sideBarTab!);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [sideBarBookKey]);
|
|
|
|
// reset to toc if history tab was active but AI is now disabled
|
|
useEffect(() => {
|
|
if ((activeTab === 'history' || targetTab === 'history') && !aiEnabled) {
|
|
setActiveTab('toc');
|
|
setTargetTab('toc');
|
|
}
|
|
}, [aiEnabled, activeTab, targetTab]);
|
|
|
|
const handleTabChange = (tab: string) => {
|
|
setFade(true);
|
|
const timeout = setTimeout(() => {
|
|
if (activeTab === tab && isMobile) {
|
|
setHoveredBookKey(sideBarBookKey);
|
|
setSideBarVisible(false);
|
|
return;
|
|
}
|
|
setTargetTab(tab);
|
|
setFade(false);
|
|
setConfig(sideBarBookKey!, config);
|
|
clearTimeout(timeout);
|
|
}, 300);
|
|
|
|
setActiveTab(tab);
|
|
const config = getConfig(sideBarBookKey!)!;
|
|
config.viewSettings!.sideBarTab = tab;
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
className={clsx(
|
|
'sidebar-content flex h-full min-h-0 flex-grow flex-col shadow-inner',
|
|
'font-sans text-base font-normal sm:text-sm',
|
|
)}
|
|
>
|
|
{targetTab === 'history' ? (
|
|
<ChatHistoryView bookKey={sideBarBookKey} />
|
|
) : (
|
|
<OverlayScrollbarsComponent
|
|
className='min-h-0 flex-1'
|
|
options={{
|
|
scrollbars: { autoHide: 'scroll', clickScroll: true },
|
|
showNativeOverlaidScrollbars: false,
|
|
}}
|
|
defer
|
|
>
|
|
<div
|
|
className={clsx(
|
|
'scroll-container h-full transition-opacity duration-300 ease-in-out',
|
|
{
|
|
'opacity-0': fade,
|
|
'opacity-100': !fade,
|
|
},
|
|
)}
|
|
>
|
|
{targetTab === 'toc' && bookDoc.toc && (
|
|
<TOCView toc={bookDoc.toc} sections={bookDoc.sections} bookKey={sideBarBookKey} />
|
|
)}
|
|
{targetTab === 'annotations' && (
|
|
<BooknoteView type='annotation' toc={bookDoc.toc ?? []} bookKey={sideBarBookKey} />
|
|
)}
|
|
{targetTab === 'bookmarks' && (
|
|
<BooknoteView type='bookmark' toc={bookDoc.toc ?? []} bookKey={sideBarBookKey} />
|
|
)}
|
|
</div>
|
|
</OverlayScrollbarsComponent>
|
|
)}
|
|
</div>
|
|
<div
|
|
className='flex-shrink-0'
|
|
style={{
|
|
paddingBottom: `${(safeAreaInsets?.bottom || 0) / 2}px`,
|
|
}}
|
|
>
|
|
<TabNavigation activeTab={activeTab} onTabChange={handleTabChange} />
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default SidebarContent;
|