콘텐츠로 이동

음성인식

필요한 모듈 설치하기

!pip install gradio
!pip install SpeechRecognition
!pip install pydub
!pip install whisper-openai
!pip install torch torchaudio
!apt-get update
!apt-get install -y ffmpeg

Gradio 음성인식

import gradio as gr
import speech_recognition as sr
import whisper
import torch
import tempfile
import os
from pydub import AudioSegment
import numpy as np

# 방법 1: Google Speech Recognition API 사용 (인터넷 필요)
def transcribe_with_google(audio_file):
    """Google Speech Recognition을 사용한 음성 인식"""
    if audio_file is None:
        return "음성 파일을 업로드해주세요."

    try:
        recognizer = sr.Recognizer()

        # 오디오 파일을 WAV로 변환
        audio = AudioSegment.from_file(audio_file)
        audio = audio.set_frame_rate(16000).set_channels(1)

        # 임시 WAV 파일 생성
        with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
            audio.export(tmp_file.name, format="wav")

            # 음성 인식 수행
            with sr.AudioFile(tmp_file.name) as source:
                audio_data = recognizer.record(source)

            # Google API로 텍스트 변환 (한국어)
            text_korean = recognizer.recognize_google(audio_data, language='ko-KR')
            # 영어도 시도
            text_english = recognizer.recognize_google(audio_data, language='en-US')

            os.unlink(tmp_file.name)  # 임시 파일 삭제

            return f"🇰🇷 한국어: {text_korean}\n\n🇺🇸 English: {text_english}"

    except sr.UnknownValueError:
        return "음성을 인식할 수 없습니다. 더 명확하게 말해주세요."
    except sr.RequestError as e:
        return f"Google Speech Recognition 서비스 오류: {e}"
    except Exception as e:
        return f"오류가 발생했습니다: {str(e)}"

# 방법 2: OpenAI Whisper 모델 사용 (오프라인 가능)
class WhisperTranscriber:
    def __init__(self):
        self.model = None
        self.model_size = "base"  # tiny, base, small, medium, large

    def load_model(self, model_size):
        """Whisper 모델 로드"""
        try:
            self.model_size = model_size
            self.model = whisper.load_model(model_size)
            return f"✅ Whisper {model_size} 모델이 로드되었습니다."
        except Exception as e:
            return f"❌ 모델 로드 실패: {str(e)}"

    def transcribe(self, audio_file):
        """Whisper로 음성 인식"""
        if audio_file is None:
            return "음성 파일을 업로드해주세요."

        if self.model is None:
            return "먼저 모델을 로드해주세요."

        try:
            # Whisper로 전사
            result = self.model.transcribe(audio_file, language='ko')  # 한국어 우선

            # 결과 포맷팅
            text = result["text"]
            language = result.get("language", "unknown")

            # 세그먼트별 상세 정보
            segments_info = ""
            if "segments" in result:
                segments_info = "\n\n📋 상세 분석:\n"
                for i, segment in enumerate(result["segments"][:5]):  # 처음 5개만
                    start = segment["start"]
                    end = segment["end"]
                    text_segment = segment["text"]
                    segments_info += f"[{start:.1f}s - {end:.1f}s] {text_segment}\n"

            return f"""
🎯 인식된 텍스트:
{text}

🌍 감지된 언어: {language}
🎚️ 모델: Whisper {self.model_size}
{segments_info}
            """.strip()

        except Exception as e:
            return f"음성 인식 중 오류 발생: {str(e)}"

# Whisper 인스턴스 생성
whisper_transcriber = WhisperTranscriber()

# 방법 3: 실시간 음성 인식 (마이크 입력)
def transcribe_microphone(audio_data):
    """마이크 입력을 실시간으로 인식"""
    if audio_data is None:
        return "마이크로 음성을 녹음해주세요."

    try:
        recognizer = sr.Recognizer()

        # 오디오 데이터 처리
        sample_rate, audio_array = audio_data

        # numpy 배열을 AudioSegment로 변환
        audio_segment = AudioSegment(
            audio_array.tobytes(),
            frame_rate=sample_rate,
            sample_width=audio_array.dtype.itemsize,
            channels=1
        )

        # 임시 파일로 저장
        with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
            audio_segment.export(tmp_file.name, format="wav")

            with sr.AudioFile(tmp_file.name) as source:
                audio = recognizer.record(source)

            # 한국어와 영어로 인식 시도
            try:
                text_ko = recognizer.recognize_google(audio, language='ko-KR')
                result = f"🇰🇷 {text_ko}"
            except:
                try:
                    text_en = recognizer.recognize_google(audio, language='en-US')
                    result = f"🇺🇸 {text_en}"
                except:
                    result = "음성을 인식할 수 없습니다."

            os.unlink(tmp_file.name)
            return result

    except Exception as e:
        return f"오류: {str(e)}"

