mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-10-14 03:28:14 +00:00
feat(app): initialize new config management
This commit is contained in:
137
src/lib/config/index.ts
Normal file
137
src/lib/config/index.ts
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import path from 'node:path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { Config, ConfigModelProvider, EnvMap, UIConfigSections } from './types';
|
||||||
|
import ModelRegistry from '../models/registry';
|
||||||
|
import { hashObj } from '../serverUtils';
|
||||||
|
|
||||||
|
class ConfigManager {
|
||||||
|
configPath: string = path.join(
|
||||||
|
process.env.DATA_DIR || process.cwd(),
|
||||||
|
'/data/config.json',
|
||||||
|
);
|
||||||
|
configVersion = 1;
|
||||||
|
currentConfig: Config = {
|
||||||
|
version: this.configVersion,
|
||||||
|
general: {},
|
||||||
|
modelProviders: [],
|
||||||
|
};
|
||||||
|
uiConfigSections: UIConfigSections = {
|
||||||
|
general: [],
|
||||||
|
modelProviders: [],
|
||||||
|
};
|
||||||
|
modelRegistry = new ModelRegistry();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initialize() {
|
||||||
|
this.initializeConfig();
|
||||||
|
this.initializeFromEnv();
|
||||||
|
}
|
||||||
|
|
||||||
|
private saveConfig() {
|
||||||
|
fs.writeFileSync(
|
||||||
|
this.configPath,
|
||||||
|
JSON.stringify(this.currentConfig, null, 2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeConfig() {
|
||||||
|
const exists = fs.existsSync(this.configPath);
|
||||||
|
if (!exists) {
|
||||||
|
fs.writeFileSync(
|
||||||
|
this.configPath,
|
||||||
|
JSON.stringify(this.currentConfig, null, 2),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
this.currentConfig = JSON.parse(
|
||||||
|
fs.readFileSync(this.configPath, 'utf-8'),
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof SyntaxError) {
|
||||||
|
console.error(
|
||||||
|
`Error parsing config file at ${this.configPath}:`,
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Loading default config and overwriting the existing file.',
|
||||||
|
);
|
||||||
|
fs.writeFileSync(
|
||||||
|
this.configPath,
|
||||||
|
JSON.stringify(this.currentConfig, null, 2),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.log('Unknown error reading config file:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentConfig = this.migrateConfigNeeded(this.currentConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private migrateConfigNeeded(config: Config): Config {
|
||||||
|
/* TODO: Add migrations */
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeFromEnv() {
|
||||||
|
const providerConfigSections = this.modelRegistry.getUIConfigSection();
|
||||||
|
|
||||||
|
this.uiConfigSections.modelProviders = providerConfigSections;
|
||||||
|
|
||||||
|
const newProviders: ConfigModelProvider[] = [];
|
||||||
|
|
||||||
|
providerConfigSections.forEach((provider) => {
|
||||||
|
const newProvider: ConfigModelProvider & { required?: string[] } = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
name: `${provider.name} ${Math.floor(Math.random() * 1000)}`,
|
||||||
|
type: provider.key,
|
||||||
|
chatModels: [],
|
||||||
|
embeddingModels: [],
|
||||||
|
config: {},
|
||||||
|
required: [],
|
||||||
|
hash: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
provider.fields.forEach((field) => {
|
||||||
|
newProvider.config[field.key] =
|
||||||
|
process.env[field.env!] ||
|
||||||
|
field.default ||
|
||||||
|
''; /* Env var must exist for providers */
|
||||||
|
|
||||||
|
if (field.required) newProvider.required?.push(field.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
let configured = true;
|
||||||
|
|
||||||
|
newProvider.required?.forEach((r) => {
|
||||||
|
if (!newProvider.config[r]) {
|
||||||
|
configured = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (configured) {
|
||||||
|
const hash = hashObj(newProvider.config);
|
||||||
|
newProvider.hash = hash;
|
||||||
|
delete newProvider.required;
|
||||||
|
|
||||||
|
const exists = this.currentConfig.modelProviders.find(
|
||||||
|
(p) => p.hash === hash,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!exists) {
|
||||||
|
newProviders.push(newProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.currentConfig.modelProviders.push(...newProviders);
|
||||||
|
|
||||||
|
this.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new ConfigManager();
|
82
src/lib/config/types.ts
Normal file
82
src/lib/config/types.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
type BaseUIConfigField = {
|
||||||
|
name: string;
|
||||||
|
key: string;
|
||||||
|
required: boolean;
|
||||||
|
description: string;
|
||||||
|
scope: 'client' | 'server';
|
||||||
|
env?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StringUIConfigField = BaseUIConfigField & {
|
||||||
|
type: 'string';
|
||||||
|
placeholder?: string;
|
||||||
|
default?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectUIConfigFieldOptions = {
|
||||||
|
name: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectUIConfigField = BaseUIConfigField & {
|
||||||
|
type: 'select';
|
||||||
|
default?: string;
|
||||||
|
options: SelectUIConfigFieldOptions[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type PasswordUIConfigField = BaseUIConfigField & {
|
||||||
|
type: 'password';
|
||||||
|
placeholder?: string;
|
||||||
|
default?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UIConfigField =
|
||||||
|
| StringUIConfigField
|
||||||
|
| SelectUIConfigField
|
||||||
|
| PasswordUIConfigField;
|
||||||
|
|
||||||
|
type ConfigModelProvider = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
chatModels: string[];
|
||||||
|
embeddingModels: string[];
|
||||||
|
config: { [key: string]: any };
|
||||||
|
hash: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Config = {
|
||||||
|
version: number;
|
||||||
|
general: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
modelProviders: ConfigModelProvider[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type EnvMap = {
|
||||||
|
[key: string]: {
|
||||||
|
fieldKey: string;
|
||||||
|
providerKey: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type ModelProviderUISection = {
|
||||||
|
name: string;
|
||||||
|
key: string;
|
||||||
|
fields: UIConfigField[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type UIConfigSections = {
|
||||||
|
general: UIConfigField[];
|
||||||
|
modelProviders: ModelProviderUISection[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type {
|
||||||
|
UIConfigField,
|
||||||
|
Config,
|
||||||
|
EnvMap,
|
||||||
|
UIConfigSections,
|
||||||
|
ModelProviderUISection,
|
||||||
|
ConfigModelProvider,
|
||||||
|
};
|
Reference in New Issue
Block a user