File size: 13,475 Bytes
f1a0148
 
62f57ec
f1a0148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62f57ec
 
 
 
 
 
 
f1a0148
 
62f57ec
f1a0148
 
 
 
 
 
 
62f57ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1a0148
 
 
 
 
 
 
 
 
62f57ec
f1a0148
 
 
62f57ec
f1a0148
62f57ec
f1a0148
 
62f57ec
f1a0148
 
62f57ec
f1a0148
62f57ec
 
 
f1a0148
 
62f57ec
 
 
 
 
f1a0148
 
62f57ec
f1a0148
62f57ec
 
f1a0148
 
62f57ec
 
 
 
 
 
f1a0148
 
62f57ec
 
 
f1a0148
62f57ec
 
 
 
f1a0148
 
62f57ec
f1a0148
62f57ec
 
f1a0148
 
62f57ec
 
 
 
 
 
 
 
 
f1a0148
 
62f57ec
 
 
 
 
 
f1a0148
 
62f57ec
 
f1a0148
62f57ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1a0148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62f57ec
f1a0148
 
 
 
 
 
 
 
 
 
 
62f57ec
 
 
 
 
 
 
 
 
f1a0148
 
 
62f57ec
 
f1a0148
 
62f57ec
 
f1a0148
 
62f57ec
 
f1a0148
 
62f57ec
 
f1a0148
 
62f57ec
 
f1a0148
 
 
 
 
 
 
 
62f57ec
f1a0148
62f57ec
 
 
 
f1a0148
62f57ec
 
 
f1a0148
 
 
62f57ec
f1a0148
62f57ec
 
f1a0148
62f57ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1a0148
62f57ec
 
 
f1a0148
62f57ec
 
 
 
 
 
 
f1a0148
 
 
62f57ec
f1a0148
62f57ec
f1a0148
62f57ec
 
f1a0148
 
 
62f57ec
f1a0148
62f57ec
 
f1a0148
 
 
62f57ec
f1a0148
62f57ec
 
f1a0148
 
 
62f57ec
f1a0148
62f57ec
 
f1a0148
 
 
 
 
62f57ec
f1a0148
62f57ec
f1a0148
62f57ec
 
 
 
 
 
 
 
f1a0148
 
 
62f57ec
f1a0148
62f57ec
f1a0148
62f57ec
 
 
 
f1a0148
62f57ec
 
 
f1a0148
 
 
 
 
62f57ec
f1a0148
62f57ec
 
f1a0148
 
62f57ec
f1a0148
 
 
62f57ec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
{% extends "base.html" %}

{% block title %}About - 한국어 TTS 아레나{% endblock %}

{% block current_page %}About{% endblock %}

{% block extra_head %}
<style>
    .about-container {
        max-width: 800px;
        margin: 0 auto;
    }

    .about-section {
        background: white;
        border-radius: var(--radius);
        padding: 24px;
        margin-bottom: 24px;
        box-shadow: var(--shadow);
    }

    .about-section h2 {
        color: var(--primary-color);
        margin-bottom: 16px;
        font-size: 24px;
    }

    .about-section h3 {
        color: var(--text-color);
        margin-top: 20px;
        margin-bottom: 12px;
        font-size: 18px;
    }

    .about-section p {
        margin-bottom: 16px;
        line-height: 1.7;
        color: #444;
    }

    .about-section p:last-child {
        margin-bottom: 0;
    }

    .highlight-box {
        background: linear-gradient(135deg, #f5f3ff 0%, #ede9fe 100%);
        border-left: 4px solid var(--primary-color);
        padding: 16px 20px;
        border-radius: 0 var(--radius) var(--radius) 0;
        margin: 20px 0;
    }

    .highlight-box p {
        margin: 0;
        color: #4c1d95;
        font-weight: 500;
    }

    .problem-list {
        list-style: none;
        padding: 0;
        margin: 16px 0;
    }

    .problem-list li {
        margin-bottom: 16px;
        padding-left: 32px;
        position: relative;
        line-height: 1.6;
    }

    .problem-list li::before {
        content: "⚠️";
        position: absolute;
        left: 0;
        top: 0;
    }

    .feature-list {
        list-style: none;
        padding: 0;
    }

    .feature-list li {
        margin-bottom: 12px;
        padding-left: 28px;
        position: relative;
        line-height: 1.6;
    }

    .feature-list li::before {
        content: "✓";
        color: var(--primary-color);
        font-weight: bold;
        position: absolute;
        left: 8px;
        top: 0;
    }

    .metric-comparison {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
        gap: 16px;
        margin: 20px 0;
    }

    .metric-card {
        background: var(--light-gray);
        border-radius: var(--radius);
        padding: 20px;
        border: 1px solid var(--border-color);
    }

    .metric-card h4 {
        color: var(--primary-color);
        margin-bottom: 8px;
        font-size: 16px;
    }

    .metric-card .status {
        font-size: 12px;
        padding: 4px 8px;
        border-radius: 4px;
        display: inline-block;
        margin-bottom: 8px;
    }

    .metric-card .status.problem {
        background: #fee2e2;
        color: #dc2626;
    }

    .metric-card .status.solution {
        background: #dcfce7;
        color: #16a34a;
    }

    .metric-card p {
        font-size: 14px;
        margin: 0;
        color: #666;
    }

    .team-section {
        margin-top: 20px;
    }

    .team-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
        gap: 16px;
        margin-top: 16px;
    }

    .team-member {
        background: var(--light-gray);
        border-radius: var(--radius);
        padding: 16px;
        text-align: center;
        border: 1px solid var(--border-color);
    }

    .team-member .name {
        font-weight: 600;
        color: var(--text-color);
        margin-bottom: 4px;
    }

    .team-member .role {
        font-size: 13px;
        color: #666;
    }

    .reference-link {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        background: var(--light-gray);
        padding: 12px 20px;
        border-radius: var(--radius);
        text-decoration: none;
        color: var(--primary-color);
        font-weight: 500;
        border: 1px solid var(--border-color);
        transition: all 0.2s;
        margin-top: 12px;
    }

    .reference-link:hover {
        background: var(--primary-color);
        color: white;
        border-color: var(--primary-color);
    }

    .faq-item {
        margin-bottom: 20px;
    }

    .faq-question {
        font-weight: 600;
        margin-bottom: 8px;
        color: var(--primary-color);
    }

    .faq-answer {
        line-height: 1.6;
    }

    /* Dark mode styles */
    @media (prefers-color-scheme: dark) {
        .about-section {
            background-color: var(--light-gray);
            border-color: var(--border-color);
        }

        .about-section p {
            color: var(--text-color);
        }

        .highlight-box {
            background: linear-gradient(135deg, rgba(91, 94, 255, 0.1) 0%, rgba(91, 94, 255, 0.05) 100%);
        }

        .highlight-box p {
            color: #a5b4fc;
        }

        .metric-card {
            background-color: var(--secondary-color);
        }

        .metric-card p {
            color: #aaa;
        }

        .team-member {
            background-color: var(--secondary-color);
        }

        .team-member .role {
            color: #aaa;
        }

        .reference-link {
            background-color: var(--secondary-color);
        }

        .faq-question {
            color: var(--primary-color);
        }
    }
