| |
| |
| |
|
|
| import { z } from "zod"; |
|
|
| const ConfigSchema = z.object({ |
| port: z.number().int().positive().default(3001), |
| logLevel: z |
| .enum(["fatal", "error", "warn", "info", "debug", "trace"]) |
| .default("info"), |
| |
| defaultModel: z.string().default("deepseek-v4-pro"), |
| defaultBaseURL: z |
| .string() |
| .default("https://api.deepseek.com"), |
| defaultApiKey: z.string().default(""), |
| defaultApiMode: z.enum(["chat", "responses"]).default("chat"), |
| |
| judgeModel: z.string().default("gpt-5.5"), |
| judgeBaseURL: z |
| .string() |
| .default("https://app-hk.ppapi.ai/v1/chat/completions"), |
| judgeApiKey: z.string().default(""), |
| judgeApiMode: z.enum(["chat", "responses"]).default("chat"), |
| |
| rubricGenModel: z.string().default("gpt-5.5"), |
| rubricGenBaseURL: z |
| .string() |
| .default("https://app-hk.ppapi.ai/v1/chat/completions"), |
| rubricGenApiKey: z.string().default(""), |
| rubricGenApiMode: z.enum(["chat", "responses"]).default("chat"), |
| |
| sqlitePath: z.string().default("/app/data/tasks.db"), |
| databaseUrl: z.string().default(""), |
| storeBackend: z.enum(["sqlite", "postgres"]).default("sqlite"), |
| uploadDir: z.string().default("/app/data/uploads"), |
| exportDir: z.string().default("/app/data/exports"), |
| |
| maxUploadMB: z.number().int().positive().default(100), |
| maxBatchFiles: z.number().int().positive().default(20), |
| itemMaxAttempts: z.number().int().positive().default(3), |
| globalLlmConcurrency: z.number().int().nonnegative().default(0), |
| |
| upstreamProxy: z.string().default(""), |
| }); |
|
|
| export type Config = z.infer<typeof ConfigSchema>; |
|
|
| function envInt(value: string | undefined, fallback: number): number { |
| if (!value) return fallback; |
| const n = Number(value); |
| return Number.isFinite(n) ? Math.trunc(n) : fallback; |
| } |
|
|
| export function loadConfig(): Config { |
| const parsed = ConfigSchema.parse({ |
| port: envInt(process.env.PORT, 3001), |
| logLevel: process.env.LOG_LEVEL, |
| defaultModel: process.env.DEFAULT_MODEL, |
| defaultBaseURL: process.env.DEFAULT_BASE_URL, |
| defaultApiKey: process.env.DEFAULT_API_KEY, |
| defaultApiMode: process.env.DEFAULT_API_MODE, |
| judgeModel: process.env.JUDGE_MODEL, |
| judgeBaseURL: process.env.JUDGE_BASE_URL, |
| judgeApiKey: process.env.JUDGE_API_KEY, |
| judgeApiMode: process.env.JUDGE_API_MODE, |
| rubricGenModel: process.env.RUBRIC_GEN_MODEL, |
| rubricGenBaseURL: process.env.RUBRIC_GEN_BASE_URL, |
| rubricGenApiKey: process.env.RUBRIC_GEN_API_KEY, |
| rubricGenApiMode: process.env.RUBRIC_GEN_API_MODE, |
| sqlitePath: process.env.SQLITE_PATH, |
| databaseUrl: process.env.DATABASE_URL, |
| storeBackend: process.env.STORE_BACKEND, |
| uploadDir: process.env.UPLOAD_DIR, |
| exportDir: process.env.EXPORT_DIR, |
| maxUploadMB: envInt(process.env.MAX_UPLOAD_MB, 100), |
| maxBatchFiles: envInt(process.env.MAX_BATCH_FILES, 20), |
| itemMaxAttempts: envInt(process.env.ITEM_MAX_ATTEMPTS, 3), |
| globalLlmConcurrency: envInt(process.env.GLOBAL_LLM_CONCURRENCY, 0), |
| upstreamProxy: process.env.UPSTREAM_PROXY, |
| }); |
| return parsed; |
| } |
|
|