

1) 프로젝트 한 줄 소개
CallPeace는 콜센터/CS 상담사가 통화 중 겪는 감정노동을 줄이기 위해, 폭언을 ‘필터링’이 아니라 ‘중화(순화)’로 번역하고, 상담 목적에 맞는 공감 톤/스크립트까지 즉시 제안하는 상담원 헬퍼 웹앱입니다.
해커톤(패스트캠퍼스 Fast Builderthon) 본선 진출 팀 “뚝딱뚝딱”으로 개발했습니다.
무박 2일로 진행하였으며, 해커톤중 가장 힘들었던 것같습니다..
2) 내가 맡은 역할 (Frontend)
- React + TypeScript 기반 UI/상태관리 설계 및 구현
- 고객/상담사 2-카드(좌우) 콘솔 레이아웃 및 반응형(작은 화면에서도 2열 유지) 구성
- STT → 중화(transform) → TTS 재생까지 이어지는 사용자 플로우를 끊김 없이 연결
- ElevenLabs API 연동(목소리 리스트, TTS 생성, 재생 속도/피치 체감 조절) 중심의 “음성 기능 UI” 개발
- 백엔드 AI 변환 API 응답을 UI에 매핑(감정/신뢰도/중화문장/추천 스크립트)
3) 핵심 기능 (사용자 가치 기준)
A. 고객 폭언 “중화(순화) 번역”
- 고객 발화를 입력/음성(STT)로 받으면 AI가 원문 + 중화문장 + 감정 + 신뢰도를 반환
- 상담사는 원문에 직접 노출되지 않고, 중화문장으로 상황을 파악하며 대응할 수 있게 설계
B. 상담사 공감 톤(스크립트/응대문) 지원
- 상담사 카드에서 공감 톤 문장을 작성하거나, AI 추천 문장을 바로 가져와 TTS로 재생
- recommendation 값이 있으면 상담사 인풋(🧑💼 공감 톤)에 자동 주입, 비어 있으면 기본 문구 유지(UX 끊김 방지)
C. 음성 출력(TTS) 및 “말맛” 조절
- Pace / Pitch를 UI 상단에서 조절해 재생 체감(속도/톤)을 빠르게 튜닝
- 음성 재생은 브라우저 오디오 플레이어 + 커스텀 playbackRate로 컨트롤
D. 운영/데모 친화 콘솔
- 콘솔 탭에서 기능이 한 번에 보이도록 구성: 고객 발화, 중화 결과, 감정/신뢰도, 상담사 응답(TTS)
- “시제품” 탭은 STT → transform → Neutral TTS를 직관적으로 보여주는 데모 모드로 분리
4) 프론트엔드 기술 스택 & 구현 포인트
- React + TypeScript + Vite
- 반응형 UI: 작은 화면에서도 두 카드가 “가능하면 계속 좌우”로 유지되도록 grid 브레이크포인트/최소폭(min-w-0) 조정
- 상태 분리: 고객 영역(입력/STT/중화/TTS)과 상담사 영역(스크립트/TTS)을 독립적으로 로딩/에러 처리
- 오디오 처리:
- 생성된 오디오 URL(Object URL) 관리 및 revoke로 메모리 누수 방지
- 재생 중단/중복 재생 방지(stopAudio, abort 흐름)
5) API 연동 이슈 대응 경험 (CORS 포함)
로컬 개발 환경에서 IP 서버(http://34.64...)로 직접 호출 시, 브라우저가 CORS preflight 차단을 발생시켰습니다.
그래서 프론트에서는 호출 대상을 동일 출처 경로(/api/...)로 고정하고, 개발/배포 환경에서 프록시 또는 서버리스 라우팅으로 우회하는 방식으로 정리했습니다. (예: Vercel 배포 환경에서 API 라우팅)
6) ElevenLabs 연동 문서 (내 프로젝트 기준)
아래는 CallPeace에서 실제로 필요했던 범위에 맞춘 “연동 문서”입니다. (키는 절대 프론트에 하드코딩하지 않고 서버/프록시에서 보호)
6-1. 인증 방식
- 헤더에
xi-api-key: <YOUR_KEY>로 인증합니다. - 키는 서버 환경변수로 관리(예:
ELEVENLABS_API_KEY).
6-2. 목소리 목록 가져오기 (Voice Picker)
목적: 사용자가 Neutral/Warm에 사용할 목소리를 선택할 수 있게 함
- Endpoint:
GET https://api.elevenlabs.io/v1/voices - 프론트 구현 흐름:
- 앱 시작 시 voice 목록 fetch
voice_id,name을 드롭다운(VoicePicker)에 바인딩- 선택된
voice_id를 TTS 생성 시 사용
6-3. TTS 생성 (Create Speech / Convert)
목적: 중화 문장(Neutral) 또는 공감 문장(Warm)을 실제 음성으로 생성
옵션 A) Create Speech (가장 단순한 형태, 음성 파일 생성)
- Endpoint:
POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id} - Content-Type:
application/json - Accept는 보통 오디오 포맷으로 받습니다(예: audio/mpeg)
예시(curl)
curl -X POST "https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" \
-H "xi-api-key: $ELEVENLABS_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: audio/mpeg" \
-d '{
"text": "기다리게 해서 정말 죄송합니다. 바로 확인하겠습니다.",
"model_id": "eleven_multilingual_v2",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 0.75
}
}' --output out.mp3
(요청 필드 예시는 Create Speech 문서 기반 )
옵션 B) Convert (세밀한 출력 포맷/스트리밍 옵션까지 확장 가능)
POST /v1/text-to-speech/{voice_id}구조는 동일하며, 문서에서 output_format 등 추가 옵션을 다룹니다.- “스트리밍/저지연” 쪽으로도 확장 가능한 패턴을 제공
6-4. 프론트에서 오디오 재생 처리 패턴
- 서버(또는 프록시)가 ElevenLabs 응답(오디오 바이너리)을 받아서
- 프론트는 이를
Blob으로 변환 →URL.createObjectURL(blob)→<audio src=...>또는Audio()로 재생 - 새 요청이 오면 기존 오디오 중단 +
URL.revokeObjectURL로 정리
CallPeace에서는 중복 재생 방지, AbortController 기반 취소, 플레이어 stop/reset 유틸로 “통화 중 연속 클릭” 상황을 안전하게 처리했습니다.
6-5. STT(음성 인식) 쪽 확장 메모
CallPeace는 마이크 입력(STT)을 콘솔에 붙이는 구조로 설계되어 있고, ElevenLabs 문서상 Speech to Text(Scribe 계열) 라인이 별도로 존재합니다.
(현재 구현은 UI/컴포넌트 중심으로 구성되어 있어, 백엔드 라우팅 방식에 맞춰 교체 가능한 형태로 분리해둔 상태)
7) 성과/배운 점
- 폭언을 “차단”이 아닌 “중화 번역”으로 풀어내는 UX를 프론트에서 설계하며, 상담사의 실제 업무 흐름(심리적 부담, 즉시 응대)을 기준으로 UI를 구성했다.
- 음성 기능(TTS/STT)은 단순 API 호출이 아니라, 오디오 리소스 관리/중복 재생/취소/반응형 레이아웃까지 합쳐져야 제품이 된다는 걸 체감했고, 그 부분을 콘솔 형태로 정리해 데모 가능한 수준의 완성도를 만들었다.
- 로컬 개발에서 CORS 같은 현실 이슈를 겪으며, 프론트 호출 경로를
/api/*로 고정해 배포/개발 환경에 안전하게 대응하는 구조로 정리했다.
https://dduck-ddack.vercel.app/
뚝딱뚝딱
dduck-ddack.vercel.app
발표 PPT











#CallPeace #뚝딱뚝딱 #FastBuilderthon #Frontend #React #TypeScript #ElevenLabs #TTS #STT #AI프로덕트 #해커톤
'개발' 카테고리의 다른 글
| 차량 ECU, TCU 맵핑과 AI가 만나다. (0) | 2026.05.15 |
|---|---|
| [ 기술 ] React + TypeScript + Supabase + AI로 만드는 민원처리 시스템 (3) | 2025.12.11 |
| AutoRepairOps 자동차 정비 예약/운영 플랫폼 (1) | 2025.06.30 |
| [ 자율프로젝트 ] Webtoon 댓글 크롤링 (1) | 2021.10.21 |