</style>
{% endblock %}

{% block content %}
<div class="about-container">
    <div class="about-section">
        <h2>🎤 한국어 TTS 아레나에 오신 것을 환영합니다</h2>
        <p>
            한국어 TTS 아레나는 다양한 음성 합성(TTS) 모델을 <strong>블라인드 테스트</strong>로 비교 평가하는 
            커뮤니티 기반 플랫폼입니다. LMsys의 
            <a href="https://chat.lmsys.org/" target="_blank" rel="noopener">Chatbot Arena</a>에서 영감을 받아, 
            누구나 한국어 TTS 모델의 품질을 직접 비교하고 평가할 수 있는 공간을 만들었습니다.
        </p>
        <div class="highlight-box">
            <p>💡 두 모델의 음성을 듣고 더 자연스러운 쪽에 투표하세요. 모델 이름은 투표 후에 공개됩니다.</p>
        </div>
    </div>

    <div class="about-section">
        <h2>🤔 왜 한국어 TTS 벤치마크가 필요한가?</h2>
        <p>
            여러 상용 TTS가 이미 존재하지만, <strong>한국어에 특화된 신뢰할 수 있는 벤치마크</strong>는 
            부재한 상황입니다. 글로벌 TTS 모델들은 한국어 처리에서 여러 한계를 보이고 있습니다.
        </p>
        
        <h3>기존 평가 방식의 한계</h3>
        <div class="metric-comparison">
            <div class="metric-card">
                <h4>WER (Word Error Rate)</h4>
                <span class="status problem">문제 있음</span>
                <p>한국어의 복잡한 발화 패턴(숫자, 날짜, 전화번호, 주문번호 등)을 STT로 평가할 때 
                정확도가 떨어져 실제 발화 품질을 제대로 반영하지 못합니다.</p>
            </div>
            <div class="metric-card">
                <h4>MOS (Mean Opinion Score)</h4>
                <span class="status problem">한계 존재</span>
                <p>소규모 참가자를 대상으로 한 주관적 평가로, 비용이 많이 들고 
                대규모 커뮤니티의 다양한 의견을 반영하기 어렵습니다.</p>
            </div>
            <div class="metric-card">
                <h4>Arena 방식</h4>
                <span class="status solution">해결책</span>
                <p>커뮤니티 전체가 참여하는 블라인드 A/B 테스트로, 
                Elo 레이팅 시스템을 통해 객관적인 순위를 도출합니다.</p>
            </div>
        </div>

        <h3>글로벌 TTS 모델의 한국어 한계</h3>
        <ul class="problem-list">
            <li>
                <strong>운율(Prosody)의 부자연스러움</strong><br>
                상담사처럼 자연스러운 억양과 톤을 구현하지 못하고, 단조로운(monotone) 발화가 생성됩니다.
            </li>
            <li>
                <strong>한국어 상식 기반 발화 처리 취약</strong><br>
                한·영 혼용, 날짜·시간, 주문/고유번호, URL·이메일 등 한국어 특유의 발화 패턴을 
                제대로 처리하지 못합니다.
            </li>
            <li>
                <strong>숫자 발화의 어려움</strong><br>
                "19,992원"을 "만 구천 구백 구십 이원"으로 자연스럽게 읽거나, 
                전화번호 형식(011-1234-1234)을 올바르게 발화하는 것이 어렵습니다.
            </li>
            <li>
                <strong>전문 용어 및 약어 처리</strong><br>
                "%p"를 "퍼센트포인트"로 읽는 등의 상식 기반 추론이 필요한 발화에 취약합니다.
            </li>
        </ul>
    </div>

    <div class="about-section">
        <h2>⚙️ 아레나 작동 방식</h2>
        <p>
            평가 방식은 간단합니다. 텍스트를 입력하면 두 개의 TTS 모델이 각각 음성을 생성합니다. 
            두 샘플을 듣고 더 자연스러운 쪽에 투표하세요. 편향을 방지하기 위해 모델 이름은 
            투표 후에만 공개됩니다.
        </p>
        <ul class="feature-list">
            <li>직접 텍스트를 입력하거나 랜덤 문장을 선택할 수 있습니다</li>
            <li>동일한 텍스트로 생성된 두 TTS 모델의 음성을 비교합니다</li>
            <li>더 자연스럽고, 명확하며, 표현력 있는 음성에 투표합니다</li>
            <li>리더보드에서 모델 순위를 확인할 수 있습니다</li>
            <li>Elo 레이팅 시스템으로 객관적인 순위가 산출됩니다</li>
        </ul>
    </div>

    <div class="about-section">
        <h2>❓ 자주 묻는 질문</h2>
        <div class="faq-item">
            <div class="faq-question">모델 순위는 어떻게 결정되나요?</div>
            <div class="faq-answer">
                체스 랭킹과 유사한 Elo 레이팅 시스템을 사용합니다. 투표를 받은 모델의 점수가 올라가고, 
                상대 모델의 점수는 내려갑니다. 변동 폭은 두 모델의 현재 레이팅에 따라 달라집니다.
            </div>
        </div>
        <div class="faq-item">
            <div class="faq-question">로그인이 필요한가요?</div>
            <div class="faq-answer">
                투표를 위해서는 Hugging Face 로그인이 필요합니다. 로그인하면 투표 기록을 추적하고 
                개인 리더보드에서 선호하는 모델을 확인할 수 있습니다.
            </div>
        </div>
        <div class="faq-item">
            <div class="faq-question">새로운 모델을 추가하고 싶어요.</div>
            <div class="faq-answer">
                새로운 TTS 모델 추가 요청은 언제든 환영합니다. 
                출시 전 익명 평가를 원하시는 경우에도 문의해 주세요.
            </div>
        </div>
        <div class="faq-item">
            <div class="faq-question">어떤 기준으로 투표해야 하나요?</div>
            <div class="faq-answer">
                자연스러움, 발음 정확도, 억양, 감정 표현 등을 종합적으로 고려해서 
                더 "사람 같은" 음성에 투표해 주세요.
            </div>
        </div>
    </div>

    <div class="about-section">
        <h2>🔗 참고 자료</h2>
        <p>
            채널톡 TTS 팀의 연구 내용과 기술적 접근 방식에 대해 더 알아보세요:
        </p>
        <a href="https://tts.ch.dev/" target="_blank" rel="noopener" class="reference-link">
            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
                <polyline points="15 3 21 3 21 9"/>
                <line x1="10" y1="14" x2="21" y2="3"/>
            </svg>
            Channel TTS: Towards Real-World Prosody for Conversational Agents
        </a>
    </div>

    <div class="about-section">
        <h2>👥 만든 사람들</h2>
        <p>
            이 프로젝트는 <a href="https://channel.io/ko" target="_blank" rel="noopener">채널톡</a> AI팀에서 제작했습니다.
        </p>
        <div class="team-grid">
            <div class="team-member">
                <div class="name">Robin (신승윤)</div>
                <div class="role">AI Team - Speech</div>
            </div>
            <div class="team-member">
                <div class="name">Jake (황정인)</div>
                <div class="role">AI Team Lead</div>
            </div>
        </div>
    </div>

    <div class="about-section">
        <h2>📜 개인정보 및 라이선스</h2>
        <p>
            입력하신 텍스트와 생성된 오디오는 연구 목적으로 저장될 수 있습니다. 
            로그인한 경우 투표 기록이 계정과 연결됩니다.
        </p>
        <p>
            생성된 오디오 클립은 개인적, 비상업적 용도로만 사용할 수 있으며 재배포할 수 없습니다.
        </p>
    </div>
</div>
{% endblock %}