File size: 4,652 Bytes
921d377 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | /**
* Form state for the new-project wizard.
*
* Lives in its own module so the step components and the parent
* Wizard can both import the same type without circular deps.
* The shape is wire-friendly: `toCreatePayload` and `toPlanPayload`
* project this struct directly into the `/v1/interactive/*`
* request bodies — no field renames at the boundary.
*/
import type { ExperienceMode } from "./types";
/**
* Which ComfyUI workflow bucket the player calls per scene.
* "video" — full Animate/SVD clip. Default. Higher VRAM.
* "image" — still-image txt2img. Cheap on GPU; lets operators
* validate the whole interactive flow without owning
* a beefy video model.
*/
export type RenderMediaType = "video" | "image";
export interface WizardForm {
// Interaction type (Step 0 header)
interaction_type: "standard_project" | "persona_live_play";
persona_project_id: string;
persona_label: string;
/** Scene render bucket — image or video. See RenderMediaType. */
render_media_type: RenderMediaType;
// Step 0
title: string;
prompt: string;
experience_mode: ExperienceMode;
// Step 1
audience_role: string;
audience_level: "beginner" | "intermediate" | "advanced";
audience_language: string;
audience_locale_hint: string;
// Step 2
branch_count: number;
depth: number;
scenes_per_branch: number;
// Step 3
policy_profile_id: string;
/** Override LLM model id used by the storyteller (scene graph
* generation + persona_live runtime). Empty string means
* "use the server default". Surfaced in the wizard only when
* ``experience_mode === "mature_gated"`` because the default
* Llama 3 / Llama 3.2 models refuse explicit content with
* "I cannot create content that describes explicit sexual
* situations." Operators can pick from the abliterated /
* uncensored models they already installed (see Models tab —
* rows tagged "🌶️ Adult" / "🔥 NSFW Pick"). The backend
* reads ``audience_profile.adult_llm`` at every LLM call site
* for the experience. */
adult_llm: string;
}
export const DEFAULT_WIZARD_FORM: WizardForm = {
interaction_type: "standard_project",
persona_project_id: "",
persona_label: "",
render_media_type: "video",
title: "",
prompt: "",
experience_mode: "sfw_general",
audience_role: "viewer",
audience_level: "beginner",
audience_language: "en",
audience_locale_hint: "",
branch_count: 3,
depth: 3,
scenes_per_branch: 3,
policy_profile_id: "sfw_general",
adult_llm: "",
};
export function toCreatePayload(f: WizardForm) {
return {
title: f.title.trim(),
description: f.prompt.trim(),
experience_mode: f.experience_mode,
policy_profile_id: f.policy_profile_id,
project_type: f.interaction_type === "persona_live_play" ? "persona_live" : "standard",
audience_profile: {
role: f.audience_role,
level: f.audience_level,
language: f.audience_language,
locale_hint: f.audience_locale_hint,
interaction_type: f.interaction_type,
persona_project_id: f.persona_project_id || undefined,
persona_label: f.persona_label || undefined,
render_media_type: f.render_media_type,
// Stored only for mature_gated experiences. Empty string is
// wire-equivalent to "use the server default" — backend treats
// both as fall-through to the configured Ollama model.
adult_llm:
f.experience_mode === "mature_gated" && f.adult_llm
? f.adult_llm
: undefined,
},
};
}
export function toPlanPayload(f: WizardForm) {
return {
prompt: f.prompt.trim(),
mode: f.experience_mode,
audience_hints: {
role: f.audience_role,
level: f.audience_level,
language: f.audience_language,
locale_hint: f.audience_locale_hint,
interaction_type: f.interaction_type,
persona_project_id: f.persona_project_id || undefined,
persona_label: f.persona_label || undefined,
render_media_type: f.render_media_type,
// Plan-auto runs BEFORE create-experience so it can't read
// audience_profile.adult_llm — pass the operator's Step 0
// pick directly so the title/topic LLM call uses the
// uncensored model the user selected. Without this, the
// default Llama refuses with "I cannot create a brief for
// an interactive video that focuses on sexual experiences."
// and the wizard's title/description land as that refusal.
adult_llm:
f.experience_mode === "mature_gated" && f.adult_llm
? f.adult_llm
: undefined,
},
};
}
|