primocode 10.16.0 → 10.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/LICENSES/edit-ia-pro.txt +32 -0
  2. package/LICENSES/fontes-OFL.txt +476 -0
  3. package/LICENSES/hyperframes-Apache-2.0.txt +205 -0
  4. package/LICENSES/permanent-marker-Apache-2.0.txt +204 -0
  5. package/LICENSES/selfie-multiclass-Apache-2.0.txt +227 -0
  6. package/LICENSES/three-MIT.txt +23 -0
  7. package/LICENSES/video-use-MIT.txt +24 -0
  8. package/LICENSES/woven-sfx-CC0.txt +16 -0
  9. package/LICENSES/yunet-MIT.txt +21 -0
  10. package/README.md +2 -2
  11. package/bin/primocode.js +11 -2
  12. package/editor/LICENSE.md +11 -0
  13. package/editor/README.md +321 -0
  14. package/editor/SKILL.md +307 -0
  15. package/editor/THIRD_PARTY_NOTICES.md +228 -0
  16. package/editor/assets/baixar.json +591 -0
  17. package/editor/assets/fonts/anton/OFL.txt +93 -0
  18. package/editor/assets/fonts/caveat/OFL.txt +93 -0
  19. package/editor/assets/fonts/figtree/OFL.txt +93 -0
  20. package/editor/assets/fonts/fonts.json +10 -0
  21. package/editor/assets/fonts/montserrat/OFL.txt +93 -0
  22. package/editor/assets/fonts/permanentmarker/LICENSE.txt +202 -0
  23. package/editor/assets/models/SELFIE_MULTICLASS_LICENSE.txt +227 -0
  24. package/editor/assets/models/YUNET_LICENSE.txt +21 -0
  25. package/editor/assets/sfx/licencas/bass_drop.txt +32 -0
  26. package/editor/assets/sfx/licencas/cash.txt +76 -0
  27. package/editor/assets/sfx/licencas/charge.txt +31 -0
  28. package/editor/assets/sfx/licencas/click.txt +46 -0
  29. package/editor/assets/sfx/licencas/coin.txt +50 -0
  30. package/editor/assets/sfx/licencas/count.txt +47 -0
  31. package/editor/assets/sfx/licencas/data.txt +31 -0
  32. package/editor/assets/sfx/licencas/error.txt +32 -0
  33. package/editor/assets/sfx/licencas/flash.txt +31 -0
  34. package/editor/assets/sfx/licencas/gears.txt +82 -0
  35. package/editor/assets/sfx/licencas/keyboard.txt +48 -0
  36. package/editor/assets/sfx/licencas/metal_hit.txt +62 -0
  37. package/editor/assets/sfx/licencas/metal_riser.txt +61 -0
  38. package/editor/assets/sfx/licencas/mouse_click.txt +50 -0
  39. package/editor/assets/sfx/licencas/notification.txt +54 -0
  40. package/editor/assets/sfx/licencas/pop.txt +38 -0
  41. package/editor/assets/sfx/licencas/rewind.txt +32 -0
  42. package/editor/assets/sfx/licencas/rise.txt +46 -0
  43. package/editor/assets/sfx/licencas/sinteticos.txt +21 -0
  44. package/editor/assets/sfx/licencas/snap.txt +50 -0
  45. package/editor/assets/sfx/licencas/success.txt +40 -0
  46. package/editor/assets/sfx/licencas/synth_hit.txt +32 -0
  47. package/editor/assets/sfx/licencas/tick.txt +14 -0
  48. package/editor/assets/sfx/licencas/whoosh.txt +47 -0
  49. package/editor/assets/sfx/licencas/wind.txt +31 -0
  50. package/editor/assets/sfx/sfx.json +832 -0
  51. package/editor/assets/sfx/sfx_sinteticos.json +317 -0
  52. package/editor/assets/sfx/sfx_woven.json +387 -0
  53. package/editor/assets/sfx/woven/LICENCA.md +16 -0
  54. package/editor/fichas/briefing-do-video.md +45 -0
  55. package/editor/fichas/conferencia-da-amostra.md +56 -0
  56. package/editor/fichas/matriz-de-ganchos.csv +3 -0
  57. package/editor/fichas/padrao.json +16 -0
  58. package/editor/fichas/planilha-de-cenas.csv +4 -0
  59. package/editor/fichas/planilha-de-versoes.csv +4 -0
  60. package/editor/fichas/plano-em-blocos.md +32 -0
  61. package/editor/fichas/registro-de-materiais.json +27 -0
  62. package/editor/helpers/assets_ocr/ocr_vision.swift +41 -0
  63. package/editor/helpers/bordas_precisas.py +272 -0
  64. package/editor/helpers/camera_viva.py +426 -0
  65. package/editor/helpers/captions.py +601 -0
  66. package/editor/helpers/common.py +308 -0
  67. package/editor/helpers/compose_final.py +3555 -0
  68. package/editor/helpers/conferir_corte.py +234 -0
  69. package/editor/helpers/conferir_dados.py +405 -0
  70. package/editor/helpers/contact_sheet.py +282 -0
  71. package/editor/helpers/corte_por_onda.py +433 -0
  72. package/editor/helpers/corte_seco.py +595 -0
  73. package/editor/helpers/denoise.py +971 -0
  74. package/editor/helpers/efeitos.py +408 -0
  75. package/editor/helpers/efeitos_gerar.py +159 -0
  76. package/editor/helpers/elevenlabs_api.py +442 -0
  77. package/editor/helpers/face_layout.py +570 -0
  78. package/editor/helpers/fetch_images.py +423 -0
  79. package/editor/helpers/ganho_por_trecho.py +214 -0
  80. package/editor/helpers/gen_image.py +312 -0
  81. package/editor/helpers/gen_music.py +316 -0
  82. package/editor/helpers/gen_sfx.py +148 -0
  83. package/editor/helpers/grade.py +307 -0
  84. package/editor/helpers/icloud.py +119 -0
  85. package/editor/helpers/make_sfx.py +940 -0
  86. package/editor/helpers/matte.py +1342 -0
  87. package/editor/helpers/medir_referencia.py +2232 -0
  88. package/editor/helpers/mixar_trilha.py +354 -0
  89. package/editor/helpers/montar_corte.py +295 -0
  90. package/editor/helpers/motion/__init__.py +13 -0
  91. package/editor/helpers/motion/engine.py +1915 -0
  92. package/editor/helpers/motion/registry.py +510 -0
  93. package/editor/helpers/motion/render.py +665 -0
  94. package/editor/helpers/motion/templates/barra_progresso.py +370 -0
  95. package/editor/helpers/motion/templates/carimbo.py +132 -0
  96. package/editor/helpers/motion/templates/checklist.py +271 -0
  97. package/editor/helpers/motion/templates/comentario_cta.py +380 -0
  98. package/editor/helpers/motion/templates/contador.py +222 -0
  99. package/editor/helpers/motion/templates/destaque.py +263 -0
  100. package/editor/helpers/motion/templates/etiqueta_preco.py +461 -0
  101. package/editor/helpers/motion/templates/grafico_barras.py +510 -0
  102. package/editor/helpers/motion/templates/grafico_linha.py +462 -0
  103. package/editor/helpers/motion/templates/notificacao.py +266 -0
  104. package/editor/helpers/motion/templates/palavra_impacto.py +410 -0
  105. package/editor/helpers/motion/templates/passos.py +321 -0
  106. package/editor/helpers/motion/templates/riscado.py +298 -0
  107. package/editor/helpers/motion/templates/selo_garantia.py +150 -0
  108. package/editor/helpers/motion_render.py +241 -0
  109. package/editor/helpers/motion_sugerir.py +961 -0
  110. package/editor/helpers/noise_check.py +134 -0
  111. package/editor/helpers/pack_transcripts.py +223 -0
  112. package/editor/helpers/palavras_na_onda.py +176 -0
  113. package/editor/helpers/plano_sfx.py +839 -0
  114. package/editor/helpers/portao.py +427 -0
  115. package/editor/helpers/preview_server.py +1177 -0
  116. package/editor/helpers/rastrear_rosto.py +298 -0
  117. package/editor/helpers/render_cut.py +1256 -0
  118. package/editor/helpers/respiros.py +89 -0
  119. package/editor/helpers/sincronizar_cameras.py +571 -0
  120. package/editor/helpers/speech_regions.py +423 -0
  121. package/editor/helpers/style_catalog.json +231 -0
  122. package/editor/helpers/style_samples.py +246 -0
  123. package/editor/helpers/tela_verde.py +2113 -0
  124. package/editor/helpers/text_render.py +2059 -0
  125. package/editor/helpers/texto_na_tela.py +366 -0
  126. package/editor/helpers/timeline_view.py +292 -0
  127. package/editor/helpers/tira_de_quadros.py +113 -0
  128. package/editor/helpers/transcribe.py +734 -0
  129. package/editor/helpers/transcribe_batch.py +129 -0
  130. package/editor/helpers/trilhas.py +1146 -0
  131. package/editor/helpers/trilhas_humores.json +66 -0
  132. package/editor/helpers/valores.py +187 -0
  133. package/editor/helpers/verify_cut.py +820 -0
  134. package/editor/helpers/voice_levels.py +233 -0
  135. package/editor/helpers/voz_check.py +386 -0
  136. package/editor/helpers/voz_limpa.py +81 -0
  137. package/editor/helpers/watch_preview.py +372 -0
  138. package/editor/modelo-projeto/LEIA.md +402 -0
  139. package/editor/modelo-projeto/assets/fontes/OFL-Caveat.txt +93 -0
  140. package/editor/modelo-projeto/assets/fontes/OFL-JetBrainsMono.txt +93 -0
  141. package/editor/modelo-projeto/assets/fontes/OFL-Montserrat.txt +93 -0
  142. package/editor/modelo-projeto/assets/fontes/larguras.json +1 -0
  143. package/editor/modelo-projeto/assets/three/BufferGeometryUtils.js +1438 -0
  144. package/editor/modelo-projeto/assets/three/GLTFLoader.js +4895 -0
  145. package/editor/modelo-projeto/assets/three/LICENSE +21 -0
  146. package/editor/modelo-projeto/assets/three/ORIGEM.txt +17 -0
  147. package/editor/modelo-projeto/assets/three/RoomEnvironment.js +185 -0
  148. package/editor/modelo-projeto/assets/three/three.core.min.js +6 -0
  149. package/editor/modelo-projeto/assets/three/three.module.min.js +6 -0
  150. package/editor/modelo-projeto/build.py +4828 -0
  151. package/editor/modelo-projeto/compositions/cenas/2d/k2d_antes_depois.html +199 -0
  152. package/editor/modelo-projeto/compositions/cenas/2d/k2d_arquivo.html +232 -0
  153. package/editor/modelo-projeto/compositions/cenas/2d/k2d_busca.html +315 -0
  154. package/editor/modelo-projeto/compositions/cenas/2d/k2d_comando.html +304 -0
  155. package/editor/modelo-projeto/compositions/cenas/2d/k2d_conversa.html +217 -0
  156. package/editor/modelo-projeto/compositions/cenas/2d/k2d_esquema.html +289 -0
  157. package/editor/modelo-projeto/compositions/cenas/2d/k2d_medidor.html +249 -0
  158. package/editor/modelo-projeto/compositions/cenas/2d/k2d_notas.html +233 -0
  159. package/editor/modelo-projeto/compositions/cenas/3d/k3d_caminho.html +197 -0
  160. package/editor/modelo-projeto/compositions/cenas/3d/k3d_explodida.html +152 -0
  161. package/editor/modelo-projeto/compositions/cenas/3d/k3d_tela.html +167 -0
  162. package/editor/modelo-projeto/compositions/cenas/3d/k3d_volume.html +124 -0
  163. package/editor/modelo-projeto/compositions/cenas/3d/motor-three.js +728 -0
  164. package/editor/modelo-projeto/compositions/cenas/LEIA.md +177 -0
  165. package/editor/modelo-projeto/ferramentas/medir_fontes.py +65 -0
  166. package/editor/modelo-projeto/ferramentas/pessoa_recortada.py +176 -0
  167. package/editor/modelo-projeto/ferramentas/rastrear_maos.py +189 -0
  168. package/editor/modelo-projeto/hyperframes.json +12 -0
  169. package/editor/modelo-projeto/package.json +11 -0
  170. package/editor/modelo-projeto/projeto.json +16 -0
  171. package/editor/preview/app.css +1009 -0
  172. package/editor/preview/app.js +2122 -0
  173. package/editor/preview/index.html +307 -0
  174. package/editor/pyproject.toml +23 -0
  175. package/editor/references/3d.md +236 -0
  176. package/editor/references/animacao-catalogo.md +672 -0
  177. package/editor/references/animacao.md +498 -0
  178. package/editor/references/comandos.md +92 -0
  179. package/editor/references/corte-seco-como-funciona.md +50 -0
  180. package/editor/references/corte-seco.md +88 -0
  181. package/editor/references/corte.md +290 -0
  182. package/editor/references/direcao-por-blocos.md +218 -0
  183. package/editor/references/enquadramento.md +654 -0
  184. package/editor/references/estilos-prontos.md +355 -0
  185. package/editor/references/estudio.md +100 -0
  186. package/editor/references/exemplo-eventos.json +67 -0
  187. package/editor/references/lettering.md +252 -0
  188. package/editor/references/modelos.md +494 -0
  189. package/editor/references/phase2.md +1007 -0
  190. package/editor/references/referencia-aplicar.md +203 -0
  191. package/editor/references/referencia-medir.md +375 -0
  192. package/editor/references/revisao.md +335 -0
  193. package/editor/references/som-e-trilha.md +146 -0
  194. package/editor/references/tabela-de-sons.md +130 -0
  195. package/editor/references/variacoes.md +234 -0
  196. package/editor/uv.lock +1141 -0
  197. package/lib/act.js +36 -8
  198. package/lib/catalogo.js +4 -0
  199. package/lib/chamada-torta.js +81 -0
  200. package/lib/editor-pro.js +786 -0
  201. package/lib/entrega.js +58 -0
  202. package/lib/estudio/conferencia-visual.js +76 -0
  203. package/lib/estudio/diretor.js +6 -1
  204. package/lib/estudio/exportar.js +3 -1
  205. package/lib/estudio/gosto.js +45 -4
  206. package/lib/estudio/index.js +8 -5
  207. package/lib/estudio/kit-ae/base.jsx +119 -13
  208. package/lib/estudio/kit-ae/cenas.jsx +47 -15
  209. package/lib/estudio/kit-ae/guarda.jsx +274 -0
  210. package/lib/estudio/kit-ae/primitivas.jsx +180 -24
  211. package/lib/estudio/maquina-diretor.js +61 -7
  212. package/lib/estudio/maquina-foto.js +177 -0
  213. package/lib/estudio/maquina-guarda.js +207 -0
  214. package/lib/estudio/maquina-layout.js +22 -1
  215. package/lib/estudio/maquina.js +60 -11
  216. package/lib/estudio/referencias.js +1 -1
  217. package/lib/estudio/visao/visao.swift +97 -0
  218. package/lib/estudio/visao.js +60 -0
  219. package/lib/local/cerebro.json +192 -6
  220. package/lib/local/motor.js +5 -2
  221. package/lib/nuvem.js +11 -1
  222. package/lib/passagem.js +50 -0
  223. package/lib/perigo.js +19 -11
  224. package/lib/protecao.js +134 -0
  225. package/lib/titulo-conversa.js +46 -0
  226. package/lib/tools.js +3 -0
  227. package/lib/ui.js +1 -1
  228. package/package.json +3 -2
  229. package/skills/editar-meu-video/SKILL.md +6 -2
  230. package/skills/editar-video/SKILL.md +113 -0
  231. package/studio/pessoa.py +52 -0
  232. package/voz/primo_voz/app.py +43 -4
  233. package/voz/primo_voz/chat.html +17 -6
  234. package/voz/primo_voz/painel_dados.py +134 -0
