Update app.py
Browse files
    	
        app.py
    CHANGED
    
    | @@ -4,11 +4,19 @@ import librosa | |
| 4 | 
             
            from transformers import pipeline
         | 
| 5 | 
             
            from datetime import datetime
         | 
| 6 | 
             
            import os
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 7 |  | 
| 8 | 
             
            # AI 모델 초기화
         | 
| 9 | 
             
            speech_recognizer = pipeline(
         | 
| 10 | 
             
                "automatic-speech-recognition",
         | 
| 11 | 
            -
                model="kresnik/wav2vec2-large-xlsr-korean" | 
| 12 | 
             
            )
         | 
| 13 | 
             
            emotion_classifier = pipeline(
         | 
| 14 | 
             
                "audio-classification",
         | 
| @@ -21,13 +29,12 @@ text_analyzer = pipeline( | |
| 21 |  | 
| 22 | 
             
            def create_interface():
         | 
| 23 | 
             
                with gr.Blocks(theme=gr.themes.Soft()) as app:
         | 
| 24 | 
            -
                    # 상태 관리
         | 
| 25 | 
             
                    state = gr.State({
         | 
| 26 | 
             
                        "user_name": "",
         | 
| 27 | 
             
                        "reflections": [],
         | 
| 28 | 
             
                        "voice_analysis": None,
         | 
| 29 | 
             
                        "final_prompt": "",
         | 
| 30 | 
            -
                        "generated_images": [] | 
| 31 | 
             
                    })
         | 
| 32 |  | 
| 33 | 
             
                    # 헤더
         | 
| @@ -44,10 +51,14 @@ def create_interface(): | |
| 44 | 
             
                        # 청신
         | 
| 45 | 
             
                        with gr.Tab("청신"):
         | 
| 46 | 
             
                            with gr.Row():
         | 
|  | |
|  | |
| 47 | 
             
                                audio = gr.Audio(
         | 
| 48 | 
            -
                                    value= | 
| 49 | 
             
                                    type="filepath",
         | 
| 50 | 
            -
                                    label="온천천의 소리"
         | 
|  | |
|  | |
| 51 | 
             
                                )
         | 
| 52 | 
             
                                with gr.Column():
         | 
| 53 | 
             
                                    reflection_input = gr.Textbox(
         | 
| @@ -64,14 +75,16 @@ def create_interface(): | |
| 64 | 
             
                        with gr.Tab("기원"):
         | 
| 65 | 
             
                            gr.Markdown("## 기원 - 목소리로 전하기")
         | 
| 66 | 
             
                            with gr.Row():
         | 
| 67 | 
            -
                                 | 
| 68 | 
            -
             | 
| 69 | 
            -
                                     | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
|  | |
|  | |
|  | |
| 73 |  | 
| 74 | 
            -
                                # 분석 결과
         | 
| 75 | 
             
                                with gr.Column():
         | 
| 76 | 
             
                                    transcribed_text = gr.Textbox(
         | 
| 77 | 
             
                                        label="인식된 텍스트",
         | 
| @@ -85,9 +98,7 @@ def create_interface(): | |
| 85 | 
             
                                        label="텍스트 감정 분석",
         | 
| 86 | 
             
                                        interactive=False
         | 
| 87 | 
             
                                    )
         | 
| 88 | 
            -
                                     | 
| 89 | 
            -
                                        label="상세 분석 결과"
         | 
| 90 | 
            -
                                    )
         | 
| 91 |  | 
| 92 | 
             
                        # 송신
         | 
| 93 | 
             
                        with gr.Tab("송신"):
         | 
| @@ -97,135 +108,91 @@ def create_interface(): | |
| 97 | 
             
                                    label="생성된 프롬프트",
         | 
| 98 | 
             
                                    interactive=False
         | 
| 99 | 
             
                                )
         | 
|  | |
| 100 | 
             
                                gallery = gr.Gallery(
         | 
| 101 | 
             
                                    label="시각화 결과",
         | 
| 102 | 
            -
                                    columns=2
         | 
|  | |
|  | |
| 103 | 
             
                                )
         | 
| 104 | 
            -
                                share_btn = gr.Button("결과 공유하기")
         | 
| 105 |  | 
| 106 | 
            -
                    def  | 
| 107 | 
            -
                        """ | 
| 108 | 
            -
                         | 
| 109 | 
            -
                            if audio_path is None:
         | 
| 110 | 
            -
                                return state, "음성 입력이 필요합니다.", "", "", {}
         | 
| 111 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 112 | 
             
                            # 오디오 로드
         | 
| 113 | 
             
                            y, sr = librosa.load(audio_path, sr=16000)
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                            #  | 
| 116 | 
             
                            transcription = speech_recognizer(y)
         | 
| 117 | 
            -
                             | 
| 118 | 
            -
             | 
| 119 | 
            -
                            #  | 
| 120 | 
            -
                            features = {
         | 
| 121 | 
            -
                                "energy": float(np.mean(librosa.feature.rms(y=y))),
         | 
| 122 | 
            -
                                "pitch": float(np.mean(librosa.piptrack(y=y, sr=sr)[1])),
         | 
| 123 | 
            -
                                "tempo": float(librosa.beat.tempo(y)[0]),
         | 
| 124 | 
            -
                                "zero_crossing_rate": float(np.mean(librosa.feature.zero_crossing_rate(y)))
         | 
| 125 | 
            -
                            }
         | 
| 126 | 
            -
             | 
| 127 | 
            -
                            # 3. 음성 감정 분석
         | 
| 128 | 
             
                            voice_emotions = emotion_classifier(y)
         | 
| 129 | 
            -
                             | 
| 130 | 
            -
             | 
| 131 | 
            -
                            # 4. 텍스트 감정 분석
         | 
| 132 | 
            -
                            text_sentiment = text_analyzer(spoken_text)[0]
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                            # 결과 종합
         | 
| 135 | 
            -
                            analysis_result = {
         | 
| 136 | 
            -
                                "acoustic_features": features,
         | 
| 137 | 
            -
                                "voice_emotion": primary_emotion,
         | 
| 138 | 
            -
                                "text_sentiment": text_sentiment
         | 
| 139 | 
            -
                            }
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                            # 프롬프트 생성
         | 
| 142 | 
            -
                            prompt = generate_art_prompt(spoken_text, analysis_result, state["reflections"])
         | 
| 143 | 
            -
                            state["final_prompt"] = prompt
         | 
| 144 | 
            -
             | 
| 145 | 
             
                            return (
         | 
| 146 | 
             
                                state,
         | 
| 147 | 
            -
                                 | 
| 148 | 
            -
                                f"음성 감정: { | 
| 149 | 
             
                                f"텍스트 감정: {text_sentiment['label']} ({text_sentiment['score']:.2f})",
         | 
| 150 | 
            -
                                 | 
| 151 | 
             
                            )
         | 
| 152 | 
            -
             | 
| 153 | 
             
                        except Exception as e:
         | 
| 154 | 
            -
                            return state, f"오류 발생: {str(e)}", "", "",  | 
| 155 | 
            -
             | 
| 156 | 
            -
                    def generate_art_prompt(text, analysis, reflections):
         | 
| 157 | 
            -
                        """예술적 프롬프트 생성"""
         | 
| 158 | 
            -
                        # 음성 감정
         | 
| 159 | 
            -
                        voice_emotion = analysis["voice_emotion"]["label"]
         | 
| 160 | 
            -
                        # 텍스트 감정
         | 
| 161 | 
            -
                        text_sentiment = analysis["text_sentiment"]["label"]
         | 
| 162 | 
            -
                        # 에너지 레벨
         | 
| 163 | 
            -
                        energy = analysis["acoustic_features"]["energy"]
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                        # 감정에 따른 색상 매핑
         | 
| 166 | 
            -
                        emotion_colors = {
         | 
| 167 | 
            -
                            "happy": "따뜻한 노란색과 주황색",
         | 
| 168 | 
            -
                            "sad": "깊은 파랑색과 보라색",
         | 
| 169 | 
            -
                            "angry": "강렬한 빨강색과 검정색",
         | 
| 170 | 
            -
                            "neutral": "부드러운 회색과 베이지색"
         | 
| 171 | 
            -
                        }
         | 
| 172 | 
            -
             | 
| 173 | 
            -
                        # 기본 프롬프트 구성
         | 
| 174 | 
            -
                        prompt = f"한국 전통 민화 스타일의 추상화, {emotion_colors.get(voice_emotion, '자연스러운 색상')} 사용. "
         | 
| 175 | 
            -
                        prompt += f"음성의 감정({voice_emotion})과 텍스트의 감정({text_sentiment})이 조화를 이루며, "
         | 
| 176 | 
            -
                        prompt += f"에너지 레벨({energy:.2f})을 통해 화면의 동적인 느낌을 표현. "
         | 
| 177 | 
            -
             | 
| 178 | 
            -
                        # 이전 감상들 반영
         | 
| 179 | 
            -
                        if reflections:
         | 
| 180 | 
            -
                            prompt += "이전 감상들의 정서를 배경에 은은하게 담아내기. "
         | 
| 181 | 
            -
             | 
| 182 | 
            -
                        return prompt
         | 
| 183 | 
            -
             | 
| 184 | 
            -
                    def save_reflection(text, state):
         | 
| 185 | 
            -
                        """감상 저장 및 감정 분석"""
         | 
| 186 | 
            -
                        if not text.strip():
         | 
| 187 | 
            -
                            return state, state["reflections"]
         | 
| 188 | 
            -
             | 
| 189 | 
            -
                        current_time = datetime.now().strftime("%H:%M:%S")
         | 
| 190 | 
            -
                        sentiment = text_analyzer(text)[0]
         | 
| 191 | 
            -
                        new_reflection = [current_time, text, f"{sentiment['label']} ({sentiment['score']:.2f})"]
         | 
| 192 | 
            -
                        
         | 
| 193 | 
            -
                        state["reflections"].append(new_reflection)
         | 
| 194 | 
            -
                        return state, state["reflections"]
         | 
| 195 |  | 
| 196 | 
            -
                    def  | 
| 197 | 
            -
                        """ | 
| 198 | 
            -
                         | 
| 199 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 200 |  | 
| 201 | 
             
                    # 이벤트 연결
         | 
| 202 | 
             
                    start_btn.click(
         | 
| 203 | 
            -
                        fn= | 
| 204 | 
             
                        inputs=[name_input],
         | 
| 205 | 
             
                        outputs=[user_display, tabs]
         | 
| 206 | 
             
                    )
         | 
| 207 |  | 
| 208 | 
             
                    save_btn.click(
         | 
| 209 | 
            -
                        fn=save_reflection,
         | 
| 210 | 
             
                        inputs=[reflection_input, state],
         | 
| 211 | 
             
                        outputs=[state, reflections_display]
         | 
| 212 | 
             
                    )
         | 
| 213 |  | 
| 214 | 
            -
                     | 
| 215 | 
            -
                        fn= | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 216 | 
             
                        inputs=[voice_input, state],
         | 
| 217 | 
            -
                        outputs=[
         | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
                        ]
         | 
| 224 | 
             
                    )
         | 
