feat: initial commit - Carinha Control Panel v1.0 com UI glassmorphism, watch-bar, emojis, braco robotico e conversa IA
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""Inferencia MediaPipe real, com modelos locais e imagens oficiais de teste."""
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
ROOT=Path(__file__).resolve().parents[1]
|
||||
FIXTURES=ROOT.parents[1]/'work/tracking-fixtures'
|
||||
sys.path.insert(0,str(ROOT))
|
||||
spec=importlib.util.spec_from_file_location('kiosk_tracking',ROOT/'kiosk-server.py')
|
||||
kiosk=importlib.util.module_from_spec(spec);spec.loader.exec_module(kiosk)
|
||||
|
||||
class Handler(kiosk.Handler):
|
||||
def do_GET(self):
|
||||
if self.path in ('/test-portrait','/test-hands'):
|
||||
name='portrait.jpg' if self.path=='/test-portrait' else 'right_hands.jpg'
|
||||
return self.enviar((FIXTURES/name).read_bytes(),'image/jpeg')
|
||||
super().do_GET()
|
||||
|
||||
def main():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
server=kiosk.Servidor(('127.0.0.1',0),Handler)
|
||||
server.controle=kiosk.ControlePC(Path(tmp)/'config.json')
|
||||
thread=threading.Thread(target=server.serve_forever,daemon=True);thread.start()
|
||||
base='http://127.0.0.1:'+str(server.server_port)
|
||||
try:
|
||||
with sync_playwright() as p:
|
||||
browser=p.chromium.launch(headless=True)
|
||||
page=browser.new_page();errors=[];external=[]
|
||||
page.on('pageerror',lambda e: errors.append(str(e)))
|
||||
page.on('console',lambda m: print('WORKER',m.text[:180]) if m.type=='error' else None)
|
||||
def route(r):
|
||||
if not r.request.url.startswith(base): external.append(r.request.url);r.abort()
|
||||
else:r.continue_()
|
||||
page.route('**/*',route)
|
||||
page.goto(base+'/painel')
|
||||
results=page.evaluate("""async () => {
|
||||
const worker=new Worker('/rastreador-worker.js');
|
||||
const send=msg=>new Promise((resolve,reject)=>{
|
||||
worker.onmessage=({data})=>data.tipo==='erro'?reject(Error(data.erro)):resolve(data);
|
||||
worker.onerror=e=>reject(Error(e.message));
|
||||
worker.postMessage(msg,msg.bitmap?[msg.bitmap]:[]);
|
||||
});
|
||||
const config={rosto:true,maos:true};
|
||||
await send({config});
|
||||
const a=await createImageBitmap(await (await fetch('/test-portrait')).blob());
|
||||
const face=await send({config,bitmap:a,timestamp:1000});
|
||||
const b=await createImageBitmap(await (await fetch('/test-hands')).blob());
|
||||
const hand=await send({config,bitmap:b,timestamp:2000});
|
||||
worker.terminate();return {face,hand};
|
||||
}""")
|
||||
assert results['face']['faces'], 'Rosto da imagem oficial nao detectado'
|
||||
assert results['hand']['hands'], 'Maos da imagem oficial nao detectadas'
|
||||
assert len(results['hand']['hands'][0])==21
|
||||
print('Inferencia real: %s rosto(s), %s mao(s); %.1f/%.1f ms' % (
|
||||
len(results['face']['faces']),len(results['hand']['hands']),results['face']['ms'],results['hand']['ms']))
|
||||
# Feed the same real worker into the panel, using a local canvas stream.
|
||||
page.request.post(base+'/app/config',data={'preview':True})
|
||||
page.request.post(base+'/app/status',data={'rosto':'carinha','dormindo':False})
|
||||
page.evaluate("""async () => {
|
||||
const image=await createImageBitmap(await (await fetch('/test-hands')).blob());
|
||||
const c=document.createElement('canvas');c.width=640;c.height=Math.round(640*image.height/image.width);
|
||||
const ctx=c.getContext('2d');ctx.drawImage(image,0,0,c.width,c.height);image.close();
|
||||
window.testStream=c.captureStream(30);
|
||||
window.testDraw=setInterval(()=>ctx.drawImage(c,0,0),33);
|
||||
const v=document.getElementById('cameraVideo');v.srcObject=testStream;v.hidden=false;await v.play();
|
||||
window.testTargets=[];
|
||||
window.CarinhaVideo={rastrear(t){testTargets.push(t)},parar(){},atualizar(){}};
|
||||
window.CarinhaRastreamento.atualizar({online:true,estado:{}}, {preview:true,sensorCamera:true,
|
||||
rastrearRosto:true,rastrearMaos:true,mostrarRastreamento:true,seguirRastreamento:true});
|
||||
}""")
|
||||
page.wait_for_function("window.CarinhaRastreamento.estado().result?.hands.length > 0",timeout=15000)
|
||||
assert page.locator('#trackingOverlay').is_visible()
|
||||
assert page.evaluate("testTargets.some(t=>t?.tipo==='mao')")
|
||||
work=ROOT.parents[1]/'work';page.screenshot(path=str(work/'rastreamento-teste.png'),full_page=True)
|
||||
page.locator('#ajuste-mostrarRastreamento').uncheck()
|
||||
page.wait_for_function("document.getElementById('trackingOverlay').hidden",timeout=5000)
|
||||
page.locator('#ajuste-seguirRastreamento').uncheck()
|
||||
page.wait_for_timeout(1200)
|
||||
assert page.evaluate('testTargets[testTargets.length-1] === null')
|
||||
page.evaluate("CarinhaRastreamento.atualizar({online:true,estado:{dormindo:true}},{preview:true,sensorCamera:true,cameraSono:false,rastrearRosto:true,rastrearMaos:true})")
|
||||
assert not page.evaluate('CarinhaRastreamento.estado().active')
|
||||
assert not external,external
|
||||
assert not errors,errors
|
||||
browser.close()
|
||||
print('Overlay, alvo, controles, sono e inferencia sem acesso externo: OK')
|
||||
finally:
|
||||
server.shutdown();server.server_close();thread.join()
|
||||
|
||||
if __name__=='__main__':main()
|
||||
Reference in New Issue
Block a user