feat(project): init

This commit is contained in:
zhangheng
2026-04-25 11:26:33 +08:00
commit 9bf212f67c
63 changed files with 11141 additions and 0 deletions

95
lib/config.ts Normal file
View File

@@ -0,0 +1,95 @@
import path from "node:path";
interface AppConfig {
openAiApiKey: string;
openAiBaseUrl: string;
openAiImageModel: string;
openAiTimeoutMs: number;
databasePath: string;
generatedImagesPath: string;
adminUsername: string;
adminPassword: string;
adminSyncOnBoot: boolean;
defaultMonthlyQuota: number;
sessionDays: number;
}
function parseInteger(value: unknown, fallbackValue: number): number {
const numericValue = Number.parseInt(String(value ?? ""), 10);
if (Number.isFinite(numericValue)) {
return numericValue;
}
return fallbackValue;
}
function parseBoolean(value: unknown, fallbackValue: boolean): boolean {
if (value === undefined || value === null || value === "") {
return fallbackValue;
}
const normalizedValue = String(value).trim().toLowerCase();
if (["1", "true", "yes", "on"].includes(normalizedValue)) {
return true;
}
if (["0", "false", "no", "off"].includes(normalizedValue)) {
return false;
}
return fallbackValue;
}
function resolveDatabasePath(rawPath?: string): string {
if (!rawPath) {
return path.join(
/* turbopackIgnore: true */ process.cwd(),
"data",
"image-prompt-studio.db",
);
}
if (path.isAbsolute(rawPath)) {
return rawPath;
}
return path.resolve(/* turbopackIgnore: true */ process.cwd(), rawPath);
}
function resolveGeneratedImagesPath(
databasePath: string,
rawPath?: string,
): string {
if (!rawPath) {
return path.join(path.dirname(databasePath), "generated-images");
}
if (path.isAbsolute(rawPath)) {
return rawPath;
}
return path.resolve(/* turbopackIgnore: true */ process.cwd(), rawPath);
}
const databasePath = resolveDatabasePath(process.env.DATABASE_PATH);
export const appConfig: AppConfig = {
openAiApiKey: process.env.OPENAI_API_KEY ?? "",
openAiBaseUrl: process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1",
openAiImageModel: process.env.OPENAI_IMAGE_MODEL ?? "gpt-image-2",
openAiTimeoutMs: parseInteger(process.env.OPENAI_TIMEOUT_MS, 140000),
databasePath,
generatedImagesPath: resolveGeneratedImagesPath(
databasePath,
process.env.GENERATED_IMAGES_PATH,
),
adminUsername: String(process.env.ADMIN_USERNAME ?? "admin")
.trim()
.toLowerCase(),
adminPassword: String(process.env.ADMIN_PASSWORD ?? "change-me-now"),
adminSyncOnBoot: parseBoolean(process.env.ADMIN_SYNC_ON_BOOT, true),
defaultMonthlyQuota: parseInteger(process.env.DEFAULT_MONTHLY_QUOTA, 20),
sessionDays: parseInteger(process.env.SESSION_DAYS, 30),
};