This commit is contained in:
duanfuxiang
2025-01-05 11:51:39 +08:00
commit 0c7ee142cb
215 changed files with 20611 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
import { App } from 'obsidian'
import React from 'react'
// App context
const AppContext = React.createContext<App | undefined>(undefined)
export const AppProvider = ({
children,
app,
}: {
children: React.ReactNode
app: App
}) => {
return <AppContext.Provider value={app}>{children}</AppContext.Provider>
}
export const useApp = () => {
const app = React.useContext(AppContext)
if (!app) {
throw new Error('useApp must be used within an AppProvider')
}
return app
}

View File

@@ -0,0 +1,46 @@
import {
ReactNode,
createContext,
useContext,
useEffect,
useState,
} from 'react'
import { useApp } from './AppContext'
type DarkModeContextType = {
isDarkMode: boolean
}
const DarkModeContext = createContext<DarkModeContextType | undefined>(
undefined,
)
export function DarkModeProvider({ children }: { children: ReactNode }) {
const [isDarkMode, setIsDarkMode] = useState(false)
const app = useApp()
useEffect(() => {
const handleDarkMode = () => {
setIsDarkMode(document.body.classList.contains('theme-dark'))
}
handleDarkMode()
app.workspace.on('css-change', handleDarkMode)
return () => app.workspace.off('css-change', handleDarkMode)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<DarkModeContext.Provider value={{ isDarkMode }}>
{children}
</DarkModeContext.Provider>
)
}
export function useDarkModeContext() {
const context = useContext(DarkModeContext)
if (context === undefined) {
throw new Error('useDarkModeContext must be used within a DarkModeProvider')
}
return context
}

View File

@@ -0,0 +1,58 @@
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
} from 'react'
import { DBManager } from '../database/database-manager'
import { TemplateManager } from '../database/modules/template/template-manager'
import { VectorManager } from '../database/modules/vector/vector-manager'
type DatabaseContextType = {
getDatabaseManager: () => Promise<DBManager>
getVectorManager: () => Promise<VectorManager>
getTemplateManager: () => Promise<TemplateManager>
}
const DatabaseContext = createContext<DatabaseContextType | null>(null)
export function DatabaseProvider({
children,
getDatabaseManager,
}: {
children: React.ReactNode
getDatabaseManager: () => Promise<DBManager>
}) {
const getVectorManager = useCallback(async () => {
return (await getDatabaseManager()).getVectorManager()
}, [getDatabaseManager])
const getTemplateManager = useCallback(async () => {
return (await getDatabaseManager()).getTemplateManager()
}, [getDatabaseManager])
useEffect(() => {
// start initialization of dbManager in the background
void getDatabaseManager()
}, [getDatabaseManager])
const value = useMemo(() => {
return { getDatabaseManager, getVectorManager, getTemplateManager }
}, [getDatabaseManager, getVectorManager, getTemplateManager])
return (
<DatabaseContext.Provider value={value}>
{children}
</DatabaseContext.Provider>
)
}
export function useDatabase(): DatabaseContextType {
const context = useContext(DatabaseContext)
if (!context) {
throw new Error('useDatabase must be used within a DatabaseProvider')
}
return context
}

View File

@@ -0,0 +1,27 @@
import React, { createContext, useContext } from 'react'
const DialogContext = createContext<HTMLElement | null>(null)
export function DialogProvider({
children,
container,
}: {
children: React.ReactNode
container: HTMLElement | null
}) {
return (
<DialogContext.Provider value={container}>
{children}
</DialogContext.Provider>
)
}
export function useDialogContainer() {
const context = useContext(DialogContext)
if (!context) {
throw new Error(
'useDialogContainer must be used within a DialogContainerProvider',
)
}
return context
}

135
src/contexts/LLMContext.tsx Normal file
View File

