| import Dexie, { Table } from "dexie"; |
| import { IConfig, DEFAULT_CONFIG, loadAllModels } from "./types"; |
|
|
| export class ConfigManager extends Dexie { |
| configs!: Table<IConfig>; |
| private static instance: ConfigManager; |
| private currentConfig: IConfig | null = null; |
| private initPromise: Promise<IConfig> | null = null; |
|
|
| private constructor() { |
| super("configs"); |
| this.version(1).stores({ |
| configs: "id, createdAt, updatedAt", |
| }); |
| this.initPromise = this.initialize(); |
| } |
|
|
| public static getInstance(): ConfigManager { |
| if (!ConfigManager.instance) { |
| ConfigManager.instance = new ConfigManager(); |
| } |
| return ConfigManager.instance; |
| } |
|
|
| async initialize(): Promise<IConfig> { |
| |
| if (this.currentConfig) return this.currentConfig; |
| if (this.initPromise) return this.initPromise; |
| |
| try { |
| const configs = await this.configs.toArray(); |
| |
| if (configs.length === 0) { |
| |
| const defaultConfig: IConfig = { |
| ...DEFAULT_CONFIG, |
| id: crypto.randomUUID(), |
| createdAt: Date.now(), |
| updatedAt: Date.now(), |
| ollama_available: false |
| }; |
| |
| |
| if (defaultConfig.ollama_base_url.trim() !== '') { |
| defaultConfig.ollama_available = await this.checkOllamaAvailability(defaultConfig.ollama_base_url); |
| } |
| |
| await this.configs.add(defaultConfig); |
| this.currentConfig = defaultConfig; |
| } else { |
| |
| this.currentConfig = configs.sort((a, b) => b.updatedAt - a.updatedAt)[0]; |
| |
| |
| if (this.currentConfig.ollama_base_url.trim() !== '') { |
| const ollamaAvailable = await this.checkOllamaAvailability(this.currentConfig.ollama_base_url); |
| |
| |
| if (ollamaAvailable !== this.currentConfig.ollama_available) { |
| await this.updateConfig({ ollama_available: ollamaAvailable }); |
| } |
| } |
| } |
| |
| |
| await this.loadModels(); |
| return this.currentConfig; |
| } catch (error) { |
| console.error("Error initializing config:", error); |
| throw error; |
| } finally { |
| this.initPromise = null; |
| } |
| } |
|
|
| private async checkOllamaAvailability(baseUrl: string): Promise<boolean> { |
| if (!baseUrl || baseUrl.trim() === '') return false; |
| |
| try { |
| const response = await fetch(`${baseUrl}/api/tags`); |
| if (!response.ok) return false; |
| |
| const data = await response.json(); |
| return Array.isArray(data.models) && data.models.length > 0; |
| } catch (error) { |
| console.error("Ollama server not available:", error); |
| return false; |
| } |
| } |
|
|
| private async loadModels(): Promise<void> { |
| if (!this.currentConfig) return; |
| |
| try { |
| const { ollamaAvailable } = await loadAllModels( |
| this.currentConfig.ollama_base_url, |
| this.currentConfig.openai_model, |
| this.currentConfig.hf_custom_models |
| ); |
| |
| |
| if (ollamaAvailable !== this.currentConfig.ollama_available) { |
| await this.updateConfig({ ollama_available: ollamaAvailable }); |
| } |
| } catch (error) { |
| console.error("Error loading models:", error); |
| } |
| } |
|
|
| async getConfig(): Promise<IConfig> { |
| return this.currentConfig || this.initialize(); |
| } |
|
|
| async updateConfig(updates: Partial<Omit<IConfig, 'id' | 'createdAt' | 'updatedAt'>>): Promise<IConfig> { |
| const current = await this.getConfig(); |
| const updatedConfig: IConfig = { |
| ...current, |
| ...updates, |
| updatedAt: Date.now(), |
| }; |
| |
| await this.configs.put(updatedConfig); |
| this.currentConfig = updatedConfig; |
| |
| |
| if (updates.ollama_base_url !== undefined && |
| updates.ollama_base_url !== current.ollama_base_url) { |
| |
| |
| const ollamaAvailable = updates.ollama_base_url.trim() === '' |
| ? false |
| : await this.checkOllamaAvailability(updates.ollama_base_url); |
| |
| if (ollamaAvailable !== this.currentConfig.ollama_available) { |
| return this.updateConfig({ ollama_available: ollamaAvailable }); |
| } |
| |
| |
| await this.loadModels(); |
| } |
| |
| |
| if (updates.openai_model !== undefined && |
| updates.openai_model !== current.openai_model) { |
| await this.loadModels(); |
| } |
| |
| |
| if (updates.hf_custom_models !== undefined && |
| updates.hf_custom_models !== current.hf_custom_models) { |
| await this.loadModels(); |
| } |
| |
| return updatedConfig; |
| } |
|
|
| async resetToDefaults(): Promise<IConfig> { |
| const current = await this.getConfig(); |
| const resetConfig: IConfig = { |
| ...DEFAULT_CONFIG, |
| id: current.id, |
| createdAt: current.createdAt, |
| updatedAt: Date.now(), |
| ollama_available: false |
| }; |
| |
| |
| if (resetConfig.ollama_base_url.trim() !== '') { |
| resetConfig.ollama_available = await this.checkOllamaAvailability(resetConfig.ollama_base_url); |
| } |
| |
| await this.configs.put(resetConfig); |
| this.currentConfig = resetConfig; |
| |
| |
| await this.loadModels(); |
| |
| return resetConfig; |
| } |
| } |
|
|