From 3c161ac9a6a79cf4025d8e3c7119e3172e258ad9 Mon Sep 17 00:00:00 2001 From: Matthias Meister Date: Tue, 7 Apr 2026 21:45:51 +0200 Subject: [PATCH] feat(ai): add full image model catalog and tier filters --- lib/ai-models.ts | 102 ++++++++++++++++++++++++++++++------ tests/lib/ai-models.test.ts | 35 +++++++++++++ 2 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 tests/lib/ai-models.test.ts diff --git a/lib/ai-models.ts b/lib/ai-models.ts index 246eccf..e64d154 100644 --- a/lib/ai-models.ts +++ b/lib/ai-models.ts @@ -22,23 +22,78 @@ export const IMAGE_MODELS: AiModel[] = [ creditCost: 4, minTier: "free", }, - // Phase 2 — uncomment when model selector UI is ready: - // { - // id: "black-forest-labs/flux.2-klein-4b", - // name: "FLUX.2 Klein", - // tier: "budget", - // description: "Photorealism, fastest Flux", - // estimatedCost: "~€0.02", - // minTier: "free", - // }, - // { - // id: "openai/gpt-5-image", - // name: "GPT-5 Image", - // tier: "premium", - // description: "Best instruction following, text in image", - // estimatedCost: "~€0.15", - // minTier: "starter", - // }, + { + id: "black-forest-labs/flux.2-klein-4b", + name: "FLUX.2 Klein 4B", + tier: "budget", + description: "Low-cost image generation for quick drafts", + estimatedCost: "~€0.02", + creditCost: 2, + minTier: "free", + }, + { + id: "bytedance-seed/seedream-4.5", + name: "Seedream 4.5", + tier: "standard", + description: "Balanced detail and speed for everyday prompts", + estimatedCost: "~€0.05", + 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"; @@ -46,3 +101,16 @@ export const DEFAULT_MODEL_ID = "google/gemini-2.5-flash-image"; export function getModel(id: string): AiModel | undefined { return IMAGE_MODELS.find((m) => m.id === id); } + +const IMAGE_MODEL_TIER_ORDER: Record = { + 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); +} diff --git a/tests/lib/ai-models.test.ts b/tests/lib/ai-models.test.ts new file mode 100644 index 0000000..cad0b27 --- /dev/null +++ b/tests/lib/ai-models.test.ts @@ -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); + }); +});