Update app.py
Browse files
app.py
CHANGED
@@ -2,6 +2,7 @@ import gradio as gr
|
|
2 |
import numpy as np
|
3 |
import librosa
|
4 |
from transformers import pipeline
|
|
|
5 |
from datetime import datetime
|
6 |
import os
|
7 |
import requests
|
@@ -23,6 +24,10 @@ text_analyzer = pipeline(
|
|
23 |
"sentiment-analysis",
|
24 |
model="nlptown/bert-base-multilingual-uncased-sentiment"
|
25 |
)
|
|
|
|
|
|
|
|
|
26 |
|
27 |
def generate_image_from_prompt(prompt):
|
28 |
"""HuggingFace Inference API를 통한 이미지 생성"""
|
@@ -134,43 +139,106 @@ def create_interface():
|
|
134 |
return None
|
135 |
|
136 |
def analyze_voice(audio_path, state):
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
|
175 |
def save_reflection(text, state):
|
176 |
"""감상 저장"""
|
|
|
2 |
import numpy as np
|
3 |
import librosa
|
4 |
from transformers import pipeline
|
5 |
+
import torch
|
6 |
from datetime import datetime
|
7 |
import os
|
8 |
import requests
|
|
|
24 |
"sentiment-analysis",
|
25 |
model="nlptown/bert-base-multilingual-uncased-sentiment"
|
26 |
)
|
27 |
+
korean_sentiment = pipeline(
|
28 |
+
"text-classification",
|
29 |
+
model="searle-j/korean_sentiment_analysis" # 한국어 감정 분석 모델
|
30 |
+
)
|
31 |
|
32 |
def generate_image_from_prompt(prompt):
|
33 |
"""HuggingFace Inference API를 통한 이미지 생성"""
|
|
|
139 |
return None
|
140 |
|
141 |
def analyze_voice(audio_path, state):
|
142 |
+
"""음성 분석 개선"""
|
143 |
+
if audio_path is None:
|
144 |
+
return state, "음성을 먼저 녹음해주세요.", "", "", ""
|
145 |
+
|
146 |
+
try:
|
147 |
+
# 오디오 로드
|
148 |
+
y, sr = librosa.load(audio_path, sr=16000)
|
149 |
+
|
150 |
+
# 1. 음향학적 특성 분석
|
151 |
+
acoustic_features = {
|
152 |
+
"energy": float(np.mean(librosa.feature.rms(y=y))),
|
153 |
+
"tempo": float(librosa.beat.tempo(y)[0]),
|
154 |
+
"pitch": float(np.mean(librosa.feature.zero_crossing_rate(y))),
|
155 |
+
"volume": float(np.mean(np.abs(y)))
|
156 |
+
}
|
157 |
+
|
158 |
+
# 음성의 특성에 따른 감정 매핑
|
159 |
+
voice_emotion = map_acoustic_to_emotion(acoustic_features)
|
160 |
+
|
161 |
+
# 2. 음성-텍스트 변환
|
162 |
+
transcription = speech_recognizer(y)
|
163 |
+
text = transcription["text"]
|
164 |
+
|
165 |
+
# 3. 텍스트 감정 분석
|
166 |
+
text_sentiment = korean_sentiment(text)[0]
|
167 |
+
|
168 |
+
# 결과 포맷팅
|
169 |
+
voice_result = f"음성 감정: {voice_emotion['emotion']} (강도: {voice_emotion['intensity']:.2f})"
|
170 |
+
text_result = f"텍스트 감정: {text_sentiment['label']} ({text_sentiment['score']:.2f})"
|
171 |
+
|
172 |
+
# 프롬프트 생성
|
173 |
+
prompt = generate_detailed_prompt(text, voice_emotion, text_sentiment, acoustic_features)
|
174 |
+
|
175 |
+
return (
|
176 |
+
state,
|
177 |
+
text,
|
178 |
+
voice_result,
|
179 |
+
text_result,
|
180 |
+
prompt
|
181 |
+
)
|
182 |
+
except Exception as e:
|
183 |
+
return state, f"오류 발생: {str(e)}", "", "", ""
|
184 |
+
|
185 |
+
def map_acoustic_to_emotion(features):
|
186 |
+
"""음향학적 특성을 감정으로 매핑"""
|
187 |
+
# 에너지 기반 감정 강도
|
188 |
+
intensity = features["energy"] * 100
|
189 |
+
|
190 |
+
# 음성 특성에 따른 감정 분류
|
191 |
+
if features["energy"] > 0.7:
|
192 |
+
if features["tempo"] > 120:
|
193 |
+
emotion = "기쁨/흥분"
|
194 |
+
else:
|
195 |
+
emotion = "분노/강조"
|
196 |
+
elif features["pitch"] > 0.6:
|
197 |
+
emotion = "놀람/관심"
|
198 |
+
elif features["energy"] < 0.3:
|
199 |
+
emotion = "슬픔/우울"
|
200 |
+
else:
|
201 |
+
emotion = "평온/중립"
|
202 |
+
|
203 |
+
return {
|
204 |
+
"emotion": emotion,
|
205 |
+
"intensity": intensity,
|
206 |
+
"features": features
|
207 |
+
}
|
208 |
+
|
209 |
+
def generate_detailed_prompt(text, voice_emotion, text_sentiment, acoustic_features):
|
210 |
+
"""더 상세한 프롬프트 생성"""
|
211 |
+
# 감정별 색상 매핑
|
212 |
+
emotion_colors = {
|
213 |
+
"기쁨/흥분": "밝은 노랑과 주황색",
|
214 |
+
"분노/강조": "강렬한 빨강과 검정",
|
215 |
+
"놀람/관심": "선명한 파랑과 보라",
|
216 |
+
"슬픔/우울": "어두운 파랑과 회색",
|
217 |
+
"평온/중립": "부드러운 초록과 베이지"
|
218 |
+
}
|
219 |
+
|
220 |
+
# 음성 특성에 따른 시각적 요소
|
221 |
+
visual_elements = {
|
222 |
+
"high_energy": "역동적인 붓질과 강한 대비",
|
223 |
+
"medium_energy": "균형잡힌 구도와 자연스러운 흐름",
|
224 |
+
"low_energy": "부드러운 그라데이션과 차분한 톤"
|
225 |
+
}
|
226 |
+
|
227 |
+
# 에너지 레벨 결정
|
228 |
+
energy_level = "medium_energy"
|
229 |
+
if acoustic_features["energy"] > 0.7:
|
230 |
+
energy_level = "high_energy"
|
231 |
+
elif acoustic_features["energy"] < 0.3:
|
232 |
+
energy_level = "low_energy"
|
233 |
+
|
234 |
+
# 프롬프트 구성
|
235 |
+
prompt = f"한국 전통 민화 스타일의 추상화, {emotion_colors.get(voice_emotion['emotion'], '자연스러운 색상')} 기반. "
|
236 |
+
prompt += f"{visual_elements[energy_level]}를 통해 감정의 깊이를 표현. "
|
237 |
+
prompt += f"음성의 {voice_emotion['emotion']} 감정과 텍스트의 {text_sentiment['label']} 감정이 조화를 이루며, "
|
238 |
+
prompt += f"목소리의 특징(강도:{voice_emotion['intensity']:.1f})을 화면의 동적인 요소로 표현. "
|
239 |
+
prompt += f"발화 내용 '{text}'의 의미를 은유적 이미지로 담아내기."
|
240 |
+
|
241 |
+
return prompt
|
242 |
|
243 |
def save_reflection(text, state):
|
244 |
"""감상 저장"""
|