HUTAMS_AUDIO/ARCHITECTURE.md

8.1 KiB

HUTAMS — 지능형 무전 관제 플랫폼 아키텍처 문서

Heavy-rail Unified Traffic Analysis & Monitoring System
LTE-R 기반 무전 통신을 실시간으로 수집·전사·분석하는 AI 관제 플랫폼


목차

  1. 프로젝트 개요
  2. 전체 파이프라인 다이어그램
  3. 디렉토리 구조
  4. 핵심 파이프라인 상세
  5. API 엔드포인트 스펙
  6. 환경변수(.env) 설정법
  7. 서버 구동 & 운영 가이드

1. 프로젝트 개요

항목 내용
언어 Python 3.11+
웹 프레임워크 FastAPI 0.115 + Uvicorn
STT 엔진 faster-whisper (large-v3-turbo, INT8 양자화)
LLM Qwen3 0.8B GGUF (llama-cpp-python, GPU 가속)
DB SQLite (whisper.db via SQLAlchemy)
프론트엔드 Vanilla JS + Bootstrap 5
실시간 통신 WebSocket (FastAPI native)

2. 전체 파이프라인 다이어그램

[ 오디오 소스 ]
   │  Line-in / 마이크 (mic 모드)
   │  로컬 wav 파일     (mock 모드)
   ↓
[ RadioListener / MockAudioListener ]  ← 백그라운드 데몬 스레드
   │  VAD (RMS 임계치 기반 음성구간 감지)
   │  침묵 1.8초 지속 → 녹음 종료 → 임시 .wav 생성
   ↓
[ app/services/stt_service.py :: WhisperSTTService ]
   │  faster-whisper → full_text + segments[] 생성
   │  domain_dict.post_process_correction() (RapidFuzz 교정)
   │  HARDCODED_FIXES (신호질로→신호 진로 등)
   │  guess_speaker (룰 정규식 → LLM 체이닝 fallback)
   ↓
[ app/services/llm_service.py :: LocalLLMService ]
   │  Qwen3 0.8B GGUF
   │  제목 / 요약 / 키워드 / 긴급도 추출
   │  _parse_response() — <think> 태그 제거 후 정규식 파싱
   ↓
[ SQLite (whisper.db) ]
   │  TranscriptionRecord — LLM 메타 포함
   │  TranscriptionSegment — 화자 뱃지 포함
   ↓
[ WebSocket ws_manager.broadcast() ]
   ↓
[ 브라우저 (index.html) ]
   ├── Live Mode: 타자기 효과 즉시 렌더링
   └── Test Mode: 업로드 → REST POST → 동일 렌더링

3. 디렉토리 구조

Wisper/
├── app/
│   ├── core/
│   │   ├── config.py          # Pydantic Settings (환경변수 관리)
│   │   ├── dictionary.py      # 철도 도메인 사전 + 하드코딩 교정
│   │   └── exceptions.py      # 도메인 예외 클래스
│   ├── db/
│   │   ├── database.py        # SQLAlchemy 엔진 + SessionLocal
│   │   └── models.py          # ORM 모델 (TranscriptionRecord, TranscriptionSegment)
│   ├── models/
│   │   ├── stt.py             # STTRequest / STTResponse / STTSegment Pydantic 모델
│   │   └── record.py          # RecordListResponse 등 API 응답 모델
│   ├── routers/
│   │   └── records.py         # GET /api/v1/records 라우터
│   ├── services/
│   │   ├── audio_listener.py      # RadioListener (실제 마이크 VAD 감청)
│   │   ├── audio_parser.py        # pydub 포맷 변환 + 무음 제거
│   │   ├── llm_service.py         # LocalLLMService (Qwen3 GGUF 래퍼)
│   │   ├── mock_audio_listener.py # MockAudioListener (파일 스트리밍 시뮬레이터)
│   │   └── stt_service.py         # WhisperSTTService + guess_speaker()
│   ├── static/
│   │   └── audio/             # 영구 저장된 무전 오디오 파일 (/static/audio/{filename})
│   ├── templates/
│   │   └── index.html         # 대시보드 SPA (Bootstrap 5 + Vanilla JS)
│   ├── main.py                # FastAPI 앱 진입점 / lifespan / WS 매니저
│   └── .env                   # 로컬 환경변수 오버라이드
├── whisper.db                 # SQLite 데이터베이스
└── ARCHITECTURE.md            # 이 문서

4. 핵심 파이프라인 상세

4.1 VAD (음성 활동 감지)

