Hay un momento en una llamada en frío: ya han descolgado, la persona habla, tú asientes. Pero por dentro hay silencio. No has entendido ni una palabra.
Sobre todo si al otro lado hay un británico con un acento particular o un indio que habla muy rápido y con mucha seguridad. Ambas situaciones fueron mi realidad en mis primeras semanas como agente en Dubái.
Soy diseñador. Sé diseñar sistemas complejos. Entiendo el producto. Pero hablar por teléfono con un acento desconocido es una habilidad aparte y no aparece solo por desearlo.
Podría haberme limitado a practicar y esperar. Decidí construir una herramienta.
Qué es CallCoach
Una aplicación nativa de iOS en Swift con Apple Intelligence y Live Translation.
Durante la llamada reconoce el habla del interlocutor en tiempo real y muestra el texto en pantalla. Analiza lo que ha dicho y propone sugerencias: qué responder, cómo continuar, qué pregunta hacer.

No es transcribir por transcribir. Es un asistente de guiones que aparece justo cuando hace falta, en una conversación en vivo y sin demora.
Por qué Swift y Apple Intelligence
Podría haber usado cualquier stack web. Pero la web no ofrece la velocidad necesaria ni la integración nativa con el micrófono y las API del sistema.
Apple Intelligence es un motor de lenguaje local, en el propio dispositivo. Sin solicitudes a la nube, sin retraso, sin filtración de los datos de la conversación. Todo en el teléfono.
Live Translation maneja el inglés con acento con la precisión necesaria. Justo lo que hace falta en el Dubái multinacional.