| 225 |  | 
| 226 | 
             
                return app
         | 
| 227 |  | 
| 228 | 
            -
            # 앱 실행
         | 
| 229 | 
             
            if __name__ == "__main__":
         | 
| 230 | 
             
                demo = create_interface()
         | 
| 231 | 
             
                demo.launch()
         | 
|  | |
| 4 | 
             
            from transformers import pipeline
         | 
| 5 | 
             
            from datetime import datetime
         | 
| 6 | 
             
            import os
         | 
| 7 | 
            +
            from diffusers import StableDiffusionPipeline
         | 
| 8 | 
            +
            import torch
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            # 스테이블 디퓨전 초기화
         | 
| 11 | 
            +
            model_id = "runwayml/stable-diffusion-v1-5"
         | 
| 12 | 
            +
            pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
         | 
| 13 | 
            +
            if torch.cuda.is_available():
         | 
| 14 | 
            +
                pipe = pipe.to("cuda")
         | 
| 15 |  | 
| 16 | 
             
            # AI 모델 초기화
         | 
| 17 | 
             
            speech_recognizer = pipeline(
         | 
| 18 | 
             
                "automatic-speech-recognition",
         | 
| 19 | 
            +
                model="kresnik/wav2vec2-large-xlsr-korean"
         | 
| 20 | 
             
            )
         | 
