Entrada por texto (teclado ademas de voz) y escote cirurgico con parche de piel en runtime
Browse files- chunk-4t726cmy.css +2 -1
- chunk-p1yb2ca4.js +248 -2
- index.html +9 -0
- workers/model-worker.js +8 -3
chunk-4t726cmy.css
CHANGED
|
@@ -1 +1,2 @@
|
|
| 1 |
-
:root{--bg:#050506;--bg-elev:#13151c;--bg-elev-2:#1b1e29;--border:#ffffff14;--border-strong:#ffffff29;--text:#f5f6fa;--text-dim:#f5f6faa6;--text-faint:#f5f6fa6b;--error:#ff6a75;--live:#22d3ee;--font-mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace;--radius-sm:8px;--radius-md:14px}*{box-sizing:border-box}html,body{height:100%;margin:0}body{background:var(--bg);color:var(--text);overflow:hidden;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif}#app{position:relative;height:100dvh}#stage{position:absolute;background:#050506;inset:0}#stage canvas{display:block}[hidden]{display:none!important}#loading{position:absolute;display:grid;font-family:var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--text-faint);background:var(--bg);pointer-events:none;place-items: center;transition:opacity .6s;font-size:12px;font-weight:500;inset:0}#loading.done{opacity:0}#topbar{position:absolute;display:flex;pointer-events:none;justify-content:space-between;align-items: flex-start;padding:18px 20px;top:0;left:0;right:0}#topbar>*{pointer-events:auto}#identity h1{letter-spacing:.01em;margin:0;font-size:15px;font-weight:600}#identity p{color:var(--text-faint);max-width:340px;margin:4px 0 0;font-size:12px;line-height:1.45}#identity strong{color:var(--text-dim);font-weight:500}.icon-btn{display:grid;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev);color:var(--text-dim);cursor:pointer;touch-action:manipulation;place-items: center;width:36px;height:36px;padding:0;transition:color .15s,border-color .15s}.icon-btn:hover{color:var(--text);border-color:var(--border-strong)}.icon-btn.active{color:var(--error);border-color:var(--border-strong)}#main-btn{background:var(--text);color:var(--bg);cursor:pointer;touch-action:manipulation;border:none;border-radius:23px;min-width:190px;height:46px;padding:0 26px;transition:transform .12s,opacity .15s;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:14px;font-weight:600}#main-btn:hover:not(:disabled){transform:translateY(-1px)}#main-btn:disabled{pointer-events:none;opacity:.45;cursor:default}#main-btn.live{background:var(--bg-elev);color:var(--text);border:1px solid var(--border-strong)}#controls{position:absolute;display:flex;padding:0 20px calc(22px + env(safe-area-inset-bottom));flex-direction:column;align-items: center;gap:14px;bottom:0;left:0;right:0}#buttons{display:flex;align-items: center;gap:10px}#caption{font-family:var(--font-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--text-faint);transition:color .2s;font-size:11px;font-weight:500}#caption.live{color:var(--live)}#caption.error{color:var(--error);text-align:center;max-width:560px;line-height:1.5}#progress{background:var(--border-strong);overflow:hidden;border-radius:1px;width:min(240px,60vw);height:2px}#progress-fill{background:var(--text-dim);width:0;height:100%;transition:width .3s}#subtitles{position:absolute;border-radius:var(--radius-md);backdrop-filter:blur(6px);border:1px solid var(--border);text-align:center;text-wrap:balance;color:var(--text);opacity:0;pointer-events:none;display:-webkit-box;-webkit-line-clamp:3;overflow:hidden;background:#0a0b10b8;-webkit-box-orient:vertical;max-width:min(640px,100vw - 48px);padding:10px 16px;transition:opacity .25s;font-size:15px;line-height:1.5;bottom:118px;left:50%;transform:translate(-50%)}#subtitles.visible{opacity:1}#settings{border:1px solid var(--border-strong);border-radius:var(--radius-md);background:var(--bg-elev);color:var(--text);width:min(440px,100vw - 40px);padding:22px;box-shadow:0 4px 18px #00000052}#settings::backdrop{backdrop-filter:blur(2px);background:#05060999}#settings h2{margin:0 0 16px;font-size:15px;font-weight:600}#settings label{display:block;color:var(--text-dim);margin-bottom:14px;font-size:12px}#settings select,#settings textarea,#settings input{display:block;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev-2);color:var(--text);width:100%;margin-top:6px;padding:9px 11px;font-family:inherit;font-size:13px}#settings select:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings input:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea{resize:vertical}#settings .hint{display:block;margin-top:6px;font-size:11px;line-height:1.4}#settings .check-row{display:flex;align-items: center;gap:9px}#settings .check-row input{display:inline-block;accent-color:var(--text);width:auto;margin:0}.dialog-actions{display:flex;justify-content:space-between;gap:12px;margin-top:6px}#reset-prompt{color:var(--text-dim);cursor:pointer;background:0 0;border:none;padding:9px 0;font-size:13px}#reset-prompt:hover{color:var(--text)}.dialog-actions .primary{border-radius:var(--radius-sm);background:var(--text);color:var(--bg);cursor:pointer;border:none;padding:9px 20px;font-size:13px;font-weight:600}button:focus-visible{outline:2px solid var(--text-dim);outline-offset:2px}
|
|
|
|
|
|
| 1 |
+
:root{--bg:#050506;--bg-elev:#13151c;--bg-elev-2:#1b1e29;--border:#ffffff14;--border-strong:#ffffff29;--text:#f5f6fa;--text-dim:#f5f6faa6;--text-faint:#f5f6fa6b;--error:#ff6a75;--live:#22d3ee;--font-mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace;--radius-sm:8px;--radius-md:14px}*{box-sizing:border-box}html,body{height:100%;margin:0}body{background:var(--bg);color:var(--text);overflow:hidden;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif}#app{position:relative;height:100dvh}#stage{position:absolute;background:#050506;inset:0}#stage canvas{display:block}[hidden]{display:none!important}#loading{position:absolute;display:grid;font-family:var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--text-faint);background:var(--bg);pointer-events:none;place-items: center;transition:opacity .6s;font-size:12px;font-weight:500;inset:0}#loading.done{opacity:0}#topbar{position:absolute;display:flex;pointer-events:none;justify-content:space-between;align-items: flex-start;padding:18px 20px;top:0;left:0;right:0}#topbar>*{pointer-events:auto}#identity h1{letter-spacing:.01em;margin:0;font-size:15px;font-weight:600}#identity p{color:var(--text-faint);max-width:340px;margin:4px 0 0;font-size:12px;line-height:1.45}#identity strong{color:var(--text-dim);font-weight:500}.icon-btn{display:grid;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev);color:var(--text-dim);cursor:pointer;touch-action:manipulation;place-items: center;width:36px;height:36px;padding:0;transition:color .15s,border-color .15s}.icon-btn:hover{color:var(--text);border-color:var(--border-strong)}.icon-btn.active{color:var(--error);border-color:var(--border-strong)}#main-btn{background:var(--text);color:var(--bg);cursor:pointer;touch-action:manipulation;border:none;border-radius:23px;min-width:190px;height:46px;padding:0 26px;transition:transform .12s,opacity .15s;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:14px;font-weight:600}#main-btn:hover:not(:disabled){transform:translateY(-1px)}#main-btn:disabled{pointer-events:none;opacity:.45;cursor:default}#main-btn.live{background:var(--bg-elev);color:var(--text);border:1px solid var(--border-strong)}#controls{position:absolute;display:flex;padding:0 20px calc(22px + env(safe-area-inset-bottom));flex-direction:column;align-items: center;gap:14px;bottom:0;left:0;right:0}#buttons{display:flex;align-items: center;gap:10px}#caption{font-family:var(--font-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--text-faint);transition:color .2s;font-size:11px;font-weight:500}#caption.live{color:var(--live)}#caption.error{color:var(--error);text-align:center;max-width:560px;line-height:1.5}#progress{background:var(--border-strong);overflow:hidden;border-radius:1px;width:min(240px,60vw);height:2px}#progress-fill{background:var(--text-dim);width:0;height:100%;transition:width .3s}#subtitles{position:absolute;border-radius:var(--radius-md);backdrop-filter:blur(6px);border:1px solid var(--border);text-align:center;text-wrap:balance;color:var(--text);opacity:0;pointer-events:none;display:-webkit-box;-webkit-line-clamp:3;overflow:hidden;background:#0a0b10b8;-webkit-box-orient:vertical;max-width:min(640px,100vw - 48px);padding:10px 16px;transition:opacity .25s;font-size:15px;line-height:1.5;bottom:118px;left:50%;transform:translate(-50%)}#subtitles.visible{opacity:1}#settings{border:1px solid var(--border-strong);border-radius:var(--radius-md);background:var(--bg-elev);color:var(--text);width:min(440px,100vw - 40px);padding:22px;box-shadow:0 4px 18px #00000052}#settings::backdrop{backdrop-filter:blur(2px);background:#05060999}#settings h2{margin:0 0 16px;font-size:15px;font-weight:600}#settings label{display:block;color:var(--text-dim);margin-bottom:14px;font-size:12px}#settings select,#settings textarea,#settings input{display:block;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev-2);color:var(--text);width:100%;margin-top:6px;padding:9px 11px;font-family:inherit;font-size:13px}#settings select:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings input:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea{resize:vertical}#settings .hint{display:block;margin-top:6px;font-size:11px;line-height:1.4}#settings .check-row{display:flex;align-items: center;gap:9px}#settings .check-row input{display:inline-block;accent-color:var(--text);width:auto;margin:0}.dialog-actions{display:flex;justify-content:space-between;gap:12px;margin-top:6px}#reset-prompt{color:var(--text-dim);cursor:pointer;background:0 0;border:none;padding:9px 0;font-size:13px}#reset-prompt:hover{color:var(--text)}.dialog-actions .primary{border-radius:var(--radius-sm);background:var(--text);color:var(--bg);cursor:pointer;border:none;padding:9px 20px;font-size:13px;font-weight:600}button:focus-visible{outline:2px solid var(--text-dim);outline-offset:2px}#type-form{display:flex;gap:8px;align-items:center;margin:0 0 10px;justify-content:center}#type-input{background:var(--bg-elev);border:1px solid var(--border);border-radius:23px;color:var(--text);font-family:inherit;font-size:14px;padding:0 16px;height:46px;width:min(340px,72vw);outline:none;transition:border-color .15s;touch-action:manipulation}#type-input:focus{border-color:var(--border-strong)}#type-input::placeholder{color:var(--text-faint)}#send-btn{display:grid;place-items:center;background:var(--bg-elev);border:1px solid var(--border);border-radius:23px;color:var(--text-dim);cursor:pointer;touch-action:manipulation;width:46px;height:46px;padding:0;transition:color .15s,border-color .15s}#send-btn:hover{color:var(--text);border-color:var(--border-strong)}#send-btn:focus-visible{outline:2px solid var(--text-dim);outline-offset:2px}
|
| 2 |
+
@media (prefers-reduced-motion:reduce){*{transition-duration:.01ms!important}}@media (max-width:600px){#identity p{display:none}#subtitles{font-size:14px;bottom:128px}}
|
chunk-p1yb2ca4.js
CHANGED
|
@@ -34416,6 +34416,198 @@ function Ji(e, t) {
|
|
| 34416 |
if (e[i] !== void 0) n[i] = e[i]?.clone && !e[i].isTexture ? e[i].clone() : e[i];
|
| 34417 |
return Object.assign(n, t);
|
| 34418 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34419 |
function vp(e, t = {}) {
|
| 34420 |
let { studio: n = !0, materials: i = !0, shadows: s = !0 } = t,
|
| 34421 |
{ renderer: r, scene: o, armature: a } = e,
|
|
@@ -34621,6 +34813,7 @@ varying float vShellX; uniform vec2 lidBlink;`,
|
|
| 34621 |
envMapIntensity: 0.35,
|
| 34622 |
});
|
| 34623 |
}
|
|
|
|
| 34624 |
a.traverse((h) => {
|
| 34625 |
if (!h.isMesh) return;
|
| 34626 |
for (let u of [h.material.map, h.material.normalMap, h.material.roughnessMap])
|
|
@@ -34967,6 +35160,31 @@ class uh extends EventTarget {
|
|
| 34967 |
this._setStatus("processing"),
|
| 34968 |
this.model.respond(t, e));
|
| 34969 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34970 |
onText(e, t) {
|
| 34971 |
let n = this.turn;
|
| 34972 |
if (!n || n.id !== e) return;
|
|
@@ -35282,7 +35500,7 @@ function Ap() {
|
|
| 35282 |
w1(t);
|
| 35283 |
break;
|
| 35284 |
case "ready":
|
| 35285 |
-
if (((Es = !0), Rn?.finished(), Gn)) Vp();
|
| 35286 |
(xr?.configure(t.sampleRate),
|
| 35287 |
Object.assign(rn, { device: t.device, modelSampleRate: t.sampleRate }),
|
| 35288 |
(Sh.hidden = !0),
|
|
@@ -35404,7 +35622,10 @@ async function T1() {
|
|
| 35404 |
l = new uh({
|
| 35405 |
voice: a,
|
| 35406 |
model: {
|
| 35407 |
-
respond: (c, h) =>
|
|
|
|
|
|
|
|
|
|
| 35408 |
abort: (c) => ts.postMessage({ kind: "abort", id: c }),
|
| 35409 |
reset: () => ts.postMessage({ kind: "reset" }),
|
| 35410 |
},
|
|
@@ -35434,6 +35655,9 @@ async function T1() {
|
|
| 35434 |
(yt.endOfReply(), Fp());
|
| 35435 |
}),
|
| 35436 |
l.addEventListener("interrupted", () => Ts.classList.remove("visible")),
|
|
|
|
|
|
|
|
|
|
| 35437 |
l.addEventListener("error", (c) => {
|
| 35438 |
let { error: h } = c.detail;
|
| 35439 |
if ((console.error("generation failed:", h), h.fatal))
|
|
@@ -35444,8 +35668,30 @@ async function T1() {
|
|
| 35444 |
no.classList.remove("active"),
|
| 35445 |
ai("stop", "End conversation"),
|
| 35446 |
Ia("connected"),
|
|
|
|
| 35447 |
yt.setConversationState("connected"));
|
| 35448 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35449 |
async function Wp(e = !1) {
|
| 35450 |
let t = Ht;
|
| 35451 |
if (((Ht = null), t?.close(), yt.setConversationState("idle"), Ts.classList.remove("visible"), !e)) Jt(Pa.idle);
|
|
|
|
| 34416 |
if (e[i] !== void 0) n[i] = e[i]?.clone && !e[i].isTexture ? e[i].clone() : e[i];
|
| 34417 |
return Object.assign(n, t);
|
| 34418 |
}
|
| 34419 |
+
function mq(c) {
|
| 34420 |
+
let i = c.Wolf3D_Outfit_Top;
|
| 34421 |
+
if (!i) return;
|
| 34422 |
+
let h = new URLSearchParams(location.search),
|
| 34423 |
+
y = h.get("neck") ?? "v";
|
| 34424 |
+
if (y === "off") return;
|
| 34425 |
+
if (h.get("collar") === "off" && c.Ava_Collar) c.Ava_Collar.visible = !1;
|
| 34426 |
+
let p = Number(h.get("neckDepth") ?? 0.1),
|
| 34427 |
+
g = Number(h.get("neckW") ?? 0.108),
|
| 34428 |
+
M = Number(h.get("neckTop") ?? 1.5015),
|
| 34429 |
+
F = Number(h.get("neckFront") ?? 0.014),
|
| 34430 |
+
T = y === "u" ? 0 : 1,
|
| 34431 |
+
b = i.geometry.attributes,
|
| 34432 |
+
R = b.position,
|
| 34433 |
+
_ = b.normal,
|
| 34434 |
+
x = b.skinIndex,
|
| 34435 |
+
P = b.skinWeight;
|
| 34436 |
+
if (!R || !_) return;
|
| 34437 |
+
let K = 10,
|
| 34438 |
+
se = (u, v, w2) => {
|
| 34439 |
+
let S = [],
|
| 34440 |
+
px = 0,
|
| 34441 |
+
py = 0,
|
| 34442 |
+
pz = 0,
|
| 34443 |
+
nx = 0,
|
| 34444 |
+
ny = 0,
|
| 34445 |
+
nz = 0,
|
| 34446 |
+
ch = 0;
|
| 34447 |
+
for (let j2 = 0; j2 < R.count; j2++) {
|
| 34448 |
+
let m = {
|
| 34449 |
+
d:
|
| 34450 |
+
(R.array[j2 * 3] - u) ** 2 +
|
| 34451 |
+
(R.array[j2 * 3 + 1] - v) ** 2 +
|
| 34452 |
+
(R.array[j2 * 3 + 2] - w2) ** 2,
|
| 34453 |
+
j: j2,
|
| 34454 |
+
};
|
| 34455 |
+
if (S.length < K) S.push(m);
|
| 34456 |
+
else if (m.d < S[K - 1].d) ((S[K - 1] = m), S.sort((B, D) => B.d - D.d));
|
| 34457 |
+
}
|
| 34458 |
+
for (let m of S) {
|
| 34459 |
+
let j2 = m.j,
|
| 34460 |
+
q = 1 / (m.d + 1e-6);
|
| 34461 |
+
(ch += q),
|
| 34462 |
+
(px += R.array[j2 * 3] * q),
|
| 34463 |
+
(py += R.array[j2 * 3 + 1] * q),
|
| 34464 |
+
(pz += R.array[j2 * 3 + 2] * q),
|
| 34465 |
+
(nx += _.array[j2 * 3] * q),
|
| 34466 |
+
(ny += _.array[j2 * 3 + 1] * q),
|
| 34467 |
+
(nz += _.array[j2 * 3 + 2] * q);
|
| 34468 |
+
}
|
| 34469 |
+
let acc = new Map();
|
| 34470 |
+
if (x && P)
|
| 34471 |
+
for (let m of S) {
|
| 34472 |
+
let j2 = m.j,
|
| 34473 |
+
q = 1 / (m.d + 1e-6);
|
| 34474 |
+
for (let k4 = 0; k4 < 4; k4++) {
|
| 34475 |
+
let bone = x.array[j2 * 4 + k4],
|
| 34476 |
+
bw = P.array[j2 * 4 + k4] * q;
|
| 34477 |
+
acc.set(bone, (acc.get(bone) ?? 0) + bw);
|
| 34478 |
+
}
|
| 34479 |
+
}
|
| 34480 |
+
let bs = [...acc.entries()].sort((B, D) => D[1] - B[1]).slice(0, 4),
|
| 34481 |
+
wsum = bs.reduce((B, D) => B + D[1], 0) || 1;
|
| 34482 |
+
return {
|
| 34483 |
+
p: [px / ch, py / ch, pz / ch],
|
| 34484 |
+
n: [nx / ch, ny / ch, nz / ch],
|
| 34485 |
+
idx: bs.map((B) => B[0]),
|
| 34486 |
+
w: bs.map((B) => B[1] / wsum),
|
| 34487 |
+
};
|
| 34488 |
+
},
|
| 34489 |
+
Q = (u) => (u <= 0.04045 ? u / 12.92 : ((u + 0.055) / 1.055) ** 2.4),
|
| 34490 |
+
tone = null;
|
| 34491 |
+
try {
|
| 34492 |
+
let img = c.Wolf3D_Head?.material?.map?.image;
|
| 34493 |
+
if (img?.width) {
|
| 34494 |
+
let cv = document.createElement("canvas"),
|
| 34495 |
+
cx = cv.getContext("2d", { willReadFrequently: !0 });
|
| 34496 |
+
cv.width = img.width;
|
| 34497 |
+
cv.height = img.height;
|
| 34498 |
+
cx.drawImage(img, 0, 0);
|
| 34499 |
+
let [l0, m0, l1, m1] = $t.lids_uv,
|
| 34500 |
+
px = Math.round(((l0 + l1) / 2) * img.width),
|
| 34501 |
+
py = Math.round(((m0 + m1) / 2) * img.height),
|
| 34502 |
+
dtd = cx.getImageData(Math.max(0, px - 12), Math.max(0, py - 12), 24, 24).data,
|
| 34503 |
+
rr = 0,
|
| 34504 |
+
gg = 0,
|
| 34505 |
+
bb = 0,
|
| 34506 |
+
n5 = dtd.length / 4;
|
| 34507 |
+
for (let k5 = 0; k5 < dtd.length; k5 += 4) (rr += dtd[k5]), (gg += dtd[k5 + 1]), (bb += dtd[k5 + 2]);
|
| 34508 |
+
tone = new re(Q(rr / n5 / 255), Q(gg / n5 / 255), Q(bb / n5 / 255));
|
| 34509 |
+
}
|
| 34510 |
+
} catch {}
|
| 34511 |
+
let sk = tone ?? new re(0.6, 0.34, 0.26);
|
| 34512 |
+
{
|
| 34513 |
+
let ubc = i.material.onBeforeCompile,
|
| 34514 |
+
U1 = { value: new Ye(M, p, g, T) },
|
| 34515 |
+
U2 = { value: new ve(F, 0) };
|
| 34516 |
+
let V3 = (sh, cxA) => {
|
| 34517 |
+
ubc?.(sh, cxA);
|
| 34518 |
+
Object.assign(sh.uniforms, { uNeck: U1, uNeckF: U2 });
|
| 34519 |
+
sh.vertexShader = sh.vertexShader
|
| 34520 |
+
.replace("#include <common>", `#include <common>
|
| 34521 |
+
varying vec3 vBindN;`)
|
| 34522 |
+
.replace("#include <begin_vertex>", `#include <begin_vertex>
|
| 34523 |
+
vBindN = position;`);
|
| 34524 |
+
sh.fragmentShader = sh.fragmentShader
|
| 34525 |
+
.replace("#include <common>", `#include <common>
|
| 34526 |
+
varying vec3 vBindN; uniform vec4 uNeck; uniform vec2 uNeckF;`)
|
| 34527 |
+
.replace(
|
| 34528 |
+
"#include <clipping_planes_fragment>",
|
| 34529 |
+
`#include <clipping_planes_fragment>
|
| 34530 |
+
{
|
| 34531 |
+
float rel = abs(vBindN.x) / uNeck.z;
|
| 34532 |
+
if (vBindN.z > uNeckF.x && vBindN.y > uNeck.x - uNeck.y - 0.012 && vBindN.y < uNeck.x + 0.001) {
|
| 34533 |
+
if (uNeck.w > 0.5) { if ((uNeck.x - vBindN.y) > uNeck.y * rel) discard; }
|
| 34534 |
+
else { if ((uNeck.x - vBindN.y) > uNeck.y * sqrt(max(0.0, 1.0 - rel * rel))) discard; }
|
| 34535 |
+
}
|
| 34536 |
+
}`,
|
| 34537 |
+
);
|
| 34538 |
+
};
|
| 34539 |
+
((i.material.onBeforeCompile = V3),
|
| 34540 |
+
(i.material.customProgramCacheKey = () => `ava-neck-cut-${i.material.uuid}`),
|
| 34541 |
+
(i.material.needsUpdate = !0));
|
| 34542 |
+
}
|
| 34543 |
+
let GX = 40,
|
| 34544 |
+
GY = 16,
|
| 34545 |
+
padX = 0.02,
|
| 34546 |
+
padY = 0.012,
|
| 34547 |
+
yUp = M + 0.0025,
|
| 34548 |
+
yBot = M - p - padY,
|
| 34549 |
+
gW = g + padX,
|
| 34550 |
+
pos = [],
|
| 34551 |
+
nor = [],
|
| 34552 |
+
js = [],
|
| 34553 |
+
ws = [],
|
| 34554 |
+
vm = [],
|
| 34555 |
+
insideM =
|
| 34556 |
+
y === "u"
|
| 34557 |
+
? (xx, yy) => yy < M + 0.0025 - 1e-4 && yy > M - p * Math.max(0, 1 - (xx / g) ** 2) ** 0.5 - padY && Math.abs(xx) < gW
|
| 34558 |
+
: (xx, yy) => yy < M + 0.0025 - 1e-4 && yy > yBot && (M - yy) > (p * Math.abs(xx)) / g && Math.abs(xx) < gW;
|
| 34559 |
+
for (let gy = 0; gy < GY; gy++) {
|
| 34560 |
+
let vv = yUp - ((yUp - yBot) * gy) / (GY - 1);
|
| 34561 |
+
for (let gx = 0; gx < GX; gx++) {
|
| 34562 |
+
let uu = (-gW + (2 * gW * gx) / (GX - 1)),
|
| 34563 |
+
sm = se(uu, vv, 0),
|
| 34564 |
+
nx2 = sm.n,
|
| 34565 |
+
nn = (nx2[0] ** 2 + nx2[1] ** 2 + nx2[2] ** 2) ** 0.5 || 1;
|
| 34566 |
+
(pos.push(sm.p[0] - (nx2[0] / nn) * 0.0035, sm.p[1] - (nx2[1] / nn) * 0.0035, sm.p[2] - (nx2[2] / nn) * 0.0035),
|
| 34567 |
+
nor.push(nx2[0] / nn, nx2[1] / nn, nx2[2] / nn));
|
| 34568 |
+
for (let k6 = 0; k6 < 4; k6++) (js.push(sm.idx[k6] ?? 0), ws.push(sm.w[k6] ?? 0));
|
| 34569 |
+
vm.push(insideM(uu, vv) ? 1 : 0);
|
| 34570 |
+
}
|
| 34571 |
+
}
|
| 34572 |
+
let geo = new Et();
|
| 34573 |
+
(geo.setAttribute("position", new at(pos, 3)),
|
| 34574 |
+
geo.setAttribute("normal", new at(nor, 3)),
|
| 34575 |
+
x && P && (geo.setAttribute("skinIndex", new er(js, 4)), geo.setAttribute("skinWeight", new at(ws, 4))));
|
| 34576 |
+
let idx = [];
|
| 34577 |
+
for (let gy = 0; gy < GY - 1; gy++)
|
| 34578 |
+
for (let gx = 0; gx < GX - 1; gx++) {
|
| 34579 |
+
let a1 = gy * GX + gx,
|
| 34580 |
+
q1 = a1 + 1,
|
| 34581 |
+
v1 = a1 + GX,
|
| 34582 |
+
y1 = v1 + 1;
|
| 34583 |
+
if (vm[a1] && vm[q1] && vm[v1] && vm[y1]) idx.push(a1, v1, q1, q1, v1, y1);
|
| 34584 |
+
}
|
| 34585 |
+
geo.setIndex(idx);
|
| 34586 |
+
let mat = new tn({
|
| 34587 |
+
side: Yt,
|
| 34588 |
+
color: sk,
|
| 34589 |
+
roughness: 0.48,
|
| 34590 |
+
metalness: 0,
|
| 34591 |
+
specularIntensity: 0.4,
|
| 34592 |
+
sheen: 0.4,
|
| 34593 |
+
sheenColor: new re(1, 0.96, 0.92),
|
| 34594 |
+
sheenRoughness: 0.7,
|
| 34595 |
+
clearcoat: 0.05,
|
| 34596 |
+
clearcoatRoughness: 0.35,
|
| 34597 |
+
}),
|
| 34598 |
+
mk = new Bi(geo, mat);
|
| 34599 |
+
(t1(mat),
|
| 34600 |
+
mk.bind(i.skeleton, i.bindMatrix),
|
| 34601 |
+
mk.position.copy(i.position),
|
| 34602 |
+
mk.quaternion.copy(i.quaternion),
|
| 34603 |
+
mk.scale.copy(i.scale),
|
| 34604 |
+
mk.updateMatrix(),
|
| 34605 |
+
(mk.castShadow = !1),
|
| 34606 |
+
(mk.receiveShadow = !0),
|
| 34607 |
+
(mk.frustumCulled = !1),
|
| 34608 |
+
mk.matrixAutoUpdate && mk.updateMatrixWorld(!0),
|
| 34609 |
+
i.parent.add(mk));
|
| 34610 |
+
}
|
| 34611 |
function vp(e, t = {}) {
|
| 34612 |
let { studio: n = !0, materials: i = !0, shadows: s = !0 } = t,
|
| 34613 |
{ renderer: r, scene: o, armature: a } = e,
|
|
|
|
| 34813 |
envMapIntensity: 0.35,
|
| 34814 |
});
|
| 34815 |
}
|
| 34816 |
+
mq(c);
|
| 34817 |
a.traverse((h) => {
|
| 34818 |
if (!h.isMesh) return;
|
| 34819 |
for (let u of [h.material.map, h.material.normalMap, h.material.roughnessMap])
|
|
|
|
| 35160 |
this._setStatus("processing"),
|
| 35161 |
this.model.respond(t, e));
|
| 35162 |
}
|
| 35163 |
+
sendText(e) {
|
| 35164 |
+
if (!this._closed && (e = (e ?? "").trim())) {
|
| 35165 |
+
if (this.turn) this._interrupt();
|
| 35166 |
+
(this.voice.beginTurn(),
|
| 35167 |
+
(this.turn = {
|
| 35168 |
+
id: this.nextTurnId++,
|
| 35169 |
+
finished: !1,
|
| 35170 |
+
reply: "",
|
| 35171 |
+
metric: {
|
| 35172 |
+
id: this.nextTurnId - 1,
|
| 35173 |
+
userSeconds: null,
|
| 35174 |
+
speechEndedAt: performance.now(),
|
| 35175 |
+
firstTextMs: null,
|
| 35176 |
+
firstAudioMs: null,
|
| 35177 |
+
replySeconds: 0,
|
| 35178 |
+
reply: "",
|
| 35179 |
+
tools: [],
|
| 35180 |
+
outcome: "streaming",
|
| 35181 |
+
},
|
| 35182 |
+
}),
|
| 35183 |
+
this.metrics.push(this.turn.metric),
|
| 35184 |
+
this.model.respond(this.turn.id, null, e),
|
| 35185 |
+
this.dispatchEvent(new CustomEvent("user-text", { detail: { text: e } })));
|
| 35186 |
+
}
|
| 35187 |
+
}
|
| 35188 |
onText(e, t) {
|
| 35189 |
let n = this.turn;
|
| 35190 |
if (!n || n.id !== e) return;
|
|
|
|
| 35500 |
w1(t);
|
| 35501 |
break;
|
| 35502 |
case "ready":
|
| 35503 |
+
if (((Es = !0), Aq(), Rn?.finished(), Gn)) Vp();
|
| 35504 |
(xr?.configure(t.sampleRate),
|
| 35505 |
Object.assign(rn, { device: t.device, modelSampleRate: t.sampleRate }),
|
| 35506 |
(Sh.hidden = !0),
|
|
|
|
| 35622 |
l = new uh({
|
| 35623 |
voice: a,
|
| 35624 |
model: {
|
| 35625 |
+
respond: (c, h, w) =>
|
| 35626 |
+
h != null
|
| 35627 |
+
? ts.postMessage({ kind: "respond", id: c, audio: h }, [h.buffer])
|
| 35628 |
+
: ts.postMessage({ kind: "respond", id: c, text: w }),
|
| 35629 |
abort: (c) => ts.postMessage({ kind: "abort", id: c }),
|
| 35630 |
reset: () => ts.postMessage({ kind: "reset" }),
|
| 35631 |
},
|
|
|
|
| 35655 |
(yt.endOfReply(), Fp());
|
| 35656 |
}),
|
| 35657 |
l.addEventListener("interrupted", () => Ts.classList.remove("visible")),
|
| 35658 |
+
l.addEventListener("user-text", (c) => {
|
| 35659 |
+
if (Ln.subtitles) (Np(`Tú: ${c.detail.text}`), Fp(3200));
|
| 35660 |
+
}),
|
| 35661 |
l.addEventListener("error", (c) => {
|
| 35662 |
let { error: h } = c.detail;
|
| 35663 |
if ((console.error("generation failed:", h), h.fatal))
|
|
|
|
| 35668 |
no.classList.remove("active"),
|
| 35669 |
ai("stop", "End conversation"),
|
| 35670 |
Ia("connected"),
|
| 35671 |
+
Aq(),
|
| 35672 |
yt.setConversationState("connected"));
|
| 35673 |
}
|
| 35674 |
+
function Aq() {
|
| 35675 |
+
if (Es && Ht && typedPending) {
|
| 35676 |
+
let e = typedPending;
|
| 35677 |
+
((typedPending = null), Ht.sendText(e));
|
| 35678 |
+
}
|
| 35679 |
+
}
|
| 35680 |
+
var typedPending = null,
|
| 35681 |
+
typedFormEl = on("#type-form"),
|
| 35682 |
+
typedInputEl = on("#type-input");
|
| 35683 |
+
typedFormEl?.addEventListener("submit", (e) => {
|
| 35684 |
+
e.preventDefault();
|
| 35685 |
+
let t = (typedInputEl.value ?? "").trim();
|
| 35686 |
+
if (!t) return;
|
| 35687 |
+
if (!Es) return Jt(vh(ws));
|
| 35688 |
+
if (Ht) {
|
| 35689 |
+
if (Ht.status === "closed") return;
|
| 35690 |
+
(Ht.sendText(t), (typedInputEl.value = ""));
|
| 35691 |
+
} else if (xh !== "busy") {
|
| 35692 |
+
((typedPending = t), T1());
|
| 35693 |
+
} else typedPending = t;
|
| 35694 |
+
});
|
| 35695 |
async function Wp(e = !1) {
|
| 35696 |
let t = Ht;
|
| 35697 |
if (((Ht = null), t?.close(), yt.setConversationState("idle"), Ts.classList.remove("visible"), !e)) Jt(Pa.idle);
|
index.html
CHANGED
|
@@ -57,6 +57,15 @@
|
|
| 57 |
<footer id="controls">
|
| 58 |
<div id="progress" hidden><div id="progress-fill"></div></div>
|
| 59 |
<div id="caption">LOADING…</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
<div id="buttons">
|
| 61 |
<button id="main-btn" disabled>
|
| 62 |
<span id="main-btn-label">Loading…</span>
|
|
|
|
| 57 |
<footer id="controls">
|
| 58 |
<div id="progress" hidden><div id="progress-fill"></div></div>
|
| 59 |
<div id="caption">LOADING…</div>
|
| 60 |
+
<form id="type-form" autocomplete="off">
|
| 61 |
+
<input id="type-input" type="text" enterkeyhint="send" maxlength="2000" placeholder="O escríbele aquí…" />
|
| 62 |
+
<button id="send-btn" type="submit" aria-label="Enviar mensaje" title="Enviar">
|
| 63 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
| 64 |
+
<line x1="22" y1="2" x2="11" y2="13"></line>
|
| 65 |
+
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
| 66 |
+
</svg>
|
| 67 |
+
</button>
|
| 68 |
+
</form>
|
| 69 |
<div id="buttons">
|
| 70 |
<button id="main-btn" disabled>
|
| 71 |
<span id="main-btn-label">Loading…</span>
|
workers/model-worker.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
| 7 |
* main -> worker:
|
| 8 |
* { kind: "load", model, system }
|
| 9 |
* { kind: "respond", id, audio } a user turn, 16 kHz Float32
|
|
|
|
| 10 |
* { kind: "abort", id } barge-in: stop generating this turn
|
| 11 |
* { kind: "system", system } new persona / instructions
|
| 12 |
* { kind: "reset" } forget the conversation
|
|
@@ -121,8 +122,12 @@ async function load({ model: modelId, system: sys }) {
|
|
| 121 |
post({ kind: "failed", name: lastErr?.name ?? "Error", message: lastErr?.message ?? String(lastErr) });
|
| 122 |
}
|
| 123 |
|
| 124 |
-
/** One user turn. */
|
| 125 |
-
async function respond({ id, audio }) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
const controller = new AbortController();
|
| 127 |
running.set(id, controller);
|
| 128 |
const { signal } = controller;
|
|
@@ -137,7 +142,7 @@ async function respond({ id, audio }) {
|
|
| 137 |
try {
|
| 138 |
await prior;
|
| 139 |
signal.throwIfAborted();
|
| 140 |
-
history.push({ role: "user", content: [{ type: "audio", audio }] });
|
| 141 |
|
| 142 |
for (;;) {
|
| 143 |
const stream = session.generate(messages(), { generation_mode: "interleaved", signal });
|
|
|
|
| 7 |
* main -> worker:
|
| 8 |
* { kind: "load", model, system }
|
| 9 |
* { kind: "respond", id, audio } a user turn, 16 kHz Float32
|
| 10 |
+
* { kind: "respond", id, text } a user turn typed in the chat box
|
| 11 |
* { kind: "abort", id } barge-in: stop generating this turn
|
| 12 |
* { kind: "system", system } new persona / instructions
|
| 13 |
* { kind: "reset" } forget the conversation
|
|
|
|
| 122 |
post({ kind: "failed", name: lastErr?.name ?? "Error", message: lastErr?.message ?? String(lastErr) });
|
| 123 |
}
|
| 124 |
|
| 125 |
+
/** One user turn: spoken (audio) or typed (text). */
|
| 126 |
+
async function respond({ id, audio, text }) {
|
| 127 |
+
if (!audio && !text) {
|
| 128 |
+
post({ kind: "finished", id, reason: "noop" });
|
| 129 |
+
return;
|
| 130 |
+
}
|
| 131 |
const controller = new AbortController();
|
| 132 |
running.set(id, controller);
|
| 133 |
const { signal } = controller;
|
|
|
|
| 142 |
try {
|
| 143 |
await prior;
|
| 144 |
signal.throwIfAborted();
|
| 145 |
+
history.push(audio ? { role: "user", content: [{ type: "audio", audio }] } : { role: "user", content: text });
|
| 146 |
|
| 147 |
for (;;) {
|
| 148 |
const stream = session.generate(messages(), { generation_mode: "interleaved", signal });
|