@@ -121,6 +121,7 @@ a{color:#67e8f9}a:hover{color:#22d3ee}
121
121
  .enviar.vazio .i-voz{opacity:1;transform:none}
122
122
  .enviar.cheio .i-seta{opacity:1;transform:none}
123
123
  .enviar.parar .i-stop{opacity:1;transform:none}
124
+ .enviar.semvoz{visibility:hidden;pointer-events:none}
124
125
  /* mascote e título */
125
126
  .mascote{transition:transform .35s cubic-bezier(.3,1.5,.5,1);filter:drop-shadow(0 0 26px rgba(34,211,238,.35))}
126
127
  .pula-entra{animation:cai .9s cubic-bezier(.3,1.6,.5,1) both}
@@ -464,6 +465,7 @@ function extDe(nome){var m=/\.([A-Za-z0-9]+)$/.exec(nome||'');return m?m[1].toLo
464
465
  var EXT_TIPO={};
465
466
  [['video','mp4 mov m4v webm mkv avi'],['imagem','png jpg jpeg gif webp svg avif heic bmp'],['audio','mp3 wav m4a aac ogg flac'],['pdf','pdf'],['html','html htm'],['codigo','js jsx ts tsx mjs cjs json py sh bash zsh css scss md txt yml yaml toml rb go rs java c h cpp swift kt php sql xml vue lock csv']].forEach(function(p){p[1].split(' ').forEach(function(e){EXT_TIPO[e]=p[0];});});
466
467
  function tipoDe(nome){return EXT_TIPO[extDe(nome)]||'arquivo';}
468
+ function urlArq(c){return estado.arqBase?estado.arqBase+String(c).split('/').map(encodeURIComponent).join('/'):'file://'+encodeURI(c);}
467
469
  function fmtTam(b){
468
470
  b=Number(b);if(!isFinite(b)||b<0)return '';
469
471
  if(b<1024)return b+' B';
@@ -664,7 +666,8 @@ var estado={
664
666
  esperando:false,ignorando:false,passos:[],erro:'',
665
667
  anexos:[],menu:false,aviso:null,
666
668
  skills:null,ajustes:null,busca:'',
667
- comandos:[],pal:{aberta:false,itens:[],sel:0,q:null},abertas:{},confirma:null,provSel:'',chaveDraft:'',chaveSalva:false
669
+ comandos:[],pal:{aberta:false,itens:[],sel:0,q:null},abertas:{},confirma:null,provSel:'',chaveDraft:'',chaveSalva:false,
670
+ semVoz:false,arqBase:'' /* o app desktop manda semVoz (sem motor de voz) e arqBase (o protocolo que serve os arquivos); no Mac ficam vazios */
668
671
  };
669
672
  var animar=false;
670
673
  var mx=0,my=0;
@@ -838,9 +841,10 @@ function htmlSkills(anim){
838
841
  /* ajustes */
839
842
  function tg(a,on,rot,extra){return '<button class="tg'+(on?' on':'')+'" data-a="'+a+'" aria-label="'+esc(rot)+'"'+(extra||'')+'></button>';}
840
843
  function htmlConfig(anim){
841
- var abas=ABAS.map(function(a){
844
+ var abas=ABAS.filter(function(a){return !(estado.semVoz&&a.id==='voz');}).map(function(a){
842
845
  return '<button class="lado-cfg'+(estado.aba===a.id?' on':'')+'" data-a="aba" data-id="'+a.id+'"><span class="tile" style="background:'+a.cor+'">'+ic(a.ico,14,2.2)+'</span>'+a.t+'</button>';
843
846
  }).join('');
847
+ if(estado.semVoz&&estado.aba==='voz')estado.aba='modelos';
844
848
  var corpo={geral:cfgGeral,modelos:cfgModelos,voz:cfgVoz,conta:cfgConta}[estado.aba]();
845
849
  return '<div class="'+(anim?'tela-entra':'')+'" style="width:100%;max-width:860px;align-self:center;margin-bottom:auto;display:flex;flex-wrap:wrap;gap:32px">'+
846
850
  '<nav style="flex:1 1 170px;max-width:210px;display:flex;flex-direction:column;gap:2px"><h2 style="margin:0 0 14px 8px;font-family:\'Instrument Serif\',serif;font-weight:400;font-size:34px">Ajustes</h2>'+abas+'</nav>'+
@@ -1157,13 +1161,14 @@ function renderAvisos(){
1157
1161
  var a=estado.aviso,el=$('avisos');
1158
1162
  if(!a){el.innerHTML='';return;}
1159
1163
  if(a.tipo==='login')el.innerHTML='<div class="cartao-av"><span>Entre na sua conta do PrimoCode pra conversar.</span><span style="display:flex;align-items:center;gap:6px"><button class="entrar" data-a="entrar">Entrar</button><button class="x" data-a="fechaAviso" aria-label="Fechar">'+ic(ICO.x,12,2.4)+'</button></span></div>';
1164
+ else if(a.tipo==='voz')el.innerHTML='<div class="cartao-av"><span style="min-width:0;overflow-wrap:anywhere">'+esc(a.texto)+'</span><span style="display:flex;align-items:center;gap:6px">'+(a.instalar?'<button class="entrar" data-a="vozInstalar">Instalar a voz</button>':'')+(a.instalando?'':'<button class="x" data-a="fechaAviso" aria-label="Fechar">'+ic(ICO.x,12,2.4)+'</button>')+'</span></div>';
1160
1165
  else if(a.tipo==='sair')el.innerHTML='<div class="cartao-av"><span>Sair da conta?</span><span style="display:flex;align-items:center;gap:6px"><button class="mc-b" data-a="fechaAviso">Cancelar</button><button class="entrar" style="background:#b8473d" data-a="sairConfirma">Sair</button></span></div>';
1161
1166
  else el.innerHTML='<div class="cartao-av erro"><span style="min-width:0;overflow-wrap:anywhere">'+esc(a.texto)+'</span><button class="x" data-a="fechaAviso" aria-label="Fechar">'+ic(ICO.x,12,2.4)+'</button></div>';
1162
1167
  }
1163
1168
  function atualizaBotao(){
1164
1169
  var b=$('enviar'),vazio=!ta().value.trim()&&!estado.anexos.length;
1165
1170
  if(estado.esperando){b.className='enviar parar';b.setAttribute('aria-label','Parar');}
1166
- else if(vazio){b.className='enviar vazio';b.setAttribute('aria-label','Abrir a voz do Primo');}
1171
+ else if(vazio){b.className='enviar vazio'+(estado.semVoz?' semvoz':'');b.setAttribute('aria-label','Abrir a voz do Primo');}
1167
1172
  else{b.className='enviar cheio';b.setAttribute('aria-label','Enviar');}
1168
1173
  }
1169
1174
  function cresce(){var t=ta();t.style.height='auto';t.style.height=Math.min(t.scrollHeight,160)+'px';}
@@ -1302,7 +1307,7 @@ function appCmd(c,args){
1302
1307
  var u=ultimaResposta();
1303
1308
  if(u){copiarTexto(u,{textContent:'Copiar'});toast('Copiado');}else toast('Nada pra copiar');
1304
1309
  break;
1305
- case 'voz':post({acao:'voz'});break;
1310
+ case 'voz':if(!estado.semVoz)post({acao:'voz'});break;
1306
1311
  case 'voz_nome':
1307
1312
  estado.aba='voz';post({acao:'ajustes'});
1308
1313
  if(args){post({acao:'ajuste',chave:'voz_nome',valor:String(args)});if(estado.ajustes&&estado.ajustes.voz)estado.ajustes.voz.nome=String(args);}
@@ -1337,7 +1342,7 @@ function enviar(pular){
1337
1342
  if(!estado.logado){estado.aviso={tipo:'login'};renderAvisos();return;}
1338
1343
  var nomes=estado.anexos.map(function(a){return a.nome;});
1339
1344
  var texto=t||('Anexei '+nomes.join(', '));
1340
- var midias=estado.anexos.map(function(a){return {achado:'',caminho:a.caminho,nome:a.nome,tipo:tipoDe(a.nome),url:'file://'+encodeURI(a.caminho)};});
1345
+ var midias=estado.anexos.map(function(a){return {achado:'',caminho:a.caminho,nome:a.nome,tipo:tipoDe(a.nome),url:urlArq(a.caminho)};});
1341
1346
  estado.mensagens.push({papel:'voce',texto:texto,midias:midias});
1342
1347
  estado.tela='chat';estado.aviso=null;estado.erro='';estado.esperando=true;estado.ignorando=false;estado.passos=[];estado.menu=false;
1343
1348
  post({acao:'enviar',texto:texto,conversa:estado.convId==null?null:estado.convId,modo:estado.modo,anexos:estado.anexos.map(function(a){return a.caminho;})});
@@ -1346,7 +1351,7 @@ function enviar(pular){
1346
1351
  }
1347
1352
  function apertar(){
1348
1353
  if(estado.esperando){post({acao:'parar'});estado.esperando=false;estado.passos=[];renderEspera();atualizaBotao();return;}
1349
- if(!ta().value.trim()&&!estado.anexos.length){post({acao:'voz'});return;}
1354
+ if(!ta().value.trim()&&!estado.anexos.length){if(!estado.semVoz)post({acao:'voz'});return;}
1350
1355
  enviar();
1351
1356
  }
1352
1357
  function setModo(v){
@@ -1448,6 +1453,7 @@ document.addEventListener('click',function(e){
1448
1453
  case 'entrar':post({acao:'entrar'});break;
1449
1454
  case 'sair':post({acao:'sair_conta'});break;
1450
1455
  case 'fechaAviso':estado.aviso=null;renderAvisos();break;
1456
+ case 'vozInstalar':estado.aviso={tipo:'voz',texto:'Preparando a voz…',instalando:true};renderAvisos();post({acao:'voz_instalar'});break;
1451
1457
  case 'link':e.preventDefault();post({acao:'abrir_link',url:d.url});break;
1452
1458
  case 'skill':
1453
1459
  var k=estado.skills&&estado.skills[+d.i];
@@ -1598,6 +1604,7 @@ var tratar={
1598
1604
  sincConta(v);
1599
1605
  if(v.pasta!=null)estado.pasta=v.pasta;
1600
1606
  if(v.modo==='chat'||v.modo==='agent')estado.modo=v.modo;
1607
+ estado.semVoz=!!v.semVoz;estado.arqBase=String(v.arqBase||'');atualizaBotao();
1601
1608
  renderConta();renderMenu();renderAvisos();
1602
1609
  if(estado.tela==='config')renderPrincipal();
1603
1610
  if(estado.logado)pedirConversas();
@@ -1655,6 +1662,10 @@ var tratar={
1655
1662
  else{estado.aviso={tipo:'erro',texto:txt};renderAvisos();}
1656
1663
  }else{estado.aviso={tipo:'erro',texto:txt};renderAvisos();}
1657
1664
  },
1665
+ vozAviso:function(v){ /* o app desktop: a voz não está instalada, está instalando ou terminou */
1666
+ if(!v)return;
1667
+ estado.aviso={tipo:'voz',texto:String(v.texto||''),instalar:!!v.instalar,instalando:!!v.instalando};renderAvisos();
1668
+ },
1658
1669
  anexo:function(v){
1659
1670
  if(!v||!v.caminho)return;
1660
1671
  if(estado.anexos.some(function(a){return a.caminho===v.caminho;}))return;
@@ -0,0 +1,134 @@
1
+ """painel_dados.py — os dados do painel (música, calendário, clima, máquina) como um processo à parte.
2
+
3
+ No Mac, quem alimenta o hud.html é o processo da janela (hud.py: as threads `medir()` e `agenda()`). O app desktop (Electron)
4
+ não tem esse processo, então este ajudante roda os MESMOS laços e escreve cada mensagem como uma linha de JSON no stdout:
5
+ o mesmo objeto que o `js(...)` do hud.py manda pra tela (`{"musica":...}`, `{"calendario":...}`, `{"hoje":...}`, `{"clima":...}`,
6
+ `{"maquina":...}`). O app repassa cada linha pra `window.primo(msg)`. O hud.py não muda.
7
+
8
+ sai (stdout): uma mensagem do painel por linha (e, ao iniciar, {"nome":..} e {"robo":..} da identidade)
9
+ entra (stdin): ações da tela, uma por linha: {"acao":"midia","arg":"proxima"}, {"acao":"calendario"},
10
+ {"acao":"volume",...}, {"acao":"app",...}, {"acao":"boot"} (toca o som de abertura)
11
+ fecha o stdin: o ajudante encerra.
12
+ Rode com: python -m primo_voz.painel_dados
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import sys
18
+ import threading
19
+ import time
20
+
21
+ from primo_voz import identidade, tela as td
22
+ from primo_voz import painel as pn
23
+ from primo_voz.sons import Sons
24
+
25
+ # Ações da janela (o app cuida delas): o ajudante ignora.
26
+ DA_JANELA = {"erro", "sair", "chat", "ptt", "entrar", "print"}
27
+
28
+
29
+ def main(entrada=None, saida=None, td_=None, pn_=None, sons=None, passo: float = 1.0) -> int:
30
+ """entrada/saida/td_/pn_/sons/passo: o teste troca por falsos e acelera os laços. `passo` = segundos do laço da máquina (o resto é múltiplo dele)."""
31
+ td_ = td_ or td
32
+ pn_ = pn_ or pn
33
+ entrada = sys.stdin if entrada is None else entrada
34
+ escrever = saida or sys.stdout
35
+ trava = threading.Lock()
36
+ parar = threading.Event()
37
+ sons = sons if sons is not None else Sons(True)
38
+
39
+ def js(msg: dict) -> None:
40
+ with trava:
41
+ try:
42
+ escrever.write(json.dumps(msg, ensure_ascii=False) + "\n")
43
+ escrever.flush()
44
+ except Exception:
45
+ parar.set() # o app fechou o cano: acabou
46
+
47
+ def espera(s: float) -> None:
48
+ parar.wait(s)
49
+
50
+ def medir() -> None:
51
+ am = pn_.Amostrador()
52
+ cache: dict = {}
53
+ k = 0
54
+ while not parar.is_set():
55
+ try:
56
+ js({"maquina": td_.maquina(am)})
57
+ js({"musica": td_.musica()})
58
+ if k % 20 == 0:
59
+ js({"clima": td_.clima_widget(cache)})
60
+ except Exception as e:
61
+ sys.stderr.write(f"painel_dados: {e}\n")
62
+ k += 1
63
+ espera(passo)
64
+
65
+ def agenda() -> None: # em outra thread: o pedido de permissão do Calendário pode demorar
66
+ evs: dict = {"permissao": "pendente", "eventos": []}
67
+ k = 0
68
+ falhas = 0
69
+ while not parar.is_set():
70
+ try:
71
+ if k % 12 == 0 or evs["permissao"] != "ok": # sem acesso, olha a cada 5 s (a pessoa pode ter liberado)
72
+ novo = td_.eventos_do_mes()
73
+ if evs["permissao"] == "ok" and novo["permissao"] != "ok":
74
+ falhas += 1 # erro transitório não derruba o cartão: segura os últimos eventos
75
+ if falhas >= 4:
76
+ evs, falhas = novo, 0
77
+ else:
78
+ evs, falhas = novo, 0
79
+ # SEMPRE manda o estado junto: o painel nunca depende de uma mensagem que pode ter chegado antes da página
80
+ js({"calendario": {"permissao": evs["permissao"], "dias": sorted({e["dia"] for e in evs["eventos"]})}})
81
+ if evs["permissao"] == "ok":
82
+ js({"hoje": td_.hoje_lista(evs["eventos"], time.time())})
83
+ except Exception as e:
84
+ sys.stderr.write(f"painel_dados agenda: {e}\n")
85
+ k += 1
86
+ espera(5 * passo)
87
+
88
+ def acao(m: dict) -> None:
89
+ try:
90
+ _acao(m)
91
+ except Exception as e: # uma ação que estoura não derruba o ajudante
92
+ sys.stderr.write(f"painel_dados: ação {m.get('acao')}: {e}\n")
93
+
94
+ def _acao(m: dict) -> None:
95
+ a = m.get("acao")
96
+ if a in DA_JANELA:
97
+ return
98
+ if a == "boot":
99
+ sons.tocar("boot")
100
+ elif td_.acao(m):
101
+ pass
102
+ else:
103
+ pn_.executar_acao(m)
104
+ if a == "midia":
105
+ espera(0.4 * passo)
106
+ js({"musica": td_.musica()})
107
+
108
+ try:
109
+ ident = identidade.ler()
110
+ js({"nome": ident["nome"]})
111
+ js({"robo": ident["robo"]})
112
+ except Exception as e:
113
+ sys.stderr.write(f"painel_dados: identidade: {e}\n")
114
+ threading.Thread(target=medir, daemon=True).start()
115
+ threading.Thread(target=agenda, daemon=True).start()
116
+ for linha in entrada: # stdin fechado = o app saiu ou voltou pro chat
117
+ if parar.is_set():
118
+ break
119
+ try:
120
+ m = json.loads(linha)
121
+ except ValueError:
122
+ continue
123
+ if not isinstance(m, dict):
124
+ continue
125
+ try:
126
+ threading.Thread(target=acao, args=(m,), daemon=True).start() # ação lenta (osascript) não trava o laço de leitura
127
+ except Exception as e:
128
+ sys.stderr.write(f"painel_dados: ação {m.get('acao')}: {e}\n")
129
+ parar.set()
130
+ return 0
131
+
132
+
133
+ if __name__ == "__main__":
134
+ sys.exit(main())