| 21 | 
             
            emotion_classifier = pipeline(
         | 
| 22 | 
             
                "audio-classification",
         | 
|  | |
| 29 |  | 
| 30 | 
             
            def create_interface():
         | 
| 31 | 
             
                with gr.Blocks(theme=gr.themes.Soft()) as app:
         | 
|  | |
| 32 | 
             
                    state = gr.State({
         | 
| 33 | 
             
                        "user_name": "",
         | 
| 34 | 
             
                        "reflections": [],
         | 
| 35 | 
             
                        "voice_analysis": None,
         | 
| 36 | 
             
                        "final_prompt": "",
         | 
| 37 | 
            +
                        "generated_images": []
         | 
| 38 | 
             
                    })
         | 
| 39 |  | 
| 40 | 
             
                    # 헤더
         | 
|  | |
| 51 | 
             
                        # 청신
         | 
| 52 | 
             
                        with gr.Tab("청신"):
         | 
| 53 | 
             
                            with gr.Row():
         | 
| 54 | 
            +
                                # 절대 경로로 변경
         | 
| 55 | 
            +
                                audio_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "assets", "main_music.mp3"))
         | 
| 56 | 
             
                                audio = gr.Audio(
         | 
| 57 | 
            +
                                    value=audio_path,
         | 
| 58 | 
             
                                    type="filepath",
         | 
| 59 | 
            +
                                    label="온천천의 소리",
         | 
| 60 | 
            +
                                    interactive=False,
         | 
| 61 | 
            +
                                    autoplay=True
         | 
| 62 | 
             
                                )
         | 
