Fix desktop video generation ignoring selected resolution

The desktop video promptbox built the GenerateVideoRequest without ever
setting `resolution`, so generation always omitted it and the backend
fell back to the model's default (720p) — and billed for it. The cost
preview reads the same store value and sends it, so the preview was
correct (e.g. 117 for 480p) while the charge stayed at the 720p price
(240). Populate request.resolution in buildRequest, mapping the store's
legacy display string ("480p"/"720p"/"1080p") to CommonResolution,
guarded on the model exposing resolutionOptions.

Also fix useImageCostEstimate (webapp) omitting `quality` from its
effect deps, which meant the image cost preview didn't refresh when only
the quality option changed.
This commit is contained in:
Tanish Manku committed 2026-06-11 14:29:53 -07:00
1 parent 5979002f7e
commit a4ef7ffb05
2 files changed
+34

No files matched your search

@@ -62,6 +62,7 @@ export function useImageCostEstimate(params: ImageCostParams): number | null {
params.model,
params.aspectRatio,
params.resolution,
params.quality,
params.numImages,
params.hasReferenceImages,
params.imageMediaTokenCount,
@@ -18,6 +18,7 @@ import { faCircleInfo } from "@fortawesome/pro-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { GalleryItem, GalleryModal } from "@storyteller/ui-gallery-modal";
import {
CommonResolution,
SizeIconOption,
SizeOption,
VideoModel,
@@ -58,6 +59,27 @@ type GROK_ASPECT_RATIO = "landscape" | "portrait" | "square";
const EMPTY_CHARACTERS: StoredCharacter[] = [];
// The video store keeps resolution as a legacy display string ("480p" / "720p"
// / "1080p") taken from the model's `resolutionOptions`. The generate request,
// however, needs the `CommonResolution` enum. Map here so the user's resolution
// choice is actually sent: omitting it makes the backend fall back to the
// model's default resolution (and bill for it), which is what made the charge
// disagree with the cost preview — the preview reads the same store value and
// converts it correctly. Snake_case forms are accepted too for robustness.
const RESOLUTION_STRING_TO_COMMON: Record<string, CommonResolution> = {
"480p": CommonResolution.FourEightyP,
"720p": CommonResolution.SevenTwentyP,
"1080p": CommonResolution.TenEightyP,
half_k: CommonResolution.HalfK,
one_k: CommonResolution.OneK,
two_k: CommonResolution.TwoK,
three_k: CommonResolution.ThreeK,
four_k: CommonResolution.FourK,
four_eighty_p: CommonResolution.FourEightyP,
seven_twenty_p: CommonResolution.SevenTwentyP,
ten_eighty_p: CommonResolution.TenEightyP,
};
const DEFAULT_RESOLUTIONS: SizeOption[] = [
{
tauriValue: "720p",
@@ -767,6 +789,17 @@ export const PromptBoxVideo = ({
request.duration_seconds = duration;
}
// Pass the chosen resolution when the model exposes a resolution picker.
// Guarded on `resolutionOptions` so a stale store value (left over from a
// model that did support resolution) isn't sent for one that doesn't.
if (selectedModel.resolutionOptions?.length) {
const mappedResolution =
RESOLUTION_STRING_TO_COMMON[resolution as string];
if (mappedResolution) {
request.resolution = mappedResolution;
}
}
switch (selectedModel?.tauriId) {
case "grok_video":
request.grok_aspect_ratio = getGrokAspectRatio();