"""
오디오 입력 컴포넌트 - Voice Semantle 스타일
애니메이션풍 하늘색 테마의 음성 입력 인터페이스
커스텀 버튼으로 Gradio Audio 컴포넌트 제어
👨💻 담당: 개발자 A
"""
import gradio as gr
class AudioInputComponent:
"""Voice Semantle 스타일 오디오 입력 컴포넌트"""
# 마이크 버튼 HTML 템플릿
MIC_BUTTON_HTML_TEMPLATE = """
Click the play button to start game
"""
MIC_BUTTON_CSS_TEMPLATE = """
.mic-section {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 30px 0;
width: 100%;
}
.mic-status {
font-size: 13px;
color: #5a7a9a;
text-align: center;
min-height: 20px;
}
.mic-btn {
width: 80px;
height: 80px;
border-radius: 50%;
border: 3px solid #4db8ff;
background: linear-gradient(135deg, #4db8ff 0%, #5bc0eb 100%);
color: white;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4px 16px rgba(77, 184, 255, 0.4);
padding: 0 !important;
}
.mic-btn:hover {
transform: scale(1.08);
box-shadow: 0 6px 24px rgba(77, 184, 255, 0.5);
}
.mic-btn:active {
transform: scale(0.95);
}
.mic-btn.recording {
background: linear-gradient(135deg, #ff9f43 0%, #e08b2d 100%);
border-color: #ff9f43;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 159, 67, 0.5); }
50% { box-shadow: 0 0 0 15px rgba(255, 159, 67, 0); }
}
/* 다크모드 */
.dark .mic-status {
color: #818384;
}
"""
# JavaScript: 커스텀 버튼 클릭 시 Gradio Audio 컴포넌트 직접 제어
MIC_BUTTON_JS = """
const micBtn = element.querySelector('#mic-btn');
const uploadLink = element.querySelector('#upload-link');
const statusText = element.querySelector('#mic-status');
// 오디오 wrapper 표시 함수
function showAudioWrapper() {
const wrapper = document.querySelector('#audio-wrapper');
if (wrapper) {
wrapper.style.display = 'block';
}
}
// 마이크 버튼 클릭 → 오디오 컴포넌트 표시 + 녹음 시작
micBtn.addEventListener('click', () => {
showAudioWrapper();
statusText.textContent = 'Ready to play';
});
"""
def __init__(self, validator):
"""
Args:
validator: AudioValidator 인스턴스
"""
self.validator = validator
self.audio_input = None
self.submit_btn = None
self.mic_button_html = None
self.audio_wrapper = None
def render(self):
"""
Wordle 스타일 오디오 입력 UI 렌더링
Returns:
tuple: (audio_input, submit_btn)
"""
# 마이크 섹션 시각적 요소 (Gradio 6 html_template + js_on_load)
self.mic_button_html = gr.HTML(
value=self.MIC_BUTTON_HTML_TEMPLATE,
css_template=self.MIC_BUTTON_CSS_TEMPLATE,
js_on_load=self.MIC_BUTTON_JS,
elem_id="mic-section",
padding=False
)
# Gradio Audio 컴포넌트 (CSS로 처음에는 숨김)
self.audio_wrapper = gr.Column(elem_id="audio-wrapper")
with self.audio_wrapper:
self.audio_input = gr.Audio(
label="Audio recording",
type="filepath",
sources=["microphone", "upload"],
elem_id="audio-input"
)
# 검증 버튼 (Gradio Button으로 이벤트 처리)
self.submit_btn = gr.Button(
"SUBMIT",
variant="primary",
size="lg",
elem_id="verify-btn"
)
return self.audio_input, self.submit_btn
def setup_events(self, validate_handler, inputs, outputs):
"""
이벤트 바인딩
Args:
validate_handler: 검증 핸들러 함수
inputs: 입력 컴포넌트 리스트
outputs: 출력 컴포넌트 리스트
"""
# 검증 버튼 클릭
self.submit_btn.click(
fn=validate_handler,
inputs=inputs,
outputs=outputs
)