feat(ai): add full image model catalog and tier filters
This commit is contained in:
102
lib/ai-models.ts
102
lib/ai-models.ts
@@ -22,23 +22,78 @@ export const IMAGE_MODELS: AiModel[] = [
|
|||||||
creditCost: 4,
|
creditCost: 4,
|
||||||
minTier: "free",
|
minTier: "free",
|
||||||
},
|
},
|
||||||
// Phase 2 — uncomment when model selector UI is ready:
|
{
|
||||||
// {
|
id: "black-forest-labs/flux.2-klein-4b",
|
||||||
// id: "black-forest-labs/flux.2-klein-4b",
|
name: "FLUX.2 Klein 4B",
|
||||||
// name: "FLUX.2 Klein",
|
tier: "budget",
|
||||||
// tier: "budget",
|
description: "Low-cost image generation for quick drafts",
|
||||||
// description: "Photorealism, fastest Flux",
|
estimatedCost: "~€0.02",
|
||||||
// estimatedCost: "~€0.02",
|
creditCost: 2,
|
||||||
// minTier: "free",
|
minTier: "free",
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// id: "openai/gpt-5-image",
|
id: "bytedance-seed/seedream-4.5",
|
||||||
// name: "GPT-5 Image",
|
name: "Seedream 4.5",
|
||||||
// tier: "premium",
|
tier: "standard",
|
||||||
// description: "Best instruction following, text in image",
|
description: "Balanced detail and speed for everyday prompts",
|
||||||
// estimatedCost: "~€0.15",
|
estimatedCost: "~€0.05",
|
||||||
// minTier: "starter",
|
creditCost: 5,
|
||||||
// },
|
minTier: "free",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "google/gemini-3.1-flash-image-preview",
|
||||||
|
name: "Gemini 3.1 Flash Image",
|
||||||
|
tier: "standard",
|
||||||
|
description: "Fast multimodal image generation",
|
||||||
|
estimatedCost: "~€0.06",
|
||||||
|
creditCost: 6,
|
||||||
|
minTier: "free",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "openai/gpt-5-image-mini",
|
||||||
|
name: "GPT-5 Image Mini",
|
||||||
|
tier: "premium",
|
||||||
|
description: "Higher-fidelity instruction following",
|
||||||
|
estimatedCost: "~€0.08",
|
||||||
|
creditCost: 8,
|
||||||
|
minTier: "starter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "sourceful/riverflow-v2-fast",
|
||||||
|
name: "Riverflow V2 Fast",
|
||||||
|
tier: "premium",
|
||||||
|
description: "Fast premium output for production workflows",
|
||||||
|
estimatedCost: "~€0.09",
|
||||||
|
creditCost: 9,
|
||||||
|
minTier: "starter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "sourceful/riverflow-v2-pro",
|
||||||
|
name: "Riverflow V2 Pro",
|
||||||
|
tier: "premium",
|
||||||
|
description: "Pro quality with stronger composition",
|
||||||
|
estimatedCost: "~€0.12",
|
||||||
|
creditCost: 12,
|
||||||
|
minTier: "starter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "google/gemini-3-pro-image-preview",
|
||||||
|
name: "Gemini 3 Pro Image",
|
||||||
|
tier: "premium",
|
||||||
|
description: "Advanced quality and prompt adherence",
|
||||||
|
estimatedCost: "~€0.13",
|
||||||
|
creditCost: 13,
|
||||||
|
minTier: "starter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "openai/gpt-5-image",
|
||||||
|
name: "GPT-5 Image",
|
||||||
|
tier: "premium",
|
||||||
|
description: "Highest quality and best text rendering",
|
||||||
|
estimatedCost: "~€0.15",
|
||||||
|
creditCost: 15,
|
||||||
|
minTier: "starter",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_MODEL_ID = "google/gemini-2.5-flash-image";
|
export const DEFAULT_MODEL_ID = "google/gemini-2.5-flash-image";
|
||||||
@@ -46,3 +101,16 @@ export const DEFAULT_MODEL_ID = "google/gemini-2.5-flash-image";
|
|||||||
export function getModel(id: string): AiModel | undefined {
|
export function getModel(id: string): AiModel | undefined {
|
||||||
return IMAGE_MODELS.find((m) => m.id === id);
|
return IMAGE_MODELS.find((m) => m.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IMAGE_MODEL_TIER_ORDER: Record<AiModel["minTier"], number> = {
|
||||||
|
free: 0,
|
||||||
|
starter: 1,
|
||||||
|
pro: 2,
|
||||||
|
max: 3,
|
||||||
|
business: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getAvailableImageModels(tier: AiModel["minTier"]): AiModel[] {
|
||||||
|
const maxTier = IMAGE_MODEL_TIER_ORDER[tier];
|
||||||
|
return IMAGE_MODELS.filter((model) => IMAGE_MODEL_TIER_ORDER[model.minTier] <= maxTier);
|
||||||
|
}
|
||||||
|
|||||||
35
tests/lib/ai-models.test.ts
Normal file
35
tests/lib/ai-models.test.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
DEFAULT_MODEL_ID,
|
||||||
|
IMAGE_MODELS,
|
||||||
|
getAvailableImageModels,
|
||||||
|
getModel,
|
||||||
|
} from "@/lib/ai-models";
|
||||||
|
|
||||||
|
describe("ai image models registry", () => {
|
||||||
|
it("contains all 9 PRD models in stable order", () => {
|
||||||
|
expect(IMAGE_MODELS.map((model) => model.id)).toEqual([
|
||||||
|
"google/gemini-2.5-flash-image",
|
||||||
|
"black-forest-labs/flux.2-klein-4b",
|
||||||
|
"bytedance-seed/seedream-4.5",
|
||||||
|
"google/gemini-3.1-flash-image-preview",
|
||||||
|
"openai/gpt-5-image-mini",
|
||||||
|
"sourceful/riverflow-v2-fast",
|
||||||
|
"sourceful/riverflow-v2-pro",
|
||||||
|
"google/gemini-3-pro-image-preview",
|
||||||
|
"openai/gpt-5-image",
|
||||||
|
]);
|
||||||
|
expect(DEFAULT_MODEL_ID).toBe("google/gemini-2.5-flash-image");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters by subscription tier", () => {
|
||||||
|
expect(getAvailableImageModels("free").every((model) => model.minTier === "free")).toBe(
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves model lookup", () => {
|
||||||
|
expect(getModel(DEFAULT_MODEL_ID)?.creditCost).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user