| 63 | 
             
                                with gr.Column():
         | 
| 64 | 
             
                                    reflection_input = gr.Textbox(
         | 
|  | |
| 75 | 
             
                        with gr.Tab("기원"):
         | 
| 76 | 
             
                            gr.Markdown("## 기원 - 목소리로 전하기")
         | 
| 77 | 
             
                            with gr.Row():
         | 
| 78 | 
            +
                                with gr.Column():
         | 
| 79 | 
            +
                                    record_btn = gr.Button("🎤 녹음 시작/중지")
         | 
| 80 | 
            +
                                    voice_input = gr.Audio(
         | 
| 81 | 
            +
                                        label="나누고 싶은 이야기를 들려주세요",
         | 
| 82 | 
            +
                                        sources=["microphone"],
         | 
| 83 | 
            +
                                        type="filepath",
         | 
| 84 | 
            +
                                        interactive=True
         | 
| 85 | 
            +
                                    )
         | 
| 86 | 
            +
                                    clear_btn = gr.Button("녹음 지우기")
         | 
| 87 |  | 
|  | |
| 88 | 
             
                                with gr.Column():
         | 
| 89 | 
             
                                    transcribed_text = gr.Textbox(
         | 
| 90 | 
             
                                        label="인식된 텍스트",
         | 
|  | |
| 98 | 
             
                                        label="텍스트 감정 분석",
         | 
| 99 | 
             
                                        interactive=False
         | 
| 100 | 
             
                                    )
         | 
| 101 | 
            +
                                    analyze_btn = gr.Button("분석하기")
         | 
|  | |
|  | |
| 102 |  | 
| 103 | 
             
                        # 송신
         | 
| 104 | 
             
                        with gr.Tab("송신"):
         | 
|  | |
| 108 | 
             
                                    label="생성된 프롬프트",
         | 
| 109 | 
             
                                    interactive=False
         | 
| 110 | 
             
                                )
         | 
| 111 | 
            +
                                generate_btn = gr.Button("이미지 생성하기")
         | 
| 112 | 
             
                                gallery = gr.Gallery(
         | 
| 113 | 
             
                                    label="시각화 결과",
         | 
| 114 | 
            +
                                    columns=2,
         | 
| 115 | 
            +
                                    show_label=True,
         | 
| 116 | 
            +
                                    elem_id="gallery"
         | 
| 117 | 
             
                                )
         | 
|  | |
| 118 |  | 
| 119 | 
            +
                    def clear_voice_input():
         | 
| 120 | 
            +
                        """음성 입력 초기화"""
         | 
| 121 | 
            +
                        return None
         | 
|  | |
|  | |
| 122 |  | 
| 123 | 
            +
                    def analyze_voice(audio_path, state):
         | 
| 124 | 
            +
                        """음성 분석"""
         | 
| 125 | 
            +
                        if audio_path is None:
         | 
| 126 | 
            +
                            return state, "음성을 먼저 녹음해주세요.", "", "", ""
         | 
