2796gauravc's picture
Update index.html
06a65ac verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FUNCTIONGEMMA | TUTORIAL</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bungee&family=JetBrains+Mono:wght@400;700;800&family=Space+Grotesk:wght@400;700&display=swap" rel="stylesheet">
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-2Q4M55VKPR"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-2Q4M55VKPR', {
page_path: window.location.pathname,
anonymize_ip: true
});
</script>
<style>
:root {
--black: #000000;
--white: #FFFFFF;
--yellow: #FFFF00;
--red: #FF0000;
--green: #00FF00;
--cyan: #00FFFF;
--border-width: 4px;
--shadow-offset: 8px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Space Grotesk', sans-serif;
background: var(--black);
color: var(--white);
min-height: 100vh;
padding: 20px;
line-height: 1.6;
position: relative;
overflow-x: hidden;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
repeating-linear-gradient(90deg, transparent, transparent 50px, rgba(255,255,0,0.03) 50px, rgba(255,255,0,0.03) 52px),
repeating-linear-gradient(0deg, transparent, transparent 50px, rgba(255,0,0,0.03) 50px, rgba(255,0,0,0.03) 52px);
pointer-events: none;
z-index: 0;
}
.container {
max-width: 1600px;
margin: 0 auto;
position: relative;
z-index: 1;
}
.header {
background: var(--black);
border: var(--border-width) solid var(--white);
padding: 40px;
margin-bottom: 30px;
box-shadow: var(--shadow-offset) var(--shadow-offset) 0 var(--yellow);
position: relative;
animation: slideDown 0.6s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.header::before {
content: '';
position: absolute;
top: -4px;
left: -4px;
right: -4px;
bottom: -4px;
border: 2px solid var(--yellow);
z-index: -1;
}
.header h1 {
font-family: 'Bungee', cursive;
font-size: 3.5em;
color: var(--yellow);
margin-bottom: 15px;
text-transform: uppercase;
letter-spacing: 2px;
text-shadow: 4px 4px 0 var(--red);
line-height: 1.1;
}
.header p {
font-size: 1.3em;
color: var(--white);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
}
.model-loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--black);
z-index: 10000;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: var(--border-width) solid var(--yellow);
}
.model-loading-overlay.hidden {
display: none;
}
.loading-content {
max-width: 800px;
padding: 40px;
background: var(--black);
border: var(--border-width) solid var(--white);
box-shadow: var(--shadow-offset) var(--shadow-offset) 0 var(--cyan);
}
.loading-title {
font-family: 'Bungee', cursive;
font-size: 2.5em;
color: var(--yellow);
margin-bottom: 30px;
text-transform: uppercase;
text-align: center;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.loading-steps {
list-style: none;
margin: 20px 0;
}
.loading-step {
padding: 15px;
margin: 10px 0;
background: var(--black);
border: 2px solid var(--white);
color: var(--white);
font-family: 'JetBrains Mono', monospace;
position: relative;
transition: all 0.3s ease;
}
.loading-step.active {
border-color: var(--yellow);
background: rgba(255, 255, 0, 0.1);
box-shadow: 4px 4px 0 var(--yellow);
}
.loading-step.completed {
border-color: var(--green);
background: rgba(0, 255, 0, 0.1);
}
.loading-step.completed::after {
content: ' โœ“';
color: var(--green);
font-weight: bold;
}
.model-info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 30px 0;
}
.info-card {
background: var(--black);
border: var(--border-width) solid var(--white);
padding: 20px;
box-shadow: 6px 6px 0 var(--cyan);
}
.info-card h3 {
font-family: 'Bungee', cursive;
color: var(--cyan);
font-size: 1.2em;
margin-bottom: 10px;
text-transform: uppercase;
}
.info-card p {
font-family: 'JetBrains Mono', monospace;
color: var(--white);
font-size: 0.9em;
}
.resource-links {
margin: 30px 0;
padding: 20px;
background: var(--black);
border: var(--border-width) solid var(--yellow);
box-shadow: var(--shadow-offset) var(--shadow-offset) 0 var(--red);
}
.resource-links h3 {
font-family: 'Bungee', cursive;
color: var(--yellow);
margin-bottom: 15px;
text-transform: uppercase;
font-size: 1.5em;
}
.resource-links ul {
list-style: none;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 15px;
}
.resource-links li {
padding: 15px;
background: var(--black);
border: 2px solid var(--white);
}
.resource-links a {
color: var(--cyan);
text-decoration: none;
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
transition: all 0.2s ease;
display: block;
}
.resource-links a:hover {
color: var(--yellow);
transform: translateX(5px);
}
.progress-bar {
background: var(--black);
border: var(--border-width) solid var(--white);
padding: 20px;
margin-bottom: 30px;
display: flex;
align-items: center;
gap: 20px;
box-shadow: var(--shadow-offset) var(--shadow-offset) 0 var(--cyan);
}
.progress-fill {
flex: 1;
height: 40px;
background: var(--black);
border: 2px solid var(--white);
position: relative;
overflow: hidden;
}
.progress-inner {
height: 100%;
background: var(--yellow);
transition: width 0.5s ease;
display: flex;
align-items: center;
justify-content: center;
color: var(--black);
font-weight: 800;
font-family: 'Bungee', cursive;
font-size: 1.1em;
text-transform: uppercase;
}
.main-content {
display: grid;
grid-template-columns: 320px 1fr;
gap: 30px;
}
.sidebar {
background: var(--black);
border: var(--border-width) solid var(--white);
padding: 25px;
box-shadow: var(--shadow-offset) var(--shadow-offset) 0 var(--red);
height: fit-content;
position: sticky;
top: 20px;
}
.model-status {
background: var(--black);
border: 2px solid var(--white);
padding: 15px;
margin-bottom: 25px;
text-align: center;
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
}
.model-status.loaded {
border-color: var(--green);
box-shadow: 4px 4px 0 var(--green);
}
.model-status-text {
color: var(--white);
}
.model-status.loaded .model-status-text {
color: var(--green);
}
.lesson-list {
list-style: none;
}
.lesson-item {
padding: 18px;
margin: 12px 0;
background: var(--black);
border: 2px solid var(--white);
cursor: pointer;
transition: all 0.2s ease;
font-weight: 700;
text-transform: uppercase;
font-size: 0.9em;
letter-spacing: 0.5px;
}
.lesson-item:hover {
transform: translate(4px, 4px);
box-shadow: -4px -4px 0 var(--yellow);
}
.lesson-item.active {
background: var(--yellow);
color: var(--black);
border-color: var(--yellow);
box-shadow: var(--shadow-offset) var(--shadow-offset) 0 var(--red);
}
.lesson-item.completed {
border-color: var(--green);
}
.lesson-item.completed::after {
content: " โœ“";
color: var(--green);
font-weight: bold;
}
.content-area {
background: var(--black);
border: var(--border-width) solid var(--white);
padding: 40px;
box-shadow: var(--shadow-offset) var(--shadow-offset) 0 var(--cyan);
min-height: 600px;
}
.lesson-content {
display: none;
}
.lesson-content.active {
display: block;
animation: fadeInSlide 0.5s ease;
}
@keyframes fadeInSlide {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.lesson-title {
font-family: 'Bungee', cursive;
font-size: 2.5em;
margin-bottom: 25px;
color: var(--yellow);
text-transform: uppercase;
text-shadow: 3px 3px 0 var(--red);
border-bottom: var(--border-width) solid var(--yellow);
padding-bottom: 15px;
}
.lesson-description {
font-size: 1.1em;
line-height: 1.8;
margin-bottom: 30px;
color: var(--white);
}
.code-block {
background: var(--black);
border: var(--border-width) solid var(--yellow);
padding: 25px;
margin: 25px 0;
overflow-x: auto;
position: relative;
box-shadow: 6px 6px 0 var(--cyan);
}
.code-block pre {
color: var(--green);
font-family: 'JetBrains Mono', monospace;
font-size: 14px;
line-height: 1.8;
margin: 0;
font-weight: 400;
}
.code-comment {
color: #888;
font-style: italic;
}
.code-keyword {
color: var(--red);
font-weight: 700;
}
.code-string {
color: var(--cyan);
}
.code-function {
color: var(--yellow);
}
.interactive-demo {
background: var(--black);
border: var(--border-width) solid var(--white);
padding: 25px;
margin: 25px 0;
box-shadow: 6px 6px 0 var(--red);
}
.interactive-demo h3 {
font-family: 'Bungee', cursive;
color: var(--yellow);
margin-bottom: 20px;
text-transform: uppercase;
font-size: 1.5em;
}
.demo-controls {
display: flex;
gap: 15px;
margin-bottom: 20px;
flex-wrap: wrap;
}
button {
background: var(--black);
color: var(--white);
border: var(--border-width) solid var(--white);
padding: 15px 30px;
font-size: 16px;
font-weight: 800;
cursor: pointer;
transition: all 0.2s ease;
font-family: 'Space Grotesk', sans-serif;
text-transform: uppercase;
letter-spacing: 1px;
box-shadow: 4px 4px 0 var(--yellow);
}
button:hover:not(:disabled) {
transform: translate(2px, 2px);
box-shadow: 2px 2px 0 var(--yellow);
}
button:active:not(:disabled) {
transform: translate(4px, 4px);
box-shadow: 0 0 0 var(--yellow);
}
button:disabled {
background: #333;
border-color: #666;
color: #666;
cursor: not-allowed;
box-shadow: none;
}
.btn-success {
border-color: var(--green);
box-shadow: 4px 4px 0 var(--green);
color: var(--green);
}
.btn-success:hover:not(:disabled) {
box-shadow: 2px 2px 0 var(--green);
}
.btn-danger {
border-color: var(--red);
box-shadow: 4px 4px 0 var(--red);
color: var(--red);
}
.btn-danger:hover:not(:disabled) {
box-shadow: 2px 2px 0 var(--red);
}
.output-area {
background: var(--black);
border: var(--border-width) solid var(--cyan);
padding: 20px;
margin: 20px 0;
min-height: 150px;
max-height: 500px;
overflow-y: auto;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
box-shadow: 6px 6px 0 var(--yellow);
}
.token-visualization {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin: 25px 0;
}
.token-box {
background: var(--black);
border: 2px solid var(--white);
padding: 15px 20px;
text-align: center;
min-width: 140px;
transition: all 0.2s ease;
box-shadow: 4px 4px 0 var(--cyan);
}
.token-box:hover {
transform: translate(-2px, -2px);
box-shadow: 6px 6px 0 var(--yellow);
border-color: var(--yellow);
}
.token-id {
font-size: 11px;
color: #888;
margin-bottom: 8px;
font-family: 'JetBrains Mono', monospace;
}
.token-text {
font-size: 18px;
color: var(--green);
font-weight: 800;
font-family: 'JetBrains Mono', monospace;
}
.hint-box, .info-box, .success-box, .error-box {
background: var(--black);
border-left: var(--border-width) solid;
padding: 20px;
margin: 20px 0;
box-shadow: 4px 4px 0;
}
.hint-box {
border-color: var(--yellow);
box-shadow: 4px 4px 0 var(--yellow);
}
.hint-box h4 {
color: var(--yellow);
margin-bottom: 12px;
font-family: 'Bungee', cursive;
text-transform: uppercase;
font-size: 1.2em;
}
.info-box {
border-color: var(--cyan);
box-shadow: 4px 4px 0 var(--cyan);
}
.info-box h4 {
color: var(--cyan);
margin-bottom: 12px;
font-family: 'Bungee', cursive;
text-transform: uppercase;
font-size: 1.2em;
}
.success-box {
border-color: var(--green);
box-shadow: 4px 4px 0 var(--green);
}
.success-box h4 {
color: var(--green);
margin-bottom: 12px;
font-family: 'Bungee', cursive;
text-transform: uppercase;
font-size: 1.2em;
}
.error-box {
border-color: var(--red);
box-shadow: 4px 4px 0 var(--red);
}
.error-box h4 {
color: var(--red);
margin-bottom: 12px;
font-family: 'Bungee', cursive;
text-transform: uppercase;
font-size: 1.2em;
}
.comparison-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin: 25px 0;
border: var(--border-width) solid var(--white);
}
.comparison-table th,
.comparison-table td {
padding: 15px;
text-align: left;
border-bottom: 2px solid var(--white);
border-right: 2px solid var(--white);
}
.comparison-table th {
background: var(--yellow);
color: var(--black);
font-family: 'Bungee', cursive;
text-transform: uppercase;
font-weight: 400;
}
.comparison-table tr:hover {
background: rgba(255, 255, 0, 0.1);
}
.comparison-table td:last-child,
.comparison-table th:last-child {
border-right: none;
}
.achievement-badge {
display: inline-block;
background: var(--yellow);
color: var(--black);
padding: 8px 15px;
border: 2px solid var(--black);
font-size: 12px;
font-weight: 800;
margin: 5px;
text-transform: uppercase;
font-family: 'Bungee', cursive;
box-shadow: 3px 3px 0 var(--red);
}
input[type="text"],
textarea {
background: var(--black);
border: var(--border-width) solid var(--white);
color: var(--white);
padding: 15px;
font-size: 14px;
width: 100%;
font-family: 'JetBrains Mono', monospace;
margin-bottom: 15px;
box-shadow: 4px 4px 0 var(--cyan);
}
input[type="text"]:focus,
textarea:focus {
outline: none;
border-color: var(--yellow);
box-shadow: 4px 4px 0 var(--yellow);
}
.loading-spinner {
display: inline-block;
width: 24px;
height: 24px;
border: 3px solid var(--white);
border-top-color: var(--yellow);
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.playground-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 25px;
margin: 25px 0;
}
.playground-section {
background: var(--black);
border: var(--border-width) solid var(--white);
padding: 25px;
box-shadow: 6px 6px 0 var(--red);
}
.playground-section h3 {
font-family: 'Bungee', cursive;
color: var(--yellow);
margin-bottom: 15px;
text-transform: uppercase;
}
textarea {
min-height: 300px;
resize: vertical;
}
.resource-badge {
display: inline-block;
background: var(--black);
border: 2px solid var(--cyan);
padding: 5px 10px;
margin: 5px;
font-size: 11px;
font-family: 'JetBrains Mono', monospace;
color: var(--cyan);
text-transform: uppercase;
}
.example-item {
background: var(--black);
border: 2px solid var(--white);
padding: 20px;
margin: 15px 0;
box-shadow: 4px 4px 0 var(--cyan);
position: relative;
}
.example-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.example-item h4 {
font-family: 'Bungee', cursive;
color: var(--yellow);
font-size: 1em;
margin: 0;
text-transform: uppercase;
}
.example-item input,
.example-item textarea {
width: 100%;
margin-bottom: 10px;
font-size: 13px;
}
.example-item textarea {
min-height: 60px;
resize: vertical;
}
.remove-example-btn {
background: var(--black);
color: var(--red);
border: 2px solid var(--red);
padding: 8px 15px;
font-size: 12px;
cursor: pointer;
font-weight: 700;
text-transform: uppercase;
box-shadow: 3px 3px 0 var(--red);
}
.remove-example-btn:hover {
transform: translate(1px, 1px);
box-shadow: 2px 2px 0 var(--red);
}
@media (max-width: 1024px) {
.main-content {
grid-template-columns: 1fr;
}
.sidebar {
position: static;
}
.playground-grid {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2.5em;
}
}
@media (max-width: 768px) {
.header h1 {
font-size: 2em;
}
.lesson-title {
font-size: 1.8em;
}
.model-info-grid {
grid-template-columns: 1fr;
}
.resource-links ul {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<!-- Model Loading Overlay -->
<div class="model-loading-overlay" id="loadingOverlay">
<div class="loading-content">
<h2 class="loading-title">LOADING FUNCTIONGEMMA</h2>
<ul class="loading-steps" id="loadingSteps">
<li class="loading-step" id="step1">Initializing transformers.js...</li>
<li class="loading-step" id="step2">Loading tokenizer...</li>
<li class="loading-step" id="step3">Detecting device capabilities...</li>
<li class="loading-step" id="step4">Loading ONNX model...</li>
<li class="loading-step" id="step5">Model ready!</li>
</ul>
<div class="model-info-grid" id="modelInfoGrid" style="display: none;">
<div class="info-card">
<h3>MODEL</h3>
<p>functiongemma-270m-it-ONNX</p>
</div>
<div class="info-card">
<h3>PARAMETERS</h3>
<p>270 Million</p>
</div>
<div class="info-card">
<h3>FORMAT</h3>
<p id="modelFormat">Detecting...</p>
</div>
<div class="info-card">
<h3>DEVICE</h3>
<p id="modelDevice">Detecting...</p>
</div>
</div>
</div>
</div>
<div class="container">
<div class="header">
<h1>FUNCTIONGEMMA</h1>
<p>INTERACTIVE TUTORIAL</p>
<p style="font-size: 0.9em; margin-top: 10px; font-weight: 400; text-transform: none;">Master Function Calling, Tokenization & Prompt Engineering</p>
</div>
<div class="progress-bar">
<div class="progress-fill">
<div class="progress-inner" id="progressBar" style="width: 0%">0% COMPLETE</div>
</div>
<div id="achievements"></div>
</div>
<div class="main-content">
<div class="sidebar">
<div class="model-status" id="modelStatus">
<strong>STATUS:</strong> <span class="model-status-text" id="modelStatusText">READY</span>
</div>
<ul class="lesson-list">
<li class="lesson-item active" data-lesson="0">๐Ÿš€ WELCOME</li>
<li class="lesson-item" data-lesson="1">๐Ÿ”ค TOKENIZATION</li>
<li class="lesson-item" data-lesson="2">โŒ ZERO-SHOT</li>
<li class="lesson-item" data-lesson="3">โš ๏ธ ONE-SHOT</li>
<li class="lesson-item" data-lesson="4">โœ… FEW-SHOT</li>
<li class="lesson-item" data-lesson="5">๐Ÿ” TOKEN DIVE</li>
<li class="lesson-item" data-lesson="6">๐ŸŽฏ PLAYGROUND</li>
<li class="lesson-item" data-lesson="7">๐Ÿ“š RESOURCES</li>
</ul>
</div>
<div class="content-area">
<!-- Lesson 0: Welcome -->
<div class="lesson-content active" data-lesson="0">
<h2 class="lesson-title">WELCOME TO FUNCTIONGEMMA</h2>
<div class="lesson-description">
<p>Welcome to the tutorial on FunctionGemma. This interactive experience will teach you everything about function calling, tokenization, and prompt engineering through hands-on experimentation.</p>
<div class="info-box">
<h4>WHAT YOU'LL LEARN</h4>
<ul style="margin-left: 20px; line-height: 2.5;">
<li>How tokenization works in language models</li>
<li>Why zero-shot function calling fails</li>
<li>How few-shot examples solve the problem</li>
<li>Token-level analysis and debugging</li>
<li>Best practices for prompt engineering</li>
<li>ONNX model optimization and deployment</li>
</ul>
</div>
<div class="hint-box">
<h4>ABOUT FUNCTIONGEMMA-270M-IT-ONNX</h4>
<p><strong>Model:</strong> onnx-community/functiongemma-270m-it-ONNX</p>
<p><strong>Size:</strong> 270 million parameters</p>
<p><strong>Purpose:</strong> Specialized for function calling tasks</p>
<p><strong>Format:</strong> ONNX quantized (q4 for WebGPU, q8 for WASM)</p>
<p><strong>Key Finding:</strong> Requires few-shot examples to generate correct function calls!</p>
<p><strong>Architecture:</strong> Based on Google's Gemma 3 270M, fine-tuned for function calling</p>
</div>
<div class="success-box">
<h4>MODEL LOADED SUCCESSFULLY</h4>
<p>The model has been automatically loaded and is ready to use. You can now proceed with the lessons!</p>
</div>
</div>
</div>
<!-- Lesson 1: Tokenization -->
<div class="lesson-content" data-lesson="1">
<h2 class="lesson-title">TOKENIZATION BASICS</h2>
<div class="lesson-description">
<p>Tokenization is the process of converting text into tokens (numbers) that the model can understand. Let's explore this interactively!</p>
<div class="info-box">
<h4>WHAT IS TOKENIZATION?</h4>
<p>Language models don't understand words directly. They work with <strong>tokens</strong> - numeric IDs that represent pieces of text. A token can be a word, part of a word, or even a single character.</p>
</div>
<div class="interactive-demo">
<h3>TRY IT YOURSELF</h3>
<input type="text" id="tokenizeInput" placeholder="Enter text to tokenize..." value="call:get_current_temperature">
<button onclick="demonstrateTokenization()">TOKENIZE</button>
<div id="tokenizationOutput" class="output-area" style="margin-top: 15px;"></div>
</div>
<div class="code-block">
<pre><span class="code-comment">// How tokenization works in code:</span>
<span class="code-keyword">const</span> text = <span class="code-string">"call:get_current_temperature"</span>;
<span class="code-comment">// Tokenize the text</span>
<span class="code-keyword">const</span> tokens = <span class="code-function">await tokenizer</span>.encode(text);
<span class="code-comment">// Result: [6639, 236787, 828, 236779, 4002, 236779, 27495]</span>
<span class="code-comment">// Each number represents a token ID</span>
<span class="code-comment">// Decode tokens back to text</span>
<span class="code-keyword">const</span> decoded = <span class="code-function">await tokenizer</span>.decode(tokens);
<span class="code-comment">// Result: "call:get_current_temperature"</span></pre>
</div>
<div class="hint-box">
<h4>KEY INSIGHT</h4>
<p>Special tokens like <code>&lt;start_function_call&gt;</code> have specific token IDs (e.g., token 48). The model uses these to understand structure.</p>
</div>
</div>
</div>
<!-- Lesson 2: Zero-Shot -->
<div class="lesson-content" data-lesson="2">
<h2 class="lesson-title">ZERO-SHOT FUNCTION CALLING (WHY IT FAILS)</h2>
<div class="lesson-description">
<p>Zero-shot means asking the model to do something without showing it an example. Let's see what happens!</p>
<div class="error-box">
<h4>THE PROBLEM</h4>
<p>Without examples, FunctionGemma generates <code>error:</code> instead of <code>call:</code> after <code>&lt;start_function_call&gt;</code>.</p>
</div>
<div class="interactive-demo">
<h3>TEST ZERO-SHOT APPROACH</h3>
<input type="text" id="zeroShotQuery" value="What's the temperature in London?" placeholder="Enter your query...">
<button onclick="testZeroShot()">TEST ZERO-SHOT</button>
<div id="zeroShotOutput" class="output-area" style="margin-top: 15px;"></div>
</div>
<div class="code-block">
<pre><span class="code-comment">// Zero-shot approach - NO examples provided</span>
<span class="code-keyword">const</span> messages = [
{
role: <span class="code-string">"developer"</span>,
content: <span class="code-string">"You are a model that can do function calling..."</span>
},
{
role: <span class="code-string">"user"</span>,
content: <span class="code-string">"What's the temperature in London?"</span>
}
<span class="code-comment">// โŒ No example shown to the model!</span>
];
<span class="code-comment">// Result: Model generates "error:" instead of "call:"</span>
<span class="code-comment">// Token 1899 ("error") is chosen instead of token 6639 ("call")</span></pre>
</div>
<div class="hint-box">
<h4>TOKEN ANALYSIS</h4>
<p>After <code>&lt;start_function_call&gt;</code> (token 48), the model's probability distribution favors token 1899 ("error") over token 6639 ("call") when no example is provided.</p>
</div>
</div>
</div>
<!-- Lesson 3: One-Shot -->
<div class="lesson-content" data-lesson="3">
<h2 class="lesson-title">ONE-SHOT FUNCTION CALLING (PARTIAL SUCCESS)</h2>
<div class="lesson-description">
<p>One-shot means showing the model ONE example. Let's see if this helps!</p>
<div class="interactive-demo">
<h3>TEST ONE-SHOT APPROACH</h3>
<input type="text" id="oneShotQuery" value="What's the temperature in Tokyo?" placeholder="Enter your query...">
<button onclick="testOneShot()">TEST ONE-SHOT</button>
<div id="oneShotOutput" class="output-area" style="margin-top: 15px;"></div>
</div>
<div class="code-block">
<pre><span class="code-comment">// One-shot approach - ONE example provided</span>
<span class="code-keyword">const</span> messages = [
{
role: <span class="code-string">"developer"</span>,
content: <span class="code-string">"You are a model that can do function calling..."</span>
},
{
role: <span class="code-string">"user"</span>,
content: <span class="code-string">"What's the temperature in Paris?"</span>
},
{
role: <span class="code-string">"assistant"</span>,
<span class="code-comment">// โœ… ONE example showing correct format</span>
content: <span class="code-string">"&lt;start_function_call&gt;call:get_current_temperature{location:&lt;escape&gt;Paris&lt;escape&gt;}&lt;end_function_call&gt;"</span>
},
{
role: <span class="code-string">"user"</span>,
content: <span class="code-string">"What's the temperature in Tokyo?"</span>
}
];</pre>
</div>
<div class="info-box">
<h4>RESULTS MAY VARY</h4>
<p>One-shot can work sometimes, but it's not as reliable as few-shot. The model needs more context to consistently generate correct function calls.</p>
</div>
</div>
</div>
<!-- Lesson 4: Few-Shot -->
<div class="lesson-content" data-lesson="4">
<h2 class="lesson-title">FEW-SHOT FUNCTION CALLING (THE SOLUTION!)</h2>
<div class="lesson-description">
<p>Few-shot means showing the model multiple examples. This is the proven solution!</p>
<div class="success-box">
<h4>THE SOLUTION</h4>
<p>By providing a few-shot example, we shift the model's token probabilities. Token 6639 ("call") becomes more likely than token 1899 ("error").</p>
</div>
<div class="interactive-demo">
<h3>TEST FEW-SHOT APPROACH</h3>
<input type="text" id="fewShotQuery" value="What's the temperature in New York?" placeholder="Enter your query...">
<button onclick="testFewShot()">TEST FEW-SHOT</button>
<div id="fewShotOutput" class="output-area" style="margin-top: 15px;"></div>
</div>
<div class="code-block">
<pre><span class="code-comment">// โœ… FEW-SHOT APPROACH (PROVEN TO WORK):</span>
<span class="code-comment">// Add example conversation showing correct format</span>
<span class="code-keyword">const</span> messages = [
{
role: <span class="code-string">"developer"</span>,
content: <span class="code-string">"You are a model that can do function calling with the following functions"</span>
},
{
role: <span class="code-string">"user"</span>,
content: <span class="code-string">"What's the temperature in Paris?"</span>
},
{
role: <span class="code-string">"assistant"</span>,
<span class="code-comment">// โœ… Example showing the EXACT format we want</span>
content: <span class="code-string">"&lt;start_function_call&gt;call:get_current_temperature{location:&lt;escape&gt;Paris&lt;escape&gt;}&lt;end_function_call&gt;"</span>
},
{
role: <span class="code-string">"user"</span>,
content: query <span class="code-comment">// Your actual query</span>
}
];
<span class="code-comment">// Apply chat template with tools</span>
<span class="code-keyword">const</span> inputs = <span class="code-function">await tokenizer</span>.apply_chat_template(messages, {
tools: [weatherFunction],
tokenize: <span class="code-keyword">true</span>,
add_generation_prompt: <span class="code-keyword">true</span>,
return_dict: <span class="code-keyword">true</span>
});
<span class="code-comment">// Generate response</span>
<span class="code-keyword">const</span> output = <span class="code-function">await model</span>.generate({
...inputs,
max_new_tokens: <span class="code-keyword">512</span>,
do_sample: <span class="code-keyword">false</span>,
temperature: <span class="code-keyword">0.0</span>
});
<span class="code-comment">// โœ… Result: Correct function call generated!</span>
<span class="code-comment">// &lt;start_function_call&gt;call:get_current_temperature{location:&lt;escape&gt;New York&lt;escape&gt;}&lt;end_function_call&gt;</span></pre>
</div>
<div class="hint-box">
<h4>WHY FEW-SHOT WORKS</h4>
<ul style="margin-left: 20px; line-height: 2.5;">
<li>Shows the model the <strong>exact format</strong> we expect</li>
<li>Shifts token probabilities in favor of "call:" instead of "error:"</li>
<li>Provides context about the task structure</li>
<li>Works consistently with the quantized ONNX model</li>
</ul>
</div>
</div>
</div>
<!-- Lesson 5: Token Analysis -->
<div class="lesson-content" data-lesson="5">
<h2 class="lesson-title">TOKEN-LEVEL DEEP DIVE</h2>
<div class="lesson-description">
<p>Let's examine what happens at the token level when the model generates function calls.</p>
<div class="interactive-demo">
<h3>TOKEN-LEVEL ANALYSIS</h3>
<button onclick="analyzeTokens()">ANALYZE TOKEN GENERATION</button>
<div id="tokenAnalysisOutput" class="output-area" style="margin-top: 15px;"></div>
<div id="tokenVisualization" class="token-visualization" style="margin-top: 15px;"></div>
</div>
<table class="comparison-table">
<thead>
<tr>
<th>TOKEN ID</th>
<th>TOKEN TEXT</th>
<th>CONTEXT</th>
<th>PROBABILITY SHIFT</th>
</tr>
</thead>
<tbody>
<tr>
<td>48</td>
<td>&lt;start_function_call&gt;</td>
<td>Always correct</td>
<td>N/A</td>
</tr>
<tr>
<td>1899</td>
<td>"error"</td>
<td>Zero-shot (no example)</td>
<td>โŒ High probability</td>
</tr>
<tr>
<td>6639</td>
<td>"call"</td>
<td>Few-shot (with example)</td>
<td>โœ… High probability</td>
</tr>
<tr>
<td>236787</td>
<td>":"</td>
<td>Always correct</td>
<td>N/A</td>
</tr>
</tbody>
</table>
<div class="code-block">
<pre><span class="code-comment">// Token-level analysis of generated output</span>
<span class="code-comment">// First 20 generated tokens:</span>
<span class="code-comment">// Token 48: "&lt;start_function_call&gt;" โœ…</span>
<span class="code-comment">// Token 6639: "call" โœ… (with few-shot) or Token 1899: "error" โŒ (zero-shot)</span>
<span class="code-comment">// Token 236787: ":" โœ…</span>
<span class="code-comment">// Token 828: "get" โœ…</span>
<span class="code-comment">// Token 236779: "_" โœ…</span>
<span class="code-comment">// Token 4002: "current" โœ…</span>
<span class="code-comment">// Token 236779: "_" โœ…</span>
<span class="code-comment">// Token 27495: "temperature" โœ…</span>
<span class="code-comment">// Token 236782: "{" โœ…</span>
<span class="code-comment">// Token 7125: "location" โœ…</span>
<span class="code-comment">// Token 236787: ":" โœ…</span>
<span class="code-comment">// Token 52: "&lt;escape&gt;" โœ…</span>
<span class="code-comment">// Token 27822: "London" โœ…</span>
<span class="code-comment">// Token 52: "&lt;escape&gt;" โœ…</span>
<span class="code-comment">// Token 236783: "}" โœ…</span>
<span class="code-comment">// Token 49: "&lt;end_function_call&gt;" โœ…</span>
<span class="code-comment">// The critical decision point is after token 48:</span>
<span class="code-comment">// - Without example: Token 1899 ("error") is more likely</span>
<span class="code-comment">// - With example: Token 6639 ("call") is more likely</span></pre>
</div>
<div class="info-box">
<h4>HYPOTHESIS</h4>
<p>The model was trained on function calling data that included error handling examples. Without context, it defaults to the error generation pattern. Few-shot examples provide the necessary context to trigger the correct generation path.</p>
</div>
</div>
</div>
<!-- Lesson 6: Playground -->
<div class="lesson-content" data-lesson="6">
<h2 class="lesson-title">INTERACTIVE PLAYGROUND</h2>
<div class="lesson-description">
<p>Now it's your turn! Experiment with different queries and see how the model responds. Add your own examples to test zero-shot, one-shot, and few-shot approaches.</p>
<div class="playground-grid">
<div class="playground-section">
<h3>FUNCTION SCHEMA</h3>
<textarea id="playgroundSchema" rows="15" style="font-family: 'JetBrains Mono', monospace; font-size: 12px;">{
"type": "function",
"function": {
"name": "get_current_temperature",
"description": "Gets the current temperature for a given location.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco"
}
},
"required": ["location"]
}
}
}</textarea>
</div>
<div class="playground-section">
<h3>SYSTEM MESSAGE</h3>
<textarea id="playgroundSystemMessage" rows="3" style="font-family: 'JetBrains Mono', monospace; font-size: 12px; margin-bottom: 15px;">You are a model that can do function calling with the following functions</textarea>
<h3 style="margin-top: 20px;">YOUR QUERY</h3>
<input type="text" id="playgroundQuery" value="What's the temperature in London?" placeholder="Enter your query...">
<div class="demo-controls" style="margin-top: 15px;">
<button onclick="playgroundTest('zero')" class="btn-danger">ZERO-SHOT</button>
<button onclick="playgroundTest('one')">ONE-SHOT</button>
<button onclick="playgroundTest('few')" class="btn-success">FEW-SHOT</button>
</div>
<div style="margin-top: 15px;">
<label style="display: block; margin-bottom: 10px; font-weight: 700;">MAX TOKENS:</label>
<input type="number" id="maxTokens" value="512" min="50" max="1024" style="width: 100px;">
</div>
</div>
</div>
<div class="interactive-demo" style="margin-top: 25px;">
<h3>CUSTOM EXAMPLES</h3>
<p style="margin-bottom: 15px; font-size: 0.9em; color: #888;">Add example conversations to use in one-shot and few-shot modes. Each example should show a user query and the expected assistant response with function call.</p>
<div id="playgroundExamples" style="margin-bottom: 15px;">
<!-- Examples will be added here dynamically -->
</div>
<button onclick="addPlaygroundExample()" style="margin-top: 10px;">+ ADD EXAMPLE</button>
<div class="info-box" style="margin-top: 15px;">
<h4>EXAMPLE FORMAT</h4>
<p style="font-family: 'JetBrains Mono', monospace; font-size: 0.85em; margin-top: 10px;">
User: "What's the temperature in Paris?"<br>
Assistant: "&lt;start_function_call&gt;call:get_current_temperature{location:&lt;escape&gt;Paris&lt;escape&gt;}&lt;end_function_call&gt;"
</p>
<p style="margin-top: 10px; font-size: 0.9em;">For few-shot, add multiple examples. For one-shot, only the first example will be used. For zero-shot, no examples are used.</p>
</div>
</div>
<div class="interactive-demo">
<h3>OUTPUT</h3>
<div id="playgroundOutput" class="output-area"></div>
</div>
<div class="hint-box">
<h4>TIPS FOR EXPERIMENTATION</h4>
<ul style="margin-left: 20px; line-height: 2.5;">
<li>Try different cities and locations</li>
<li>Compare zero-shot vs few-shot results</li>
<li>Modify the function schema and see what happens</li>
<li>Add custom examples to test different scenarios</li>
<li>Watch the token visualization to understand the generation process</li>
<li>Experiment with different max_tokens values</li>
</ul>
</div>
</div>
</div>
<!-- Lesson 7: Resources -->
<div class="lesson-content" data-lesson="7">
<h2 class="lesson-title">RESOURCES & LINKS</h2>
<div class="lesson-description">
<p>Explore these resources to deepen your understanding of FunctionGemma, ONNX, and function calling.</p>
<div class="resource-links">
<h3>OFFICIAL DOCUMENTATION</h3>
<ul>
<li><a href="https://ai.google.dev/gemma/docs/functiongemma" target="_blank">FunctionGemma Model Overview - Google AI</a></li>
<li><a href="https://ai.google.dev/gemma/docs/capabilities/function-calling" target="_blank">Function Calling with Gemma - Google AI</a></li>
<li><a href="https://ai.google.dev/gemma/docs/functiongemma/full-function-calling-sequence-with-functiongemma" target="_blank">Full Function Calling Sequence - Google AI</a></li>
<li><a href="https://blog.google/technology/developers/functiongemma/" target="_blank">FunctionGemma Blog Post - Google</a></li>
</ul>
</div>
<div class="resource-links">
<h3>TUTORIALS & GUIDES</h3>
<ul>
<li><a href="https://docs.unsloth.ai/models/functiongemma" target="_blank">FunctionGemma: How to Run & Fine-tune - Unsloth</a></li>
<li><a href="https://huggingface.co/onnx-community/functiongemma-270m-it-ONNX" target="_blank">FunctionGemma ONNX Model - Hugging Face</a></li>
<li><a href="https://huggingface.co/docs/transformers.js" target="_blank">Transformers.js Documentation</a></li>
</ul>
</div>
<div class="resource-links">
<h3>ONNX & OPTIMIZATION</h3>
<ul>
<li><a href="https://onnx.ai/" target="_blank">ONNX - Open Neural Network Exchange</a></li>
<li><a href="https://onnx.ai/onnx/" target="_blank">ONNX Runtime Documentation</a></li>
<li><a href="https://huggingface.co/docs/optimum/onnxruntime/usage_guides/quantization" target="_blank">ONNX Model Quantization Guide</a></li>
</ul>
</div>
<div class="resource-links">
<h3>FUNCTION CALLING & AI</h3>
<ul>
<li><a href="https://platform.openai.com/docs/guides/function-calling" target="_blank">OpenAI Function Calling Guide</a></li>
<li><a href="https://ai.google.dev/gemma/docs/functiongemma" target="_blank">Google Function Calling Best Practices</a></li>
<li><a href="https://blog.google/technology/developers/functiongemma/" target="_blank">FunctionGemma Physics Playground Demo</a></li>
</ul>
</div>
<div class="info-box">
<h4>KEY RESOURCES SUMMARY</h4>
<p><strong>FunctionGemma</strong> is a specialized 270M parameter model fine-tuned from Google's Gemma 3 for function calling tasks. It's optimized for edge deployment and requires few-shot examples for reliable function call generation.</p>
<p><strong>ONNX</strong> (Open Neural Network Exchange) is an open format for representing machine learning models, enabling interoperability between different frameworks and optimized inference across platforms.</p>
<p>The model is available in quantized formats (q4 for WebGPU, q8 for WASM) to enable efficient browser-based inference.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="module">
// Global state
let model = null;
let tokenizer = null;
let currentLesson = 0;
let completedLessons = new Set();
let achievements = new Set();
// Initialize
document.addEventListener('DOMContentLoaded', () => {
setupLessonNavigation();
updateProgress();
initializePlayground(); // Initialize playground with default example
loadModel(); // Auto-load model
});
function setupLessonNavigation() {
document.querySelectorAll('.lesson-item').forEach(item => {
item.addEventListener('click', () => {
const lessonNum = parseInt(item.dataset.lesson);
switchLesson(lessonNum);
});
});
}
function switchLesson(lessonNum) {
// Update active lesson
document.querySelectorAll('.lesson-item').forEach(item => {
item.classList.remove('active');
if (parseInt(item.dataset.lesson) === lessonNum) {
item.classList.add('active');
}
});
// Update content
document.querySelectorAll('.lesson-content').forEach(content => {
content.classList.remove('active');
if (parseInt(content.dataset.lesson) === lessonNum) {
content.classList.add('active');
}
});
currentLesson = lessonNum;
// Initialize playground when switching to lesson 6
if (lessonNum === 6) {
setTimeout(() => initializePlayground(), 100);
}
}
function completeLesson(lessonNum) {
completedLessons.add(lessonNum);
document.querySelectorAll('.lesson-item').forEach(item => {
if (parseInt(item.dataset.lesson) === lessonNum) {
item.classList.add('completed');
}
});
updateProgress();
}
function addAchievement(text) {
achievements.add(text);
const achievementsDiv = document.getElementById('achievements');
achievementsDiv.innerHTML = Array.from(achievements).map(a =>
`<span class="achievement-badge">${a}</span>`
).join('');
}
function updateProgress() {
const total = 8;
const completed = completedLessons.size;
const percentage = Math.round((completed / total) * 100);
document.getElementById('progressBar').style.width = percentage + '%';
document.getElementById('progressBar').textContent = `${percentage}% COMPLETE`;
}
function updateLoadingStep(stepId, status) {
const step = document.getElementById(stepId);
if (!step) return;
step.classList.remove('active', 'completed');
if (status === 'active') {
step.classList.add('active');
} else if (status === 'completed') {
step.classList.add('completed');
}
}
function log(message, type = 'info', targetId = null) {
const colors = {
error: '#FF0000',
success: '#00FF00',
log: '#FFFF00',
info: '#00FFFF',
warning: '#FF6B6B'
};
const icon = {
error: 'โŒ',
success: 'โœ…',
log: '๐Ÿ“',
info: 'โ„น๏ธ',
warning: 'โš ๏ธ'
};
const output = targetId ? document.getElementById(targetId) : null;
if (output) {
const timestamp = new Date().toLocaleTimeString();
const div = document.createElement('div');
div.style.color = colors[type] || colors.info;
div.style.marginBottom = '8px';
div.style.fontFamily = "'JetBrains Mono', monospace";
div.textContent = `[${timestamp}] ${icon[type] || ''} ${message}`;
output.appendChild(div);
output.scrollTop = output.scrollHeight;
}
console.log(`[${type.toUpperCase()}]`, message);
}
async function loadModel() {
const overlay = document.getElementById('loadingOverlay');
const statusText = document.getElementById('modelStatusText');
const modelStatus = document.getElementById('modelStatus');
const modelInfoGrid = document.getElementById('modelInfoGrid');
try {
updateLoadingStep('step1', 'active');
log('๐Ÿš€ Starting model load...', 'log');
await new Promise(resolve => setTimeout(resolve, 500));
log('๐Ÿ“ฆ Importing transformers.js...', 'log');
const { env, AutoTokenizer, AutoModelForCausalLM } = await import(
"https://cdn.jsdelivr.net/npm/@huggingface/transformers@latest"
);
env.allowRemoteModels = true;
env.allowLocalModels = false;
env.useBrowserCache = true;
updateLoadingStep('step1', 'completed');
updateLoadingStep('step2', 'active');
await new Promise(resolve => setTimeout(resolve, 300));
const modelId = "onnx-community/functiongemma-270m-it-ONNX";
log('๐Ÿ”ค Loading tokenizer...', 'log');
tokenizer = await AutoTokenizer.from_pretrained(modelId);
log('โœ… Tokenizer loaded', 'success');
updateLoadingStep('step2', 'completed');
updateLoadingStep('step3', 'active');
await new Promise(resolve => setTimeout(resolve, 300));
log('๐Ÿค– Detecting device capabilities...', 'log');
const hasWebGPU = !!navigator.gpu;
const modelConfig = hasWebGPU
? { dtype: "q4", device: "webgpu" }
: { dtype: "q8", device: "wasm" };
document.getElementById('modelFormat').textContent = hasWebGPU ? 'q4 (WebGPU)' : 'q8 (WASM)';
document.getElementById('modelDevice').textContent = hasWebGPU ? 'WebGPU' : 'WASM';
modelInfoGrid.style.display = 'grid';
log(`โš™๏ธ Using config: ${JSON.stringify(modelConfig)}`, 'info');
updateLoadingStep('step3', 'completed');
updateLoadingStep('step4', 'active');
await new Promise(resolve => setTimeout(resolve, 300));
log('๐Ÿค– Loading model...', 'log');
model = await AutoModelForCausalLM.from_pretrained(modelId, modelConfig);
log('โœ… Model loaded successfully!', 'success');
updateLoadingStep('step4', 'completed');
updateLoadingStep('step5', 'active');
await new Promise(resolve => setTimeout(resolve, 500));
updateLoadingStep('step5', 'completed');
statusText.textContent = 'READY';
modelStatus.classList.add('loaded');
addAchievement('๐ŸŽฏ MODEL LOADED');
completeLesson(0);
// Hide overlay after a brief delay
setTimeout(() => {
overlay.classList.add('hidden');
}, 1000);
} catch (error) {
log(`โŒ Error loading model: ${error.message}`, 'error');
statusText.textContent = 'ERROR';
console.error(error);
overlay.innerHTML = `
<div class="loading-content">
<h2 class="loading-title" style="color: #FF0000;">LOADING FAILED</h2>
<p style="color: #FFFFFF; font-family: 'JetBrains Mono', monospace; margin-top: 20px;">${error.message}</p>
<button onclick="location.reload()" style="margin-top: 30px;">RETRY</button>
</div>
`;
}
}
async function demonstrateTokenization() {
if (!tokenizer) {
alert('Model not loaded yet!');
return;
}
const input = document.getElementById('tokenizeInput').value;
const output = document.getElementById('tokenizationOutput');
output.innerHTML = '';
log(`Tokenizing: "${input}"`, 'info', 'tokenizationOutput');
try {
const tokens = await tokenizer.encode(input, { return_tensors: false });
log(`Token IDs: [${tokens.join(', ')}]`, 'info', 'tokenizationOutput');
log(`Total tokens: ${tokens.length}`, 'info', 'tokenizationOutput');
// Visualize tokens
const viz = document.createElement('div');
viz.className = 'token-visualization';
viz.style.marginTop = '15px';
for (let i = 0; i < Math.min(tokens.length, 20); i++) {
const tokenId = tokens[i];
const tokenText = await tokenizer.decode([tokenId], { skip_special_tokens: false });
const tokenBox = document.createElement('div');
tokenBox.className = 'token-box';
tokenBox.innerHTML = `
<div class="token-id">ID: ${tokenId}</div>
<div class="token-text">${tokenText.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</div>
`;
viz.appendChild(tokenBox);
}
output.appendChild(viz);
addAchievement('๐Ÿ”ค TOKEN MASTER');
} catch (error) {
log(`Error: ${error.message}`, 'error', 'tokenizationOutput');
}
}
async function testZeroShot() {
if (!model || !tokenizer) {
alert('Model not loaded yet!');
return;
}
const query = document.getElementById('zeroShotQuery').value;
const output = document.getElementById('zeroShotOutput');
output.innerHTML = '';
log('๐Ÿงช Testing Zero-Shot Approach...', 'log', 'zeroShotOutput');
log(`Query: "${query}"`, 'info', 'zeroShotOutput');
try {
const weatherFunction = {
type: "function",
function: {
name: "get_current_temperature",
description: "Gets the current temperature for a given location.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city name, e.g. San Francisco",
},
},
required: ["location"],
},
},
};
const messages = [
{
role: "developer",
content: "You are a model that can do function calling with the following functions"
},
{
role: "user",
content: query
}
];
log('โŒ No example provided to the model', 'warning', 'zeroShotOutput');
const inputs = await tokenizer.apply_chat_template(messages, {
tools: [weatherFunction],
tokenize: true,
add_generation_prompt: true,
return_dict: true
});
const output_tensor = await model.generate({
...inputs,
max_new_tokens: 512,
do_sample: false,
temperature: 0.0
});
const seqLen = inputs.input_ids.dims[1];
const generated = output_tensor.slice(0, [seqLen, null]);
const decoded = await tokenizer.decode(generated, { skip_special_tokens: false });
log('๐Ÿ“ค Generated output:', 'info', 'zeroShotOutput');
log(decoded, 'log', 'zeroShotOutput');
if (decoded.includes('error:')) {
log('โŒ Model generated "error:" instead of "call:"', 'error', 'zeroShotOutput');
log('๐Ÿ’ก This is why zero-shot fails!', 'info', 'zeroShotOutput');
} else if (decoded.includes('call:')) {
log('โœ… Unexpected success! (This is rare)', 'success', 'zeroShotOutput');
}
completeLesson(2);
} catch (error) {
log(`Error: ${error.message}`, 'error', 'zeroShotOutput');
}
}
async function testOneShot() {
if (!model || !tokenizer) {
alert('Model not loaded yet!');
return;
}
const query = document.getElementById('oneShotQuery').value;
const output = document.getElementById('oneShotOutput');
output.innerHTML = '';
log('๐Ÿงช Testing One-Shot Approach...', 'log', 'oneShotOutput');
log(`Query: "${query}"`, 'info', 'oneShotOutput');
try {
const weatherFunction = {
type: "function",
function: {
name: "get_current_temperature",
description: "Gets the current temperature for a given location.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city name, e.g. San Francisco",
},
},
required: ["location"],
},
},
};
// One-shot: ONE example
const messages = [
{
role: "developer",
content: "You are a model that can do function calling with the following functions"
},
{
role: "user",
content: "What's the temperature in Paris?"
},
{
role: "assistant",
content: "<start_function_call>call:get_current_temperature{location:<escape>Paris<escape>}<end_function_call>"
},
{
role: "user",
content: query
}
];
log('โš ๏ธ One example provided', 'info', 'oneShotOutput');
const inputs = await tokenizer.apply_chat_template(messages, {
tools: [weatherFunction],
tokenize: true,
add_generation_prompt: true,
return_dict: true
});
const output_tensor = await model.generate({
...inputs,
max_new_tokens: 512,
do_sample: false,
temperature: 0.0
});
const seqLen = inputs.input_ids.dims[1];
const generated = output_tensor.slice(0, [seqLen, null]);
const decoded = await tokenizer.decode(generated, { skip_special_tokens: false });
log('๐Ÿ“ค Generated output:', 'info', 'oneShotOutput');
log(decoded, 'log', 'oneShotOutput');
if (decoded.includes('call:')) {
log('โœ… Success! One-shot worked', 'success', 'oneShotOutput');
} else {
log('โš ๏ธ One-shot may not always work reliably', 'warning', 'oneShotOutput');
}
completeLesson(3);
} catch (error) {
log(`Error: ${error.message}`, 'error', 'oneShotOutput');
}
}
async function testFewShot() {
if (!model || !tokenizer) {
alert('Model not loaded yet!');
return;
}
const query = document.getElementById('fewShotQuery').value;
const output = document.getElementById('fewShotOutput');
output.innerHTML = '';
log('๐Ÿงช Testing Few-Shot Approach...', 'log', 'fewShotOutput');
log(`Query: "${query}"`, 'info', 'fewShotOutput');
try {
const weatherFunction = {
type: "function",
function: {
name: "get_current_temperature",
description: "Gets the current temperature for a given location.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city name, e.g. San Francisco",
},
},
required: ["location"],
},
},
};
// Few-shot: Example provided
const messages = [
{
role: "developer",
content: "You are a model that can do function calling with the following functions"
},
{
role: "user",
content: "What's the temperature in Paris?"
},
{
role: "assistant",
content: "<start_function_call>call:get_current_temperature{location:<escape>Paris<escape>}<end_function_call>"
},
{
role: "user",
content: query
}
];
log('โœ… Few-shot example provided', 'success', 'fewShotOutput');
const inputs = await tokenizer.apply_chat_template(messages, {
tools: [weatherFunction],
tokenize: true,
add_generation_prompt: true,
return_dict: true
});
const output_tensor = await model.generate({
...inputs,
max_new_tokens: 512,
do_sample: false,
temperature: 0.0
});
const seqLen = inputs.input_ids.dims[1];
const generated = output_tensor.slice(0, [seqLen, null]);
const decoded = await tokenizer.decode(generated, { skip_special_tokens: false });
log('๐Ÿ“ค Generated output:', 'info', 'fewShotOutput');
log(decoded, 'log', 'fewShotOutput');
if (decoded.includes('call:')) {
log('โœ… SUCCESS! Few-shot works perfectly!', 'success', 'fewShotOutput');
addAchievement('๐ŸŽฏ FEW-SHOT MASTER');
}
completeLesson(4);
} catch (error) {
log(`Error: ${error.message}`, 'error', 'fewShotOutput');
}
}
async function analyzeTokens() {
if (!model || !tokenizer) {
alert('Model not loaded yet!');
return;
}
const output = document.getElementById('tokenAnalysisOutput');
const viz = document.getElementById('tokenVisualization');
output.innerHTML = '';
viz.innerHTML = '';
log('๐Ÿ” Analyzing token generation...', 'log', 'tokenAnalysisOutput');
try {
const weatherFunction = {
type: "function",
function: {
name: "get_current_temperature",
description: "Gets the current temperature for a given location.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city name, e.g. San Francisco",
},
},
required: ["location"],
},
},
};
const messages = [
{
role: "developer",
content: "You are a model that can do function calling with the following functions"
},
{
role: "user",
content: "What's the temperature in Paris?"
},
{
role: "assistant",
content: "<start_function_call>call:get_current_temperature{location:<escape>Paris<escape>}<end_function_call>"
},
{
role: "user",
content: "What's the temperature in London?"
}
];
const inputs = await tokenizer.apply_chat_template(messages, {
tools: [weatherFunction],
tokenize: true,
add_generation_prompt: true,
return_dict: true
});
const output_tensor = await model.generate({
...inputs,
max_new_tokens: 512,
do_sample: false,
temperature: 0.0
});
const seqLen = inputs.input_ids.dims[1];
const generated = output_tensor.slice(0, [seqLen, null]);
const generatedTokens = Array.from(generated.data.slice(0, 20));
log('๐Ÿ”ข First 20 generated token IDs:', 'info', 'tokenAnalysisOutput');
log(`[${generatedTokens.join(', ')}]`, 'log', 'tokenAnalysisOutput');
log('๐Ÿ”ค Decoding tokens individually:', 'info', 'tokenAnalysisOutput');
for (let i = 0; i < generatedTokens.length; i++) {
const tokenId = generatedTokens[i];
const tokenText = await tokenizer.decode([tokenId], { skip_special_tokens: false });
log(`Token ${tokenId}: "${tokenText}"`, 'info', 'tokenAnalysisOutput');
const tokenBox = document.createElement('div');
tokenBox.className = 'token-box';
tokenBox.innerHTML = `
<div class="token-id">ID: ${tokenId}</div>
<div class="token-text">${tokenText.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</div>
`;
viz.appendChild(tokenBox);
}
log('โœ… Token analysis complete!', 'success', 'tokenAnalysisOutput');
addAchievement('๐Ÿ” TOKEN ANALYST');
completeLesson(5);
} catch (error) {
log(`Error: ${error.message}`, 'error', 'tokenAnalysisOutput');
}
}
function addPlaygroundExample() {
const examplesContainer = document.getElementById('playgroundExamples');
const exampleIndex = examplesContainer.children.length;
const exampleDiv = document.createElement('div');
exampleDiv.className = 'example-item';
exampleDiv.dataset.index = exampleIndex;
const defaultUserQuery = exampleIndex === 0 ? 'What\'s the temperature in Paris?' : '';
const defaultAssistantResponse = exampleIndex === 0 ? '<start_function_call>call:get_current_temperature{location:<escape>Paris<escape>}<end_function_call>' : '';
exampleDiv.innerHTML = `
<div class="example-item-header">
<h4>EXAMPLE ${exampleIndex + 1}</h4>
<button class="remove-example-btn" data-remove-index="${exampleIndex}">REMOVE</button>
</div>
<label style="display: block; margin-bottom: 5px; font-weight: 700; font-size: 0.9em;">USER QUERY:</label>
<input type="text" class="example-user-query" placeholder="Enter user query..." value="${defaultUserQuery}">
<label style="display: block; margin-bottom: 5px; margin-top: 10px; font-weight: 700; font-size: 0.9em;">ASSISTANT RESPONSE (with function call):</label>
<textarea class="example-assistant-response" placeholder="Enter assistant response with function call..." rows="2">${defaultAssistantResponse}</textarea>
`;
// Attach event listener to remove button
const removeBtn = exampleDiv.querySelector('.remove-example-btn');
removeBtn.addEventListener('click', () => {
removePlaygroundExample(exampleIndex);
});
examplesContainer.appendChild(exampleDiv);
}
function removePlaygroundExample(index) {
const examplesContainer = document.getElementById('playgroundExamples');
const exampleItem = examplesContainer.querySelector(`[data-index="${index}"]`);
if (exampleItem) {
exampleItem.remove();
// Reindex remaining examples
Array.from(examplesContainer.children).forEach((item, idx) => {
item.dataset.index = idx;
item.querySelector('h4').textContent = `EXAMPLE ${idx + 1}`;
const removeBtn = item.querySelector('.remove-example-btn');
// Remove old listener and add new one
const newRemoveBtn = removeBtn.cloneNode(true);
removeBtn.parentNode.replaceChild(newRemoveBtn, removeBtn);
newRemoveBtn.addEventListener('click', () => {
removePlaygroundExample(idx);
});
});
}
}
function getPlaygroundExamples() {
const examplesContainer = document.getElementById('playgroundExamples');
const examples = [];
Array.from(examplesContainer.children).forEach(item => {
const userQuery = item.querySelector('.example-user-query').value.trim();
const assistantResponse = item.querySelector('.example-assistant-response').value.trim();
if (userQuery && assistantResponse) {
examples.push({
user: userQuery,
assistant: assistantResponse
});
}
});
return examples;
}
async function playgroundTest(mode) {
if (!model || !tokenizer) {
alert('Model not loaded yet!');
return;
}
const query = document.getElementById('playgroundQuery').value;
const schemaText = document.getElementById('playgroundSchema').value;
const systemMessage = document.getElementById('playgroundSystemMessage').value.trim() || "You are a model that can do function calling with the following functions";
const maxTokens = parseInt(document.getElementById('maxTokens')?.value || 512);
const output = document.getElementById('playgroundOutput');
output.innerHTML = '';
let weatherFunction;
try {
weatherFunction = JSON.parse(schemaText);
} catch (e) {
log('โŒ Invalid JSON schema', 'error', 'playgroundOutput');
return;
}
// Get custom examples
const customExamples = getPlaygroundExamples();
log(`๐Ÿงช Testing ${mode === 'zero' ? 'Zero-Shot' : mode === 'one' ? 'One-Shot' : 'Few-Shot'} approach...`, 'log', 'playgroundOutput');
log(`Query: "${query}"`, 'info', 'playgroundOutput');
log(`Max Tokens: ${maxTokens}`, 'info', 'playgroundOutput');
log(`Custom Examples: ${customExamples.length}`, 'info', 'playgroundOutput');
try {
let messages = [
{
role: "developer",
content: systemMessage
}
];
if (mode === 'zero') {
// Zero-shot: No examples
messages.push({
role: "user",
content: query
});
} else if (mode === 'one') {
// One-shot: Use first example if available, otherwise use default
if (customExamples.length > 0) {
messages.push({
role: "user",
content: customExamples[0].user
});
messages.push({
role: "assistant",
content: customExamples[0].assistant
});
} else {
// Fallback to default example
messages.push({
role: "user",
content: "What's the temperature in Paris?"
});
messages.push({
role: "assistant",
content: `<start_function_call>call:${weatherFunction.function.name}{location:<escape>Paris<escape>}<end_function_call>`
});
}
messages.push({
role: "user",
content: query
});
} else {
// Few-shot: Use all available examples
if (customExamples.length > 0) {
customExamples.forEach(example => {
messages.push({
role: "user",
content: example.user
});
messages.push({
role: "assistant",
content: example.assistant
});
});
} else {
// Fallback to default example
messages.push({
role: "user",
content: "What's the temperature in Paris?"
});
messages.push({
role: "assistant",
content: `<start_function_call>call:${weatherFunction.function.name}{location:<escape>Paris<escape>}<end_function_call>`
});
}
messages.push({
role: "user",
content: query
});
}
log(`๐Ÿ“ Message count: ${messages.length}`, 'info', 'playgroundOutput');
const inputs = await tokenizer.apply_chat_template(messages, {
tools: [weatherFunction],
tokenize: true,
add_generation_prompt: true,
return_dict: true
});
const output_tensor = await model.generate({
...inputs,
max_new_tokens: maxTokens,
do_sample: false,
temperature: 0.0
});
const seqLen = inputs.input_ids.dims[1];
const generated = output_tensor.slice(0, [seqLen, null]);
const decoded = await tokenizer.decode(generated, { skip_special_tokens: false });
log('๐Ÿ“ค Generated output:', 'info', 'playgroundOutput');
log(decoded, 'log', 'playgroundOutput');
if (decoded.includes('call:')) {
log('โœ… Function call generated successfully!', 'success', 'playgroundOutput');
} else if (decoded.includes('error:')) {
log('โŒ Model generated error instead of call', 'error', 'playgroundOutput');
}
completeLesson(6);
addAchievement('๐ŸŽฎ PLAYGROUND EXPLORER');
} catch (error) {
log(`Error: ${error.message}`, 'error', 'playgroundOutput');
console.error(error);
}
}
// Initialize playground with default example
function initializePlayground() {
const examplesContainer = document.getElementById('playgroundExamples');
if (examplesContainer && examplesContainer.children.length === 0) {
addPlaygroundExample();
}
}
// Make functions available globally
window.loadModel = loadModel;
window.demonstrateTokenization = demonstrateTokenization;
window.testZeroShot = testZeroShot;
window.testOneShot = testOneShot;
window.testFewShot = testFewShot;
window.analyzeTokens = analyzeTokens;
window.playgroundTest = playgroundTest;
window.addPlaygroundExample = addPlaygroundExample;
window.removePlaygroundExample = removePlaygroundExample;
</script>
</body>
</html>