# Gradio 인터페이스 생성
with gr.Blocks(
    theme=gr.themes.Soft(),
    title="🎤 AI 음성 인식 스튜디오",
    css="""
    .gradio-container {
        max-width: 1200px;
        margin: 0 auto;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
    }

    .main-header {
        text-align: center;
        color: white;
        padding: 2rem 0;
        text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
    }

    .method-card {
        background: rgba(255, 255, 255, 0.95);
        border-radius: 20px;
        padding: 2rem;
        margin: 1rem;
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
        backdrop-filter: blur(10px);
        border: 1px solid rgba(255, 255, 255, 0.2);
    }

    .upload-area {
        border: 2px dashed #cbd5e0;
        border-radius: 12px;
        padding: 2rem;
        text-align: center;
        transition: all 0.3s ease;
    }

    .upload-area:hover {
        border-color: #4299e1;
        background-color: #f7fafc;
    }

    .btn-primary {
        background: linear-gradient(45deg, #4299e1, #3182ce) !important;
        border: none !important;
        border-radius: 25px !important;
        padding: 12px 24px !important;
        font-weight: 600 !important;
    }

    .status-success {
        color: #38a169;
        font-weight: 600;
    }

    .status-error {
        color: #e53e3e;
        font-weight: 600;
    }
    """
) as demo:

    gr.HTML("""

        <h1>🎤 AI 음성 인식 스튜디오</h1>
        <p>다양한 방법으로 음성을 텍스트로 변환하세요</p>

    """)

    with gr.Tabs():
        # 탭 1: 파일 업로드 (Google API)
        with gr.TabItem("📁 파일 업로드 (Google)", elem_classes=["method-card"]):
            gr.Markdown("""
            ### 🌐 Google Speech Recognition
            음성 파일을 업로드하여 텍스트로 변환합니다. (인터넷 연결 필요)
            지원 형식: WAV, MP3, M4A, FLAC
            """)

            with gr.Row():
                with gr.Column():
                    audio_upload = gr.Audio(
                        label="🎵 음성 파일 업로드",
                        type="filepath",
                        elem_classes=["upload-area"]
                    )

                    transcribe_btn = gr.Button(
                        "🚀 텍스트 변환",
                        variant="primary",
                        size="lg"
                    )

                with gr.Column():
                    google_output = gr.Textbox(
                        label="📝 인식 결과",
                        lines=8,
                        placeholder="여기에 변환된 텍스트가 표시됩니다..."
                    )

            transcribe_btn.click(
                transcribe_with_google,
                inputs=audio_upload,
                outputs=google_output
            )

        # 탭 2: Whisper 모델
        with gr.TabItem("🧠 Whisper AI", elem_classes=["method-card"]):
            gr.Markdown("""
            ### 🤖 OpenAI Whisper
            고성능 AI 모델로 정확한 음성 인식 (오프라인 가능)
            """)

            with gr.Row():
                with gr.Column():
                    # 모델 선택 및 로드
                    model_selector = gr.Dropdown(
                        choices=["tiny", "base", "small", "medium", "large"],
                        value="base",
                        label="🎯 Whisper 모델 크기",
                        info="large가 가장 정확하지만 느림"
                    )

                    load_model_btn = gr.Button("📥 모델 로드", variant="secondary")
                    model_status = gr.Textbox(
                        label="모델 상태", 
                        value="모델을 선택하고 로드 버튼을 눌러주세요.",
                        interactive=False,
                        lines=2
                    )

                    whisper_audio = gr.Audio(
                        label="🎵 음성 파일",
                        type="filepath"
                    )

                    whisper_transcribe_btn = gr.Button(
                        "🎯 Whisper 인식",
                        variant="primary",
                        size="lg"
                    )

                with gr.Column():
                    whisper_output = gr.Textbox(
                        label="🤖 Whisper 결과",
                        lines=12,
                        placeholder="Whisper AI가 분석한 결과가 여기에 표시됩니다..."
                    )

            # 이벤트 핸들러
            load_model_btn.click(
                whisper_transcriber.load_model,
                inputs=model_selector,
                outputs=model_status
            )

            whisper_transcribe_btn.click(
                whisper_transcriber.transcribe,
                inputs=whisper_audio,
                outputs=whisper_output
            )

        # 탭 3: 실시간 마이크 인식
        with gr.TabItem("🎙️ 실시간 마이크", elem_classes=["method-card"]):
            gr.Markdown("""
            ### 🎙️ 실시간 음성 인식
            마이크로 직접 녹음하여 즉시 텍스트로 변환
            """)

            with gr.Row():
                with gr.Column():
                    microphone = gr.Audio(
                        label="🎤 마이크 녹음",
                        sources=["microphone"],
                        type="numpy",
                        streaming=False
                    )

                    mic_transcribe_btn = gr.Button(
                        "🎯 음성 인식",
                        variant="primary",
                        size="lg"
                    )

                    # 녹음 팁
                    gr.Markdown("""
                    💡 녹음 팁:
                    - 조용한 환경에서 녹음하세요
                    - 마이크에 가까이서 명확하게 말하세요
                    - 3-10초 정도의 짧은 문장이 가장 좋습니다
                    """)

                with gr.Column():
                    microphone_output = gr.Textbox(
                        label="🎙️ 실시간 인식 결과",
                        lines=8,
                        placeholder="마이크로 녹음하고 인식 버튼을 눌러주세요..."
                    )

                    # 음성 품질 정보
                    audio_info = gr.Textbox(
                        label="📊 오디오 정보",
                        lines=3,
                        interactive=False
                    )

            def analyze_microphone_audio(audio_data):
                if audio_data is None:
                    return "녹음된 데이터가 없습니다.", "정보 없음"

                sample_rate, audio_array = audio_data
                duration = len(audio_array) / sample_rate
                max_amplitude = np.max(np.abs(audio_array))

                # 음성 인식 수행
                recognition_result = transcribe_microphone(audio_data)

                # 오디오 정보
                info = f"""
샘플링 레이트: {sample_rate} Hz
녹음 길이: {duration:.2f}
최대 진폭: {max_amplitude:.3f}
품질: {'좋음' if max_amplitude > 0.1 else '낮음'}
                """.strip()

                return recognition_result, info

            mic_transcribe_btn.click(
                analyze_microphone_audio,
                inputs=microphone,
                outputs=[microphone_output, audio_info]
            )

        # 탭 4: 배치 처리
        with gr.TabItem("📦 배치 처리", elem_classes=["method-card"]):
            gr.Markdown("""
            ### 📦 다중 파일 음성 인식
            여러 음성 파일을 한 번에 처리합니다.
            """)

            with gr.Row():
                with gr.Column():
                    file_list = gr.File(
                        label="🗂️ 음성 파일들",
                        file_count="multiple",
                        file_types=["audio"]
                    )

                    batch_method = gr.Radio(
                        choices=["Google API", "Whisper"],
                        label="인식 방법",
                        value="Google API"
                    )

                    batch_process_btn = gr.Button(
                        "🔄 배치 처리 시작",
                        variant="primary",
                        size="lg"
                    )

                with gr.Column():
                    batch_output = gr.Textbox(
                        label="📊 배치 처리 결과",
                        lines=15,
                        placeholder="파일들을 선택하고 배치 처리를 시작하세요..."
                    )

                    # 진행률 표시
                    progress_bar = gr.HTML("""

                    """)

            def process_batch_files(files, method):
                if not files:
                    return "처리할 파일을 선택해주세요."

                results = []
                total_files = len(files)

                for i, file in enumerate(files):
                    try:
                        filename = os.path.basename(file.name)

                        if method == "Google API":
                            result = transcribe_with_google(file.name)
                        else:  # Whisper
                            if whisper_transcriber.model is None:
                                whisper_transcriber.load_model("base")
                            result = whisper_transcriber.transcribe(file.name)

                        results.append(f"""
📁 파일: {filename}
{result}
{'='*50}
                        """)

                    except Exception as e:
                        results.append(f"❌ {filename}: 처리 실패 - {str(e)}\n{'='*50}\n")

                return "\n".join(results)

            batch_process_btn.click(
                process_batch_files,
                inputs=[file_list, batch_method],
                outputs=batch_output
            )

    # 하단 정보
    gr.Markdown("""
    ---
    ### 📚 사용 가이드

    🌐 Google API: 빠르고 정확하지만 인터넷 연결 필요
    🧠 Whisper: 오프라인 가능, 매우 정확하지만 초기 모델 로드 시간 필요
    🎙️ 실시간: 마이크로 직접 녹음하여 즉시 변환
    📦 배치: 여러 파일을 한 번에 처리

    💡 팁: 명확한 발음과 조용한 환경에서 최상의 결과를 얻을 수 있습니다.
    """)

# Colab에서 실행
if __name__ == "__main__":
    demo.launch(
        share=True,  # 공유 링크 생성
        debug=True,  # 디버그 모드
        server_name="0.0.0.0",  # Colab용 설정
        server_port=7860
    )