파라미터 기본값 설명
THRESHOLD 600 RMS 볼륨 임계치 (0~32767 범위)
SILENCE_LIMIT 1.8s 침묵 지속 시간 초과 시 발화 종료 판정
PRE_ROLL_SECS 0.3s 발화 시작 직전 버퍼 (첫 음절 잘림 방지)
RECORD_TIMEOUT 30s 단일 녹음 최대 시간 (무한 루프 방지)

4.2 화자 분리 (Speaker Diarization)

1차: 룰 기반 정규식 (guess_speaker)

  • "전철 OO" 패턴 → 관제
  • 숫자 + "열차" 패턴 → 열차
  • 짧은 응답어 + Gap ≥ 1.5s → 교차 할당 휴리스틱

2차: LLM 체이닝 Fallback (guess_speaker_with_llm)

  • 룰에서 "미상" 반환 시 Qwen3 0.8B 추론 (max_tokens=256)
  • <think> 블록 제거 후 "관제" / "열차" 키워드 파싱

4.3 LLM 메타데이터 추출

system: "철도 관제 무전 분석 시스템. 지정된 포맷으로만 답변."
user:   1-Shot 예시 → 실제 무전 텍스트
format: 제목: ... / 요약: ... / 키워드: ... / 긴급도: 긴급|일반

5. API 엔드포인트 스펙

Method Path 설명
GET / 대시보드 HTML
POST /api/v1/transcribe 오디오 파일 업로드 → STT + LLM 분석
GET /api/v1/records 이력 목록 조회 (?limit=50&skip=0&keyword=검색어)
GET /static/audio/{filename} 저장된 무전 오디오 스트리밍
WS /api/v1/ws/live 실시간 감청 결과 WebSocket 구독

POST /api/v1/transcribe 요청 형식

Content-Type: multipart/form-data
Fields:
  audio        : UploadFile  (m4a, mp3, wav 등)
  language     : str         (기본: "ko")
  base_datetime: ISO8601 str (선택, 예: 2026-03-07T09:00:00+09:00)

WebSocket 수신 메시지 포맷

{
  "type": "stt_result",
  "text": "좌천 하선 궤도 검측차 신호 진로 확인...",
  "title": "좌천 하선 신호 진로 확인",
  "summary": "궤도 검측차가 신호 진로를 확인하고 통과함.",
  "keywords": "좌천 하선, 검측차, 신호, 통과",
  "urgency": "일반",
  "language": "ko",
  "segments": [
    {
      "start_sec": 8.11,
      "end_sec": 41.12,
      "text": "좌천 하선 있는 궤도 검측차는...",
      "speaker": "관제"
    }
  ]
}

6. 환경변수(.env) 설정법

app/.env 파일(또는 프로젝트 루트 .env)에 아래 항목을 설정:

# ─── Whisper ─────────────────────────────────────
WHISPER_MODEL_NAME=large-v3-turbo

# ─── LLM ─────────────────────────────────────────
LLM_ENABLED=true
LLM_MODEL_PATH=./Qwen3.5-0.8B-Q4_K_M.gguf
# LLM_ENABLED=false 로 설정 시 LLM 분석 전체 스킵

# ─── 실시간 감청 소스 ─────────────────────────────
# "mock" : 로컬 파일 시뮬레이션 (개발/테스트용)
# "mic"  : 서버 PC 실제 마이크/Line-in (상용 운영용)
AUDIO_SOURCE=mock
MOCK_AUDIO_PATH=./sample1.m4a

7. 서버 구동 & 운영 가이드

개발 서버 기동

# 프로젝트 루트에서
.\.venv\Scripts\uvicorn.exe app.main:app --host 127.0.0.1 --port 28000

Mock 시뮬레이션 모드 확인 절차

  1. .env에서 AUDIO_SOURCE=mock 설정 (기본값)
  2. MOCK_AUDIO_PATH=./sample1.m4a 경로 확인
  3. 서버 기동 후 http://127.0.0.1:28000 접속
  4. 우측 상단 Live Mode 토글 ON
  5. 서버 로그에서 🧪 [Mock] 발화 감지, 📡 WebSocket broadcast 확인
  6. 브라우저 우측 화면에 타자기 효과로 무전 내용이 실시간 렌더링됨

실제 마이크 감청 전환 방법

# app/.env
AUDIO_SOURCE=mic

재기동 시 🎙️ RadioListener(실마이크) 기동 로그 확인 후,
Line-in 단자에 무전 수신기 연결 → Live Mode 토글 ON으로 즉시 감청 시작.