Compare commits

...
Author SHA1 Message Date
BFlat a60fb817c8 Webapp: omni gen added bitrate field 2026-06-22 21:52:53 +07:00
5 changed files with 83 additions and 2 deletions
@@ -117,6 +117,7 @@ export interface VideoCostParams {
model: string;
aspectRatio?: string;
resolution?: string | null;
bitrate?: string | null;
duration?: number | null;
numVideos?: number;
hasStartFrame: boolean;
@@ -142,6 +143,7 @@ export function useVideoCostEstimate(params: VideoCostParams): number | null {
model: params.model,
aspect_ratio: params.aspectRatio ?? null,
resolution: params.resolution ?? null,
bitrate: params.bitrate ?? null,
duration_seconds: params.duration ?? null,
generate_audio: params.generateAudio ?? null,
video_batch_count: params.numVideos ?? 1,
@@ -178,6 +180,7 @@ export function useVideoCostEstimate(params: VideoCostParams): number | null {
params.model,
params.aspectRatio,
params.resolution,
params.bitrate,
params.duration,
params.numVideos,
params.hasStartFrame,
@@ -33,6 +33,7 @@ export type VideoUiState = {
selectedSize: string;
duration: number | null;
resolution: string | null;
bitrate: string | null;
generateWithSound: boolean;
inputMode: VideoInputMode;
numVideos: number;
@@ -69,6 +70,7 @@ const DEFAULT_UI: VideoUiState = {
selectedSize: "wide_sixteen_by_nine",
duration: null,
resolution: null,
bitrate: null,
generateWithSound: false,
inputMode: "keyframe",
numVideos: 1,
@@ -121,6 +121,15 @@ const LABEL_TO_RES: Record<string, string> = Object.fromEntries(
Object.entries(RES_LABELS).map(([k, v]) => [v, k]),
);
const BITRATE_LABELS: Record<string, string> = {
normal: "Normal",
high: "High",
};
const LABEL_TO_BITRATE: Record<string, string> = Object.fromEntries(
Object.entries(BITRATE_LABELS).map(([k, v]) => [v, k]),
);
// ── Model lookup ─────────────────────────────────────────────────────────
// Placeholder entries shown in the picker as disabled "SOON" items. These are
@@ -294,6 +303,16 @@ export default function CreateVideo() {
(v: string | null) => setUi({ resolution: v }),
[setUi],
);
const bitrate =
resolveModelOption(
ui.bitrate ?? undefined,
selectedModel?.bitrate_options,
selectedModel?.bitrate_default,
) ?? null;
const setBitrate = useCallback(
(v: string | null) => setUi({ bitrate: v }),
[setUi],
);
const generateWithSound = ui.generateWithSound;
const numVideos = resolveModelCount(
ui.numVideos,
@@ -386,6 +405,8 @@ export default function CreateVideo() {
const hasSizeOptions = (selectedModel?.aspect_ratio_options?.length ?? 0) > 0;
const hasResolutionOptions =
(selectedModel?.resolution_options?.length ?? 0) > 0;
const hasBitrateOptions =
(selectedModel?.bitrate_options?.length ?? 0) > 0;
const hasSound = !!selectedModel?.show_generate_with_sound_toggle;
const supportsImagePrompts =
!!selectedModel?.starting_keyframe_supported ||
@@ -463,6 +484,7 @@ export default function CreateVideo() {
model: selectedModel?.model ?? "",
aspectRatio: selectedSize,
resolution,
bitrate,
duration: effectiveDuration,
numVideos,
hasStartFrame: !isReferenceMode && referenceImages.length > 0,
@@ -579,6 +601,16 @@ export default function CreateVideo() {
: null,
[selectedModel, resolution],
);
const bitrateItems = useMemo(
(): PopoverItem[] | null =>
selectedModel?.bitrate_options
? selectedModel.bitrate_options.map((b) => ({
label: BITRATE_LABELS[b] ?? b,
selected: b === (bitrate ?? selectedModel.bitrate_default),
}))
: null,
[selectedModel, bitrate],
);
const inputModeItems = useMemo(
(): PopoverItem[] | null =>
supportsRefMode
@@ -736,6 +768,12 @@ export default function CreateVideo() {
[setResolution],
);
const handleBitrateChange = useCallback(
(item: PopoverItem) =>
setBitrate(LABEL_TO_BITRATE[item.label] ?? item.label),
[setBitrate],
);
const handleInputModeChange = useCallback(
(item: PopoverItem) => {
const mode = item.label === "Reference" ? "reference" : "keyframe";
@@ -905,6 +943,9 @@ export default function CreateVideo() {
resolution: hasResolutionOptions
? (resolution ?? selectedModel.resolution_default ?? undefined)
: undefined,
bitrate: hasBitrateOptions
? (bitrate ?? selectedModel.bitrate_default ?? undefined)
: undefined,
generateAudio: hasSound ? generateWithSound : undefined,
startFrameImageMediaToken: startFrameToken?.length
? startFrameToken
@@ -998,8 +1039,10 @@ export default function CreateVideo() {
numVideos,
effectiveDuration,
resolution,
bitrate,
generateWithSound,
hasResolutionOptions,
hasBitrateOptions,
hasSound,
supportsImagePrompts,
hasEndFrame,
@@ -1018,7 +1061,12 @@ export default function CreateVideo() {
// ── Mobile form ───────────────────────────────────────────────────────
const activeResolutionLabel = resolutionItems?.find((i) => i.selected)?.label;
const outputSummary = [`${effectiveDuration}s`, activeResolutionLabel]
const activeBitrateLabel = bitrateItems?.find((i) => i.selected)?.label;
const outputSummary = [
`${effectiveDuration}s`,
activeResolutionLabel,
activeBitrateLabel,
]
.filter(Boolean)
.join(" · ");
@@ -1147,7 +1195,7 @@ export default function CreateVideo() {
/>
</div>
)}
{(durationRange || resolutionItems) && (
{(durationRange || resolutionItems || bitrateItems) && (
<>
<MobileFieldButton
label="Output"
@@ -1194,6 +1242,14 @@ export default function CreateVideo() {
/>
</DrawerSection>
)}
{bitrateItems && (
<DrawerSection label="Bitrate">
<DrawerOptionList
items={bitrateItems}
onSelect={handleBitrateChange}
/>
</DrawerSection>
)}
</SettingsDrawer>
</>
)}
@@ -1431,6 +1487,21 @@ export default function CreateVideo() {
/>
</Tooltip>
)}
{bitrateItems && (
<Tooltip
content="Bitrate"
position="top"
className="z-50"
closeOnClick
>
<PopoverMenu
items={bitrateItems}
onSelect={handleBitrateChange}
mode="toggle"
panelTitle="Bitrate"
/>
</Tooltip>
)}
{durationRange && (
<Tooltip content="Duration" position="top" className="z-50">
<PopoverMenu
@@ -11,6 +11,7 @@ export interface GenerateVideoParams {
aspectRatio?: string;
duration?: number;
resolution?: string;
bitrate?: string;
generateAudio?: boolean;
startFrameImageMediaToken?: string;
endFrameImageMediaToken?: string;
@@ -36,6 +37,7 @@ export async function enqueueVideoGeneration(
idempotency_token: crypto.randomUUID(),
aspect_ratio: params.aspectRatio ?? null,
resolution: params.resolution ?? null,
bitrate: params.bitrate ?? null,
duration_seconds: params.duration ?? null,
generate_audio: params.generateAudio ?? null,
video_batch_count: params.numVideos ?? 1,
+3
View File
@@ -45,6 +45,7 @@ export interface OmniGenVideoRequest {
aspect_ratio?: string | null;
resolution?: string | null;
quality?: string | null;
bitrate?: string | null;
duration_seconds?: number | null;
video_batch_count?: number | null;
generate_audio?: boolean | null;
@@ -124,6 +125,8 @@ export interface OmniGenVideoModelInfo {
batch_size_max: number | null;
quality_options: string[] | null;
default_quality: string | null;
bitrate_options: string[] | null;
bitrate_default: string | null;
duration_seconds_options: number[] | null;
duration_seconds_default: number | null;
duration_seconds_min: number | null;