| 127 | 
            +
                        
         | 
| 128 | 
            +
                        try:
         | 
| 129 | 
             
                            # 오디오 로드
         | 
| 130 | 
             
                            y, sr = librosa.load(audio_path, sr=16000)
         | 
| 131 | 
            +
                            
         | 
| 132 | 
            +
                            # 음성 인식
         | 
| 133 | 
             
                            transcription = speech_recognizer(y)
         | 
| 134 | 
            +
                            text = transcription["text"]
         | 
| 135 | 
            +
                            
         | 
| 136 | 
            +
                            # 감정 분석
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 137 | 
             
                            voice_emotions = emotion_classifier(y)
         | 
| 138 | 
            +
                            text_sentiment = text_analyzer(text)[0]
         | 
| 139 | 
            +
                            
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 140 | 
             
                            return (
         | 
| 141 | 
             
                                state,
         | 
| 142 | 
            +
                                text,
         | 
| 143 | 
            +
                                f"음성 감정: {voice_emotions[0]['label']} ({voice_emotions[0]['score']:.2f})",
         | 
| 144 | 
             
                                f"텍스트 감정: {text_sentiment['label']} ({text_sentiment['score']:.2f})",
         | 
| 145 | 
            +
                                "분석이 완료되었습니다."
         | 
| 146 | 
             
                            )
         | 
|  | |
| 147 | 
             
                        except Exception as e:
         | 
| 148 | 
            +
                            return state, f"오류 발생: {str(e)}", "", "", ""
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 149 |  | 
| 150 | 
            +
                    def generate_image(prompt, state):
         | 
| 151 | 
            +
                        """이미지 생성"""
         | 
| 152 | 
            +
                        try:
         | 
| 153 | 
            +
                            images = pipe(prompt).images
         | 
| 154 | 
            +
                            image_paths = []
         | 
| 155 | 
            +
                            for i, image in enumerate(images):
         | 
| 156 | 
            +
                                path = f"output_{i}.png"
         | 
| 157 | 
            +
                                image.save(path)
         | 
| 158 | 
            +
                                image_paths.append(path)
         | 
| 159 | 
            +
                            return image_paths
         | 
| 160 | 
            +
                        except Exception as e:
         | 
| 161 | 
            +
                            return []
         | 
| 162 |  | 
| 163 | 
             
                    # 이벤트 연결
         | 
| 164 | 
             
                    start_btn.click(
         | 
| 165 | 
            +
                        fn=lambda name: (f"# 환영합니다, {name}님의 디지털 굿판", gr.update(selected="청신")),
         | 
| 166 | 
             
                        inputs=[name_input],
         | 
| 167 | 
             
                        outputs=[user_display, tabs]
         | 
| 168 | 
             
                    )
         | 
| 169 |  | 
| 170 | 
             
                    save_btn.click(
         | 
| 171 | 
            +
                        fn=lambda text, state: save_reflection(text, state),
         | 
| 172 | 
             
                        inputs=[reflection_input, state],
         | 
| 173 | 
             
                        outputs=[state, reflections_display]
         | 
| 174 | 
             
                    )
         | 
| 175 |  | 
| 176 | 
            +
                    clear_btn.click(
         | 
| 177 | 
            +
                        fn=clear_voice_input,
         | 
| 178 | 
            +
                        inputs=[],
         | 
| 179 | 
            +
                        outputs=[voice_input]
         | 
| 180 | 
            +
                    )
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                    analyze_btn.click(
         | 
| 183 | 
            +
                        fn=analyze_voice,
         | 
| 184 | 
             
                        inputs=[voice_input, state],
         | 
| 185 | 
            +
                        outputs=[state, transcribed_text, voice_emotion, text_emotion, final_prompt]
         | 
| 186 | 
            +
                    )
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                    generate_btn.click(
         | 
| 189 | 
            +
                        fn=generate_image,
         | 
| 190 | 
            +
                        inputs=[final_prompt, state],
         | 
| 191 | 
            +
                        outputs=[gallery]
         | 
| 192 | 
             
                    )
         | 
| 193 |  | 
| 194 | 
             
                return app
         | 
| 195 |  | 
|  | |
| 196 | 
             
            if __name__ == "__main__":
         | 
| 197 | 
             
                demo = create_interface()
         | 
| 198 | 
             
                demo.launch()
         | 
