Initial WallMuse project
This commit is contained in:
9
packages/shared/src/api-paths.ts
Executable file
9
packages/shared/src/api-paths.ts
Executable file
@@ -0,0 +1,9 @@
|
||||
export const API_V1_PREFIX = "/api/v1" as const;
|
||||
|
||||
export const apiPaths = {
|
||||
appConfig: `${API_V1_PREFIX}/app/config`,
|
||||
providers: `${API_V1_PREFIX}/providers`,
|
||||
models: `${API_V1_PREFIX}/models`,
|
||||
generations: `${API_V1_PREFIX}/generations`,
|
||||
generationGroup: (id: string) => `${API_V1_PREFIX}/generation-groups/${id}`
|
||||
} as const;
|
||||
101
packages/shared/src/dto/api-management.ts
Executable file
101
packages/shared/src/dto/api-management.ts
Executable file
@@ -0,0 +1,101 @@
|
||||
import { z } from "zod";
|
||||
import { ApiKeyModeSchema, ModelCapabilitySchema, ModelPricingSchema, ModelStatusSchema, ProviderStatusSchema } from "../model-capability";
|
||||
|
||||
export const UserRoleSchema = z.enum(["user", "admin", "super_admin"]);
|
||||
|
||||
export const PublicUserSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
email: z.string().email(),
|
||||
name: z.string().optional(),
|
||||
roles: z.array(UserRoleSchema),
|
||||
createdAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export const RegisterRequestSchema = z.object({
|
||||
email: z.string().email().max(255),
|
||||
password: z.string().min(8).max(128),
|
||||
name: z.string().min(1).max(80).optional()
|
||||
});
|
||||
|
||||
export const LoginRequestSchema = z.object({
|
||||
email: z.string().email().max(255),
|
||||
password: z.string().min(1).max(128)
|
||||
});
|
||||
|
||||
export const AuthResponseSchema = z.object({
|
||||
user: PublicUserSchema,
|
||||
token: z.string().min(1)
|
||||
});
|
||||
|
||||
export const CreateUserApiKeyRequestSchema = z.object({
|
||||
providerId: z.string().uuid(),
|
||||
name: z.string().min(1).max(80),
|
||||
apiKey: z.string().min(6).max(4096),
|
||||
baseUrl: z.string().url().optional(),
|
||||
defaultModelId: z.string().uuid().optional()
|
||||
});
|
||||
|
||||
export const UserApiKeyResponseSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
userId: z.string().uuid(),
|
||||
providerId: z.string().uuid(),
|
||||
name: z.string(),
|
||||
maskedKey: z.string(),
|
||||
baseUrl: z.string().url().optional(),
|
||||
defaultModelId: z.string().uuid().optional(),
|
||||
enabled: z.boolean(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export const CreateProviderRequestSchema = z.object({
|
||||
slug: z.string().min(2).max(80).regex(/^[a-z0-9][a-z0-9-_]*$/),
|
||||
displayName: z.string().min(1).max(120),
|
||||
baseUrl: z.string().url().optional(),
|
||||
authType: z.enum(["bearer", "api_key", "custom"]).default("bearer"),
|
||||
status: ProviderStatusSchema.default("healthy"),
|
||||
keyMode: ApiKeyModeSchema.default("hybrid"),
|
||||
supportsUserKeys: z.boolean().default(true),
|
||||
supportsPlatformKeys: z.boolean().default(true),
|
||||
healthCheckPath: z.string().max(255).optional()
|
||||
});
|
||||
|
||||
export const UpdateProviderRequestSchema = CreateProviderRequestSchema.partial().omit({ slug: true });
|
||||
|
||||
export const CreateModelRequestSchema = z.object({
|
||||
providerId: z.string().uuid(),
|
||||
slug: z.string().min(1).max(160),
|
||||
displayName: z.string().min(1).max(160),
|
||||
status: ModelStatusSchema.default("enabled"),
|
||||
keyMode: ApiKeyModeSchema.default("hybrid"),
|
||||
capability: ModelCapabilitySchema,
|
||||
pricing: ModelPricingSchema.optional(),
|
||||
sortOrder: z.number().int().default(0)
|
||||
});
|
||||
|
||||
export const UpdateModelRequestSchema = CreateModelRequestSchema.partial().omit({ providerId: true });
|
||||
|
||||
export const ProviderCallLogSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
taskId: z.string().uuid().optional(),
|
||||
providerId: z.string().uuid(),
|
||||
modelId: z.string().uuid().optional(),
|
||||
status: z.enum(["success", "failed"]),
|
||||
latencyMs: z.number().int().nonnegative().optional(),
|
||||
errorCode: z.string().optional(),
|
||||
errorMessage: z.string().optional(),
|
||||
createdAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export type UserRole = z.infer<typeof UserRoleSchema>;
|
||||
export type PublicUser = z.infer<typeof PublicUserSchema>;
|
||||
export type RegisterRequest = z.infer<typeof RegisterRequestSchema>;
|
||||
export type LoginRequest = z.infer<typeof LoginRequestSchema>;
|
||||
export type AuthResponse = z.infer<typeof AuthResponseSchema>;
|
||||
export type CreateUserApiKeyRequest = z.infer<typeof CreateUserApiKeyRequestSchema>;
|
||||
export type UserApiKeyResponse = z.infer<typeof UserApiKeyResponseSchema>;
|
||||
export type CreateProviderRequest = z.infer<typeof CreateProviderRequestSchema>;
|
||||
export type UpdateProviderRequest = z.infer<typeof UpdateProviderRequestSchema>;
|
||||
export type CreateModelRequest = z.infer<typeof CreateModelRequestSchema>;
|
||||
export type UpdateModelRequest = z.infer<typeof UpdateModelRequestSchema>;
|
||||
export type ProviderCallLog = z.infer<typeof ProviderCallLogSchema>;
|
||||
33
packages/shared/src/dto/app-config.ts
Executable file
33
packages/shared/src/dto/app-config.ts
Executable file
@@ -0,0 +1,33 @@
|
||||
import { z } from "zod";
|
||||
import { AspectRatioSchema, ModelSummarySchema, ProviderSummarySchema, ResolutionTierSchema } from "../model-capability";
|
||||
|
||||
export const AppFeatureFlagsSchema = z.object({
|
||||
authEnabled: z.boolean().default(true),
|
||||
galleryEnabled: z.boolean().default(true),
|
||||
userApiKeysEnabled: z.boolean().default(true),
|
||||
generationEnabled: z.boolean().default(true),
|
||||
darkModeEnabled: z.boolean().default(true)
|
||||
});
|
||||
|
||||
export const AppConfigResponseSchema = z.object({
|
||||
site: z.object({
|
||||
name: z.string().default("WallMuse"),
|
||||
tagline: z.string().optional(),
|
||||
logoUrl: z.string().url().optional(),
|
||||
supportEmail: z.string().email().optional()
|
||||
}),
|
||||
generation: z.object({
|
||||
defaultModelId: z.string().uuid().optional(),
|
||||
defaultAspectRatios: z.array(AspectRatioSchema).min(1).default(["16:9", "9:16"]),
|
||||
defaultResolution: ResolutionTierSchema.default("2k"),
|
||||
maxBatchSize: z.number().int().positive().default(4),
|
||||
allowedResolutions: z.array(ResolutionTierSchema).min(1)
|
||||
}),
|
||||
features: AppFeatureFlagsSchema,
|
||||
providers: z.array(ProviderSummarySchema),
|
||||
models: z.array(ModelSummarySchema),
|
||||
updatedAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export type AppFeatureFlags = z.infer<typeof AppFeatureFlagsSchema>;
|
||||
export type AppConfigResponse = z.infer<typeof AppConfigResponseSchema>;
|
||||
84
packages/shared/src/dto/generation.ts
Executable file
84
packages/shared/src/dto/generation.ts
Executable file
@@ -0,0 +1,84 @@
|
||||
import { z } from "zod";
|
||||
import { AspectRatioSchema, GenerationModeSchema, GenerationQualitySchema, ResolutionTierSchema } from "../model-capability";
|
||||
import { GenerationGroupStatusSchema, GenerationTaskStatusSchema } from "../status";
|
||||
|
||||
export const AssetKindSchema = z.enum(["reference", "master", "landscape", "portrait", "thumbnail", "preview", "download_zip"]);
|
||||
export const AssetStatusSchema = z.enum(["temporary", "active", "deleted", "failed"]);
|
||||
export const ModerationStatusSchema = z.enum(["pending", "passed", "rejected", "manual_review"]);
|
||||
|
||||
export const CreateGenerationRequestSchema = z.object({
|
||||
mode: GenerationModeSchema,
|
||||
modelId: z.string().uuid(),
|
||||
prompt: z.string().min(1).max(4000),
|
||||
negativePrompt: z.string().max(2000).optional(),
|
||||
aspectRatios: z.array(AspectRatioSchema).min(1).max(3).default(["16:9", "9:16"]),
|
||||
resolution: ResolutionTierSchema.default("2k"),
|
||||
quality: GenerationQualitySchema.default("standard"),
|
||||
batchSize: z.number().int().min(1).max(8).default(1),
|
||||
seed: z.number().int().optional(),
|
||||
referenceAssetId: z.string().uuid().optional(),
|
||||
stylePresetId: z.string().uuid().optional(),
|
||||
userApiKeyId: z.string().uuid().optional(),
|
||||
publishToGallery: z.boolean().default(false),
|
||||
metadata: z.record(z.unknown()).default({})
|
||||
});
|
||||
|
||||
export const GenerationTaskSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
groupId: z.string().uuid(),
|
||||
status: GenerationTaskStatusSchema,
|
||||
mode: GenerationModeSchema,
|
||||
aspectRatio: AspectRatioSchema,
|
||||
resolution: ResolutionTierSchema,
|
||||
quality: GenerationQualitySchema,
|
||||
attempt: z.number().int().nonnegative(),
|
||||
maxAttempts: z.number().int().positive(),
|
||||
progress: z.number().int().min(0).max(100),
|
||||
errorCode: z.string().optional(),
|
||||
errorMessage: z.string().optional(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export const GeneratedAssetSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
taskId: z.string().uuid().optional(),
|
||||
kind: AssetKindSchema,
|
||||
status: AssetStatusSchema,
|
||||
width: z.number().int().positive().optional(),
|
||||
height: z.number().int().positive().optional(),
|
||||
mimeType: z.string().optional(),
|
||||
publicUrl: z.string().url().optional(),
|
||||
blurHash: z.string().optional(),
|
||||
createdAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export const GenerationGroupSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
status: GenerationGroupStatusSchema,
|
||||
modelId: z.string().uuid(),
|
||||
prompt: z.string(),
|
||||
negativePrompt: z.string().optional(),
|
||||
tasks: z.array(GenerationTaskSchema),
|
||||
assets: z.array(GeneratedAssetSchema).default([]),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export const CreateGenerationResponseSchema = z.object({
|
||||
generationGroup: GenerationGroupSchema,
|
||||
pollingUrl: z.string().min(1)
|
||||
});
|
||||
|
||||
export const GenerationGroupParamsSchema = z.object({
|
||||
id: z.string().uuid()
|
||||
});
|
||||
|
||||
export type AssetKind = z.infer<typeof AssetKindSchema>;
|
||||
export type AssetStatus = z.infer<typeof AssetStatusSchema>;
|
||||
export type ModerationStatus = z.infer<typeof ModerationStatusSchema>;
|
||||
export type CreateGenerationRequest = z.infer<typeof CreateGenerationRequestSchema>;
|
||||
export type GenerationTask = z.infer<typeof GenerationTaskSchema>;
|
||||
export type GeneratedAsset = z.infer<typeof GeneratedAssetSchema>;
|
||||
export type GenerationGroup = z.infer<typeof GenerationGroupSchema>;
|
||||
export type CreateGenerationResponse = z.infer<typeof CreateGenerationResponseSchema>;
|
||||
92
packages/shared/src/dto/web.ts
Executable file
92
packages/shared/src/dto/web.ts
Executable file
@@ -0,0 +1,92 @@
|
||||
import { z } from "zod";
|
||||
import { AspectRatioSchema, ResolutionTierSchema } from "../model-capability";
|
||||
import { GenerationGroupStatusSchema } from "../status";
|
||||
|
||||
export const ThemePreferenceSchema = z.enum(["system", "light", "dark"]);
|
||||
|
||||
export const WebWallpaperSchema = z.object({
|
||||
id: z.string(),
|
||||
title: z.string(),
|
||||
prompt: z.string(),
|
||||
imageUrl: z.string().url(),
|
||||
ratio: AspectRatioSchema,
|
||||
resolution: ResolutionTierSchema,
|
||||
style: z.string(),
|
||||
model: z.string(),
|
||||
likes: z.number().int().nonnegative(),
|
||||
downloads: z.number().int().nonnegative(),
|
||||
colors: z.array(z.string()),
|
||||
createdAt: z.string().datetime(),
|
||||
featured: z.boolean().optional()
|
||||
});
|
||||
|
||||
export const WebGenerationAssetSchema = z.object({
|
||||
id: z.string(),
|
||||
label: z.enum(["Desktop", "Mobile", "Master"]),
|
||||
ratio: AspectRatioSchema,
|
||||
width: z.number().int().positive(),
|
||||
height: z.number().int().positive(),
|
||||
imageUrl: z.string().url()
|
||||
});
|
||||
|
||||
export const WebGenerationGroupSchema = z.object({
|
||||
id: z.string(),
|
||||
prompt: z.string(),
|
||||
negativePrompt: z.string().optional(),
|
||||
status: GenerationGroupStatusSchema,
|
||||
style: z.string(),
|
||||
model: z.string(),
|
||||
resolution: ResolutionTierSchema,
|
||||
consistencyScore: z.number().int().min(0).max(100),
|
||||
createdAt: z.string().datetime(),
|
||||
assets: z.array(WebGenerationAssetSchema)
|
||||
});
|
||||
|
||||
export const WebUserSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string().email(),
|
||||
avatarInitials: z.string(),
|
||||
theme: ThemePreferenceSchema
|
||||
});
|
||||
|
||||
export const WebUserApiKeySchema = z.object({
|
||||
id: z.string(),
|
||||
provider: z.string(),
|
||||
baseUrl: z.string(),
|
||||
model: z.string(),
|
||||
maskedKey: z.string(),
|
||||
isDefault: z.boolean(),
|
||||
status: z.enum(["untested", "connected", "failed"]),
|
||||
updatedAt: z.string().datetime()
|
||||
});
|
||||
|
||||
export const WebCreateGenerationInputSchema = z.object({
|
||||
mode: z.enum(["text_to_image", "image_to_image"]),
|
||||
prompt: z.string().min(1),
|
||||
negativePrompt: z.string().optional(),
|
||||
style: z.string(),
|
||||
resolution: ResolutionTierSchema,
|
||||
outputPair: z.boolean(),
|
||||
provider: z.string(),
|
||||
model: z.string(),
|
||||
privateMode: z.boolean()
|
||||
});
|
||||
|
||||
export const WebSaveApiKeyInputSchema = z.object({
|
||||
provider: z.string(),
|
||||
baseUrl: z.string().url(),
|
||||
apiKey: z.string().min(1),
|
||||
model: z.string(),
|
||||
saveToAccount: z.boolean(),
|
||||
isDefault: z.boolean()
|
||||
});
|
||||
|
||||
export type ThemePreference = z.infer<typeof ThemePreferenceSchema>;
|
||||
export type WebWallpaper = z.infer<typeof WebWallpaperSchema>;
|
||||
export type WebGenerationAsset = z.infer<typeof WebGenerationAssetSchema>;
|
||||
export type WebGenerationGroup = z.infer<typeof WebGenerationGroupSchema>;
|
||||
export type WebUser = z.infer<typeof WebUserSchema>;
|
||||
export type WebUserApiKey = z.infer<typeof WebUserApiKeySchema>;
|
||||
export type WebCreateGenerationInput = z.infer<typeof WebCreateGenerationInputSchema>;
|
||||
export type WebSaveApiKeyInput = z.infer<typeof WebSaveApiKeyInputSchema>;
|
||||
7
packages/shared/src/index.ts
Executable file
7
packages/shared/src/index.ts
Executable file
@@ -0,0 +1,7 @@
|
||||
export * from "./api-paths";
|
||||
export * from "./model-capability";
|
||||
export * from "./status";
|
||||
export * from "./dto/app-config";
|
||||
export * from "./dto/generation";
|
||||
export * from "./dto/api-management";
|
||||
export * from "./dto/web";
|
||||
84
packages/shared/src/model-capability.ts
Executable file
84
packages/shared/src/model-capability.ts
Executable file
@@ -0,0 +1,84 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const GenerationModeSchema = z.enum(["text_to_image", "image_to_image"]);
|
||||
export const GenerationQualitySchema = z.enum(["standard", "hd", "ultra"]);
|
||||
export const ResolutionTierSchema = z.enum(["1k", "2k", "4k"]);
|
||||
export const AspectRatioSchema = z.enum(["1:1", "4:3", "3:4", "16:9", "9:16", "21:9"]);
|
||||
export const ProviderStatusSchema = z.enum(["disabled", "healthy", "degraded", "error"]);
|
||||
export const ModelStatusSchema = z.enum(["draft", "enabled", "disabled", "deprecated"]);
|
||||
export const ApiKeyModeSchema = z.enum(["platform", "user_own", "hybrid"]);
|
||||
|
||||
export type GenerationMode = z.infer<typeof GenerationModeSchema>;
|
||||
export type GenerationQuality = z.infer<typeof GenerationQualitySchema>;
|
||||
export type ResolutionTier = z.infer<typeof ResolutionTierSchema>;
|
||||
export type AspectRatio = z.infer<typeof AspectRatioSchema>;
|
||||
export type ProviderStatus = z.infer<typeof ProviderStatusSchema>;
|
||||
export type ModelStatus = z.infer<typeof ModelStatusSchema>;
|
||||
export type ApiKeyMode = z.infer<typeof ApiKeyModeSchema>;
|
||||
|
||||
export const ImageSizePresetSchema = z.object({
|
||||
aspectRatio: AspectRatioSchema,
|
||||
resolution: ResolutionTierSchema,
|
||||
width: z.number().int().positive(),
|
||||
height: z.number().int().positive(),
|
||||
providerSizeValue: z.string().optional(),
|
||||
native: z.boolean().default(true),
|
||||
requiresUpscale: z.boolean().default(false)
|
||||
});
|
||||
|
||||
export const ModelPricingSchema = z.object({
|
||||
currency: z.string().min(3).max(8).default("USD"),
|
||||
unit: z.enum(["image", "megapixel", "request", "credit"]),
|
||||
amount: z.number().nonnegative(),
|
||||
estimatedCredits: z.number().nonnegative().optional()
|
||||
});
|
||||
|
||||
export const ModelCapabilitySchema = z.object({
|
||||
supportsTextToImage: z.boolean(),
|
||||
supportsImageToImage: z.boolean(),
|
||||
supportsEdit: z.boolean().default(false),
|
||||
supportsNegativePrompt: z.boolean().default(false),
|
||||
supportsSeed: z.boolean().default(false),
|
||||
supportsBatch: z.boolean().default(false),
|
||||
supportsStreaming: z.boolean().default(false),
|
||||
supportsBase64Result: z.boolean().default(false),
|
||||
supportsUrlResult: z.boolean().default(true),
|
||||
supportsNative4k: z.boolean().default(false),
|
||||
maxBatchSize: z.number().int().positive().default(1),
|
||||
maxInputImages: z.number().int().nonnegative().default(0),
|
||||
maxPromptLength: z.number().int().positive().default(4000),
|
||||
maxNegativePromptLength: z.number().int().positive().default(2000),
|
||||
maxPixels: z.number().int().positive().optional(),
|
||||
supportedAspectRatios: z.array(AspectRatioSchema).min(1),
|
||||
supportedResolutions: z.array(ResolutionTierSchema).min(1),
|
||||
sizePresets: z.array(ImageSizePresetSchema).min(1),
|
||||
defaultParams: z.record(z.unknown()).default({})
|
||||
});
|
||||
|
||||
export type ImageSizePreset = z.infer<typeof ImageSizePresetSchema>;
|
||||
export type ModelPricing = z.infer<typeof ModelPricingSchema>;
|
||||
export type ModelCapability = z.infer<typeof ModelCapabilitySchema>;
|
||||
|
||||
export const ModelSummarySchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
providerId: z.string().uuid(),
|
||||
slug: z.string().min(1),
|
||||
displayName: z.string().min(1),
|
||||
status: ModelStatusSchema,
|
||||
keyMode: ApiKeyModeSchema,
|
||||
capability: ModelCapabilitySchema,
|
||||
pricing: ModelPricingSchema.optional(),
|
||||
sortOrder: z.number().int().default(0)
|
||||
});
|
||||
|
||||
export const ProviderSummarySchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
slug: z.string().min(1),
|
||||
displayName: z.string().min(1),
|
||||
status: ProviderStatusSchema,
|
||||
keyMode: ApiKeyModeSchema,
|
||||
modelCount: z.number().int().nonnegative().default(0)
|
||||
});
|
||||
|
||||
export type ModelSummary = z.infer<typeof ModelSummarySchema>;
|
||||
export type ProviderSummary = z.infer<typeof ProviderSummarySchema>;
|
||||
59
packages/shared/src/status.ts
Executable file
59
packages/shared/src/status.ts
Executable file
@@ -0,0 +1,59 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const generationGroupStatuses = [
|
||||
"queued",
|
||||
"running",
|
||||
"partial_succeeded",
|
||||
"succeeded",
|
||||
"failed",
|
||||
"canceled"
|
||||
] as const;
|
||||
|
||||
export const generationTaskStatuses = [
|
||||
"created",
|
||||
"queued",
|
||||
"dispatching",
|
||||
"running",
|
||||
"uploading",
|
||||
"post_processing",
|
||||
"moderating",
|
||||
"succeeded",
|
||||
"failed",
|
||||
"retrying",
|
||||
"canceled",
|
||||
"expired"
|
||||
] as const;
|
||||
|
||||
export const terminalGenerationTaskStatuses = [
|
||||
"succeeded",
|
||||
"failed",
|
||||
"canceled",
|
||||
"expired"
|
||||
] as const;
|
||||
|
||||
export const retryableGenerationTaskStatuses = ["failed", "retrying"] as const;
|
||||
|
||||
export const GenerationGroupStatusSchema = z.enum(generationGroupStatuses);
|
||||
export const GenerationTaskStatusSchema = z.enum(generationTaskStatuses);
|
||||
|
||||
export type GenerationGroupStatus = z.infer<typeof GenerationGroupStatusSchema>;
|
||||
export type GenerationTaskStatus = z.infer<typeof GenerationTaskStatusSchema>;
|
||||
|
||||
export const generationTaskStateTransitions: Record<GenerationTaskStatus, readonly GenerationTaskStatus[]> = {
|
||||
created: ["queued", "canceled"],
|
||||
queued: ["dispatching", "canceled", "expired"],
|
||||
dispatching: ["running", "retrying", "failed", "canceled"],
|
||||
running: ["uploading", "retrying", "failed", "canceled"],
|
||||
uploading: ["post_processing", "retrying", "failed", "canceled"],
|
||||
post_processing: ["moderating", "retrying", "failed", "canceled"],
|
||||
moderating: ["succeeded", "failed", "canceled"],
|
||||
succeeded: [],
|
||||
failed: ["retrying"],
|
||||
retrying: ["queued", "failed", "canceled", "expired"],
|
||||
canceled: [],
|
||||
expired: []
|
||||
};
|
||||
|
||||
export function isTerminalGenerationTaskStatus(status: GenerationTaskStatus): boolean {
|
||||
return terminalGenerationTaskStatuses.includes(status as (typeof terminalGenerationTaskStatuses)[number]);
|
||||
}
|
||||
Reference in New Issue
Block a user