본문으로 건너뛰기

Whisper AI로 회의록 자동 생성하기 — OpenAI 음성 인식 실전 가이드

·1450 단어수·7 분
작성자
Engineer

팀 회의가 끝난 후 회의록을 작성하는 일은 대부분의 팀에서 누군가 억지로 맡는 일입니다. 손으로 작성하면 30분~1시간, 그것도 회의 내용을 기억하면서 정리해야 하니 쉽지 않습니다. 저도 몇 년간 이 문제를 해결하고 싶었는데, OpenAI의 Whisper가 공개된 이후 상황이 완전히 달라졌습니다.

지금은 회의 녹음 파일을 넣으면 5~10분 안에 전체 텍스트 변환과 요약까지 자동으로 나옵니다. 이 글에서는 Whisper 설치부터 LLM 요약 연동까지 실제로 돌아가는 파이프라인을 공개합니다.

Whisper AI 회의록 자동화 파이프라인


Whisper란 무엇인가
#

Whisper는 OpenAI가 2022년 공개한 오픈소스 음성 인식(STT, Speech-to-Text) 모델입니다. 99개 언어를 지원하고, 한국어 인식률이 상당히 높습니다. 무엇보다 완전 무료로 로컬에서 실행할 수 있다는 점이 핵심입니다.

기존에 사용하던 Google Cloud Speech-to-Text나 네이버 Clova는 API 비용이 발생하고 외부 서버로 음성 데이터를 전송해야 했습니다. 보안에 민감한 내부 회의 내용을 외부로 보내는 것은 부담스럽습니다. Whisper는 이 두 가지 문제를 모두 해결합니다.

2024년 말 기준으로 large-v3 모델이 가장 최신이며, 한국어 인식 정확도가 크게 개선되었습니다.


환경 설정
#

필수 요구사항
#

1
2
3
4
5
6
# Python 3.9 이상 필요
python --version

# CUDA GPU가 있으면 속도가 10배 이상 빠름
# CPU만 있어도 동작하지만 large 모델은 느림
nvidia-smi  # NVIDIA GPU 확인

GPU가 없는 경우, tinybase 모델을 쓰거나 OpenAI API를 통한 Whisper를 사용하는 것이 현실적입니다. 1시간 회의를 large-v3 모델로 CPU만으로 처리하면 3060분이 걸리기도 합니다. RTX 3080 이상의 GPU가 있으면 510분 내에 처리됩니다.

설치
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 가상환경 생성 권장
python -m venv whisper-env
source whisper-env/bin/activate  # Windows: whisper-env\Scripts\activate

# Whisper 설치
pip install openai-whisper

# ffmpeg 설치 필요 (음성 파일 처리용)
# macOS
brew install ffmpeg

# Ubuntu
sudo apt install ffmpeg

# Windows (chocolatey)
choco install ffmpeg

기본 사용법
#

커맨드라인으로 빠르게 시작
#

설치가 완료되면 명령어 한 줄로 바로 쓸 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 기본 사용 (자동 언어 감지)
whisper meeting.mp3

# 한국어 지정 (더 정확함)
whisper meeting.mp3 --language Korean

# 모델 선택 + 출력 형식 지정
whisper meeting.mp3 --model large-v3 --language Korean --output_format txt

# 타임스탬프 포함 SRT 자막 파일 생성
whisper meeting.mp3 --model medium --language Korean --output_format srt

Python으로 프로그래밍 방식 사용
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import whisper
import json

def transcribe_audio(audio_path: str, model_name: str = "large-v3") -> dict:
    """
    음성 파일을 텍스트로 변환합니다.

    Args:
        audio_path: 음성 파일 경로 (mp3, wav, m4a, ogg 등)
        model_name: 사용할 Whisper 모델 (tiny, base, small, medium, large-v3)

    Returns:
        변환 결과 딕셔너리 (text, segments 포함)
    """
    print(f"모델 로딩 중: {model_name}")
    model = whisper.load_model(model_name)

    print(f"음성 인식 시작: {audio_path}")
    result = model.transcribe(
        audio_path,
        language="ko",           # 한국어 지정
        verbose=True,            # 진행 상황 출력
        word_timestamps=True,    # 단어별 타임스탬프
    )

    return result

