0%

Unity

수화기를 들면 시작되는 이야기

전*원··수정됨 2026.07.21

수화기를 들면 시작되는 이야기

전시장 한쪽에 놓인 구식 수화기를 들어 올리는 순간 화면은 녹음 모드로 바뀌고, 10초 뒤에는 내 목소리가 30자 편지로 인쇄되어 손에 쥐어집니다. 이번 포스팅에서는 '마음아 안녕' 콘텐츠의 기술적인 구현 과정을 공유합니다.

아키텍처_01_전체구조.png

1. 시스템 아키텍처 개요

본 프로젝트는 크게 세 가지 단계로 구성됩니다.

- 수화기 감지: 물리 수화기의 픽업·드롭을 시리얼 릴레이로 감지해 녹음 플로우를 시작·종료합니다.

- 음성 텍스트 변환: 10초 녹음된 WAV 를 로컬 Python Flask 서버로 보내 Whisper 로 한국어 STT 를 수행합니다.

- 편지 생성과 송출: 변환된 텍스트를 랜덤 배경 편지로 합성해 영수증 프린터로 인쇄하고, 동시에 별도 프로젝션 벽으로 UDP 송신합니다.

메인 플랫폼은 Unity 이며, STT 파트는 Flask + OpenAI Whisper medium 모델이 별도 프로세스로 붙어 동작합니다.

2. 주요 기술적 구현

2.1 물리 수화기 시리얼 감지 SerialPortManager_GuestBook.cs)

전통적인 전화기 수화기 형태를 하드웨어로 그대로 차용했기 때문에, 버튼 대신 리드 스위치와 시리얼 릴레이로 수화기의 픽업·드롭을 감지합니다. 프로토콜은 [0xFA][Command] 2바이트 구조로, baud 9600 으로 전송되는 0x31 은 수화기 픽업, 0x30 은 "수화기를 들어주세요" 안내 팝업 트리거로 매핑됩니다.

포트 번호를 사전에 고정하지 않고 UnusedPorts.txt 로 제외 목록만 걸어 둔 뒤 사용 가능한 포트를 자동으로 탐색하기 때문에, 설치 현장마다 달라지는 USB 열거 순서에 유연하게 대응할 수 있도록 했습니다. 오디오 자체는 시리얼이 아니라 별도 Windows 마이크 장치로 들어오므로, 센서와 음원을 완전히 분리한 구조입니다.

2.2 녹음과 Whisper 기반 STT MicrophoneManager.cs, STTManager.cs)

수화기 픽업 신호가 들어오면 MicrophoneManager.cs44100Hz 로 녹음을 시작하고, UI 타이머(10초) 만료 또는 수동 종료 시 WAV 로 디스크에 떨어뜨립니다. 이후 STTManager.csmultipart/form-data POST 로 로컬 Flask 서버의 /upload 엔드포인트에 파일을 올리면, Python 측 SoundToText.py 가 Whisper medium 모델로 language="ko" 설정 아래 한국어 전사를 수행합니다.

Whisper 가 짧은 묵음 구간에서 "오늘도 시청해주셔서 감사합니다" 같은 유튜브 관용구를 환각 생성하는 특성이 있기 때문에, 서버 단에 BLOCK_PHRASES 리스트를 두고 해당 문구가 포함된 응답은 빈 문자열로 치환해 Unity 에 돌려줍니다. 최종 텍스트는 STTManager 에서 30자로 자른 뒤 FilteringManagerbadwords.txt 기반 욕설 필터를 통과해야 UI 에 반영됩니다.

- 녹음 시간: Time_Contents04_TalkTime = 10

- 최대 메시지 길이: 30자

- 재시도 기회: 1회

2.3 편지 인쇄와 프로젝션 송신 PrintManager.cs, CommunicationManager.cs)

녹음이 마무리되면 ResultPanelManager_GuestBook 이 랜덤 배경 위에 사용자 텍스트를 얹은 편지 이미지를 만들고, PrintManager.csPrintDocument API 를 통해 Windows 기본 프린터로 413×610px 영수증 용지에 출력합니다. 여백 0, 상하 200px 패딩으로 영수증 폭을 정확히 채워, 관람객이 실제로 자신의 편지를 뜯어 가져갈 수 있게 했습니다.

동시에 CommunicationManager.cs 가 동일 텍스트를 [1byte prefabType][UTF8 text] 형식으로 UDP 패킷에 실어 별도 프로젝션 벽 서버로 송신합니다. 이 메시지가 프로젝션 벽에서 떠다니는 말풍선으로 스폰되기 때문에, 관람객은 왼쪽 공간으로 이동하면 자신의 마음이 벽 위를 흐르는 모습을 직접 확인할 수 있습니다.

3. 사용자 경험(UX) 최적화

익숙한 수화기 제스처 : 버튼이 아닌 물리 수화기를 들어 올리는 동작으로 녹음을 시작하게 하여, 디지털 UI 조작에 낯선 어린 관람객도 "전화를 건다"는 익숙한 행위로 진입할 수 있게 했습니다.

시간·글자 수의 명시 : "10초 동안 이야기할 수 있어요 / 30글자까지 이야기할 수 있어요" 처럼 정확한 제약을 UI 에 상시 노출해, 이야기 도중 예상 못한 컷오프가 느껴지지 않도록 했습니다.

다시 말할 기회 : Whisper 가 어린이 발음을 오인식하는 경우가 있어 재녹음 1회를 보장하여, "틀려도 다시 할 수 있다"는 감각으로 발화 부담을 낮췄습니다.

손에 쥐어지는 결과 : 녹음된 마음을 영수증 프린터로 즉시 출력해, 체험 후 관람객이 자신의 편지를 실제로 들고 다음 공간으로 이어질 수 있게 했습니다.

4. 마치며

기술적으로 이 프로젝트는 Unity 클라이언트와 Python STT 서버를 로컬 HTTP 로 연결하고, 영수증 프린터와 UDP 벽 디스플레이라는 두 출력을 병렬로 쏘는 구조로 구현됐습니다. Whisper 의 환각 필터와 욕설 필터를 서버·클라이언트 양쪽에 이중으로 배치한 덕분에, 장시간 무인 운영에서도 부적절한 문구가 벽에 노출될 확률을 최소화할 수 있었습니다.

향후에는 Whisper 모델을 아동 음성에 미세 조정된 버전으로 교체해 인식 정확도를 높이고, 재녹음 기회를 발화 길이와 인식 신뢰도에 따라 동적으로 조정할 계획입니다. 또한 환각 차단 문구 리스트를 서버 외부의 설정 파일로 분리해, 모델 업그레이드 시 재배포 없이도 새로운 환각 패턴을 빠르게 반영할 수 있는 구조로 확장할 예정입니다.

읽기 도구

6분 읽기

이 글이 도움이 되었나요?

다음으로 읽기