A newer version of the Gradio SDK is available:
6.1.0
π¨ νλ‘ νΈμλ νμΌ κ΅¬μ‘° λ¬Έμ
π λλ ν 리 ꡬ쑰
audio_validation_app/
βββ app.py # κΈ°μ‘΄ νμΌ (λ°±μ
μ©)
βββ app_new.py # μλ‘μ΄ λ©μΈ μ± (μ»΄ν¬λνΈ λΆλ¦¬ λ²μ )
β
βββ frontend/ # π νλ‘ νΈμλ λλ ν 리
β βββ __init__.py
β β
β βββ app_ui.py # UI 쑰립 λ©μΈ νμΌ
β β
β βββ components/ # UI μ»΄ν¬λνΈ
β β βββ __init__.py
β β βββ header.py # π¨βπ» κ°λ°μ A
β β βββ audio_input.py # π¨βπ» κ°λ°μ A
β β βββ history_display.py # π¨βπ» κ°λ°μ B
β β βββ failure_modal.py # π¨βπ» κ°λ°μ B
β β βββ success_screen.py # π¨βπ» κ°λ°μ A
β β
β βββ styles/ # CSS μ€νμΌ
β βββ custom_css.py
β
βββ components/ # λ°±μλ λ‘μ§ (κΈ°μ‘΄)
β βββ audio_validator.py
β βββ ui_renderer.py
β
βββ utils/ # μ νΈλ¦¬ν° (κΈ°μ‘΄)
β βββ stt_handler.py
β βββ state_manager.py
β
βββ config/ # μ€μ (κΈ°μ‘΄)
βββ settings.py
π₯ ν λΆλ΄
π¨βπ» κ°λ°μ A: μ λ ₯ κ΄λ ¨ μ»΄ν¬λνΈ
frontend/components/header.py- ν€λ λ° λμ΄λ μ€μ frontend/components/audio_input.py- μ€λμ€ μ λ ₯ λ° κ²μ¦ λ²νΌfrontend/components/success_screen.py- μ±κ³΅ νλ©΄
π¨βπ» κ°λ°μ B: νΌλλ°± κ΄λ ¨ μ»΄ν¬λνΈ
frontend/components/history_display.py- μ€ν¨ κΈ°λ‘ νμfrontend/components/failure_modal.py- μ€ν¨ νμ λͺ¨λ¬
π€ κ³΅ν΅ μμ
frontend/styles/custom_css.py- CSS μ€νμΌ (νμ μ κ°μ μΆκ°)frontend/app_ui.py- UI 쑰립 (μ΅μ’ ν΅ν© μ μμ )
π νμΌλ³ μμΈ μ€λͺ
1. frontend/app_ui.py (UI 쑰립 λ©μΈ)
μν : λͺ¨λ μ»΄ν¬λνΈλ₯Ό importνκ³ μ°κ²°
μ£Όμ ν΄λμ€: AppUI
# μ¬μ© μμ
ui_builder = AppUI(validator, ui_renderer)
components = ui_builder.build() # UI λΉλ
ui_builder.setup_events(components, handlers) # μ΄λ²€νΈ μ°κ²°
μ£Όμ λ©μλ:
build(): μ 체 UI ꡬμ±setup_events(): μ΄λ²€νΈ λ°μΈλ©
2. frontend/components/header.py (π¨βπ» κ°λ°μ A)
μν : μ± νμ΄ν, λμ΄λ μ¬λΌμ΄λ, λͺ©ν λ¬Έμ₯ νμ
μ£Όμ ν΄λμ€: HeaderComponent
λ λλ§ μ»΄ν¬λνΈ:
- νμ΄ν: "ποΈ μμ± κ²μ¦ μμ€ν "
- λμ΄λ μ¬λΌμ΄λ (1-5)
- νμ¬ λͺ©ν λ¬Έμ₯ ν μ€νΈλ°μ€
μ΄λ²€νΈ:
- λμ΄λ λ³κ²½ μ β λͺ©ν λ¬Έμ₯ μ λ°μ΄νΈ
μμ κ°λ₯ μμ:
- νμ΄ν μ€νμΌ λ³κ²½
- μ¬λΌμ΄λ λ²μ/λ μ΄λΈ μμ
- μ€μ Accordion λ΄λΆμ μΆκ° μ΅μ μΆκ°
3. frontend/components/audio_input.py (π¨βπ» κ°λ°μ A)
μν : μμ± λ Ήμ/μ λ‘λ λ° κ²μ¦ λ²νΌ
μ£Όμ ν΄λμ€: AudioInputComponent
λ λλ§ μ»΄ν¬λνΈ:
- λͺ©ν λ¬Έμ₯ νμ (Markdown)
- μ€λμ€ μ λ ₯ μμ ― (λ Ήμ + μ λ‘λ)
- κ²μ¦ λ²νΌ
μ΄λ²€νΈ:
- κ²μ¦ λ²νΌ ν΄λ¦ β
validate_audio_handlerνΈμΆ
μμ κ°λ₯ μμ:
- λ²νΌ ν μ€νΈ/μ€νμΌ
- μ€λμ€ μ λ ₯ μ€μ (μνλ μ΄νΈ λ±)
- λͺ©ν λ¬Έμ₯ νμ μ€νμΌ
4. frontend/components/history_display.py (π¨βπ» κ°λ°μ B)
μν : μ€ν¨ κΈ°λ‘μ HTMLλ‘ νμ
μ£Όμ ν΄λμ€: HistoryDisplayComponent
λ λλ§ μ»΄ν¬λνΈ:
- μ€ν¨ κΈ°λ‘ HTML μμ
λ°μ΄ν° νλ¦:
ui_renderer.render_failure_history()β HTML μμ±- κ²μ¦ μ€ν¨ μ μλ μ λ°μ΄νΈ
μμ κ°λ₯ μμ:
- κΈ°λ‘ νμ λ μ΄μμ
- μΉμ νμ΄ν λ³κ²½
- μΆκ° ν΅κ³ μ 보 νμ
5. frontend/components/failure_modal.py (π¨βπ» κ°λ°μ B)
μν : μ€ν¨ μ νμ λͺ¨λ¬λ‘ κ²°κ³Ό νμ
μ£Όμ ν΄λμ€: FailureModalComponent
λ λλ§ μ»΄ν¬λνΈ:
- Modal 컨ν μ΄λ
- HTML μ½ν μΈ μμ
- λ«κΈ° λ²νΌ
μ μ λ©μλ:
create_modal_content(recognized_text, score, hint): λͺ¨λ¬ HTML μμ±
μ΄λ²€νΈ:
- λ«κΈ° λ²νΌ ν΄λ¦ β λͺ¨λ¬ μ¨κΉ
μμ κ°λ₯ μμ:
- λͺ¨λ¬ HTML ν νλ¦Ώ (μμ, λ μ΄μμ)
- λ²νΌ μ€νμΌ
- μ λλ©μ΄μ ν¨κ³Ό μΆκ°
λͺ¨λ¬ HTML ꡬ쑰:
<div style="padding: 20px; text-align: center;">
<h2>β μ€ν¨!</h2>
<div><strong>μΈμλ ν
μ€νΈ:</strong> ...</div>
<div><strong>μ μ:</strong> ...μ </div>
<div><strong>π‘ ννΈ:</strong> ...</div>
</div>
6. frontend/components/success_screen.py (π¨βπ» κ°λ°μ B)
μν : μ±κ³΅ μ μ 체 νλ©΄ μ ν
μ£Όμ ν΄λμ€: SuccessScreenComponent
λ λλ§ μ»΄ν¬λνΈ:
- μ±κ³΅ νλ©΄ 컨ν
μ΄λ (
elem_id="success-screen") - μΆν λ©μμ§ (Markdown)
- μ²μλΆν° λ€μ λ²νΌ
μ΄λ²€νΈ:
- μ²μλΆν° λ€μ λ²νΌ β
window.location.reload()(JavaScript)
μμ κ°λ₯ μμ:
- μΆν λ©μμ§ ν μ€νΈ/μ€νμΌ
- λ²νΌ λμμΈ
- μ λλ©μ΄μ ν¨κ³Ό μΆκ°
CSS μ°κ²°:
frontend/styles/custom_css.pyμ SUCCESS_SCREEN_CSS μ°Έμ‘°
7. frontend/styles/custom_css.py (곡ν΅)
μν : μ 체 μ±μ CSS μ€νμΌ μ μ
νμ¬ CSS:
#success-screen: μ±κ³΅ νλ©΄ μ 체 μ€λ²λ μ΄ μ€νμΌ- κ³ μ μμΉ (position: fixed)
- 보λΌμ κ·ΈλΌλ°μ΄μ λ°°κ²½
- μ€μ μ λ ¬
μμ κ°λ₯:
- μλ‘μ΄ CSS μΆκ°
- μμ ν λ§ λ³κ²½
- λ°μν λμμΈ μΆκ°
μ¬μ© λ°©λ²:
from frontend.styles.custom_css import get_all_css
gr.Blocks(css=get_all_css())
π λ°μ΄ν° νλ¦
κ²μ¦ νλ‘μΈμ€
- μ¬μ©μ μ‘μ : μ€λμ€ μ λ‘λ β κ²μ¦ λ²νΌ ν΄λ¦
- νΈλ€λ¬ νΈμΆ:
validate_audio_handler(audio, difficulty, history, storage) - λλ―Έ λ‘μ§ μ€ν:
- 5λ²κΉμ§ μ€ν¨ β λͺ¨λ¬ νμ + κΈ°λ‘ μΆκ°
- 6λ²μ§Έ μ±κ³΅ β μ±κ³΅ νλ©΄ μ ν
- UI μ
λ°μ΄νΈ:
- μ€ν¨:
failure_modalνμ,history_htmlμ λ°μ΄νΈ - μ±κ³΅:
main_screenμ¨κΉ,success_screenνμ
- μ€ν¨:
μν κ΄λ¦¬
gr.State: μΈμ μν (μλ‘κ³ μΉ¨ μ μ΄κΈ°ν)difficulty: νμ¬ λμ΄λfailure_history: μ€ν¨ κΈ°λ‘ λ¦¬μ€νΈ
gr.BrowserState: localStorage μꡬ μ μ₯storage_key="audio_validation_history"- ꡬ쑰:
{"date": "YYYY-MM-DD", "failures": [...], "successes": [...]} - λ μ§ λ³κ²½ μ μλ μ΄κΈ°ν
π οΈ κ°λ° κ°μ΄λ
μ»΄ν¬λνΈ μμ μ
- ν΄λΉ μ»΄ν¬λνΈ νμΌλ§ μμ
- ν΄λμ€μ
render()λ©μλμμ UI κ΅¬μ± - νμ μ
setup_events()λ©μλμμ μ΄λ²€νΈ μ°κ²°
μ μ»΄ν¬λνΈ μΆκ° μ
frontend/components/μ μ νμΌ μμ±- ν΄λμ€ μμ± (
render(),setup_events()λ©μλ ꡬν) frontend/app_ui.pyμμ import λ° μ°κ²°
CSS μ€νμΌ μΆκ° μ
frontend/styles/custom_css.pyμ CSS λ¬Έμμ΄ μΆκ°get_all_css()ν¨μμμ λ°νκ°μ ν¬ν¨
π§ͺ ν μ€νΈ λ°©λ²
κ°λ³ μ»΄ν¬λνΈ ν μ€νΈ
κ° μ»΄ν¬λνΈλ λ 립μ μΌλ‘ ν μ€νΈ κ°λ₯:
# header.py ν
μ€νΈ
from frontend.components.header import HeaderComponent
from components.audio_validator import AudioValidator
validator = AudioValidator(config)
header = HeaderComponent(validator)
# Gradio μ±μμ header.render() νΈμΆ
ν΅ν© ν μ€νΈ
python app_new.py
π μ»€λ° μ»¨λ²€μ (κΆμ₯)
[κ°λ°μA] header: λμ΄λ μ¬λΌμ΄λ λ²μ μμ
[κ°λ°μB] modal: μ€ν¨ λͺ¨λ¬ μ€νμΌ κ°μ
[곡ν΅] css: λ°μν λμμΈ μΆκ°
π§ λ°±μλ μ°κ²° (μΆν μμ )
νμ¬ λλ―Έ λ°μ΄ν°λ‘ λμνλ©°, μ€μ λ°±μλ μ°κ²° μ:
app_new.pyμvalidate_audio_handler()μμ components/audio_validator.pyλ‘μ§ νμ±νutils/stt_handler.pyμ€μ STT API μ°κ²°
λ³κ²½μ΄ νμν λΆλΆ:
# app_new.py:72-90 (λλ―Έ λ°μ΄ν° λΆλΆ)
# μ€μ κ²μ¦ λ‘μ§μΌλ‘ κ΅μ²΄
result = self.validator.validate(audio_path, expected_text)
recognized_text = result['text']
score = result['score']
π μ°Έκ³ λ¬Έμ
- Gradio 곡μ λ¬Έμ:
docs/GRADIO_BASICS.md - Gradio Modal μ»΄ν¬λνΈ: https://huggingface.co/spaces/aliabid94/gradio_modal
- κΈ°μ‘΄ μ± κ΅¬μ‘°:
app.py(λ°±μ )
π μμνκΈ°
1. νκ²½ μ€μ
# κ°μνκ²½ νμ±ν
source .venv/bin/activate # Linux/Mac
.venv\Scripts\activate # Windows
# μμ‘΄μ± μ€μΉ (gradio_modal μΆκ°)
pip install gradio_modal
2. μ± μ€ν
# μλ‘μ΄ μ»΄ν¬λνΈ λΆλ¦¬ λ²μ
python app_new.py
# κΈ°μ‘΄ λ²μ (λ°±μ
)
python app.py
3. λΈλΌμ°μ μ μ
http://localhost:7860
β FAQ
Q1: κ°λ°μ Aμ Bκ° λμμ μμ νλ©΄ μΆ©λμ΄ λμ§ μλμ?
A: κ°μ λ€λ₯Έ νμΌμ μμ νλ―λ‘ Git μΆ©λμ΄ κ±°μ μμ΅λλ€. app_ui.pyλ§ μ΅μ’
ν΅ν© μ μ‘°μ¬ν λ³ν©νλ©΄ λ©λλ€.
Q2: μ»΄ν¬λνΈ κ° ν΅μ μ μ΄λ»κ² νλμ?
A: app_ui.pyμ setup_events()μμ μ΄λ²€νΈλ₯Ό μ°κ²°ν©λλ€. κ° μ»΄ν¬λνΈλ λ
립μ μ΄λ©°, μνλ gr.Stateλ₯Ό ν΅ν΄ 곡μ λ©λλ€.
Q3: CSSλ₯Ό μ»΄ν¬λνΈλ³λ‘ λΆλ¦¬ν μ μλμ?
A: λ€, frontend/styles/ μ μ¬λ¬ νμΌμ λ§λ€κ³ get_all_css()μμ ν©μΉ μ μμ΅λλ€.
Q4: κΈ°μ‘΄ app.pyλ μμ ν΄μΌ νλμ?
A: μλμ, λ°±μ
μ©μΌλ‘ λ¨κ²¨λμΈμ. app_new.pyκ° μμ νλλ©΄ κ΅μ²΄νλ©΄ λ©λλ€.
Q5: "Cannot call change outside of a gradio.Blocks context" μλ¬κ° λ°μν©λλ€!
A: Gradio μ΄λ²€νΈ(.click(), .change() λ±)λ λ°λμ gr.Blocks() 컨ν
μ€νΈ λ΄λΆμμ νΈμΆν΄μΌ ν©λλ€.
λ¬Έμ μν©:
# β μλͺ»λ λ°©λ²
with gr.Blocks() as demo:
components = build() # UIλ§ λΉλ
return components
# gr.Blocks 컨ν
μ€νΈ λ°μμ μ΄λ²€νΈ λ°μΈλ© (μλ¬ λ°μ!)
setup_events(components)
ν΄κ²° λ°©λ²:
# β
μ¬λ°λ₯Έ λ°©λ²
with gr.Blocks() as demo:
components = build() # UI λΉλ
setup_events(components) # μ΄λ²€νΈ λ°μΈλ©λ μ¬κΈ°μ!
return components
νμ¬ κ΅¬μ‘°μμμ ꡬν:
frontend/app_ui.pyμbuild(handlers)λ©μλ μμμ UI λ λλ§κ³Ό μ΄λ²€νΈ λ°μΈλ©μ λͺ¨λ μν- κ° μ»΄ν¬λνΈμ
setup_events()λ©μλλgr.Blocks()컨ν μ€νΈ λ΄λΆμμ νΈμΆλ¨
π μ°λ½μ²
λ¬Έμ κ° λ°μνλ©΄:
- ν΄λΉ μ»΄ν¬λνΈ νμΌμ docstring νμΈ
GRADIO_BASICS.mdμ°Έκ³- ν μ±λμ μ§λ¬Έ
π λ³κ²½ μ΄λ ₯
v1.1 (2024-11-25)
- FAQ Q5 μΆκ°: Gradio μ΄λ²€νΈ λ°μΈλ© 컨ν μ€νΈ μ΄μ ν΄κ²° λ°©λ²
app_ui.pyꡬ쑰 κ°μ :build()λ©μλμμ μ΄λ²€νΈ λ°μΈλ© ν΅ν©
v1.0 (2024-11-24)
- μ΄κΈ° λ¬Έμ μμ±
- νλ‘ νΈμλ μ»΄ν¬λνΈ λΆλ¦¬ ꡬ쑰 μ€κ³
μ΅μ’ μμ μΌ: 2024-11-25 λ²μ : 1.1 μμ±μ: Claude Code Assistant