https://d226lax1qjow5r.cloudfront.net/blog/blogposts/next-web-voice-journal-python-vue-javascript-dr/p2p-voice-journal-featured.png

Creación de un diario de voz para la próxima web

Publicado el May 13, 2021

Tiempo de lectura: 6 minutos

La World Wide Web es algo maravilloso. Podemos crear y compartir información más fácilmente que nunca en la historia de la humanidad.

Escribiendo un tutorial para @NexmoDev a 35.000 pies sobre el Atlántico #devrellife pic.twitter.com/mvxGDuEDky

- Aaron Bassett - ¿Qué zona horaria es? (@aaronbassett) 15 de mayo de 2018

Sin embargo, gran parte de lo que creamos vive dentro de jardines amurallados; esto es la antítesis de la idea original de la www. Derribar estos jardines amurallados es algo de lo que Tim Berners Lee lleva hablando al menos desde 2009.

De hecho, los datos están sobre nuestras vidas. Simplemente... entras en tu red social, tu favorita, dices: "Este es mi amigo" ¡Bing! Relación. Datos. Dices, "Esta fotografía, es sobre... representa a esta persona." ¡Bing! Eso son datos. Datos, datos, datos. Cada vez que haces cosas en la red social, la red social está cogiendo datos y usándolos - reutilizándolos - y usándolos para hacer la vida de otras personas más interesante en el sitio. Pero, cuando vas a otro sitio de datos enlazados -- y digamos que este es uno sobre viajes, y dices: "Quiero enviar esta foto a todas las personas de ese grupo", no puedes traspasar los muros.

- Sir Tim Berners-Lee

De hecho, la descentralización ha sido un aspecto fundamental de la www desde su creación.

Descentralización: No se necesita permiso de una autoridad central para publicar nada en la red, no hay un nodo central de control y, por tanto, no hay un único punto de fallo... ¡ni un "interruptor de apagado"! Esto también implica libertad frente a la censura y la vigilancia indiscriminadas.

- Web Foundation, Historia de la Web

Presentación de la web de persona a persona

Voice Journal ScreenshotVoice Journal Screenshot

Con la web de persona a persona, no se necesita servidor. Cada visitante de su sitio se convierte en un compañero del enjambre. Se conectan directamente entre sí y comparten los archivos de su sitio. Esto no sólo ayuda a mantener su sitio en línea, sino que también crea libertad frente a la censura indiscriminada.

Veamos cómo podemos utilizar el protocolo protocolo Dat con Voice API de Nexmo para crear un sitio web distribuido para alojar un diario de audio. Puedes descargar el código de este ejemplo en Github.

Flujo del proceso

El flujo del proceso para nuestra aplicación es sencillo. Cuando llamamos a nuestro Número Virtual Nexmo, graba el audio como un MP3, notifica a nuestro servidor que hay una nueva grabación. Entonces, cuando nuestro servidor recibe la notificación de Nexmo, descarga el archivo MP3 y lo añade a nuestro archivo, y se comparte automáticamente con todos los compañeros que utilizan el protocolo Dat.

Objeto de control de llamadas Nexmo y la acción de grabación

Grabar el audio es excepcionalmente sencilla con Nexmo. Creamos un archivo archivo NCCO con una sola record acción. Es posible que también desee utilizar la funcionalidad TTS para reproducir un mensaje antes de la grabación; yo he optado por no hacerlo y, en su lugar, ordeno a Nexmo que reproduzca un pitido cuando esté listo para grabar. Muy parecido a un contestador automático.

@hug.get('/')
def ncco():
    return [
        {
            "action": "record",
            "eventUrl": ["<SERVER URL>/recordings"],
            "endOnKey": "*",
            "beepStart": True
        }
    ]

En el código anterior estoy usando Hug para crear un endpoint JSON para servir mi archivo NCCO a la API de Nexmo. Para obtener más información sobre la creación de aplicaciones de voz con Nexmo (y para más detalles sobre lo que es un archivo NCCO), por favor lea algunos de mis tutoriales anteriores:

También explico más sobre Nexmo Voice Applications en mis webinars de codificación en directo; dura unos 20 minutos:

Guardar la grabación

Una vez finalizada la llamada, o cuando el usuario haya pulsado ""* Nexmo nos avisa de la nueva grabación a través del webhook que especificamos eventUrl en el código anterior. La petición a nuestro webhook contiene el recording_url que podemos utilizar para descargar el archivo MP3. Sin embargo, primero tenemos que autenticarnos con Nexmo para asegurarnos de que tenemos permiso para descargar la grabación. Utilizamos JWTs para la autenticación.

@hug.post('/recordings')
def recordings(recording_url, recording_uuid):
    iat = int(time.time())
    now = datetime.datetime.now()

    with open('nexmo_private.key', 'rb') as key_file:
        private_key = key_file.read()

    payload = {
        'application_id': os.environ['APPLICATION_ID'],
        'iat': iat,
        'exp': iat + 60,
        'jti': str(uuid.uuid4()),
    }

    token = jwt.encode(payload, private_key, algorithm='RS256')

    recording_response = requests.get(
        recording_url,
        headers={
            'Authorization': b'Bearer ' + token,
            'User-Agent': 'voice-journal'
        }
    )
    if recording_response.status_code == 200:
        recordingfile = f'./site/recordings/{now.year}/{now.month}/{recording_uuid}.mp3'
        os.makedirs(os.path.dirname(recordingfile), exist_ok=True)

        with open(recordingfile, 'wb') as f:
            f.write(recording_response.content)

