KillerKing93/Transformers-TextEngine-OpenAPI
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Debug Interface - Qwen3 Inference Server</title>7 <style>8 * {9 margin: 0;10 padding: 0;11 box-sizing: border-box;12 }13 14 body {15 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;16 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);17 color: #333;18 min-height: 100vh;19 }20 21 .container {22 max-width: 1400px;23 margin: 0 auto;24 padding: 20px;25 }26 27 .header {28 background: rgba(255, 255, 255, 0.95);29 border-radius: 15px;30 padding: 25px;31 margin-bottom: 20px;32 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);33 backdrop-filter: blur(10px);34 }35 36 .header h1 {37 color: #4a5568;38 font-size: 2rem;39 margin-bottom: 10px;40 }41 42 .status-grid {43 display: grid;44 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));45 gap: 20px;46 margin-bottom: 20px;47 }48 49 .status-card {50 background: rgba(255, 255, 255, 0.95);51 border-radius: 12px;52 padding: 20px;53 box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);54 backdrop-filter: blur(10px);55 }56 57 .status-card h3 {58 color: #2d3748;59 margin-bottom: 15px;60 font-size: 1.2rem;61 }62 63 .status-item {64 display: flex;65 justify-content: space-between;66 margin-bottom: 8px;67 padding: 5px 0;68 border-bottom: 1px solid #e2e8f0;69 }70 71 .status-value {72 font-weight: 600;73 color: #4a5568;74 }75 76 .chat-container {77 background: rgba(255, 255, 255, 0.95);78 border-radius: 15px;79 padding: 20px;80 margin-bottom: 20px;81 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);82 backdrop-filter: blur(10px);83 }84 85 .chat-tabs {86 display: flex;87 margin-bottom: 20px;88 border-bottom: 2px solid #e2e8f0;89 }90 91 .tab {92 padding: 12px 24px;93 background: none;94 border: none;95 cursor: pointer;96 font-size: 1rem;97 color: #718096;98 border-bottom: 3px solid transparent;99 transition: all 0.3s ease;100 }101 102 .tab.active {103 color: #4a5568;104 border-bottom-color: #667eea;105 font-weight: 600;106 }107 108 .tab:hover {109 color: #4a5568;110 background: rgba(102, 126, 234, 0.1);111 }112 113 .chat-messages {114 height: 300px;115 overflow-y: auto;116 border: 1px solid #e2e8f0;117 border-radius: 8px;118 padding: 15px;119 margin-bottom: 15px;120 background: #f8fafc;121 }122 123 .message {124 margin-bottom: 15px;125 padding: 12px;126 border-radius: 8px;127 max-width: 80%;128 }129 130 .user-message {131 background: #4299e1;132 color: white;133 margin-left: auto;134 text-align: right;135 }136 137 .assistant-message {138 background: #e2e8f0;139 color: #2d3748;140 }141 142 .debug-message {143 background: #fef5e7;144 border: 1px solid #f6ad55;145 color: #744210;146 font-family: 'Courier New', monospace;147 font-size: 0.9rem;148 white-space: pre-wrap;149 max-width: 95%;150 }151 152 .input-group {153 display: flex;154 gap: 10px;155 margin-bottom: 15px;156 }157 158 .input-group input, .input-group select, .input-group textarea {159 flex: 1;160 padding: 12px;161 border: 1px solid #cbd5e0;162 border-radius: 8px;163 font-size: 1rem;164 }165 166 .input-group input:focus, .input-group select:focus, .input-group textarea:focus {167 outline: none;168 border-color: #667eea;169 box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);170 }171 172 .btn {173 padding: 12px 24px;174 border: none;175 border-radius: 8px;176 cursor: pointer;177 font-size: 1rem;178 font-weight: 600;179 transition: all 0.3s ease;180 }181 182 .btn-primary {183 background: #4299e1;184 color: white;185 }186 187 .btn-primary:hover {188 background: #3182ce;189 transform: translateY(-2px);190 box-shadow: 0 4px 12px rgba(66, 153, 225, 0.3);191 }192 193 .btn-secondary {194 background: #718096;195 color: white;196 }197 198 .btn-secondary:hover {199 background: #4a5568;200 }201 202 .btn-success {203 background: #48bb78;204 color: white;205 }206 207 .btn-success:hover {208 background: #38a169;209 }210 211 .debug-log {212 background: #1a202c;213 color: #e2e8f0;214 padding: 15px;215 border-radius: 8px;216 font-family: 'Courier New', monospace;217 font-size: 0.85rem;218 height: 200px;219 overflow-y: auto;220 margin-top: 15px;221 }222 223 .log-entry {224 margin-bottom: 5px;225 padding: 3px 0;226 }227 228 .log-error {229 color: #fc8181;230 }231 232 .log-success {233 color: #68d391;234 }235 236 .log-info {237 color: #63b3ed;238 }239 240 .log-warning {241 color: #f6ad55;242 }243 244 .controls {245 display: flex;246 gap: 10px;247 flex-wrap: wrap;248 margin-bottom: 15px;249 }250 251 .endpoint-info {252 background: #edf2f7;253 padding: 10px;254 border-radius: 6px;255 margin-bottom: 10px;256 font-size: 0.9rem;257 color: #4a5568;258 }259 260 .loading {261 display: inline-block;262 width: 20px;263 height: 20px;264 border: 3px solid #f3f3f3;265 border-top: 3px solid #4299e1;266 border-radius: 50%;267 animation: spin 1s linear infinite;268 margin-left: 10px;269 }270 271 @keyframes spin {272 0% { transform: rotate(0deg); }273 100% { transform: rotate(360deg); }274 }275 276 .hidden {277 display: none;278 }279 280 .streaming-chunk {281 background: #f0fff4;282 border-left: 3px solid #48bb78;283 padding: 8px;284 margin-bottom: 5px;285 border-radius: 0 4px 4px 0;286 font-family: 'Courier New', monospace;287 font-size: 0.9rem;288 }289 290 .timestamp {291 color: #718096;292 font-size: 0.8rem;293 }294 </style>295</head>296<body>297 <div class="container">298 <div class="header">299 <h1>๐ Debug Interface - Qwen3 Inference Server</h1>300 <p>Comprehensive debugging and testing interface for the inference server</p>301 </div>302 303 <!-- Status Cards -->304 <div class="status-grid">305 <div class="status-card">306 <h3>๐ฅ Server Health</h3>307 <div class="status-item">308 <span>Status:</span>309 <span class="status-value" id="server-status">Checking...</span>310 </div>311 <div class="status-item">312 <span>Model Ready:</span>313 <span class="status-value" id="model-ready">Checking...</span>314 </div>315 <div class="status-item">316 <span>Model ID:</span>317 <span class="status-value" id="model-id" style="font-size: 0.8rem;">Checking...</span>318 </div>319 </div>320 321 <div class="status-card">322 <h3>๐ง API Endpoints</h3>323 <div class="endpoint-info">324 <strong>Working Endpoints:</strong><br>325 โข Health: <code>GET /health</code><br>326 โข Simple Chat: <code>POST /debug/simple-chat</code><br>327 โข Test Stream: <code>POST /debug/test-stream</code><br>328 โข Model Debug: <code>GET /debug/model</code>329 </div>330 </div>331 332 <div class="status-card">333 <h3>๐ System Info</h3>334 <div class="status-item">335 <span>API Base URL:</span>336 <span class="status-value" id="api-base">Current Space</span>337 </div>338 <div class="status-item">339 <span>Last Check:</span>340 <span class="status-value" id="last-check">Never</span>341 </div>342 <div class="status-item">343 <span>Connection:</span>344 <span class="status-value" id="connection-status">Unknown</span>345 </div>346 </div>347 </div>348 349 <!-- Main Chat Interface -->350 <div class="chat-container">351 <div class="chat-tabs">352 <button class="tab active" onclick="switchTab('chat')">๐ฌ Chat Test</button>353 <button class="tab" onclick="switchTab('streaming')">๐ Streaming Test</button>354 <button class="tab" onclick="switchTab('debug')">๐ง Debug Mode</button>355 <button class="tab" onclick="switchTab('logs')">๐ Logs</button>356 </div>357 358 <!-- Chat Messages -->359 <div id="chat-messages" class="chat-messages"></div>360 361 <!-- Controls -->362 <div class="controls">363 <input type="text" id="message-input" placeholder="Enter your message here..." value="Hello! Can you count to 5 for me?">364 <select id="max-tokens">365 <option value="10">10 tokens</option>366 <option value="20">20 tokens</option>367 <option value="50" selected>50 tokens</option>368 <option value="100">100 tokens</option>369 </select>370 <select id="temperature">371 <option value="0.1">0.1 (precise)</option>372 <option value="0.7" selected>0.7 (balanced)</option>373 <option value="1.0">1.0 (creative)</option>374 </select>375 </div>376 377 <div class="controls">378 <button class="btn btn-primary" onclick="sendChatMessage()">๐ฌ Send Chat</button>379 <button class="btn btn-success" onclick="sendStreamingMessage()">๐ Start Streaming</button>380 <button class="btn btn-secondary" onclick="checkHealth()">๐ฅ Check Health</button>381 <button class="btn btn-secondary" onclick="testModel()">๐ง Test Model</button>382 <button class="btn btn-secondary" onclick="clearMessages()">๐๏ธ Clear Messages</button>383 </div>384 385 <!-- Debug Log -->386 <div id="debug-log" class="debug-log hidden"></div>387 </div>388 </div>389 390 <script>391 // Configuration392 const API_BASE = window.location.origin; // Automatically use current domain393 let currentTab = 'chat';394 let streamingController = null;395 396 // Initialize397 document.addEventListener('DOMContentLoaded', function() {398 updateServerStatus();399 logMessage('info', 'Debug interface initialized');400 logMessage('info', `API Base: ${API_BASE}`);401 });402 403 // Tab switching404 function switchTab(tab) {405 currentTab = tab;406 document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));407 event.target.classList.add('active');408 409 if (tab === 'logs') {410 document.getElementById('debug-log').classList.remove('hidden');411 } else {412 document.getElementById('debug-log').classList.add('hidden');413 }414 415 logMessage('info', `Switched to ${tab} tab`);416 }417 418 // Server status check419 async function updateServerStatus() {420 try {421 logMessage('info', 'Checking server health...');422 const response = await fetch(`${API_BASE}/health`);423 const data = await response.json();424 425 document.getElementById('server-status').textContent = data.ok ? 'โ
Online' : 'โ Error';426 document.getElementById('server-status').style.color = data.ok ? '#48bb78' : '#fc8181';427 document.getElementById('model-ready').textContent = data.modelReady ? 'โ
Ready' : 'โ Not Ready';428 document.getElementById('model-ready').style.color = data.modelReady ? '#48bb78' : '#fc8181';429 document.getElementById('model-id').textContent = data.modelId ? data.modelId.split('/').pop() : 'Unknown';430 document.getElementById('connection-status').textContent = 'โ
Connected';431 document.getElementById('connection-status').style.color = '#48bb78';432 document.getElementById('last-check').textContent = new Date().toLocaleTimeString();433 434 logMessage('success', `Server health check passed: ${data.modelId}`);435 } catch (error) {436 document.getElementById('server-status').textContent = 'โ Offline';437 document.getElementById('server-status').style.color = '#fc8181';438 document.getElementById('model-ready').textContent = 'โ Unknown';439 document.getElementById('connection-status').textContent = 'โ Failed';440 document.getElementById('connection-status').style.color = '#fc8181';441 document.getElementById('last-check').textContent = new Date().toLocaleTimeString();442 443 logMessage('error', `Health check failed: ${error.message}`);444 }445 }446 447 // Send chat message (non-streaming)448 async function sendChatMessage() {449 const message = document.getElementById('message-input').value;450 const maxTokens = parseInt(document.getElementById('max-tokens').value);451 const temperature = parseFloat(document.getElementById('temperature').value);452 453 if (!message.trim()) {454 logMessage('warning', 'Please enter a message');455 return;456 }457 458 addMessage('user', message);459 addMessage('debug', `Sending request: max_tokens=${maxTokens}, temperature=${temperature}`);460 461 try {462 logMessage('info', 'Sending non-streaming chat request...');463 464 const response = await fetch(`${API_BASE}/debug/simple-chat`, {465 method: 'POST',466 headers: {467 'Content-Type': 'application/json',468 },469 body: JSON.stringify({470 message: message471 })472 });473 474 if (!response.ok) {475 throw new Error(`HTTP ${response.status}: ${response.statusText}`);476 }477 478 const data = await response.json();479 480 if (data.status === 'success') {481 addMessage('assistant', data.response);482 logMessage('success', `Response received (${data.response.length} characters)`);483 } else {484 addMessage('assistant', `Error: ${data.error}`);485 logMessage('error', `API error: ${data.error}`);486 }487 488 } catch (error) {489 addMessage('assistant', `Network error: ${error.message}`);490 logMessage('error', `Network error: ${error.message}`);491 }492 }493 494 // Send streaming message495 async function sendStreamingMessage() {496 const message = document.getElementById('message-input').value;497 const maxTokens = parseInt(document.getElementById('max-tokens').value);498 const temperature = parseFloat(document.getElementById('temperature').value);499 500 if (!message.trim()) {501 logMessage('warning', 'Please enter a message');502 return;503 }504 505 addMessage('user', message);506 addMessage('debug', `Starting streaming: max_tokens=${maxTokens}, temperature=${temperature}`);507 508 // Create a placeholder for streaming response509 const streamingMessage = addMessage('assistant', '๐ Starting streaming...');510 511 try {512 logMessage('info', 'Starting SSE streaming request...');513 514 // Cancel any existing stream515 if (streamingController) {516 streamingController.abort();517 }518 519 streamingController = new AbortController();520 521 const response = await fetch(`${API_BASE}/debug/test-stream`, {522 method: 'POST',523 headers: {524 'Content-Type': 'application/json',525 },526 body: JSON.stringify({}),527 signal: streamingController.signal528 });529 530 if (!response.ok) {531 throw new Error(`HTTP ${response.status}: ${response.statusText}`);532 }533 534 const reader = response.body.getReader();535 const decoder = new TextDecoder();536 let buffer = '';537 let chunkCount = 0;538 539 updateStreamingMessage(streamingMessage, '๐ Receiving streaming data...\n\n');540 541 while (true) {542 const { done, value } = await reader.read();543 544 if (done) {545 logMessage('info', `Streaming completed: ${chunkCount} chunks received`);546 break;547 }548 549 buffer += decoder.decode(value, { stream: true });550 const lines = buffer.split('\n');551 buffer = lines.pop() || ''; // Keep incomplete line in buffer552 553 for (const line of lines) {554 if (line.startsWith('data: ')) {555 try {556 const data = JSON.parse(line.substring(6));557 chunkCount++;558 559 if (data.choices && data.choices[0] && data.choices[0].delta && data.choices[0].delta.content) {560 const content = data.choices[0].delta.content;561 appendToStreamingMessage(streamingMessage, content);562 logMessage('info', `Chunk ${chunkCount}: "${content}"`);563 }564 565 if (data.choices && data.choices[0] && data.choices[0].finish_reason === 'stop') {566 updateStreamingMessage(streamingMessage, streamingMessage.textContent + '\n\nโ
Streaming completed');567 logMessage('success', 'Streaming finished successfully');568 }569 570 } catch (e) {571 if (line.trim() === 'data: [DONE]') {572 updateStreamingMessage(streamingMessage, streamingMessage.textContent + '\n\nโ
Streaming completed');573 logMessage('success', 'Streaming finished with [DONE]');574 } else {575 logMessage('warning', `Failed to parse chunk: ${line}`);576 }577 }578 }579 }580 }581 582 } catch (error) {583 if (error.name === 'AbortError') {584 updateStreamingMessage(streamingMessage, streamingMessage.textContent + '\n\nโน๏ธ Streaming cancelled');585 logMessage('info', 'Streaming was cancelled');586 } else {587 updateStreamingMessage(streamingMessage, `โ Streaming error: ${error.message}`);588 logMessage('error', `Streaming error: ${error.message}`);589 }590 } finally {591 streamingController = null;592 }593 }594 595 // Test model596 async function testModel() {597 try {598 logMessage('info', 'Testing model status...');599 600 const response = await fetch(`${API_BASE}/debug/model`);601 const data = await response.json();602 603 addMessage('debug', `Model Test Results:\nStatus: ${data.status}\nModel ID: ${data.model_id}\nDevice: ${data.device}\nMessage: ${data.message}`);604 605 logMessage('success', `Model test passed: ${data.status}`);606 607 } catch (error) {608 addMessage('debug', `Model test failed: ${error.message}`);609 logMessage('error', `Model test error: ${error.message}`);610 }611 }612 613 // Check health614 async function checkHealth() {615 await updateServerStatus();616 }617 618 // Clear messages619 function clearMessages() {620 document.getElementById('chat-messages').innerHTML = '';621 logMessage('info', 'Messages cleared');622 }623 624 // Add message to chat625 function addMessage(type, content) {626 const messagesDiv = document.getElementById('chat-messages');627 const messageDiv = document.createElement('div');628 messageDiv.className = `message ${type}-message`;629 630 if (type === 'assistant') {631 messageDiv.innerHTML = `<strong>Assistant:</strong> ${content}`;632 } else if (type === 'user') {633 messageDiv.innerHTML = `<strong>You:</strong> ${content}`;634 } else if (type === 'debug') {635 messageDiv.className = 'message debug-message';636 messageDiv.innerHTML = `<strong>๐ง Debug:</strong> ${content}`;637 }638 639 messageDiv.innerHTML += `<br><span class="timestamp">${new Date().toLocaleTimeString()}</span>`;640 messagesDiv.appendChild(messageDiv);641 messagesDiv.scrollTop = messagesDiv.scrollHeight;642 643 return messageDiv;644 }645 646 // Update streaming message647 function updateStreamingMessage(messageElement, content) {648 messageElement.innerHTML = `<strong>Assistant:</strong> ${content}<br><span class="timestamp">${new Date().toLocaleTimeString()}</span>`;649 document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight;650 }651 652 // Append to streaming message653 function appendToStreamingMessage(messageElement, content) {654 const currentContent = messageElement.innerHTML;655 const assistantText = currentContent.replace(/<strong>Assistant:<\/strong>.*?<br>/, '');656 messageElement.innerHTML = `<strong>Assistant:</strong> ${assistantText}${content}<br><span class="timestamp">${new Date().toLocaleTimeString()}</span>`;657 document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight;658 }659 660 // Add log entry661 function logMessage(level, message) {662 const logDiv = document.getElementById('debug-log');663 const logEntry = document.createElement('div');664 logEntry.className = `log-entry log-${level}`;665 666 const timestamp = new Date().toLocaleTimeString();667 const levelIcon = {668 'info': 'โน๏ธ',669 'success': 'โ
',670 'warning': 'โ ๏ธ',671 'error': 'โ'672 }[level] || 'โน๏ธ';673 674 logEntry.textContent = `[${timestamp}] ${levelIcon} ${message}`;675 logDiv.appendChild(logEntry);676 logDiv.scrollTop = logDiv.scrollHeight;677 }678 679 // Auto-update status every 30 seconds680 setInterval(updateServerStatus, 30000);681 </script>682</body>683</html>