create: choose the render model; length and price follow it
This commit is contained in:
parent
0daf74cfac
commit
dd92ed7aba
1 changed files with 62 additions and 4 deletions
66
create.html
66
create.html
|
|
@ -45,6 +45,12 @@
|
|||
<span class="hint">This decides the set, the framing and how it is written, before a word exists.</span>
|
||||
<select id="format"><option value="podcast">Podcast episode</option></select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="model">Filmed with</label>
|
||||
<span class="hint">Different engines shoot different shot lengths and cost different amounts. Leave it alone if you are not sure.</span>
|
||||
<select id="model"></select>
|
||||
<p class="foot" id="modelnote" style="margin:8px 0 0;color:var(--muted)"></p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="scene">Override the setting <span style="color:var(--muted);font-weight:400">(optional)</span></label>
|
||||
<span class="hint">Leave blank to use the format's own set. Real or not: a field of tall grass, floating on a surfboard.</span>
|
||||
|
|
@ -64,11 +70,11 @@
|
|||
<h2 class="sec" style="margin-top:34px">4 · How long</h2>
|
||||
<div class="field">
|
||||
<div class="chips" id="len">
|
||||
<span class="chip" data-v="2">16 seconds</span>
|
||||
<span class="chip on" data-v="4">32 seconds</span>
|
||||
<span class="chip" data-v="6">48 seconds</span>
|
||||
<span class="chip" data-v="2">2 shots</span>
|
||||
<span class="chip on" data-v="4">4 shots</span>
|
||||
<span class="chip" data-v="6">6 shots</span>
|
||||
</div>
|
||||
<span class="hint" style="margin-top:10px;display:block">The piece is written as one continuous monologue, then cut into 8 second shots that flow into each other.</span>
|
||||
<span class="hint" style="margin-top:10px;display:block" id="lenhint">The piece is written as one continuous monologue, then cut into shots that flow into each other.</span>
|
||||
</div>
|
||||
<div class="quote">
|
||||
<div><div class="big" id="price">$8.85</div><div class="sub" id="plen">32 seconds · 4 shots</div></div>
|
||||
|
|
@ -136,11 +142,42 @@
|
|||
navBar("create");
|
||||
var email = requireSession();
|
||||
var stance = "auto", segments = 4, havePets = false, FORMATS = [];
|
||||
// The render engines the server will accept. Shot length and price both come
|
||||
// from here rather than being assumed, because they differ per engine: Veo
|
||||
// shoots 8s, Omni 1.1 shoots 10s.
|
||||
var MODELS = [], MODEL = null;
|
||||
function modelOf(id) {
|
||||
for (var i = 0; i < MODELS.length; i++) if (MODELS[i].id === id) return MODELS[i];
|
||||
return null;
|
||||
}
|
||||
function shotSeconds() { return (MODEL && MODEL.shot_seconds) || 8; }
|
||||
|
||||
(async function loadFormats() {
|
||||
var r = await api("camera_presets", {});
|
||||
if (!r.ok || !r.formats) return;
|
||||
FORMATS = r.formats;
|
||||
|
||||
// Models. An older worker returns none, in which case the control stays
|
||||
// hidden and the submission omits the field, so nothing breaks.
|
||||
MODELS = r.models || [];
|
||||
var msel = document.getElementById("model");
|
||||
if (MODELS.length) {
|
||||
msel.innerHTML = MODELS.map(function (m) {
|
||||
return '<option value="' + esc(m.id) + '">' + esc(m.label) + '</option>';
|
||||
}).join("");
|
||||
msel.value = r.default_model || MODELS[0].id;
|
||||
MODEL = modelOf(msel.value);
|
||||
msel.addEventListener("change", function () {
|
||||
MODEL = modelOf(msel.value);
|
||||
paintModel();
|
||||
paint();
|
||||
});
|
||||
paintModel();
|
||||
paint();
|
||||
} else {
|
||||
msel.closest(".field").style.display = "none";
|
||||
}
|
||||
|
||||
var sel = document.getElementById("format");
|
||||
sel.innerHTML = FORMATS.map(function (f) {
|
||||
return '<option value="' + esc(f.id) + '">' + esc(f.label) + '</option>';
|
||||
|
|
@ -167,8 +204,28 @@ function chipGroup(id, cb) {
|
|||
chipGroup("stance", function (v) { stance = v; });
|
||||
chipGroup("len", function (v) { segments = parseInt(v, 10); paint(); });
|
||||
|
||||
// What the chosen engine costs us per shot, marked up the same way the server
|
||||
// marks up. Mirrors quote_for(); if one changes, change both.
|
||||
function paintModel() {
|
||||
var el = document.getElementById("modelnote");
|
||||
el.textContent = MODEL ? (MODEL.shot_seconds + "s per shot. " + (MODEL.note || "")) : "";
|
||||
var chips = document.querySelectorAll("#len .chip");
|
||||
for (var i = 0; i < chips.length; i++) {
|
||||
var nshots = parseInt(chips[i].getAttribute("data-v"), 10);
|
||||
chips[i].textContent = nshots + " shots · " + (nshots * shotSeconds()) + "s";
|
||||
}
|
||||
document.getElementById("lenhint").textContent =
|
||||
"The piece is written as one continuous monologue, then cut into "
|
||||
+ shotSeconds() + " second shots that flow into each other.";
|
||||
}
|
||||
|
||||
function paint() {
|
||||
var p = priceFor(segments);
|
||||
if (MODEL && MODEL.usd_per_second) {
|
||||
var cost = segments * MODEL.shot_seconds * MODEL.usd_per_second + 0.17;
|
||||
p = { price: Math.round(cost * 5 * 100) / 100,
|
||||
seconds: segments * MODEL.shot_seconds };
|
||||
}
|
||||
document.getElementById("price").textContent = "$" + p.price.toFixed(2);
|
||||
document.getElementById("plen").textContent = p.seconds + " seconds · " + segments + " shots";
|
||||
}
|
||||
|
|
@ -364,6 +421,7 @@ document.getElementById("form").addEventListener("submit", async function (e) {
|
|||
pet_name: opt ? opt.getAttribute("data-name") : "",
|
||||
source_url: url, owner_notes: notes, scene: scene,
|
||||
format: document.getElementById("format").value,
|
||||
render_model: MODEL ? MODEL.id : "",
|
||||
stance: stance, segments: segments, hold: true
|
||||
});
|
||||
if (!r.ok) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue