| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>NVIDIA LLM Local Endpoint Tester</title> |
| <style> |
| body { |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
| background-color: #121212; |
| color: #e0e0e0; |
| margin: 0; |
| padding: 20px; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| } |
| h1 { |
| color: #76b900; |
| margin-bottom: 20px; |
| } |
| .container { |
| width: 100%; |
| max-width: 800px; |
| background-color: #1e1e1e; |
| border-radius: 10px; |
| padding: 20px; |
| box-shadow: 0 4px 15px rgba(0,0,0,0.5); |
| } |
| .form-group { |
| margin-bottom: 15px; |
| } |
| label { |
| display: block; |
| margin-bottom: 5px; |
| font-weight: bold; |
| color: #bbb; |
| } |
| textarea, input[type="text"], input[type="number"] { |
| width: 100%; |
| padding: 10px; |
| border: 1px solid #333; |
| border-radius: 5px; |
| background-color: #2a2a2a; |
| color: #fff; |
| box-sizing: border-box; |
| } |
| textarea { |
| resize: vertical; |
| height: 120px; |
| } |
| button { |
| background-color: #76b900; |
| color: #000; |
| border: none; |
| padding: 10px 20px; |
| border-radius: 5px; |
| font-weight: bold; |
| cursor: pointer; |
| transition: background-color 0.2s; |
| font-size: 16px; |
| } |
| button:hover { |
| background-color: #8ce100; |
| } |
| button:disabled { |
| background-color: #444; |
| color: #888; |
| cursor: not-allowed; |
| } |
| .response-area { |
| margin-top: 20px; |
| } |
| .response-box { |
| background-color: #2a2a2a; |
| border: 1px solid #444; |
| border-radius: 5px; |
| padding: 15px; |
| min-height: 100px; |
| white-space: pre-wrap; |
| overflow-x: auto; |
| color: #dcdcdc; |
| line-height: 1.5; |
| } |
| .error { |
| color: #ff5252; |
| font-weight: bold; |
| } |
| .spinner { |
| display: none; |
| margin-left: 10px; |
| border: 3px solid rgba(255,255,255,0.1); |
| border-top: 3px solid #76b900; |
| border-radius: 50%; |
| width: 15px; |
| height: 15px; |
| animation: spin 1s linear infinite; |
| vertical-align: middle; |
| } |
| @keyframes spin { |
| 0% { transform: rotate(0deg); } |
| 100% { transform: rotate(360deg); } |
| } |
| </style> |
| </head> |
| <body> |
|
|
| <h1>NVIDIA LLM Tester</h1> |
| |
| <div class="container"> |
| <div class="form-group"> |
| <label for="endpoint">Local API Endpoint:</label> |
| <input type="text" id="endpoint" value="http://127.0.0.1:8003/v1/completions"> |
| </div> |
| |
| <div class="form-group"> |
| <label for="prompt">Prompt:</label> |
| <textarea id="prompt" placeholder="Enter your prompt here...">What are the top 3 features of NVIDIA GPUs for AI workloads?</textarea> |
| </div> |
| |
| <div class="form-group" style="display: flex; gap: 15px;"> |
| <div style="flex: 1;"> |
| <label for="max_tokens">Max Tokens:</label> |
| <input type="number" id="max_tokens" value="1024"> |
| </div> |
| <div style="flex: 1;"> |
| <label for="temperature">Temperature:</label> |
| <input type="number" id="temperature" value="0.5" step="0.1" min="0" max="2"> |
| </div> |
| </div> |
|
|
| <button id="send-btn"> |
| Send Request |
| <span class="spinner" id="spinner"></span> |
| </button> |
|
|
| <div class="response-area"> |
| <label>Response:</label> |
| <div class="response-box" id="response-box">Awaiting input...</div> |
| </div> |
| </div> |
|
|
| <script> |
| document.getElementById('send-btn').addEventListener('click', async () => { |
| const endpoint = document.getElementById('endpoint').value.trim(); |
| const promptText = document.getElementById('prompt').value.trim(); |
| const maxTokens = parseInt(document.getElementById('max_tokens').value) || 1024; |
| const temperature = parseFloat(document.getElementById('temperature').value) || 0.5; |
| const responseBox = document.getElementById('response-box'); |
| const sendBtn = document.getElementById('send-btn'); |
| const spinner = document.getElementById('spinner'); |
| |
| if (!promptText) { |
| alert("Please enter a prompt."); |
| return; |
| } |
| |
| |
| sendBtn.disabled = true; |
| spinner.style.display = 'inline-block'; |
| responseBox.innerHTML = '<i>Processing request...</i>'; |
| responseBox.classList.remove('error'); |
| |
| const payload = { |
| prompt: promptText, |
| max_tokens: maxTokens, |
| temperature: temperature |
| }; |
| |
| try { |
| const response = await fetch(endpoint, { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json' |
| }, |
| body: JSON.stringify(payload) |
| }); |
| |
| if (!response.ok) { |
| const errorData = await response.json().catch(() => null); |
| const errorMsg = errorData && errorData.error ? errorData.error : `HTTP error ${response.status}`; |
| throw new Error(errorMsg); |
| } |
| |
| const data = await response.json(); |
| |
| if (data.choices && data.choices.length > 0) { |
| responseBox.textContent = data.choices[0].text; |
| } else if (data.error) { |
| throw new Error(data.error); |
| } else { |
| responseBox.textContent = "Received unexpected response format:\n" + JSON.stringify(data, null, 2); |
| } |
| } catch (err) { |
| responseBox.textContent = `Error: ${err.message}`; |
| responseBox.classList.add('error'); |
| } finally { |
| sendBtn.disabled = false; |
| spinner.style.display = 'none'; |
| } |
| }); |
| </script> |
| </body> |
| </html> |
|
|