File size: 3,340 Bytes
3246e54
 
 
 
c046cff
 
 
3246e54
c046cff
 
 
 
 
 
 
 
 
3246e54
 
 
 
 
 
 
c777c26
3246e54
 
d0ca958
3246e54
 
c777c26
3246e54
 
 
 
 
c777c26
3246e54
c046cff
 
3246e54
 
 
 
c777c26
3246e54
 
 
d0ca958
c777c26
 
3246e54
 
 
 
c777c26
3246e54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c046cff
 
 
 
 
 
3246e54
 
 
c777c26
 
 
 
 
 
 
c046cff
 
 
 
 
 
 
3246e54
 
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
let session = null;
let stoi = null;
let itos = null;

const chatContainer = document.getElementById('chat-container');
const userInput = document.getElementById('user-input');
const sendBtn = document.getElementById('send-btn');
const loadingMsg = document.getElementById('loading-msg');

function addMessage(text, sender) {
    const msgDiv = document.createElement('div');
    msgDiv.classList.add('message', sender === 'user' ? 'user-message' : 'ai-message');
    msgDiv.innerText = text;
    chatContainer.appendChild(msgDiv);
    chatContainer.scrollTop = chatContainer.scrollHeight;
}

async function initONNX() {
    try {
        const vocabRes = await fetch('vocab.json');
        const vocab = await vocabRes.json();
        stoi = vocab.stoi;
        itos = vocab.itos;

        ort.env.wasm.wasmPaths = "https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/";
        ort.env.wasm.numThreads = 1;

        // The critical fix: ensuring the ONNX model is fetched correctly
        session = await ort.InferenceSession.create('./ares.onnx', { executionProviders: ['wasm'] });
        
        loadingMsg.innerHTML = '<p>Ares ONNX Model successfully loaded into browser VRAM! Ready.</p>';
        userInput.disabled = false;
        sendBtn.disabled = false;

    } catch (e) {
        console.error(e);
        loadingMsg.innerHTML = `<p style="color:red">Failed to load ONNX Model: ${e.message}</p>`;
    }
}

async function generateAresResponse(query) {
    const prompt = `<|user|>${query}<|end|><|assistant|>`;
    let tokens = prompt.split('').map(c => stoi[c] || 0);

    const max_new_tokens = 40;
    const vocab_size = Object.keys(stoi).length;

    for (let i = 0; i < max_new_tokens; i++) {
        // Use Int32Array to avoid BigInt/WASM crash
        const int32Tokens = Int32Array.from(tokens);
        const tensor = new ort.Tensor('int32', int32Tokens, [1, tokens.length]);
        
        const feeds = { input_tokens: tensor };
        const results = await session.run(feeds);
        
        const logits = results.logits.data; 
        const offset = (tokens.length - 1) * vocab_size;
        
        let max_val = -Infinity;
        let best_idx = 0;
        for (let v = 0; v < vocab_size; v++) {
            let val = logits[offset + v];
            if (val > max_val) {
                max_val = val;
                best_idx = v;
            }
        }

        tokens.push(best_idx);
        let char = itos[best_idx];

        if (char === "<|end|>") break;
    }

    const outputString = tokens.map(t => itos[t]).join('');
    let reply = outputString.substring(prompt.length);
    if(reply.includes("<|end|>")) reply = reply.split("<|end|>")[0];
    
    return reply;
}

sendBtn.addEventListener('click', async () => {
    const text = userInput.value.trim();
    if (!text) return;
    
    addMessage(text, 'user');
    userInput.value = '';

    const placeholder = "Thinking...";
    addMessage(placeholder, 'ai');
    
    try {
        const reply = await generateAresResponse(text);
        chatContainer.lastChild.innerText = reply;
    } catch(e) {
        console.error(e);
        chatContainer.lastChild.innerText = "Inference Error: " + e.message;
    }
});

userInput.addEventListener('keypress', (e) => {
    if (e.key === 'Enter') {
        sendBtn.click();
    }
});

initONNX();