Spaces:
Sleeping
Sleeping
| <template> | |
| <div class="onnx-test-view"> | |
| <div class="test-header"> | |
| <h1>ONNX Model Inferencer Test</h1> | |
| <p class="subtitle">Testing GPT-2 Causal LM with ONNX Runtime Web</p> | |
| </div> | |
| <div class="test-body"> | |
| <!-- Model Status --> | |
| <div class="test-section"> | |
| <h2>Model Status</h2> | |
| <div class="status-info"> | |
| <div | |
| class="status-item" | |
| :class="{ ready: isInitialized, loading: isInitializing }" | |
| > | |
| <span class="status-label">Status:</span> | |
| <span class="status-value"> | |
| {{ | |
| isInitialized | |
| ? "✓ Ready" | |
| : isInitializing | |
| ? "⏳ Initializing..." | |
| : "⚪ Not initialized" | |
| }} | |
| </span> | |
| </div> | |
| <div v-if="modelInfo" class="status-item"> | |
| <span class="status-label">Inputs:</span> | |
| <span class="status-value">{{ modelInfo.inputs.join(", ") }}</span> | |
| </div> | |
| <div v-if="modelInfo" class="status-item"> | |
| <span class="status-label">Outputs:</span> | |
| <span class="status-value">{{ modelInfo.outputs.join(", ") }}</span> | |
| </div> | |
| <div v-if="error" class="error-message">❌ Error: {{ error }}</div> | |
| </div> | |
| <button | |
| class="btn btn-primary" | |
| @click="initialize" | |
| :disabled="isInitializing || isInitialized" | |
| > | |
| {{ isInitialized ? "Initialized" : "Initialize Model" }} | |
| </button> | |
| </div> | |
| <!-- Basic Inference Test --> | |
| <div class="test-section"> | |
| <h2>Test 1: Basic Inference</h2> | |
| <p>Run a single forward pass with random input</p> | |
| <button | |
| class="btn btn-test" | |
| @click="runBasicTest" | |
| :disabled="!isInitialized || isRunning" | |
| > | |
| {{ isRunning ? "Running..." : "Run Basic Test" }} | |
| </button> | |
| <div v-if="basicTestResult" class="test-result"> | |
| <h3>Results:</h3> | |
| <div class="result-item"> | |
| <span class="label">Inference Time:</span> | |
| <span class="value">{{ basicTestResult.inferenceTime.toFixed(2) }}ms</span> | |
| </div> | |
| <div class="result-item"> | |
| <span class="label">Sample Tokens:</span> | |
| <span class="value code" | |
| >{{ basicTestResult.tokens.slice(0, 20).join(", ") }}...</span | |
| > | |
| </div> | |
| <div class="result-item"> | |
| <span class="label">Sample Text:</span> | |
| <span class="value code">{{ basicTestResult.text.slice(0, 100) }}...</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Text Generation Test --> | |
| <div class="test-section"> | |
| <h2>Test 2: Text Generation</h2> | |
| <p>Generate tokens autoregressively from a prompt</p> | |
| <div class="input-group"> | |
| <label for="prompt">Prompt:</label> | |
| <input | |
| id="prompt" | |
| v-model="prompt" | |
| type="text" | |
| placeholder="Enter prompt text..." | |
| :disabled="!isInitialized" | |
| /> | |
| </div> | |
| <div class="input-group"> | |
| <label for="numTokens">Number of Tokens:</label> | |
| <input | |
| id="numTokens" | |
| v-model.number="numTokens" | |
| type="number" | |
| min="1" | |
| max="50" | |
| :disabled="!isInitialized" | |
| /> | |
| </div> | |
| <button | |
| class="btn btn-test" | |
| @click="runGenerationTest" | |
| :disabled="!isInitialized || isRunning || !prompt" | |
| > | |
| {{ isRunning ? "Generating..." : "Generate Text" }} | |
| </button> | |
| <div v-if="generationResult" class="test-result"> | |
| <h3>Generated Output:</h3> | |
| <div class="result-item"> | |
| <span class="label">Avg Inference Time:</span> | |
| <span class="value">{{ generationResult.inferenceTime.toFixed(2) }}ms</span> | |
| </div> | |
| <div class="result-item"> | |
| <span class="label">Tokens/sec:</span> | |
| <span class="value">{{ | |
| (1000 / generationResult.inferenceTime).toFixed(2) | |
| }}</span> | |
| </div> | |
| <div class="result-item full-width"> | |
| <span class="label">Token Sequence:</span> | |
| <span class="value code">{{ generationResult.tokens.join(", ") }}</span> | |
| </div> | |
| <div class="result-item full-width"> | |
| <span class="label">Generated Text:</span> | |
| <div class="generated-text">{{ generationResult.text }}</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Console Output --> | |
| <div class="test-section"> | |
| <h2>Console Output</h2> | |
| <p>Check the browser console (F12) for detailed logs</p> | |
| <button class="btn btn-secondary" @click="clearConsole">Clear Console</button> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <script setup lang="ts"> | |
| import { ref } from "vue"; | |
| import { OnnxInferencer, type InferenceResult } from "@/services/onnxInferencer"; | |
| // Inferencer instance | |
| let inferencer: OnnxInferencer | null = null; | |
| // State | |
| const isInitializing = ref(false); | |
| const isInitialized = ref(false); | |
| const isRunning = ref(false); | |
| const error = ref<string | null>(null); | |
| const modelInfo = ref<{ inputs: string[]; outputs: string[] } | null>(null); | |
| // Test state | |
| const basicTestResult = ref<InferenceResult | null>(null); | |
| const generationResult = ref<InferenceResult | null>(null); | |
| const prompt = ref("[Board 5x5]"); | |
| const numTokens = ref(10); | |
| /** | |
| * Initialize the inferencer | |
| */ | |
| const initialize = async () => { | |
| isInitializing.value = true; | |
| error.value = null; | |
| try { | |
| console.log("=".repeat(80)); | |
| console.log("Initializing ONNX Inferencer..."); | |
| console.log("=".repeat(80)); | |
| inferencer = new OnnxInferencer({ | |
| modelPath: "/onnx/GPT2CausalLM_ep0015_int8_seq2048_int8.onnx", | |
| vocabSize: 259, | |
| seqLen: 2048, | |
| executionProviders: ["wasm"] // Use WebAssembly for compatibility | |
| }); | |
| await inferencer.initialize(); | |
| modelInfo.value = inferencer.getModelInfo(); | |
| isInitialized.value = true; | |
| console.log("✓ Initialization complete!"); | |
| console.log("=".repeat(80)); | |
| } catch (err) { | |
| error.value = err instanceof Error ? err.message : "Unknown error"; | |
| console.error("Initialization failed:", err); | |
| } finally { | |
| isInitializing.value = false; | |
| } | |
| }; | |
| /** | |
| * Run basic inference test | |
| */ | |
| const runBasicTest = async () => { | |
| if (!inferencer) return; | |
| isRunning.value = true; | |
| error.value = null; | |
| basicTestResult.value = null; | |
| try { | |
| console.log("\n" + "=".repeat(80)); | |
| console.log("Running Basic Inference Test..."); | |
| console.log("=".repeat(80)); | |
| const result = await inferencer.testBasicInference(); | |
| basicTestResult.value = result; | |
| console.log("✓ Basic test complete!"); | |
| console.log("=".repeat(80)); | |
| } catch (err) { | |
| error.value = err instanceof Error ? err.message : "Test failed"; | |
| console.error("Basic test failed:", err); | |
| } finally { | |
| isRunning.value = false; | |
| } | |
| }; | |
| /** | |
| * Run text generation test | |
| */ | |
| const runGenerationTest = async () => { | |
| if (!inferencer) return; | |
| isRunning.value = true; | |
| error.value = null; | |
| generationResult.value = null; | |
| try { | |
| console.log("\n" + "=".repeat(80)); | |
| console.log("Running Text Generation Test..."); | |
| console.log("=".repeat(80)); | |
| const result = await inferencer.generateText(prompt.value, numTokens.value); | |
| generationResult.value = result; | |
| console.log("✓ Generation test complete!"); | |
| console.log("=".repeat(80)); | |
| } catch (err) { | |
| error.value = err instanceof Error ? err.message : "Generation failed"; | |
| console.error("Generation test failed:", err); | |
| } finally { | |
| isRunning.value = false; | |
| } | |
| }; | |
| /** | |
| * Clear browser console | |
| */ | |
| const clearConsole = () => { | |
| console.clear(); | |
| console.log("Console cleared"); | |
| }; | |
| </script> | |
| <style lang="scss" scoped> | |
| .onnx-test-view { | |
| display: flex; | |
| flex-direction: column; | |
| height: 100%; | |
| background-color: #f5f5f5; | |
| overflow: auto; | |
| } | |
| .test-header { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 2rem; | |
| text-align: center; | |
| h1 { | |
| margin: 0 0 0.5rem 0; | |
| font-size: 2rem; | |
| font-weight: 700; | |
| } | |
| .subtitle { | |
| margin: 0; | |
| opacity: 0.9; | |
| font-size: 1.1rem; | |
| } | |
| } | |
| .test-body { | |
| flex: 1; | |
| padding: 2rem; | |
| max-width: 1000px; | |
| margin: 0 auto; | |
| width: 100%; | |
| } | |
| .test-section { | |
| background: white; | |
| border-radius: 12px; | |
| padding: 1.5rem; | |
| margin-bottom: 1.5rem; | |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | |
| h2 { | |
| margin: 0 0 0.5rem 0; | |
| color: #333; | |
| font-size: 1.3rem; | |
| font-weight: 600; | |
| } | |
| p { | |
| margin: 0 0 1rem 0; | |
| color: #666; | |
| } | |
| } | |
| .status-info { | |
| background: #f8f9fa; | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin-bottom: 1rem; | |
| .status-item { | |
| display: flex; | |
| justify-content: space-between; | |
| padding: 0.5rem 0; | |
| border-bottom: 1px solid #e9ecef; | |
| &:last-child { | |
| border-bottom: none; | |
| } | |
| &.ready { | |
| .status-value { | |
| color: #28a745; | |
| font-weight: 600; | |
| } | |
| } | |
| &.loading { | |
| .status-value { | |
| color: #ffc107; | |
| font-weight: 600; | |
| } | |
| } | |
| .status-label { | |
| font-weight: 600; | |
| color: #666; | |
| } | |
| .status-value { | |
| color: #333; | |
| } | |
| } | |
| } | |
| .error-message { | |
| background: #fff3cd; | |
| border: 1px solid #ffeaa7; | |
| border-radius: 6px; | |
| padding: 0.75rem; | |
| color: #856404; | |
| margin-top: 1rem; | |
| } | |
| .btn { | |
| padding: 0.75rem 1.5rem; | |
| border: none; | |
| border-radius: 8px; | |
| font-weight: 600; | |
| font-size: 1rem; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| &:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| &.btn-primary { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| &:hover:not(:disabled) { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4); | |
| } | |
| } | |
| &.btn-test { | |
| background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); | |
| color: white; | |
| &:hover:not(:disabled) { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4); | |
| } | |
| } | |
| &.btn-secondary { | |
| background: #6c757d; | |
| color: white; | |
| &:hover:not(:disabled) { | |
| background: #5a6268; | |
| } | |
| } | |
| } | |
| .input-group { | |
| margin-bottom: 1rem; | |
| label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| font-weight: 600; | |
| color: #333; | |
| } | |
| input { | |
| width: 100%; | |
| padding: 0.75rem; | |
| border: 2px solid #e9ecef; | |
| border-radius: 8px; | |
| font-size: 1rem; | |
| transition: border-color 0.3s ease; | |
| &:focus { | |
| outline: none; | |
| border-color: #667eea; | |
| } | |
| &:disabled { | |
| background-color: #f8f9fa; | |
| cursor: not-allowed; | |
| } | |
| } | |
| } | |
| .test-result { | |
| background: #f8f9fa; | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin-top: 1rem; | |
| h3 { | |
| margin: 0 0 1rem 0; | |
| color: #333; | |
| font-size: 1.1rem; | |
| } | |
| .result-item { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: flex-start; | |
| padding: 0.5rem 0; | |
| border-bottom: 1px solid #e9ecef; | |
| &:last-child { | |
| border-bottom: none; | |
| } | |
| &.full-width { | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| .label { | |
| font-weight: 600; | |
| color: #666; | |
| min-width: 150px; | |
| } | |
| .value { | |
| color: #333; | |
| flex: 1; | |
| text-align: right; | |
| &.code { | |
| font-family: "Courier New", monospace; | |
| background: #fff; | |
| padding: 0.25rem 0.5rem; | |
| border-radius: 4px; | |
| font-size: 0.9rem; | |
| text-align: left; | |
| } | |
| } | |
| } | |
| .generated-text { | |
| background: white; | |
| border: 2px solid #e9ecef; | |
| border-radius: 8px; | |
| padding: 1rem; | |
| font-family: "Courier New", monospace; | |
| font-size: 0.95rem; | |
| line-height: 1.6; | |
| color: #333; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| } | |
| } | |
| </style> | |