mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-10-13 19:18:14 +00:00
153 lines
3.8 KiB
TypeScript
153 lines
3.8 KiB
TypeScript
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.migrateConfig(this.currentConfig);
|
|
}
|
|
}
|
|
|
|
private migrateConfig(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();
|
|
}
|
|
|
|
public getConfig(key: string, defaultValue?: any): any {
|
|
const nested = key.split('.');
|
|
let obj: any = this.currentConfig;
|
|
|
|
for (let i = 0; i < nested.length; i++) {
|
|
const part = nested[i];
|
|
if (obj == null) return defaultValue;
|
|
|
|
obj = obj[part];
|
|
}
|
|
|
|
return obj === undefined ? defaultValue : obj;
|
|
}
|
|
}
|
|
|
|
const configManager = new ConfigManager();
|
|
|
|
export default configManager |