Skip to content

Commit 5afdb5b

Browse files
committed
update webpage
max queue size added, update doc & version
1 parent d5e294f commit 5afdb5b

File tree

6 files changed

+125
-77
lines changed

6 files changed

+125
-77
lines changed

server/api.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ def __init__(self, host: str = config['host'], port: int = config['port'],
4343
self.app = web.Application()
4444
self.verify_ssl = verify_ssl
4545

46+
# Validate and set queue size
47+
try:
48+
max_queue_size = int(max_queue_size)
49+
if max_queue_size < 1:
50+
logger.warning(f"Invalid max_queue_size {max_queue_size}, defaulting to 100")
51+
max_queue_size = 100
52+
except (ValueError, TypeError):
53+
logger.warning(f"Invalid max_queue_size {max_queue_size}, defaulting to 100")
54+
max_queue_size = 100
55+
4656
# Initialize queue system with rate limiting
4757
self.queue = asyncio.Queue(maxsize=max_queue_size)
4858
self.current_task = None
@@ -55,6 +65,8 @@ def __init__(self, host: str = config['host'], port: int = config['port'],
5565

5666
self.session = None
5767

68+
logger.info(f"Initialized TTS server with max queue size: {max_queue_size}")
69+
5870
def setup_routes(self):
5971
"""Set up the API routes."""
6072
# OpenAI compatible endpoint

server/handlers.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,36 @@ async def process_tts_request(task_data: Dict[str, Any], session) -> web.Respons
283283

284284
async def handle_queue_size(request: web.Request, queue) -> web.Response:
285285
"""Handle GET requests to /api/queue-size."""
286-
return web.json_response({
287-
"queue_size": queue.qsize(),
288-
"max_queue_size": queue.maxsize
289-
}, headers={
290-
"Access-Control-Allow-Origin": "*",
291-
"Access-Control-Allow-Methods": "GET, OPTIONS",
292-
"Access-Control-Allow-Headers": "Content-Type"
293-
})
286+
try:
287+
# Get current queue size and max size
288+
current_size = queue.qsize()
289+
max_size = queue.maxsize if hasattr(queue, 'maxsize') else 100 # Fallback to 100 if maxsize not set
290+
291+
# Ensure values are valid
292+
if current_size < 0:
293+
current_size = 0
294+
if max_size < 1:
295+
max_size = 100 # Default to 100 if invalid
296+
297+
return web.json_response({
298+
"queue_size": current_size,
299+
"max_queue_size": max_size
300+
}, headers={
301+
"Access-Control-Allow-Origin": "*",
302+
"Access-Control-Allow-Methods": "GET, OPTIONS",
303+
"Access-Control-Allow-Headers": "Content-Type"
304+
})
305+
except Exception as e:
306+
logger.error(f"Error getting queue size: {str(e)}")
307+
return web.json_response({
308+
"queue_size": 0,
309+
"max_queue_size": 100, # Default values on error
310+
"error": "Failed to get queue status"
311+
}, status=500, headers={
312+
"Access-Control-Allow-Origin": "*",
313+
"Access-Control-Allow-Methods": "GET, OPTIONS",
314+
"Access-Control-Allow-Headers": "Content-Type"
315+
})
294316

295317
async def handle_static(request: web.Request) -> web.Response:
296318
"""Handle static file requests.

static/index.html

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,16 @@
1818
<!-- Header Section -->
1919
<header class="main-header">
2020
<div class="header-top">
21-
<h1>OpenAI TTS API Documentation</h1>
21+
<h1>ttsfm</h1>
2222
<a href="https://github.com/dbccccccc/ttsfm" target="_blank" class="github-link">
2323
<i class="fab fa-github"></i>
2424
<span>GitHub</span>
2525
</a>
2626
</div>
2727
<p class="subtitle">Text-to-Speech API with Multiple Voice Options</p>
2828
<div class="header-bottom">
29-
<div class="domain-badge">
30-
<span>API Domain: <strong>ttsapi.site</strong></span>
31-
</div>
3229
<div class="version-badge">
33-
<span>Version: <strong id="version">1.2.0-beta1</strong></span>
30+
<span>Version: <strong id="version">1.2.0-beta2</strong></span>
3431
</div>
3532
<div class="language-selector">
3633
<button class="lang-btn active" data-lang="en">English</button>
@@ -68,7 +65,7 @@ <h3>Queue Status</h3>
6865
</div>
6966
<div class="stat-item">
7067
<span class="stat-label">Maximum Capacity:</span>
71-
<span class="stat-value" id="max-queue-size">100</span>
68+
<span class="stat-value" id="max-queue-size">-</span>
7269
</div>
7370
</div>
7471
<div class="queue-progress-container">
@@ -325,15 +322,35 @@ <h3>Queue System</h3>
325322
<li>Requests are processed in FIFO (First In, First Out) order</li>
326323
<li>Rate limiting: Configurable via <code>RATE_LIMIT_REQUESTS</code> and <code>RATE_LIMIT_WINDOW</code> environment variables (default: 30 requests per 60 seconds per IP address)</li>
327324
<li>Queue status can be monitored via the <code>/api/queue-size</code> endpoint</li>
325+
<li>Queue status updates every 2 seconds in the web interface</li>
326+
<li>Visual indicators show queue load (Low/Medium/High) based on utilization</li>
328327
</ul>
329328

330329
<h4>Queue Status Endpoint</h4>
331330
<pre><code class="language-http">GET /api/queue-size</code></pre>
332331
<p>Returns JSON with queue information:</p>
333332
<pre><code class="language-json">{
334-
"queue_size": 0,
335-
"max_queue_size": 100
333+
"queue_size": 0, // Current number of requests in queue
334+
"max_queue_size": 100 // Maximum queue capacity
336335
}</code></pre>
336+
337+
<div class="response-codes">
338+
<h4>Response Status Codes</h4>
339+
<ul>
340+
<li><code>200</code> - Success</li>
341+
<li><code>429</code> - Queue is full or rate limit exceeded</li>
342+
<li><code>500</code> - Server error</li>
343+
</ul>
344+
</div>
345+
346+
<div class="queue-load-indicators">
347+
<h4>Queue Load Indicators</h4>
348+
<ul>
349+
<li><strong>Low Load</strong> (0-40%): Green indicator, optimal for new requests</li>
350+
<li><strong>Medium Load</strong> (40-75%): Yellow/Orange indicator, some delay expected</li>
351+
<li><strong>High Load</strong> (75-100%): Red indicator, significant delay expected</li>
352+
</ul>
353+
</div>
337354
</div>
338355
</section>
339356
</main>

static/index_zh.html

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,16 @@
1818
<!-- Header Section -->
1919
<header class="main-header">
2020
<div class="header-top">
21-
<h1>OpenAI TTS API 文档</h1>
21+
<h1>ttsfm</h1>
2222
<a href="https://github.com/dbccccccc/ttsfm" target="_blank" class="github-link">
2323
<i class="fab fa-github"></i>
2424
<span>GitHub</span>
2525
</a>
2626
</div>
2727
<p class="subtitle">支持多种语音的文本转语音 API</p>
2828
<div class="header-bottom">
29-
<div class="domain-badge">
30-
<span>API 域名: <strong>ttsapi.site</strong></span>
31-
</div>
3229
<div class="version-badge">
33-
<span>版本: <strong id="version">1.2.0-beta1</strong></span>
30+
<span>版本: <strong id="version">1.2.0-beta2</strong></span>
3431
</div>
3532
<div class="language-selector">
3633
<a href="index.html" class="lang-btn">English</a>
@@ -68,7 +65,7 @@ <h3>队列状态</h3>
6865
</div>
6966
<div class="stat-item">
7067
<span class="stat-label">最大容量:</span>
71-
<span class="stat-value" id="max-queue-size">100</span>
68+
<span class="stat-value" id="max-queue-size">-</span>
7269
</div>
7370
</div>
7471
<div class="queue-progress-container">
@@ -325,15 +322,35 @@ <h3>队列系统</h3>
325322
<li>请求按 FIFO(先进先出)顺序处理</li>
326323
<li>速率限制:可通过 <code>RATE_LIMIT_REQUESTS</code><code>RATE_LIMIT_WINDOW</code> 环境变量配置(默认:每个 IP 地址 60 秒内最多 30 个请求)</li>
327324
<li>可以通过 <code>/api/queue-size</code> 端点监控队列状态</li>
325+
<li>Web 界面每 2 秒更新一次队列状态</li>
326+
<li>根据使用率显示队列负载状态(低/中/高)</li>
328327
</ul>
329328

330329
<h4>队列状态端点</h4>
331330
<pre><code class="language-http">GET /api/queue-size</code></pre>
332331
<p>返回包含队列信息的 JSON:</p>
333332
<pre><code class="language-json">{
334-
"queue_size": 0,
335-
"max_queue_size": 100
333+
"queue_size": 0, // 当前队列中的请求数
334+
"max_queue_size": 100 // 队列最大容量
336335
}</code></pre>
336+
337+
<div class="response-codes">
338+
<h4>响应状态码</h4>
339+
<ul>
340+
<li><code>200</code> - 成功</li>
341+
<li><code>429</code> - 队列已满或超出速率限制</li>
342+
<li><code>500</code> - 服务器错误</li>
343+
</ul>
344+
</div>
345+
346+
<div class="queue-load-indicators">
347+
<h4>队列负载指示器</h4>
348+
<ul>
349+
<li><strong>低负载</strong> (0-40%):绿色指示器,适合发送新请求</li>
350+
<li><strong>中负载</strong> (40-75%):黄色/橙色指示器,可能会有延迟</li>
351+
<li><strong>高负载</strong> (75-100%):红色指示器,预计会有明显延迟</li>
352+
</ul>
353+
</div>
337354
</div>
338355
</section>
339356
</main>

static/script.js

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const queueLoadText = document.getElementById('queue-load-text');
1111
// Track active requests
1212
let currentActiveRequests = 0;
1313

14+
// Initialize current language
15+
let currentLang = 'en';
16+
1417
// Language translations
1518
const translations = {
1619
en: {
@@ -56,36 +59,22 @@ const translations = {
5659
// Language switching functionality
5760
document.addEventListener('DOMContentLoaded', function() {
5861
const langButtons = document.querySelectorAll('.lang-btn');
59-
let currentLang = 'en';
60-
61-
function updateLanguage(lang) {
62-
currentLang = lang;
63-
const t = translations[lang];
64-
65-
// Update text content
66-
document.querySelector('.main-header h1').textContent = t.title;
67-
document.querySelector('.subtitle').textContent = t.subtitle;
68-
document.querySelector('.playground-section h2').textContent = t.tryItOut;
69-
document.querySelector('label[for="playground-text"]').textContent = t.textToConvert;
70-
document.querySelector('label[for="playground-voice"]').textContent = t.voice;
71-
document.querySelector('label[for="playground-instructions"]').textContent = t.instructions;
72-
document.querySelector('.playground-button').innerHTML = `<i class="fas fa-play"></i> ${t.generateSpeech}`;
73-
document.querySelector('.content-section:nth-child(3) h2').textContent = t.quickStart;
74-
document.querySelector('.content-section:nth-child(4) h2').textContent = t.availableVoices;
75-
document.querySelector('.content-section:nth-child(5) h2').textContent = t.apiReference;
76-
document.querySelector('.status-header h3').textContent = t.queueStatus;
77-
document.querySelector('.stat-item:nth-child(1) .stat-label').textContent = t.activeRequests;
78-
document.querySelector('.stat-item:nth-child(2) .stat-label').textContent = t.maxCapacity;
79-
}
80-
81-
langButtons.forEach(button => {
82-
button.addEventListener('click', function() {
83-
const lang = this.dataset.lang;
84-
langButtons.forEach(btn => btn.classList.remove('active'));
85-
this.classList.add('active');
86-
updateLanguage(lang);
87-
});
62+
63+
// Set initial language based on current page
64+
const isChinesePage = window.location.pathname.includes('_zh.html');
65+
currentLang = isChinesePage ? 'zh' : 'en';
66+
67+
// Update active state of language buttons
68+
langButtons.forEach(btn => {
69+
if (btn.getAttribute('data-lang') === currentLang) {
70+
btn.classList.add('active');
71+
} else {
72+
btn.classList.remove('active');
73+
}
8874
});
75+
76+
// Initial queue size update
77+
updateQueueSize();
8978
});
9079

9180
function updateProcessingStatus(requestCount) {
@@ -109,6 +98,9 @@ function updateLastUpdate() {
10998
async function updateQueueSize() {
11099
try {
111100
const response = await fetch('/api/queue-size');
101+
if (!response.ok) {
102+
throw new Error(`HTTP error! status: ${response.status}`);
103+
}
112104
const data = await response.json();
113105

114106
// Update text values
@@ -119,13 +111,21 @@ async function updateQueueSize() {
119111
const loadPercentage = (data.queue_size / data.max_queue_size) * 100;
120112

121113
// Update progress bar width
122-
queueProgressBar.style.width = `${loadPercentage}%`;
114+
queueProgressBar.style.width = `${Math.min(loadPercentage, 100)}%`;
123115

124116
// Update status indicators based on load
125117
updateLoadStatus(loadPercentage);
126118

127119
} catch (error) {
128120
console.error('Error fetching queue size:', error);
121+
// Show error state in UI
122+
document.getElementById('queue-size').textContent = '?';
123+
document.getElementById('max-queue-size').textContent = '?';
124+
queueProgressBar.style.width = '0%';
125+
statusIndicator.classList.remove('indicator-low', 'indicator-medium', 'indicator-high');
126+
queueProgressBar.classList.remove('progress-low', 'progress-medium', 'progress-high');
127+
queueLoadText.classList.remove('low-load', 'medium-load', 'high-load');
128+
queueLoadText.textContent = 'Error';
129129
}
130130
}
131131

@@ -142,19 +142,19 @@ function updateLoadStatus(loadPercentage) {
142142
statusIndicator.classList.add('indicator-high');
143143
queueProgressBar.classList.add('progress-high');
144144
queueLoadText.classList.add('high-load');
145-
queueLoadText.textContent = 'High Load';
145+
queueLoadText.textContent = translations[currentLang].highLoad;
146146
} else if (loadPercentage >= 40) {
147147
// Medium load (40-75%)
148148
statusIndicator.classList.add('indicator-medium');
149149
queueProgressBar.classList.add('progress-medium');
150150
queueLoadText.classList.add('medium-load');
151-
queueLoadText.textContent = 'Medium Load';
151+
queueLoadText.textContent = translations[currentLang].mediumLoad;
152152
} else {
153153
// Low load (0-40%)
154154
statusIndicator.classList.add('indicator-low');
155155
queueProgressBar.classList.add('progress-low');
156156
queueLoadText.classList.add('low-load');
157-
queueLoadText.textContent = loadPercentage > 0 ? 'Low Load' : 'No Load';
157+
queueLoadText.textContent = loadPercentage > 0 ? translations[currentLang].lowLoad : translations[currentLang].noLoad;
158158
}
159159
}
160160

static/styles.css

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,26 +1008,6 @@ code[class*="language-"] {
10081008
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
10091009
}
10101010

1011-
/* Domain Badge */
1012-
.domain-badge {
1013-
margin-top: 1rem;
1014-
display: inline-block;
1015-
background-color: #f1f5f9;
1016-
border-radius: 4px;
1017-
padding: 0.5rem 1rem;
1018-
border-left: 3px solid #2563eb;
1019-
}
1020-
1021-
.domain-badge span {
1022-
font-size: 0.9rem;
1023-
color: #64748b;
1024-
}
1025-
1026-
.domain-badge strong {
1027-
color: var(--primary-color);
1028-
font-weight: 600;
1029-
}
1030-
10311011
.version-badge {
10321012
background-color: #fff;
10331013
border: 1px solid #e2e8f0;

0 commit comments

Comments
 (0)