Files
colanode/apps/server/src/lib/configuration.ts

316 lines
9.0 KiB
TypeScript
Raw Normal View History

2025-01-05 12:13:46 +01:00
export interface Configuration {
server: ServerConfiguration;
2025-01-05 20:25:48 +01:00
account: AccountConfiguration;
user: UserConfiguration;
2025-01-05 12:13:46 +01:00
postgres: PostgresConfiguration;
redis: RedisConfiguration;
avatarS3: S3Configuration;
fileS3: S3Configuration;
2025-01-05 12:36:40 +01:00
smtp: SmtpConfiguration;
2025-01-05 12:13:46 +01:00
ai: AiConfiguration;
}
export type ServerMode = 'standalone' | 'cluster';
2025-01-05 12:13:46 +01:00
export interface ServerConfiguration {
name: string;
avatar: string;
mode: ServerMode;
2025-01-05 12:13:46 +01:00
}
2025-01-05 20:25:48 +01:00
export type AccountVerificationType = 'automatic' | 'manual' | 'email';
export interface AccountConfiguration {
verificationType: AccountVerificationType;
otpTimeout: number;
allowGoogleLogin: boolean;
}
export interface UserConfiguration {
storageLimit: bigint;
maxFileSize: bigint;
}
2025-01-05 12:13:46 +01:00
export interface PostgresConfiguration {
url: string;
ssl: {
rejectUnauthorized?: boolean;
ca?: string;
key?: string;
cert?: string;
};
2025-01-05 12:13:46 +01:00
}
export interface RedisConfiguration {
url: string;
db: number;
2025-01-13 11:17:32 +01:00
jobs: {
prefix: string;
name: string;
};
2025-01-05 12:13:46 +01:00
eventsChannel: string;
}
export interface S3Configuration {
endpoint: string;
accessKey: string;
secretKey: string;
bucketName: string;
region: string;
}
2025-01-05 12:36:40 +01:00
export interface SmtpConfiguration {
2025-01-05 12:13:46 +01:00
host: string;
port: number;
user: string;
password: string;
2025-01-05 20:25:48 +01:00
from: {
email: string;
name: string;
};
2025-01-05 12:13:46 +01:00
}
export type AIProvider = 'openai' | 'google';
export interface AIProviderConfiguration {
apiKey: string;
enabled?: boolean;
}
export interface AIModelConfiguration {
provider: AIProvider;
modelName: string;
temperature: number;
}
2025-01-05 12:13:46 +01:00
export interface AiConfiguration {
enabled: boolean;
entryEmbedDelay: number;
providers: {
openai: AIProviderConfiguration;
google: AIProviderConfiguration;
};
langfuse: {
publicKey: string;
secretKey: string;
baseUrl: string;
};
models: {
queryRewrite: AIModelConfiguration;
response: AIModelConfiguration;
rerank: AIModelConfiguration;
summarization: AIModelConfiguration;
contextEnhancer: AIModelConfiguration;
noContext: AIModelConfiguration;
intentRecognition: AIModelConfiguration;
};
embedding: {
provider: AIProvider;
apiKey: string;
modelName: string;
dimensions: number;
batchSize: number;
};
2025-01-05 12:13:46 +01:00
chunking: ChunkingConfiguration;
retrieval: RetrievalConfiguration;
2025-01-05 12:13:46 +01:00
}
export interface ChunkingConfiguration {
defaultChunkSize: number;
defaultOverlap: number;
enhanceWithContext: boolean;
}
export interface RetrievalConfiguration {
hybridSearch: {
semanticSearchWeight: number;
keywordSearchWeight: number;
maxResults: number;
};
2025-01-05 12:13:46 +01:00
}
const getRequiredEnv = (env: string): string => {
const value = process.env[env];
if (!value) {
throw new Error(`${env} is not set`);
}
return value;
};
const getOptionalEnv = (env: string): string | undefined => {
return process.env[env];
};
export const configuration: Configuration = {
server: {
name: getRequiredEnv('SERVER_NAME'),
avatar: getOptionalEnv('SERVER_AVATAR') || '',
mode: (getOptionalEnv('SERVER_MODE') as ServerMode) || 'standalone',
2025-01-05 12:13:46 +01:00
},
2025-01-05 20:25:48 +01:00
account: {
verificationType:
(getOptionalEnv(
'ACCOUNT_VERIFICATION_TYPE'
) as AccountVerificationType) || 'manual',
otpTimeout: parseInt(getOptionalEnv('ACCOUNT_OTP_TIMEOUT') || '600'),
allowGoogleLogin: getOptionalEnv('ACCOUNT_ALLOW_GOOGLE_LOGIN') === 'true',
},
user: {
storageLimit: BigInt(getOptionalEnv('USER_STORAGE_LIMIT') || '10737418240'),
maxFileSize: BigInt(getOptionalEnv('USER_MAX_FILE_SIZE') || '104857600'),
},
2025-01-05 12:13:46 +01:00
postgres: {
url: getRequiredEnv('POSTGRES_URL'),
ssl: {
rejectUnauthorized:
getOptionalEnv('POSTGRES_SSL_REJECT_UNAUTHORIZED') === undefined
? undefined
: getOptionalEnv('POSTGRES_SSL_REJECT_UNAUTHORIZED') === 'true',
ca: getOptionalEnv('POSTGRES_SSL_CA'),
key: getOptionalEnv('POSTGRES_SSL_KEY'),
cert: getOptionalEnv('POSTGRES_SSL_CERT'),
},
2025-01-05 12:13:46 +01:00
},
redis: {
url: getRequiredEnv('REDIS_URL'),
db: parseInt(getOptionalEnv('REDIS_DB') || '0'),
2025-01-13 11:17:32 +01:00
jobs: {
name: getOptionalEnv('REDIS_JOBS_QUEUE_NAME') || 'jobs',
prefix: getOptionalEnv('REDIS_JOBS_QUEUE_PREFIX') || 'colanode',
},
2025-01-05 12:13:46 +01:00
eventsChannel: getOptionalEnv('REDIS_EVENTS_CHANNEL') || 'events',
},
avatarS3: {
endpoint: getRequiredEnv('S3_AVATARS_ENDPOINT'),
accessKey: getRequiredEnv('S3_AVATARS_ACCESS_KEY'),
secretKey: getRequiredEnv('S3_AVATARS_SECRET_KEY'),
bucketName: getRequiredEnv('S3_AVATARS_BUCKET_NAME'),
region: getRequiredEnv('S3_AVATARS_REGION'),
},
fileS3: {
endpoint: getRequiredEnv('S3_FILES_ENDPOINT'),
accessKey: getRequiredEnv('S3_FILES_ACCESS_KEY'),
secretKey: getRequiredEnv('S3_FILES_SECRET_KEY'),
bucketName: getRequiredEnv('S3_FILES_BUCKET_NAME'),
region: getRequiredEnv('S3_FILES_REGION'),
},
2025-01-05 12:36:40 +01:00
smtp: {
host: getOptionalEnv('SMTP_HOST') || '',
port: parseInt(getOptionalEnv('SMTP_PORT') || '587'),
user: getOptionalEnv('SMTP_USER') || '',
password: getOptionalEnv('SMTP_PASSWORD') || '',
2025-01-05 20:25:48 +01:00
from: {
email: getRequiredEnv('SMTP_EMAIL_FROM'),
name: getRequiredEnv('SMTP_EMAIL_FROM_NAME'),
},
2025-01-05 12:13:46 +01:00
},
ai: {
enabled: getOptionalEnv('AI_ENABLED') === 'true',
entryEmbedDelay: parseInt(
getOptionalEnv('AI_ENTRY_EMBED_DELAY') || '60000'
),
providers: {
openai: {
apiKey: getOptionalEnv('OPENAI_API_KEY') || '',
enabled: getOptionalEnv('OPENAI_ENABLED') === 'true',
},
google: {
apiKey: getOptionalEnv('GOOGLE_API_KEY') || '',
enabled: getOptionalEnv('GOOGLE_ENABLED') === 'true',
},
},
langfuse: {
publicKey: getOptionalEnv('LANGFUSE_PUBLIC_KEY') || '',
secretKey: getOptionalEnv('LANGFUSE_SECRET_KEY') || '',
baseUrl:
getOptionalEnv('LANGFUSE_BASE_URL') || 'https://cloud.langfuse.com',
},
models: {
queryRewrite: {
provider: (getOptionalEnv('QUERY_REWRITE_PROVIDER') ||
'openai') as AIProvider,
modelName: getOptionalEnv('QUERY_REWRITE_MODEL') || 'gpt-4o-mini',
temperature: parseFloat(
getOptionalEnv('QUERY_REWRITE_TEMPERATURE') || '0.3'
),
},
response: {
provider: (getOptionalEnv('RESPONSE_PROVIDER') ||
'openai') as AIProvider,
modelName: getOptionalEnv('RESPONSE_MODEL') || 'gpt-4o-mini',
temperature: parseFloat(
getOptionalEnv('RESPONSE_TEMPERATURE') || '0.3'
),
},
rerank: {
provider: (getOptionalEnv('RERANK_PROVIDER') || 'openai') as AIProvider,
modelName: getOptionalEnv('RERANK_MODEL') || 'gpt-4o-mini',
temperature: parseFloat(getOptionalEnv('RERANK_TEMPERATURE') || '0.3'),
},
summarization: {
provider: (getOptionalEnv('SUMMARIZATION_PROVIDER') ||
'openai') as AIProvider,
modelName: getOptionalEnv('SUMMARIZATION_MODEL') || 'gpt-4o-mini',
temperature: parseFloat(
getOptionalEnv('SUMMARIZATION_TEMPERATURE') || '0.3'
),
},
contextEnhancer: {
provider: (getOptionalEnv('CHUNK_CONTEXT_PROVIDER') ||
'openai') as AIProvider,
modelName: getOptionalEnv('CHUNK_CONTEXT_MODEL') || 'gpt-4o-mini',
temperature: parseFloat(
getOptionalEnv('CHUNK_CONTEXT_TEMPERATURE') || '0.3'
),
},
noContext: {
provider: (getOptionalEnv('NO_CONTEXT_PROVIDER') ||
'openai') as AIProvider,
modelName: getOptionalEnv('NO_CONTEXT_MODEL') || 'gpt-4o-mini',
temperature: parseFloat(
getOptionalEnv('NO_CONTEXT_TEMPERATURE') || '0.3'
),
},
intentRecognition: {
provider: (getOptionalEnv('INTENT_RECOGNITION_PROVIDER') ||
'openai') as AIProvider,
modelName: getOptionalEnv('INTENT_RECOGNITION_MODEL') || 'gpt-4o-mini',
temperature: parseFloat(
getOptionalEnv('INTENT_RECOGNITION_TEMPERATURE') || '0.3'
),
},
},
embedding: {
provider: (getOptionalEnv('EMBEDDING_PROVIDER') ||
'openai') as AIProvider,
modelName: getOptionalEnv('EMBEDDING_MODEL') || 'text-embedding-3-large',
dimensions: parseInt(getOptionalEnv('EMBEDDING_DIMENSIONS') || '2000'),
apiKey: getOptionalEnv('EMBEDDING_API_KEY') || '',
batchSize: parseInt(getOptionalEnv('EMBEDDING_BATCH_SIZE') || '50'),
2025-01-05 12:13:46 +01:00
},
chunking: {
defaultChunkSize: parseInt(
getOptionalEnv('CHUNK_DEFAULT_CHUNK_SIZE') || '1000'
),
defaultOverlap: parseInt(
getOptionalEnv('CHUNK_DEFAULT_OVERLAP') || '200'
),
enhanceWithContext:
getOptionalEnv('CHUNK_ENHANCE_WITH_CONTEXT') === 'true',
},
retrieval: {
hybridSearch: {
semanticSearchWeight: parseFloat(
getOptionalEnv('RETRIEVAL_HYBRID_SEARCH_SEMANTIC_WEIGHT') || '0.7'
),
keywordSearchWeight: parseFloat(
getOptionalEnv('RETRIEVAL_HYBRID_SEARCH_KEYWORD_WEIGHT') || '0.3'
),
maxResults: parseInt(
getOptionalEnv('RETRIEVAL_HYBRID_SEARCH_MAX_RESULTS') || '20'
),
},
2025-01-05 12:13:46 +01:00
},
},
};