La mayor parte del código anterior es para la autenticación JWT [*Sí, alguien realmente debería hacer eso más fácil de hacer en el cliente Python... ?]. Después de descargar la grabación, guardamos el archivo MP3, asegurándonos de mantener nuestro archivo bonito y organizado.

/recordings/<current year>/<current month>/<recording uuid>.mp3

Al estructurar nuestras grabaciones de esta forma en el disco, incluso sin nuestro frontend de aplicaciones, podemos encontrar y escuchar fácilmente una grabación de un día concreto.

Distribuir nuestras grabaciones

Existen dos formas principales de distribuir nuestro sitio a través de Dat; mediante la CLI de Dato a través del Navegador Beaker. Para simplificar, vamos a utilizar Beaker en este ejemplo. Sin embargo, si desea ejecutar su webhook en un servidor, o como una función sin servidor, a continuación, utilice el Dat CLI. Tara Vancil tiene un gran artículo sobre cómo Dat CLI para publicar actualizaciones en su blog (versión dat). Una cosa a tener en cuenta es que nuestro frontend de aplicaciones utiliza algunas APIs específicas de Beaker para interactuar con nuestro archivo y mostrar información sobre el enjambre; a diferencia del sitio de Tara, no funciona en un navegador normal, por lo que no necesita dathttpd.

Si aún no lo has hecho, deberías descargar Beaker ahora.

Únete a mi Enjambre

Nota: Al igual que BitTorrent y otros protocolos P2P, los miembros de un enjambre pueden ver necesariamente las direcciones IP de otros miembros. Recuerda que esto es distribución peer-to-peer, no pasa por un servicio centralizado. Puede saltarse la siguiente sección si no se siente cómodo compartiendo su dirección IP con otros participantes del enjambre.

Abra el siguiente dat:// enlace en Beaker: dat://8354c381e6f859e57ef6979af7e287acf3d528d8463f54774c36b6bc8aa514d6/

Enhorabuena, ahora eres miembro de mi enjambre y puedes distribuir las grabaciones de audio a otros visitantes. Eres (uno de) mis servidores web, ¡gracias!

Sin embargo, cuando cierras el navegador, abandonas el enjambre. Los archivos permanecen en tu ordenador, pero ya no los distribuyes a otros visitantes. Para garantizar que siempre haya al menos un compañero disponible, he añadido el archivo a #_hashbase.

La interfaz de la aplicación

No necesitas crear una interfaz de usuario para acceder a tus grabaciones. Beaker crea una interfaz sencilla para que la utilicemos si nuestro directorio de archivo no contiene un fichero índice. Es funcional, pero no muy bonita. Podemos hacerlo mejor.

Directory listing rendered by Beaker BrowserDirectory listing rendered by Beaker Browser

Nuestro frontend es una aplicación Vueque utiliza el sistema de diseño Volta de Vonage. Volta es el mismo sistema de diseño que que utilizamos en el reciente rediseño de Nexmo Dashboard. Desafortunadamente, Volta no es de código abierto, al menos no todavía.

También utilizamos algunas API específicas de Beaker para interactuar con nuestro archivo.

const archive = new DatArchive(window.location)
let allRecordings = await archive.readdir('/recordings', {recursive: true, stat: true})

En el código anterior interrogamos a nuestro archivo, leyendo el contenido de nuestro directorio de grabaciones y filtrando cualquier archivo que no sea MP3. La opción stat indica a Beaker que ejecute stat() en cada entrada y regrese con {name:, stat:}.

Otra parte destacable de la página son los cuadros de información de la parte superior.

Screenshot of swarm information UIScreenshot of swarm information UI

Utilizamos otra API de Beaker para recuperar esta información, getInfo()

async peers () {
    return await this.archiveInfo.peers
},
async version () {
    return await this.archiveInfo.version
},
async mtime () {
    let timestamp = await this.archiveInfo.mtime
    return moment(timestamp).startOf().fromNow()
},
async filesize () {
    let size = await this.archiveInfo.size
    return filesize(size, {round: 2})
}

Historia del Archivo

El protocolo Dat garantiza que el archivo está firmado por el autor y que puede comprobarse su exactitud consultando a los pares de la red (uniformidad de distribución). Sólo puede distribuirse una versión del historial del archivo. Si se detecta que un archivo Dat firmado difiere de la copia firmada de un par, se considera corrupto, ya que el contenido diferente podría indicar un ataque dirigido por el autor del Dat. Es importante que todos los usuarios reciban el mismo contenido, y por eso Dat incorpora la verificación de integridad.

- Beaker Browser, publicar software de forma segura

History log screenshotHistory log screenshot

Mediante las API Web de Beaker, podemos consultar y mostrar este registro de cambios en nuestro archivo; este registro muestra incluso si el autor ha eliminado alguna entrada del diario.

archiveHistory: {
    async get () {
    const archive = new DatArchive(window.location)
    const completeHistory = archive.history({start: 0, reverse: true})
    return completeHistory
    }
},

Más información

Compartir:

https://a.storyblok.com/f/270183/150x150/a3d03a85fd/placeholder.svg
Aaron BassettAntiguos alumnos de Vonage

Aaron era un defensor de los desarrolladores en Nexmo. Ingeniero de software experimentado y aspirante a artista digital, Aaron suele crear cosas con código o electrónica; a veces ambas cosas. Cuando está trabajando en algo nuevo, suele percibir el olor a componentes quemados en el aire.