Files
hao-ai-lab-FastVideo/docs-site/lib/cookbook-commands.ts
T

83 lines
3.6 KiB
TypeScript

import { stringify } from "yaml";
import type { Result, Value } from "./cookbook";
export function pythonSource(
source: string,
controls: { value: string | number | boolean; spans?: number[][] }[],
edits: Record<number, string | number | boolean> = {},
) {
const replacements = controls.flatMap((field, index) =>
(field.spans ?? []).map(([start, end]) => {
const value = Object.hasOwn(edits, index) ? edits[index] : field.value;
return { start, end, text: typeof value === "boolean" ? (value ? "True" : "False") : JSON.stringify(value) };
}),
);
for (const replacement of replacements.sort((a, b) => b.start - a.start))
source = source.slice(0, replacement.start) + replacement.text + source.slice(replacement.end);
return source;
}
/** Quoted heredocs preserve prompts literally, including shell substitutions. */
export function configAndLaunch(yaml: string, command: string) {
return fileAndLaunch("config.yaml", yaml, command);
}
export function fileAndLaunch(filename: string, content: string, command: string) {
let delimiter = "FASTVIDEO_CONFIG";
while (content.split("\n").includes(delimiter)) delimiter += "_";
return `(\nset -e\ncat > ${filename} <<'${delimiter}'\n${content.trimEnd()}\n${delimiter}\n${command}\n)`;
}
export const sdkCommand = `python - <<'FASTVIDEO_SDK'
import yaml
from fastvideo import VideoGenerator
with open("config.yaml") as file:
config = yaml.safe_load(file)
generator = VideoGenerator.from_config(config["generator"])
try:
generator.generate(config["request"])
finally:
generator.shutdown()
FASTVIDEO_SDK`;
/** The CUDA CLI uses the same generator with request instead of server defaults. */
export function inferenceOutput(result: Result, imagePath?: string) {
const defaults = (result.config.default_request ?? {}) as Record<string, Value>;
const output = (defaults.output ?? {}) as Record<string, Value>;
const generator = result.config.generator as Record<string, Value>;
const pipeline = generator.pipeline as Record<string, Value> | undefined;
const inputs = { ...((defaults.inputs ?? {}) as Record<string, Value>) };
const components = pipeline?.components as Record<string, Value> | undefined;
// Ref2VA pipelines read ordered references, not a first-frame image.
const ref2va = /ref2va/i.test(String(components?.override_pipeline_cls_name ?? ""));
if (imagePath !== undefined && imagePath.trim()) {
if (ref2va) inputs.references = [{ source: imagePath.trim(), media_type: "image" }];
else inputs.image_path = imagePath.trim();
} else if (imagePath !== undefined && !ref2va) inputs.image_path = imagePath.trim();
const references = Array.isArray(inputs.references) ? (inputs.references as Record<string, Value>[]) : [];
const images = ref2va
? references.map((reference) => reference.source)
: Array.isArray(inputs.image_path)
? inputs.image_path
: [inputs.image_path];
if (pipeline?.workload_type === "i2v" && !images.some((image) => typeof image === "string" && image.trim())) {
throw new Error("Enter a source image path before copying a CLI or Python SDK example.");
}
return {
yaml: stringify({
generator: result.config.generator,
request: {
...defaults,
...(Object.keys(inputs).length ? { inputs } : {}),
prompt: defaults.prompt ?? "A river flowing through a peaceful forest",
output: { ...output, save_video: true, return_frames: false, output_path: "outputs/cookbook/" },
},
}),
command: result.command.replace(
/\bfastvideo serve --config config\.yaml$/,
"fastvideo generate --config config.yaml",
),
};
}