feat: expose generation model choices

This commit is contained in:
2026-05-25 11:02:13 +08:00
parent 6ba84a7603
commit dcc8abc812
5 changed files with 159 additions and 15 deletions

View File

@@ -22,11 +22,13 @@ import {
deleteGeneratedVideo,
generateImage,
generateStoryboardVideo,
getRuntimeHealth,
getJob,
uploadReferenceFrame,
type GeneratedImage,
type GeneratedVideo,
type Job,
type RuntimeModelOption,
} from "@/lib/api"
type CreationMode = "text-video" | "text-image" | "first-frame-video" | "first-last-frame-video"
@@ -105,6 +107,14 @@ export default function Home() {
const [lastFrameFile, setLastFrameFile] = useState<File | null>(null)
const [firstFramePreview, setFirstFramePreview] = useState("")
const [lastFramePreview, setLastFramePreview] = useState("")
const [imageModel, setImageModel] = useState("auto")
const [videoModel, setVideoModel] = useState("seedance")
const [imageOptions, setImageOptions] = useState<RuntimeModelOption[]>([
{ id: "auto", label: "自动", model: "gpt-image-2", available: true },
])
const [videoOptions, setVideoOptions] = useState<RuntimeModelOption[]>([
{ id: "seedance", label: "Seedance", model: "seedance", available: true },
])
const [job, setJob] = useState<Job | null>(null)
const [busy, setBusy] = useState<BusyTask>(null)
const [error, setError] = useState("")
@@ -117,6 +127,30 @@ export default function Home() {
const runningVideo = (job?.generated_videos ?? []).some((item) => item.status === "queued" || item.status === "in_progress")
const submitting = busy === mode || busy === "job"
useEffect(() => {
getRuntimeHealth()
.then((health) => {
const models = health.models
const nextImageOptions = models?.image_options?.length
? models.image_options
: [
{ id: "auto", label: "自动", model: models?.image || "gpt-image-2", available: true },
{ id: models?.image || "gpt-image-2", label: "GPT Image 2", model: models?.image || "gpt-image-2", available: true },
]
const nextVideoOptions = models?.video_options?.length
? models.video_options
: [{ id: models?.video || "seedance", label: "Seedance", model: models?.video || "seedance", available: !!models?.video_configured }]
setImageOptions(nextImageOptions)
setVideoOptions(nextVideoOptions)
if (!nextImageOptions.some((item) => item.id === imageModel)) setImageModel(nextImageOptions[0]?.id || "auto")
if (!nextVideoOptions.some((item) => item.id === videoModel)) setVideoModel(nextVideoOptions[0]?.id || "seedance")
})
.catch(() => {
setImageOptions([{ id: "auto", label: "自动", model: "gpt-image-2", available: true }])
setVideoOptions([{ id: "seedance", label: "Seedance", model: "seedance", available: true }])
})
}, [])
useEffect(() => {
if (!firstFrameFile) {
setFirstFramePreview("")
@@ -211,6 +245,7 @@ export default function Home() {
const updated = await generateImage(target.id, 0, {
prompt: promptWithGuardrails(),
mode: "text",
model: imageModel,
})
setJob(updated)
toast.success("图片已生成")
@@ -237,6 +272,7 @@ export default function Home() {
first_image: activeMode.needsFirstFrame ? { kind: "keyframe", frame_idx: 0 } : null,
last_image: activeMode.needsLastFrame && lastFrame ? { kind: "keyframe", frame_idx: lastFrame.index } : null,
size: "720x1280",
model: videoModel,
})
setJob(updated)
toast.success("视频已提交")
@@ -368,7 +404,24 @@ export default function Home() {
/>
<div className="mt-3 flex flex-wrap items-center justify-between gap-3">
<div className="flex items-center gap-2 text-xs text-white/38">
<div className="flex flex-wrap items-center gap-2 text-xs text-white/38">
<label className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/7 bg-black/14 px-3">
<select
value={isVideoMode(mode) ? videoModel : imageModel}
onChange={(event) => {
if (isVideoMode(mode)) setVideoModel(event.target.value)
else setImageModel(event.target.value)
}}
className="max-w-36 bg-transparent text-white/76 outline-none"
>
{(isVideoMode(mode) ? videoOptions : imageOptions).map((item) => (
<option key={item.id} value={item.id} disabled={item.available === false}>
{item.label}
</option>
))}
</select>
</label>
{isVideoMode(mode) ? (
<label className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/7 bg-black/14 px-3">

View File

@@ -254,6 +254,14 @@ export interface GeneratedVideo {
created_at: number
}
export interface RuntimeModelOption {
id: string
label: string
model: string
description?: string
available?: boolean
}
export interface RuntimeModels {
asr?: string
asr_language?: string
@@ -271,6 +279,7 @@ export interface RuntimeModels {
product_view?: string
image?: string
image_base_url?: string
image_options?: RuntimeModelOption[]
image_fallbacks?: string[]
image_circuit?: {
primary?: string
@@ -293,6 +302,7 @@ export interface RuntimeModels {
voice_tts_paths?: string[]
video?: string
video_aliases?: Record<string, string>
video_options?: RuntimeModelOption[]
video_provider?: string
video_base_url?: string
video_configured?: boolean