@@ -0,0 +1,135 @@
import {
PropsWithChildren,
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'
import LLMManager from '../core/llm/manager'
import { CustomLLMModel } from '../types/llm/model'
import {
LLMOptions,
LLMRequestNonStreaming,
LLMRequestStreaming,
} from '../types/llm/request'
import {
LLMResponseNonStreaming,
LLMResponseStreaming,
} from '../types/llm/response'
import { useSettings } from './SettingsContext'
export type LLMContextType = {
generateResponse: (
model: CustomLLMModel,
request: LLMRequestNonStreaming,
options?: LLMOptions,
) => Promise<LLMResponseNonStreaming>
streamResponse: (
model: CustomLLMModel,
request: LLMRequestStreaming,
options?: LLMOptions,
) => Promise<AsyncIterable<LLMResponseStreaming>>
chatModel: CustomLLMModel
applyModel: CustomLLMModel
}
const LLMContext = createContext<LLMContextType | null>(null)
export function LLMProvider({ children }: PropsWithChildren) {
const [llmManager, setLLMManager] = useState<LLMManager | null>(null)
const { settings } = useSettings()
const chatModel = useMemo((): CustomLLMModel => {
const model = settings.activeModels.find(
(option) => option.name === settings.chatModelId,
)
if (!model) {
throw new Error('Invalid chat model ID')
}
return model
}, [settings])
const applyModel = useMemo((): CustomLLMModel => {
const model = settings.activeModels.find(
(option) => option.name === settings.applyModelId,
)
if (!model) {
throw new Error('Invalid apply model ID')
}
if (model.provider === 'ollama') {
return {
provider: 'ollama',
baseURL: settings.ollamaApplyModel.baseUrl,
model: settings.ollamaApplyModel.model,
}
}
return model
}, [settings])
useEffect(() => {
const manager = new LLMManager({
deepseek: settings.deepseekApiKey,
openai: settings.openAIApiKey,
anthropic: settings.anthropicApiKey,
gemini: settings.geminiApiKey,
groq: settings.groqApiKey,
infio: settings.infioApiKey,
})
setLLMManager(manager)
}, [
settings.deepseekApiKey,
settings.openAIApiKey,
settings.anthropicApiKey,
settings.geminiApiKey,
settings.groqApiKey,
settings.infioApiKey,
])
const generateResponse = useCallback(
async (
model: CustomLLMModel,
request: LLMRequestNonStreaming,
options?: LLMOptions,
) => {
if (!llmManager) {
throw new Error('LLMManager is not initialized')
}
return await llmManager.generateResponse(model, request, options)
},
[llmManager],
)
const streamResponse = useCallback(
async (
model: CustomLLMModel,
request: LLMRequestStreaming,
options?: LLMOptions,
) => {
if (!llmManager) {
throw new Error('LLMManager is not initialized')
}
return await llmManager.streamResponse(model, request, options)
},
[llmManager],
)
return (
<LLMContext.Provider
value={{ generateResponse, streamResponse, chatModel, applyModel }}
>
{children}
</LLMContext.Provider>
)
}
export function useLLM() {
const context = useContext(LLMContext)
if (!context) {
throw new Error('useLLM must be used within an LLMProvider')
}
return context
}

View File

@@ -0,0 +1,39 @@
import {
PropsWithChildren,
createContext,
useContext,
useEffect,
useMemo,
} from 'react'
import { RAGEngine } from '../core/rag/rag-engine'
export type RAGContextType = {
getRAGEngine: () => Promise<RAGEngine>
}
const RAGContext = createContext<RAGContextType | null>(null)
export function RAGProvider({
getRAGEngine,
children,
}: PropsWithChildren<{ getRAGEngine: () => Promise<RAGEngine> }>) {
useEffect(() => {
// start initialization of ragEngine in the background
void getRAGEngine()
}, [getRAGEngine])
const value = useMemo(() => {
return { getRAGEngine }
}, [getRAGEngine])
return <RAGContext.Provider value={value}>{children}</RAGContext.Provider>
}
export function useRAG() {
const context = useContext(RAGContext)
if (!context) {
throw new Error('useRAG must be used within a RAGProvider')
}
return context
}

View File

@@ -0,0 +1,58 @@
import React, { useEffect, useMemo, useState } from 'react'
import { InfioSettings } from '../types/settings'
type SettingsContextType = {
settings: InfioSettings
setSettings: (newSettings: InfioSettings) => void
}
// Settings context
const SettingsContext = React.createContext<SettingsContextType | undefined>(
undefined,
)
export const SettingsProvider = ({
children,
settings: initialSettings,
setSettings,
addSettingsChangeListener,
}: {
children: React.ReactNode
settings: InfioSettings
setSettings: (newSettings: InfioSettings) => void
addSettingsChangeListener: (
listener: (newSettings: InfioSettings) => void,
) => () => void
}) => {
const [settingsCached, setSettingsCached] = useState(initialSettings)
useEffect(() => {
const removeListener = addSettingsChangeListener((newSettings) => {
setSettingsCached(newSettings)
})
return () => {
removeListener()
}
}, [addSettingsChangeListener, setSettings])
const value = useMemo(
() => ({ settings: settingsCached, setSettings }),
[settingsCached, setSettings],
)
return (
<SettingsContext.Provider value={value}>
{children}
</SettingsContext.Provider>
)
}
export const useSettings = () => {
const settings = React.useContext(SettingsContext)
if (!settings) {
throw new Error('useSettings must be used within a SettingsProvider')
}
return settings
}