File size: 5,815 Bytes
3783386
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
(function () {
    "use strict";

    // ---- Data types & quantization ----
    const dataTypes = [
        { name: "float32", bits: 32, bytes: 4 },
        { name: "float16", bits: 16, bytes: 2 },
        { name: "bfloat16", bits: 16, bytes: 2 },
        { name: "8-bit (INT8)", bits: 8, bytes: 1 },
        { name: "6-bit (Q_6)", bits: 6, bytes: 0.75 },
        { name: "4-bit (Q_4)", bits: 4, bytes: 0.5 },
        { name: "3-bit (Q_3)", bits: 3, bytes: 0.375 },
        { name: "2-bit (Q_2)", bits: 2, bytes: 0.25 }
    ];

    // ---- DOM refs ----
    const paramInput = document.getElementById('paramInput');
    const calculateBtn = document.getElementById('calculateBtn');
    const tableBody = document.getElementById('tableBody');
    const paramDisplay = document.getElementById('paramDisplay');
    const themeToggle = document.getElementById('themeToggle');
    const themeIcon = document.getElementById('themeIcon');

    // ---- Helper: parse "1.5B", "100M", "7B", "1,000,000", etc. ----
    function parseParameters(rawInput) {
        let cleaned = String(rawInput).replace(/,/g, '').replace(/\s/g, '').trim();
        if (cleaned === '') return NaN;

        const lower = cleaned.toLowerCase();
        let multiplier = 1;
        let numStr = cleaned;

        if (lower.endsWith('b')) {
            multiplier = 1e9;
            numStr = cleaned.slice(0, -1);
        } else if (lower.endsWith('m')) {
            multiplier = 1e6;
            numStr = cleaned.slice(0, -1);
        }

        const num = parseFloat(numStr);
        if (isNaN(num) || num < 0) return NaN;

        return num * multiplier;
    }

    // ---- Helpers for formatting ----
    function formatNumber(num, decimals = 2) {
        if (num === undefined || !isFinite(num)) return '—';
        return num.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    }

    function formatBytes(bytes) {
        if (bytes === undefined || !isFinite(bytes)) return '—';
        if (Math.abs(bytes) >= 1e15) {
            return bytes.toExponential(2);
        }
        return formatNumber(bytes, 2);
    }

    function bytesToGB(bytes) { return bytes / 1e9; }
    function bytesToMiB(bytes) { return bytes / (1024 * 1024); }

    // ---- Map data type name to CSS class for color coding ----
    function getDataTypeClass(name) {
        if (name.includes('float')) return 'float';
        if (name.includes('8-bit')) return 'int8';
        if (name.includes('6-bit')) return 'q6';
        if (name.includes('4-bit')) return 'q4';
        if (name.includes('3-bit')) return 'q3';
        if (name.includes('2-bit')) return 'q2';
        return '';
    }

    // ---- Main calculation ----
    function calculateAndRender(rawInput) {
        const numParams = parseParameters(rawInput);

        if (isNaN(numParams)) {
            tableBody.innerHTML = `<tr><td colspan="5" class="text-center text-danger">Please enter a valid number (e.g., 7B, 1.5b, 100M).</td></tr>`;
            paramDisplay.textContent = 'Invalid input';
            return;
        }

        // Update badge
        let displayText = formatNumber(numParams, 0) + ' parameters';
        if (numParams >= 1e9) {
            displayText = (numParams / 1e9).toFixed(2) + 'B parameters';
        } else if (numParams >= 1e6) {
            displayText = (numParams / 1e6).toFixed(2) + 'M parameters';
        }
        paramDisplay.textContent = displayText;

        // Build rows
        let rowsHtml = '';
        dataTypes.forEach(dt => {
            const bytes = numParams * dt.bytes;
            const gb = bytesToGB(bytes);
            const mib = bytesToMiB(bytes);
            const typeClass = getDataTypeClass(dt.name);
            rowsHtml += `
                <tr data-type="${typeClass}">
                    <td><strong>${dt.name}</strong></td>
                    <td>${dt.bits}</td>
                    <td>${formatNumber(gb, 2)}</td>
                    <td>${formatNumber(mib, 2)}</td>
                    <td>${formatBytes(bytes)}</td>
                </tr>
            `;
        });
        tableBody.innerHTML = rowsHtml;
    }

    // ---- Event listeners ----
    calculateBtn.addEventListener('click', function () {
        calculateAndRender(paramInput.value);
    });

    paramInput.addEventListener('keydown', function (e) {
        if (e.key === 'Enter') {
            e.preventDefault();
            calculateAndRender(paramInput.value);
        }
    });

    document.querySelectorAll('.btn-preset').forEach(btn => {
        btn.addEventListener('click', function () {
            const value = this.getAttribute('data-value');
            paramInput.value = value;
            calculateAndRender(value);
        });
    });

    // Initial load (7B)
    calculateAndRender(paramInput.value);

    // ---- Dark / Light toggle (custom class, default = dark) ----
    function setTheme(theme) {
        const html = document.documentElement;
        if (theme === 'dark') {
            html.classList.add('dark-mode');
            themeIcon.textContent = '☀️';   // sun icon for switching to light
        } else {
            html.classList.remove('dark-mode');
            themeIcon.textContent = '🌙';   // moon icon for switching to dark
        }
        localStorage.setItem('theme', theme);
    }

    themeToggle.addEventListener('click', function () {
        const current = document.documentElement.classList.contains('dark-mode') ? 'dark' : 'light';
        setTheme(current === 'dark' ? 'light' : 'dark');
    });

    // Load saved theme, or default to dark
    function loadTheme() {
        const saved = localStorage.getItem('theme');
        if (saved) {
            setTheme(saved);
        } else {
            setTheme('dark'); // default to dark
        }
    }
    loadTheme();
})();