# 사용 예시
result = transcribe_audio("team_meeting_2026_03.mp3")

# 전체 텍스트
print(result["text"])

# 타임스탬프별 세그먼트
for segment in result["segments"]:
    start = segment["start"]
    end = segment["end"]
    text = segment["text"]
    print(f"[{start:.1f}s - {end:.1f}s] {text}")

실전 파이프라인 구현
#

단순 텍스트 변환을 넘어, LLM으로 요약까지 자동화하는 전체 파이프라인입니다.

프로젝트 구조
#

1
2
3
4
5
6
7
8
meeting-notes/
├── transcribe.py       # Whisper STT
├── summarize.py        # LLM 요약
├── pipeline.py         # 전체 파이프라인
├── output/             # 결과 저장
│   ├── raw/            # 원본 텍스트
│   └── summary/        # 요약 파일
└── recordings/         # 녹음 파일

transcribe.py
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import whisper
import os
from pathlib import Path
from datetime import timedelta

def format_timestamp(seconds: float) -> str:
    """초를 HH:MM:SS 형식으로 변환"""
    return str(timedelta(seconds=int(seconds)))[:-3] if seconds >= 3600 \
           else f"00:{str(timedelta(seconds=int(seconds)))[3:]}"

def transcribe_meeting(
    audio_path: str,
    output_dir: str = "output/raw",
    model_name: str = "medium"
) -> str:
    """
    회의 녹음을 텍스트로 변환하고 파일로 저장합니다.
    """
    os.makedirs(output_dir, exist_ok=True)

    model = whisper.load_model(model_name)
    result = model.transcribe(
        audio_path,
        language="ko",
        verbose=False
    )

    # 타임스탬프 포함 텍스트 생성
    lines = []
    for seg in result["segments"]:
        timestamp = format_timestamp(seg["start"])
        lines.append(f"[{timestamp}] {seg['text'].strip()}")

    formatted_text = "\n".join(lines)

    # 파일 저장
    base_name = Path(audio_path).stem
    output_path = os.path.join(output_dir, f"{base_name}.txt")
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(formatted_text)

    print(f"변환 완료: {output_path}")
    return formatted_text

summarize.py
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from openai import OpenAI

client = OpenAI()  # OPENAI_API_KEY 환경변수 필요

SUMMARY_PROMPT = """
당신은 회의록 전문 작성자입니다.
아래 회의 내용을 분석하여 다음 형식으로 정리해주세요.

## 회의 요약
[3~5줄로 회의의 핵심 내용]

## 주요 논의 사항
- [논의 사항 1]
- [논의 사항 2]
...

## 결정된 사항
- [결정 1]
- [결정 2]
...

## 액션 아이템
| 담당자 | 할 일 | 기한 |
|--------|--------|------|
| [이름] | [업무] | [날짜] |

## 다음 회의 안건 (언급된 경우)
- [안건]

회의 내용:
{transcript}
"""

def summarize_meeting(
    transcript: str,
    output_dir: str = "output/summary",
    filename: str = "summary"
) -> str:
    """
    회의 텍스트를 LLM으로 요약합니다.
    """
    import os
    os.makedirs(output_dir, exist_ok=True)

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "user",
                "content": SUMMARY_PROMPT.format(transcript=transcript)
            }
        ],
        temperature=0.3,  # 낮은 temperature로 일관성 확보
    )

    summary = response.choices[0].message.content

    # 파일 저장
    output_path = os.path.join(output_dir, f"{filename}.md")
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(summary)

    print(f"요약 완료: {output_path}")
    return summary

pipeline.py — 전체 자동화
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import sys
import os
from pathlib import Path
from transcribe import transcribe_meeting
from summarize import summarize_meeting