Cómo cambió el trabajo
Cuando ves el texto de lo que dice la otra persona, la ansiedad desaparece. Dejas de gastar energía en «¿qué ha dicho?» y empiezas a pensar en «¿qué respondo?».
Del modo supervivencia al modo diálogo. Un cambio fundamental.
Sigo desarrollándola. El siguiente paso es una base de guiones para distintos escenarios: primera llamada, objeción, aclarar el presupuesto, acordar una reunión. Sugerencias que no sean solo una transcripción, sino una respuesta contextual inteligente a una frase concreta.
Por qué cuento esto
CallCoach es un ejemplo de cómo pienso los productos.
No «qué tecnología probar», sino «qué problema resolver». El problema era concreto y personal. La solución, nativa, rápida y sin dependencias innecesarias.
Un diseñador que sabe escribir código no es un desarrollador. Pero a veces eso es precisamente lo que evita que una idea muera en la cola de implementación.
Implementación técnica
Desde el punto de vista técnico, construí CallCoach como una herramienta de trabajo real, no como un concepto.
Primero trabajé la idea y la arquitectura con ChatGPT: definí el problema de producto, el escenario de uso y preparé un gran prompt inicial para Codex, para que creara el proyecto base en Swift, configurara las dependencias y montara el primer esqueleto funcional de la aplicación.
Cuando se agotó la ventana de tokens de Codex, pasé el proyecto a Claude Code. La parte sustancial del desarrollo continuó allí, con el modelo Opus 4.7.
Resultó muy potente precisamente en los recorridos largos de ingeniería: piensa mucho, gasta muchos tokens, pero mantiene bien la arquitectura, escribe con cuidado código coherente y ayuda a llevar la aplicación a un estado funcional.
Después empecé a pasar con regularidad a Xcode: compilar, ejecutar pruebas, detectar cierres inesperados, devolver los errores a Claude Code y corregir juntos las partes problemáticas. Algunos cambios los hacía directamente en Xcode, donde también conecté Codex y Claude como asistentes en el propio entorno.
Cómo se organiza la lógica de la aplicación
La aplicación se construye alrededor del procesamiento local del habla en el dispositivo.
En el modo normal, CallCoach puede escuchar el flujo del micrófono y mostrar una transcripción en directo. Pero la decisión técnica clave fue separar las voces.
El problema principal era que, al llamar por altavoz, el micrófono oye a la vez al usuario y al interlocutor. La transcripción queda contaminada por ambas partes del diálogo y deja de ser útil para el coaching.
Para resolverlo creé dos modos de funcionamiento.
Modo 1: System Audio
Es el modo principal y recomendado.
Mediante ScreenCaptureKit, la aplicación captura la salida de audio del sistema, es decir, solo lo que va a los altavoces. Así transcribe precisamente la voz del interlocutor sin captar mi propia voz desde el micrófono.
También se utiliza el indicador excludesCurrentProcessAudio = true, para excluir los sonidos de la propia aplicación.
Al iniciarse por primera vez, macOS solicita permiso para grabar la pantalla; sin él no es posible capturar el audio del sistema.
Modo 2: Microphone + Push-to-Mute
Es la alternativa de respaldo.
Usa la captura normal del micrófono, pero mientras hablo puedo mantener pulsado un botón para dejar de enviar temporalmente los búferes de audio al transcriptor.
La lógica es muy sencilla: hablo, mantengo pulsado; termino, suelto, y la aplicación vuelve a escuchar al interlocutor.
Qué se escribió en el código
La arquitectura se compone de varios gestores separados, cada uno responsable de su parte del flujo de procesamiento.
AudioCaptureManager
Se encarga de capturar audio mediante AVAudioEngine.
- utiliza
installTapeninputNode startRecording()devuelveAsyncStream<AVAudioPCMBuffer>- el flujo de búferes se transmite sin problemas de
paso entre actores (actor crossing) - en paralelo se calcula el nivel de señal mediante medición RMS y en dB
- las actualizaciones de la interfaz se envían a
@MainActormedianteTask
SystemAudioCaptureManager
Es una clase independiente que añadí para capturar el audio del sistema mediante SCStream.
Fue esta clase la que permitió que la transcripción recibiera solo la voz del interlocutor desde los altavoces, en vez de todo el ruido acústico del entorno.
TranscriptionManager
Esta capa recibe el flujo de búferes de audio y lo envía a SpeechAnalyzer del framework Speech.
Después itera sobre AsyncThrowingStream<SpeechTranscriptionResult>, separa la transcripción parcial y la final y gestiona explícitamente los cambios a @MainActor.
Ya no se trata solo de «reconocer sonido», sino de integrar con cuidado la transcripción en streaming en una interfaz viva.
CoachingEngine
Es una capa lógica independiente que convierte una transcripción normal en una herramienta útil para conversar.
processNewTranscript(_:)utiliza un debounce de 1,5 segundos- el anterior
Taskse cancela si llega un nuevo fragmento de habla LanguageModelSessionse crea una vez por sesión y después se reutiliza- se conserva el historial de contexto
- el analizador interpreta las respuestas en formato
[TIPO]: textocon alternativa de respaldo en.phrase - se identifica la etapa de la conversación mediante palabras clave
- se envían al modelo aproximadamente las últimas 300 palabras, no la transcripción entera
También añadí contexto específico del mercado de Dubái: Emaar, DAMAC, Binghatti, ROI, reserva, reunión, Zoom y otras señales habituales de estas conversaciones.
ContentView
Aquí se conecta todo en la interfaz de usuario.
.tasksolicita permiso para el micrófono al iniciar.onChange(segments.count)activacoach.processNewTranscripttoggleSession()pasa el flujo y el formato astartTranscription- los errores de los gestores se muestran mediante controladores separados
.onChange
Esta capa es la que da vida a toda la aplicación: cambio de fuente de audio, inicio y fin de sesión, lógica de silencio, gestión de errores y actualización de sugerencias en tiempo real.
Cómo entrené las sugerencias
También alimenté el sistema con contexto práctico.
Para las llamadas en frío utilicé guiones de venta reales: saludo, mantener la conversación, cualificación inicial del cliente, aclarar el presupuesto, abordar dudas y cerrar una reunión o una sesión detallada por Zoom.
No eran plantillas abstractas de internet, sino la lógica que nos enseñaban en la agencia SPI Dubai.
Así las sugerencias se volvieron más prácticas. No solo «responde algo educado», sino continuar la conversación con la estructura adecuada y en la etapa correcta.
Segundo escenario: entrevistas para diseñador de producto
En paralelo desarrollé un segundo uso de este enfoque: realizar entrevistas para puestos de diseñador de producto.
Ahí entrené el sistema con mis proyectos, casos y portfolio para que ayudara no en llamadas en frío, sino en otro tipo de conversación: cuando importa responder rápido, con seguridad y de forma estructurada a preguntas sobre la propia experiencia.
En esencia, CallCoach dejó de ser solo una aplicación de voz a texto para convertirse en un asistente conversacional universal, adaptable a un escenario concreto de comunicación.
Cómo fue el proceso real de desarrollo
Y, siendo totalmente sincero, para mí también es un ejemplo importante de cómo es hoy el desarrollo real de productos.
La idea nace de un problema propio.
La arquitectura se monta rápidamente con ayuda de modelos de lenguaje.
El código complejo se escribe en colaboración con agentes.
El ajuste final se hace a mano en Xcode, mediante compilaciones, fallos, depuración e iteraciones sucesivas.
No es «magia de la red neuronal», sino un proceso de ingeniería normal, simplemente acelerado por herramientas nuevas.
Registro de cambios / cómo se construyó CallCoach
1. Formular la idea
- Identifiqué un problema concreto: en llamadas en frío con acentos británicos e indios, parte del habla simplemente no se llega a reconocer de oído a tiempo.
- Definí la tarea del producto: no solo transcribir la conversación, sino ayudar a continuarla.
- Con ChatGPT trabajé el concepto, el flujo de usuario y la estructura de la futura aplicación.
- Generé un gran prompt inicial para Codex con el que montar rápidamente el esqueleto del proyecto en Swift.
2. Montaje inicial del proyecto
- Codex creó el proyecto base en Swift.
- Se configuraron las dependencias principales.
- Se preparó la arquitectura básica.
- Se montó el primer prototipo ejecutable.
3. Implementación principal de ingeniería
- Tras agotarse la ventana de tokens de Codex, el proyecto pasó a Claude Code.
- El desarrollo principal continuó con Opus 4.7.
- Con Claude Code se construyó la parte sustancial de la aplicación: captura de audio, transcripción, lógica de coaching y conexión con la interfaz.
4. Resolver el principal problema de producto: separar las voces
- Se detectó el problema clave: el micrófono oye tanto al usuario como al interlocutor.
- Se implementaron dos modos:
- System Audio — captura únicamente de la salida de audio del sistema mediante
ScreenCaptureKit - Microphone + Push-to-Mute — modo de respaldo con desactivación manual del envío de búferes al transcriptor
- System Audio — captura únicamente de la salida de audio del sistema mediante
- Se añadió
excludesCurrentProcessAudio = true, para excluir los sonidos de la propia aplicación.
5. Componentes implementados
SystemAudioCaptureManager.swift— nueva clase para capturar el audio del sistema medianteSCStreamAudioCaptureManager.swift— captura de sonido medianteAVAudioEngine, se añadióisMutedTranscriptionManager— transcripción en streaming medianteSpeechAnalyzerCoachingEngine— debounce, reutilización de la sesión del modelo, análisis de frases, lógica de etapas de la llamadaContentView.swift— gestión de sesión, elección de fuente de audio, errores, botones e interfazInfo.plist— permisos para la captura del sistemaproject.pbxproj— integración deScreenCaptureKit.framework
6. Depuración y pruebas
- La compilación y ejecución se hicieron mediante Xcode.
- Con cada cierre inesperado, el error volvía a Claude Code.
- Las correcciones fueron iterativas: Xcode → fallo/error → Claude Code → corrección → nueva compilación.
- Algunos cambios rápidos se hicieron directamente en Xcode con Codex y Claude conectados.
7. Entrenamiento para escenarios reales
- Para las llamadas en frío se añadieron al sistema guiones de venta reales:
- saludo
- charla informal habitual
- cualificación del cliente
- identificación del interés
- cierre de una reunión o un Zoom
- Los guiones se basaban en la práctica real y la formación de SPI Dubai.
- En paralelo se creó un segundo caso de uso: ayuda en entrevistas para puestos de diseñador de producto.
- Para ello se entrenó el modelo con mis proyectos, casos y portfolio.
8. Resultado final
- transcripción local sin enviar datos a la nube
- sugerencias en tiempo real durante la conversación
- lógica separada para ventas y entrevistas
- stack nativo sin apaños web
- producto funcional construido con ChatGPT + Codex + Claude Code + Xcode




@nevsky_alexander
En Instagram, Dubái más allá de la postal: familia, ciudad, descubrimientos y la vida entre proyectos. En Threads, ideas en voz alta sobre diseño e IA. En YouTube, vídeos que necesitan más espacio que una historia. Sígueme donde te sientas más a gusto y seguimos en contacto