Add Kimodo model catalogue to demo
This commit is contained in:
parent
ac35407fc0
commit
dc9dd6f095
@ -4,7 +4,7 @@
|
||||
/* LocalAI house style: dark graphite surfaces with a cyan/violet edge. */
|
||||
:root{--la-bg:#080b0f;--la-panel:#10151b;--la-panel-2:#151c23;--la-line:#25313b;--la-text:#f3f6f4;--la-muted:#8b9aa5;--la-cyan:#3bd3d0;--la-cyan-2:#5ee6be;--la-violet:#9f7aea}body{background:var(--la-bg);color:var(--la-text)}.sidebar{background:radial-gradient(circle at 18% 0,rgba(59,211,208,.12),transparent 26rem),var(--la-panel);border-color:var(--la-line)}.card{background:var(--la-panel-2);border-color:var(--la-line)}.stage{background:#090d12}canvas{background:radial-gradient(circle at 50% 25%,#102632 0,#090d12 56%)}.eyebrow{color:var(--la-cyan);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.product-title{display:flex;align-items:center;gap:11px}.product-mark{display:grid;place-items:center;width:36px;height:36px;border-radius:11px;background:linear-gradient(135deg,var(--la-cyan),#218eac 55%,var(--la-violet));color:#051013;font-size:20px;font-weight:900;box-shadow:0 0 28px rgba(59,211,208,.2)}.localai-brand{display:flex;align-items:center;gap:9px;color:#687983;font-size:10px;letter-spacing:.1em;text-transform:uppercase}.localai-brand img{width:56px;height:56px;object-fit:contain}.promptbox label,.gallery h2{color:var(--la-text)}textarea,input{border-color:var(--la-line);background:#0b1015}button{background:linear-gradient(135deg,var(--la-cyan),var(--la-cyan-2));color:#051013;border-radius:8px;box-shadow:0 8px 22px rgba(59,211,208,.12)}.item{background:#0b1015;border-color:var(--la-line)}.item:hover,.item.active{border-color:var(--la-cyan);background:#111d24}.status,.readout,.hint,.camera{color:var(--la-muted)}.progress{color:var(--la-cyan-2)}.progress::before{background:var(--la-cyan);box-shadow:0 0 0 0 var(--la-cyan)}.item.running{border-color:var(--la-cyan)}
|
||||
</style><main><aside class="sidebar"><header><div class="eyebrow">Kimodo-SMPLX-RP-v1 · Vulkan</div><div class="product-title"><span class="product-mark">K</span><h1>Text to motion</h1></div></header><section class="card promptbox"><label for="prompt">Describe a motion</label><textarea id="prompt">A person runs forward and then leaps over an obstacle in front of them.</textarea><button id="generate">Generate motion</button><span id="status" class="readout">Ready</span><div class="hint">One generation runs at a time. Select an animation below to restore and edit its prompt.</div></section><section class="card history"><div class="gallery"><h2>Past animations</h2><div id="items" class="readout">Loading…</div></div></section><div class="localai-brand"><span>Powered locally with</span><img src="/localai.png" alt="LocalAI"></div></aside><section class="stage"><canvas id="view" width="1280" height="720" aria-label="Animated SMPL-X skeleton"></canvas><div class="controls"><button id="play">Pause</button><button id="reset">Reset view</button><input id="frame" type="range" min="0" value="0" step="1"><span id="frameText" class="readout"></span><span class="camera">Drag: rotate · wheel: zoom · Shift/right-drag: pan · double-click: reset</span></div></section></main>
|
||||
<script>
|
||||
<script src="/models.js"></script><script>
|
||||
const parents=[-1,0,0,0,1,2,3,4,5,6,7,8,9,9,9,12,13,14,16,17,18,19];
|
||||
// SMPL-X22 rest offsets calibrated from the captured upstream posed-joint /
|
||||
// global-rotation fixture. The generator persists local rotations and root
|
||||
|
||||
@ -23,6 +23,9 @@ import (
|
||||
//go:embed index.html
|
||||
var files embed.FS
|
||||
|
||||
//go:embed models.js
|
||||
var modelUI []byte
|
||||
|
||||
//go:embed assets/localai.png
|
||||
var localAILogo []byte
|
||||
|
||||
@ -168,6 +171,11 @@ func main() {
|
||||
w.Header().Set("Cache-Control", "public, max-age=86400")
|
||||
_, _ = w.Write(localAILogo)
|
||||
})
|
||||
mux.HandleFunc("/models.js", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
_, _ = w.Write(modelUI)
|
||||
})
|
||||
mux.HandleFunc("/api/animations", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(g.list())
|
||||
|
||||
38
demo/models.js
Normal file
38
demo/models.js
Normal file
@ -0,0 +1,38 @@
|
||||
// Add the model picker without duplicating the compact canvas viewer script.
|
||||
window.addEventListener('load', async () => {
|
||||
const prompt = document.querySelector('#prompt');
|
||||
const form = prompt?.closest('.promptbox');
|
||||
if (!prompt || !form) return;
|
||||
const models = await fetch('/api/models').then(r => r.json());
|
||||
const label = document.createElement('label');
|
||||
label.htmlFor = 'motionModel'; label.textContent = 'Motion model';
|
||||
const select = document.createElement('select');
|
||||
select.id = 'motionModel';
|
||||
for (const model of models) {
|
||||
const option = document.createElement('option');
|
||||
option.value = model.id;
|
||||
option.disabled = !model.available;
|
||||
option.textContent = `${model.label}${model.available ? '' : ' — coming soon'}`;
|
||||
select.append(option);
|
||||
}
|
||||
const hint = document.createElement('div'); hint.className = 'hint';
|
||||
const update = () => {
|
||||
const model = models.find(item => item.id === select.value);
|
||||
hint.textContent = model.available
|
||||
? `${model.skeleton} · ${model.upstream}`
|
||||
: `${model.skeleton} · ${model.reason}`;
|
||||
};
|
||||
select.onchange = update;
|
||||
form.insertBefore(label, prompt); form.insertBefore(select, prompt); form.insertBefore(hint, prompt);
|
||||
update();
|
||||
|
||||
const nativeFetch = window.fetch.bind(window);
|
||||
window.fetch = (input, init) => {
|
||||
if (typeof input === 'string' && input.endsWith('/api/generate') && init?.body) {
|
||||
const body = JSON.parse(init.body);
|
||||
body.model = select.value;
|
||||
return nativeFetch(input, {...init, body: JSON.stringify(body)});
|
||||
}
|
||||
return nativeFetch(input, init);
|
||||
};
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user