Una función de fotos que sale demasiado cara
Un equipo añade a su aplicación «pregunta sobre tu foto». En una semana la factura es alta, una persona ciega no puede usarla y alguien pregunta por qué se guardó una cara tres meses.
Las imágenes, las páginas y el sonido cuestan más que el texto, pueden dejar gente fuera y pueden contener datos personales. Planifica las tres cosas.
Al final de esta lección
Nota
Puedo poner precio a un día de imágenes, páginas y sonidos y marcar las entradas que piden cuidado.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Texto alternativo | palabras que sustituyen a una imagen para quien no puede verla |
| Transcripción | las palabras de un sonido, escritas |
| Datos personales | datos que pueden identificar a una persona, como una cara o una voz |
| Retención | cuánto tiempo se guardan los datos |
| Presupuesto | lo máximo que piensas gastar |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Imágenes, páginas y sonido se cobran por tamaño
El texto se cobra por tokens (mira el módulo anterior sobre coste y trazado). Una imagen se cobra por sus mosaicos, una página por sus páginas y un sonido por sus segundos.
En esta lección toda petición cuesta 1. Una imagen suma 20 y 10 por mosaico, cada página suma 5 y el sonido suma 2 por cada 10 segundos. Son unidades inventadas. Lee siempre una lista de precios real.
Poner precio a cuatro entradas
| Entrada | Tamaño | Cuenta | Coste |
|---|---|---|---|
| Imagen | 6 mosaicos | 1 + 20 + 60 | 81 |
| Página | 4 páginas | 1 + 20 | 21 |
| Audio | 25 segundos | 1 + 2 x 3 | 7 |
| Audio | 10 segundos | 1 + 2 x 1 | 3 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Acceso: ¿a quién deja fuera la función?
Una persona que no puede ver una imagen necesita texto alternativo. Una que no puede oír un sonido necesita una transcripción. Si una función no da ninguno de los dos, deja fuera a esas personas.
Un modelo suele poder escribir ambos. Pero una persona debe comprobarlos, como mostró la lección anterior. Planifica que las palabras existan antes de guardar una imagen o un sonido.
Un error frecuente
Advertencia
Mucha gente cree que una cara o una voz solo son datos personales si se nombra a la persona. Una cara o una voz pueden identificar a alguien aunque no haya un nombre al lado. Trata ambas como datos personales y no las guardes más de lo necesario.
Escribe el ayudante del modelo, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Los tokens de una respuesta, o null si no trae ninguno.' 'function count(data, name) {' ' return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el ayudante del modelo, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"estado \" + res.status);' ' const d = await res.json();' ' return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' ' } catch (error) {' ' console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' ' return { text: sample, inTokens: null, outTokens: null, recorded: true };' ' }' '}' 'module.exports = { ask };' >> model.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el script de precios, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const items = [' ' { id: 1, kind: \"image\", tiles: 6, alt: true, face: false, voice: false, days: 7 },' ' { id: 2, kind: \"image\", tiles: 16, alt: false, face: true, voice: false, days: 90 },' ' { id: 3, kind: \"page\", pages: 4, alt: true, face: false, voice: false, days: 30 },' ' { id: 4, kind: \"audio\", seconds: 25, alt: false, face: false, voice: true, days: 31 },' '];' > cost6.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el script de precios, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function price(it) {' ' if (it.kind === \"image\") return 1 + 20 + 10 * it.tiles;' ' if (it.kind === \"page\") return 1 + 5 * it.pages;' ' if (it.kind === \"audio\") return 1 + 2 * Math.ceil(it.seconds / 10);' ' return 1;' '}' >> cost6.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el script de precios, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function flags(it) {' ' const out = [];' ' if (it.face) out.push(\"cara\");' ' if (it.voice) out.push(\"voz\");' ' if (it.alt === false && it.kind === \"image\") out.push(\"sin texto alternativo\");' ' if (it.alt === false && it.kind === \"audio\") out.push(\"sin transcripción\");' ' if (it.days > 30) out.push(\"guardada demasiado\");' ' return out;' '}' >> cost6.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el script de precios, parte 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' let total = 0;' ' for (const it of items) {' ' total += price(it);' ' console.log(it.id + \" \" + it.kind + \": coste \" + price(it) + \", avisos \" + JSON.stringify(flags(it)));' ' }' ' console.log(\"total \" + total);' ' const q = \"Escribe un aviso corto que diga a los usuarios que sus notas de voz se borran a los 30 días.\";' ' const reply = await ask([{ role: \"user\", content: q }], \"Tus notas de voz se borran a los 30 días.\", 40);' ' console.log(\"respuesta: \" + reply.text);' '}' 'main();' >> cost6.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Pon precio a un día y marca entradas
docker exec -w /home/node/project agent node cost6.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Las líneas que imprime
| Línea | Qué muestra |
|---|---|
| 1 image: coste 81, avisos [] | Una entrada correcta: vista y de poca duración |
| 2 image: coste 181 ... | Una cara, sin texto alternativo y guardada 90 días |
| 4 audio: coste 7 ... | Una voz, sin transcripción y guardada 31 días |
| total 290 | Los cuatro precios sumados |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.