Add guion del agente de voz (preámbulo legal + slots + gustos)
This commit is contained in:
80
mvp/b2c/src/lib/voice/script.ts
Normal file
80
mvp/b2c/src/lib/voice/script.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import type { TipoReforma } from '@/budget/types';
|
||||||
|
|
||||||
|
export interface ScriptTurn {
|
||||||
|
quien: 'agente' | 'cliente';
|
||||||
|
texto: string;
|
||||||
|
}
|
||||||
|
export interface ScriptBlock {
|
||||||
|
id: 'preambulo' | 'confirmacion' | 'slots' | 'gustos' | 'cierre';
|
||||||
|
titulo: string;
|
||||||
|
turnos: ScriptTurn[];
|
||||||
|
}
|
||||||
|
export interface VoiceScript {
|
||||||
|
bloques: ScriptBlock[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIPO_TEXTO: Record<TipoReforma, string> = {
|
||||||
|
cocina: 'la cocina',
|
||||||
|
bano: 'el baño',
|
||||||
|
salon: 'el salón',
|
||||||
|
comedor: 'el comedor',
|
||||||
|
integral: 'el piso entero',
|
||||||
|
otro: 'la reforma',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildScript(
|
||||||
|
empresa: { nombreEmpresa: string },
|
||||||
|
lead: { nombre: string; tipoReforma: TipoReforma | null; m2Suelo: number | null },
|
||||||
|
): VoiceScript {
|
||||||
|
const nombre = lead.nombre.split(' ')[0];
|
||||||
|
const tipo = TIPO_TEXTO[lead.tipoReforma ?? 'otro'];
|
||||||
|
const m2 = lead.m2Suelo ? `${Math.round(lead.m2Suelo)} metros` : 'el espacio';
|
||||||
|
|
||||||
|
return {
|
||||||
|
bloques: [
|
||||||
|
{
|
||||||
|
id: 'preambulo',
|
||||||
|
titulo: 'Preámbulo legal',
|
||||||
|
turnos: [
|
||||||
|
{
|
||||||
|
quien: 'agente',
|
||||||
|
texto: `Hola ${nombre}, te llamo de ${empresa.nombreEmpresa}. Soy un asistente virtual con inteligencia artificial y esta llamada queda grabada y transcrita para preparar tu presupuesto. ¿Te parece bien que sigamos?`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'confirmacion',
|
||||||
|
titulo: 'Confirmación de datos',
|
||||||
|
turnos: [
|
||||||
|
{ quien: 'agente', texto: `Me dices que quieres reformar ${tipo}, ¿unos ${m2} aproximadamente, verdad?` },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'slots',
|
||||||
|
titulo: 'Datos clave',
|
||||||
|
turnos: [
|
||||||
|
{ quien: 'agente', texto: '¿Qué nivel de acabado buscas: básico, medio o premium?' },
|
||||||
|
{ quien: 'agente', texto: '¿Hay que mover sanitarios principales, tirar algún muro o cambiar la distribución?' },
|
||||||
|
{ quien: 'agente', texto: '¿Para cuándo te gustaría tenerlo?' },
|
||||||
|
{ quien: 'agente', texto: '¿Tienes una cifra en mente, aunque sea aproximada?' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'gustos',
|
||||||
|
titulo: 'Gustos y preferencias',
|
||||||
|
turnos: [
|
||||||
|
{ quien: 'agente', texto: `Cuéntame cómo te imaginas ${tipo}: estilo, colores, materiales que te gusten… y si hay algún capricho que no quieras que falte.` },
|
||||||
|
{ quien: 'agente', texto: '¿Te tira más la madera, el porcelánico, algo más industrial?' },
|
||||||
|
{ quien: 'agente', texto: '¿Hay algo imprescindible: una isla, una ducha de obra, electrodomésticos integrados?' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cierre',
|
||||||
|
titulo: 'Cierre',
|
||||||
|
turnos: [
|
||||||
|
{ quien: 'agente', texto: `Genial, con esto te preparo el render y el presupuesto orientativo y te lo enviamos por WhatsApp. ¡Muchas gracias, ${nombre}!` },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
24
mvp/b2c/tests/voice/script.test.ts
Normal file
24
mvp/b2c/tests/voice/script.test.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { buildScript } from '@/lib/voice/script';
|
||||||
|
|
||||||
|
describe('buildScript', () => {
|
||||||
|
const script = buildScript(
|
||||||
|
{ nombreEmpresa: 'Reformas Ejemplo' },
|
||||||
|
{ nombre: 'Ana Pérez', tipoReforma: 'cocina', m2Suelo: 16 },
|
||||||
|
);
|
||||||
|
|
||||||
|
it('abre con identificación de IA y aviso de grabación (RF-C-12, RNF-LEG-05)', () => {
|
||||||
|
const preambulo = script.bloques[0].turnos.map((t) => t.texto).join(' ');
|
||||||
|
expect(preambulo).toContain('inteligencia artificial');
|
||||||
|
expect(preambulo).toContain('grabada');
|
||||||
|
expect(preambulo).toContain('Reformas Ejemplo');
|
||||||
|
expect(preambulo).toContain('Ana');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('incluye los bloques de slots fijos y el bloque abierto de gustos', () => {
|
||||||
|
const ids = script.bloques.map((b) => b.id);
|
||||||
|
expect(ids).toEqual(['preambulo', 'confirmacion', 'slots', 'gustos', 'cierre']);
|
||||||
|
const gustos = script.bloques.find((b) => b.id === 'gustos')!;
|
||||||
|
expect(gustos.turnos.some((t) => t.texto.includes('imaginas'))).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user