import gradio as gr
import torch
import librosa
from transformers import AutoProcessor, AutoModelForSpeechSeq2Seq, pipeline
# -------------------------------
# 1) STT 모델 로드 (Whisper 기반)
# -------------------------------
processor = AutoProcessor.from_pretrained("openai/whisper-small")
model = AutoModelForSpeechSeq2Seq.from_pretrained("openai/whisper-small")
# -------------------------------
# 2) 감정 분석 모델 로드
# -------------------------------
sentiment_pipe = pipeline(
"sentiment-analysis",
model="monologg/koelectra-base-v3-discriminator",
tokenizer="monologg/koelectra-base-v3-discriminator"
)
# -------------------------------
# 3) 오디오 -> 텍스트
# -------------------------------
def transcribe_audio(audio_path):
speech, _ = librosa.load(audio_path, sr=16000)
input_features = processor(speech, sampling_rate=16000, return_tensors="pt").input_features
predicted_ids = model.generate(input_features)
transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
return transcription
# -------------------------------
# 4) 감정 레이블 -> 색상 매핑
# -------------------------------
def label_to_color(label):
if label in ["4 stars", "5 stars", "LABEL_4", "LABEL_5"]:
return "green" # 긍정
elif label in ["1 star", "2 stars", "LABEL_1", "LABEL_2"]:
return "red" # 부정
else: # 중립
return "orange"
# -------------------------------
# 5) 텍스트 감정 분석 (문장 전체)
# -------------------------------
def sentiment_whole_text(text):
res = sentiment_pipe(text)[0]
label = res['label']
score = res['score']
color = label_to_color(label)
styled_text = f"{text}"
legend = (
"
"
"색상 설명: "
"녹색=긍정, "
"빨강=부정, "
"주황=중립/보통"
"
"
)
return styled_text + legend, f"감정: {label}, 신뢰도: {score:.2f}"
# -------------------------------
# 6) 텍스트 감정 분석 (단어별)
# -------------------------------
def sentiment_word_level(text):
words = text.split()
styled_words = []
for w in words:
res = sentiment_pipe(w)[0]
label = res['label']
color = label_to_color(label)
styled_words.append(f"{w}")
styled_text = " ".join(styled_words)
legend = (
""
"색상 설명: "
"녹색=긍정, "
"빨강=부정, "
"주황=중립/보통"
"
"
)
return styled_text + legend, "단어별 감정 표시 완료"
# -------------------------------
# 7) 오디오 -> 텍스트 + 감정 분석 (문장+단어)
# -------------------------------
def process_audio_full(audio_file):
text = transcribe_audio(audio_file)
whole_text_result, whole_text_score = sentiment_whole_text(text)
word_level_result, word_level_status = sentiment_word_level(text)
return text, whole_text_result, whole_text_score, word_level_result, word_level_status
# -------------------------------
# 8) Gradio UI 구성
# -------------------------------
with gr.Blocks() as demo:
gr.Markdown("# 🎤 오디오/텍스트 → 감정 분석")
with gr.Tabs():
# ------------------- 오디오 -> 텍스트 -------------------
with gr.Tab("오디오 → 텍스트"):
audio_input_1 = gr.Audio(label="음성 업로드", type="filepath")
audio_text_output = gr.Textbox(label="변환된 텍스트")
audio_transcribe_btn = gr.Button("텍스트 추출")
audio_transcribe_btn.click(fn=transcribe_audio, inputs=[audio_input_1], outputs=[audio_text_output])
# ------------------- 텍스트 -> 감정 분석 -------------------
with gr.Tab("텍스트 → 감정 분석"):
text_input = gr.Textbox(label="텍스트 입력")
sentiment_whole_output = gr.HTML(label="문장 단위 감정 분석")
sentiment_whole_score = gr.Markdown(label="감정 결과")
sentiment_word_output = gr.HTML(label="단어 단위 감정 분석")
sentiment_btn = gr.Button("감정 분석")
def analyze_text(text):
whole_res, whole_score = sentiment_whole_text(text)
word_res, word_status = sentiment_word_level(text)
return whole_res, whole_score, word_res
sentiment_btn.click(
fn=analyze_text,
inputs=[text_input],
outputs=[sentiment_whole_output, sentiment_whole_score, sentiment_word_output]
)
# ------------------- 오디오 → 텍스트 + 감정 분석 -------------------
with gr.Tab("오디오 → 텍스트 + 감정 분석"):
audio_input_2 = gr.Audio(label="음성 업로드", type="filepath")
audio_text_output_2 = gr.Textbox(label="변환된 텍스트")
sentiment_whole_output_2 = gr.HTML(label="문장 단위 감정 분석")
sentiment_whole_score_2 = gr.Markdown(label="감정 결과")
sentiment_word_output_2 = gr.HTML(label="단어 단위 감정 분석")
audio_process_btn = gr.Button("분석 시작")
def process_audio_tab(audio_file):
text, whole_res, whole_score, word_res, word_status = process_audio_full(audio_file)
return text, whole_res, whole_score, word_res
audio_process_btn.click(
fn=process_audio_tab,
inputs=[audio_input_2],
outputs=[audio_text_output_2, sentiment_whole_output_2, sentiment_whole_score_2, sentiment_word_output_2]
)
demo.launch()