def process_meeting(audio_path: str, model: str = "medium") -> None:
    """
    녹음 파일 하나를 받아 전체 파이프라인을 실행합니다.
    """
    if not os.path.exists(audio_path):
        print(f"파일을 찾을 수 없습니다: {audio_path}")
        sys.exit(1)

    base_name = Path(audio_path).stem
    print(f"\n{'='*50}")
    print(f"회의록 자동화 시작: {base_name}")
    print(f"{'='*50}\n")

    # 1단계: 음성 인식
    print("[1/2] 음성 인식 중...")
    transcript = transcribe_meeting(
        audio_path,
        output_dir="output/raw",
        model_name=model
    )

    # 2단계: LLM 요약
    print("\n[2/2] AI 요약 중...")
    summary = summarize_meeting(
        transcript,
        output_dir="output/summary",
        filename=base_name
    )

    print(f"\n{'='*50}")
    print("완료!")
    print(f"원본: output/raw/{base_name}.txt")
    print(f"요약: output/summary/{base_name}.md")
    print(f"{'='*50}\n")
    print(summary)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("사용법: python pipeline.py <녹음파일> [모델명]")
        print("예시: python pipeline.py meeting.mp3 medium")
        sys.exit(1)

    audio_file = sys.argv[1]
    model_name = sys.argv[2] if len(sys.argv) > 2 else "medium"

    process_meeting(audio_file, model_name)

실행 방법은 간단합니다.

1
2
3
4
5
# 기본 실행 (medium 모델)
python pipeline.py recordings/team_meeting.mp3

# large-v3 모델 사용 (더 정확하지만 느림)
python pipeline.py recordings/team_meeting.mp3 large-v3

모델 선택 가이드
#

상황에 따른 모델 추천입니다.

상황 추천 모델 이유
짧은 미팅 (30분 이내), CPU만 있음 small 빠르고 충분한 정확도
일반적인 팀 회의, GPU 없음 medium 정확도와 속도 균형
중요한 외부 미팅, GPU 있음 large-v3 최고 정확도
실시간 처리 필요 tiny or base 속도 우선
비용 절감, API 활용 OpenAI API 서버 자원 절약

OpenAI API 방식 (로컬 GPU 없을 때)
#

GPU가 없거나 빠른 처리가 필요하다면 OpenAI API를 쓰는 것도 좋습니다. 비용은 분당 약 $0.006으로, 1시간 회의에 약 $0.36(약 500원) 수준입니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from openai import OpenAI

client = OpenAI()

def transcribe_with_api(audio_path: str) -> str:
    """OpenAI API를 통한 Whisper 사용"""
    with open(audio_path, "rb") as audio_file:
        transcript = client.audio.transcriptions.create(
            model="whisper-1",
            file=audio_file,
            language="ko",
            response_format="verbose_json",  # 타임스탬프 포함
        )
    return transcript.text

단, 보안이 중요한 회의 내용은 로컬 Whisper를 쓰는 것이 바람직합니다.


자주 겪는 문제와 해결 방법
#

문제 1: “CUDA out of memory” 오류

GPU 메모리가 부족할 때 발생합니다. large-v3는 약 10GB VRAM이 필요합니다.

1
2
# 더 작은 모델로 전환하거나 CPU 사용 강제
model = whisper.load_model("medium", device="cpu")

문제 2: 한국어 인식률이 낮을 때

language 파라미터를 명시하지 않으면 자동 감지가 틀리는 경우가 있습니다.

1
2
# 반드시 language 명시
result = model.transcribe(audio_path, language="ko")

문제 3: 여러 사람 발언 구분 (화자 분리)

기본 Whisper는 화자를 구분하지 못합니다. pyannote.audio 라이브러리를 추가로 써야 합니다.

1
pip install pyannote.audio

화자 분리까지 필요한 경우는 별도 포스트로 다루겠습니다.


실제 사용 결과
#

저희 팀에서 3개월간 사용한 결과를 공유합니다. 주 3회 1시간짜리 팀 회의 기준입니다.

  • 회의록 작성 시간: 평균 45분 → 10분 (검토 시간 포함)
  • 인식 정확도 (medium 모델): 약 92% (한국어, 마이크 근접 환경)
  • 가장 큰 오류: 고유명사, 영어 혼용 단어, 낮은 음질 구간
  • 실제 비용: 로컬 GPU 사용으로 API 비용 없음

완벽하지는 않습니다. 여전히 결과물 검토는 사람이 합니다. 하지만 “빈 문서에서 시작"과 “90% 완성된 초안을 다듬기"는 완전히 다른 경험입니다.

회의 녹음은 핸드폰 기본 녹음 앱으로 충분합니다. 가능하면 외장 마이크나 USB 마이크를 쓰면 인식률이 크게 올라갑니다.