Pedido do usuário: "adiciona upload de áudio pro prompt do IVR" — até aqui o prompt era só texto livre (na prática, sempre um tom padrão, nunca voz de verdade). `POST /ivr-menus/:id/prompt` (multipart via @fastify/multipart — primeiro upload de arquivo binário desta API) só aceita WAV (cabeçalho RIFF/WAVE validado antes de gravar; esta implantação do FreeSWITCH não tem mod_shout, então MP3 nunca funcionaria de qualquer forma). Gravado num bind mount NOVO (./data/ivr-prompts no host ↔ /ivr-prompts no container freeswitch) — mesma convenção já usada 3x neste projeto pra arquivo que o FreeSWITCH precisa enxergar de verdade (gateways externos, filas do callcenter, spool de gravação), mas na direção contrária: apps/api (host) escreve o que o usuário sobe, o FreeSWITCH lê ao vivo durante play_and_get_digits. Um fetch em rede (S3/HTTP) durante uma chamada ativa foi descartado de propósito — latência/confiabilidade desnecessárias pra um prompt de poucos segundos. GET /ivr-menus/:id/prompt (autenticado) serve o preview — mesmo princípio do player de gravações, nunca uma URL direta pro storage. Achado real corrigido antes de commitar: minha primeira versão do delete de menu deixava o .wav órfão no disco — agora deletar o menu ou trocar/remover o prompt sempre limpa o arquivo, confirmado com um teste real de upload+delete. Tela "Telefonia > IVR" ganhou upload/troca/remoção de áudio por menu + player de preview. Testado ponta a ponta com um WAV real de 44.1kHz/mono (não o formato "nativo" de telefonia, de propósito, pra confirmar que funciona com o que uma pessoa qualquer gravaria): softphone externo discou o DID, play_and_get_digits abriu e tocou o arquivo até o fim duas vezes (mod_sndfile resample automático, sem erro no log), colheu o dígito real e bridged corretamente com o ramal de destino. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
44 lines
1.2 KiB
JSON
44 lines
1.2 KiB
JSON
{
|
|
"name": "@b2bcall/api",
|
|
"version": "0.0.1",
|
|
"private": true,
|
|
"scripts": {
|
|
"dev": "tsc -p tsconfig.json && tsx dist/main.js",
|
|
"build": "tsc -p tsconfig.json",
|
|
"start": "tsx dist/main.js",
|
|
"typecheck": "tsc --noEmit"
|
|
},
|
|
"dependencies": {
|
|
"@b2bcall/ai": "workspace:*",
|
|
"@b2bcall/auth": "workspace:*",
|
|
"@b2bcall/billing": "workspace:*",
|
|
"@b2bcall/database": "workspace:*",
|
|
"@b2bcall/entitlements": "workspace:*",
|
|
"@b2bcall/shared": "workspace:*",
|
|
"@b2bcall/storage": "workspace:*",
|
|
"@b2bcall/telephony": "workspace:*",
|
|
"@fastify/cors": "11.3.0",
|
|
"@fastify/helmet": "13.1.1",
|
|
"@fastify/multipart": "^10.1.1",
|
|
"@fastify/rate-limit": "11.2.0",
|
|
"@nestjs/common": "^12.0.1",
|
|
"@nestjs/core": "^12.0.1",
|
|
"@nestjs/platform-fastify": "^12.0.1",
|
|
"@nestjs/platform-socket.io": "12.0.1",
|
|
"@nestjs/websockets": "12.0.1",
|
|
"class-transformer": "^0.5.1",
|
|
"class-validator": "^0.15.1",
|
|
"fast-xml-parser": "5.11.1",
|
|
"fastify": "5.12.1",
|
|
"ioredis": "^6.0.0",
|
|
"reflect-metadata": "^0.2.2",
|
|
"rxjs": "^7.8.2",
|
|
"socket.io": "4.8.3"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^22.0.0",
|
|
"tsx": "^4.23.12",
|
|
"typescript": "^5.7.0"
|
|
}
|
|
}
|