File size: 12,190 Bytes
441af09
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
window.HELP_IMPROVE_VIDEOJS = false;

// var INTERP_BASE = "./static/interpolation/stacked";
var NUM_INTERP_FRAMES = 240;

var interp_images = [];
// function preloadInterpolationImages() {
//   for (var i = 0; i < NUM_INTERP_FRAMES; i++) {
//     var path = INTERP_BASE + '/' + String(i).padStart(6, '0') + '.jpg';
//     interp_images[i] = new Image();
//     interp_images[i].src = path;
//   }
// }

// function setInterpolationImage(i) {
//   var image = interp_images[i];
//   image.ondragstart = function() { return false; };
//   image.oncontextmenu = function() { return false; };
//   $('#interpolation-image-wrapper').empty().append(image);
// }


$(document).ready(function() {
    // Check for click events on the navbar burger icon
    $(".navbar-burger").click(function() {
      // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
      $(".navbar-burger").toggleClass("is-active");
      $(".navbar-menu").toggleClass("is-active");

    });

    var options = {
			slidesToScroll: 1,
			slidesToShow: 3,
			loop: true,
			infinite: true,
			autoplay: false,
			autoplaySpeed: 3000,
    }

		// Initialize all div with carousel class
    var carousels = bulmaCarousel.attach('.carousel', options);

    // Loop on each carousel initialized
    for(var i = 0; i < carousels.length; i++) {
    	// Add listener to  event
    	carousels[i].on('before:show', state => {
    		console.log(state);
    	});
    }

    // Access to bulmaCarousel instance of an element
    var element = document.querySelector('#my-element');
    if (element && element.bulmaCarousel) {
    	// bulmaCarousel instance is available as element.bulmaCarousel
    	element.bulmaCarousel.on('before-show', function(state) {
    		console.log(state);
    	});
    }

    /*var player = document.getElementById('interpolation-video');
    player.addEventListener('loadedmetadata', function() {
      $('#interpolation-slider').on('input', function(event) {
        console.log(this.value, player.duration);
        player.currentTime = player.duration / 100 * this.value;
      })
    }, false);*/
    // preloadInterpolationImages();

    // $('#interpolation-slider').on('input', function(event) {
    //   setInterpolationImage(this.value);
    // });
    // setInterpolationImage(0);
    // $('#interpolation-slider').prop('max', NUM_INTERP_FRAMES - 1);

    bulmaSlider.attach();

})





// 全局初始化
// connect ws
var ws = null;
var recorder = null;
var isRecording = false;
var vc_enabled = location.search.split('vc=')[1] == '1' ? true : false;
var text = ''
var audio_base64 = null;
Recorder.CLog = function(){} //update
var wave = Recorder.WaveView({elem:"#waveform"}); //创建wave对象,写这里面浏览器妥妥的;
const audioPlayer = document.getElementById('audioPlayer');
const waveformDiv = document.getElementById('waveform');
const resultsDiv = document.getElementById('results');
const llasaLoading = document.getElementById('llasaLoading');
const container = document.getElementById('llasa');

// sent text element
function createSentMessageElement(message) {
    const sentDiv = document.createElement('div');
    sentDiv.id = 'sent';
    sentDiv.setAttribute('class', 'd-flex flex-row justify-content-end mb-2 pt-1 text-start');
    
    const sentMessageP = document.createElement('p');
    sentMessageP.setAttribute('class', 'sent-message small p-2 me-2 mb-1 text-white rounded-3 bg-primary');
    sentMessageP.textContent = message['value'];
    sentMessageP.id = message['cid']
    
    const imageDiv = document.createElement('div');
    const senderImage = document.createElement('img');
    senderImage.setAttribute('src', './images/user.png');
    senderImage.setAttribute('class', 'rounded-4');
    senderImage.setAttribute('alt', 'avatar 1');
    senderImage.setAttribute('height', '30');
    senderImage.setAttribute('width', '30');
    imageDiv.appendChild(senderImage);

    sentDiv.appendChild(sentMessageP);
    sentDiv.appendChild(imageDiv);
    
    return sentDiv;
}

// Function to add a new sent message to the DOM
function addSentMessageToDOM(message) {
    const sentDiv = createSentMessageElement(message);
    resultsDiv.appendChild(sentDiv);
}

function createRecieveMessageElement(message) {
    const responseDiv = document.createElement("div");
    responseDiv.id = "response";
    responseDiv.classList.add("d-flex", "flex-row", "justify-content-start", "pt-2", "mb-2");

    const imageDiv = document.createElement('div')
    const avatarImg = document.createElement("img");
    avatarImg.src = "../../images/gpt.png";
    avatarImg.classList.add("rounded-4");
    avatarImg.alt = "avatar 1";
    avatarImg.height = 30;
    avatarImg.width = 30;
    imageDiv.appendChild(avatarImg)
    responseDiv.appendChild(imageDiv);

    const responseMessageP = document.createElement("p");
    responseMessageP.id = message['cid'];
    responseMessageP.classList.add("small", "p-2", "ms-2", "mb-1", "rounded-3");
    responseMessageP.style.backgroundColor = "#f5f6f7";
    responseMessageP.innerText = message['value'];
    responseDiv.appendChild(responseMessageP);

    return responseDiv;
}

// Function to add a new recieve message to the DOM
function addRecieveMessageToDOM(message) {
    const reciDiv = createRecieveMessageElement(message);
    resultsDiv.appendChild(reciDiv);
    resultsDiv.scrollTo(0, resultsDiv.scrollHeight);
}

function createSentAudioMessageElement(message) {
    const sentDiv = document.createElement('div');
    sentDiv.id = 'sent';
    sentDiv.className = 'd-flex flex-row justify-content-end mb-2 pt-1 text-start';

    const audio = document.createElement('audio');
    audio.controls = true;
    audio.id = message['cid'];
    audio.className = 'sent-message p-2 me-2 bg-primagry';
    // audio.style.width = '200px';

    const sourceElement = document.createElement('source');
    sourceElement.src = message['value'];
    // sourceElement.type = 'audio/ogg';

    const unsupportedText = document.createTextNode('Your browser does not support the audio element.');

    audio.appendChild(sourceElement);
    audio.appendChild(unsupportedText);

    const imageDiv = document.createElement('div')
    const image = document.createElement('img');
    image.src = '../../images/user.png';
    image.id = 'sender-image';
    image.className = 'rounded-4';
    image.alt = 'avatar 1';
    image.height = 30;
    image.width = 30;
    imageDiv.appendChild(image);

    sentDiv.appendChild(audio);
    sentDiv.appendChild(imageDiv);
    
    return sentDiv;
}

// Function to add a new audio sent message to the DOM
function addAudioSentMessageToDOM(message) {
    const sentDiv = createSentAudioMessageElement(message);
    resultsDiv.appendChild(sentDiv);
    resultsDiv.scrollTo(0, resultsDiv.scrollHeight);
}

// stream update response
function updateResponse(cID, answer) {
    const responseP = document.getElementById("a_text_" + cID);
    responseP.innerText = answer;
}

// connect ws
window.onload = async () => {
    await connect();
}

async function connect() {
    // url = ((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/api";
    url = "wss://demo.linksoul.ai/alm/api";
    ws = new WebSocket(url);
    ws.onopen = function (e) {
        console.log('握手成功');
        if (ws.readyState == 1) { //ws进入连接状态,则每隔500毫秒发送一包数据
            console.log('连接状态成功');
            // resultsDiv.style.display = '';
            // llasaLoading.style.display = 'none';
            container.style.opacity = 1;
            llasaLoading.style.display = 'none';
        }
    };

    ws.onmessage = function (e) {
        console.log(e['data'])
        var response = JSON.parse(e['data']);
        if(response["action"] == "qa"){
            // nothing to do
            if(response['msg'] == 'ok') {
                console.log(response["data"])
                updateResponse(response['data']['cid'], response['data']['answer'])
            }else{
                console.log(response['msg']);
            }
        }
    }
    ws.onerror = function (err) {
        console.info('ws error: '+err)
    }   

    ws.onclose=function(e){
        console.info('ws close: '+e);
    };
}
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay))
const submitTextButton = document.getElementById('send_button');
submitTextButton.onclick = async () => {
    await sendMessage();
}
async function sendMessage() {
    if(ws == null || ws.readyState != 1) {
        // alert('服务未连接,请刷新页面');
        // return;
        await connect();
        await sleep(800);
    }
    var userTextDiv = document.getElementById('user-text');
    text = userTextDiv.value
    userTextDiv.value = ''
    console.log('user input text', text);
    console.log('user input audio', audio_base64);
    if (text.length == 0 && audio_base64 == null) return;
    var cid = crypto.randomUUID();
    if (text.length > 0) {
        addSentMessageToDOM({
            'cid': "q_text_" + cid,
            'from': 'human',
            'value': text,
            'type': 'text'
        });
    }
    if (audio_base64 != null) {
        addAudioSentMessageToDOM({
            'cid': "q_audio_" + cid,
            'from': 'human',
            'value': audio_base64,
            'type': 'audio'
        });
    }

    ws.send(JSON.stringify({"action": "qa", "data":{"cid": cid, "text": text, "audio": audio_base64, "vc_enabled": vc_enabled}}));

    addRecieveMessageToDOM({
        'cid': "a_text_" + cid,
        'from': 'gpt',
        'value': '',
        'type': 'text'
    })
    if (text != '') {
        text = '';
    }
    if (audio_base64 != null) {
        audio_base64 = null;
        // 清空缓存区
        audioPlayer.src = '';
        audioPlayer.style.display = 'none'; 
    }
}

function blobToDataURI(blob, callback) {
    var reader = new FileReader();
    reader.onload = function (e) {
        callback(e.target.result);
    }
    reader.readAsDataURL(blob);
}

const resetButton = document.getElementById('delete_button');
resetButton.onclick = () => {
    clear();
    resultsDiv.innerHTML = '';
    audioPlayer.src = '';
    audioPlayer.style.display = 'none';
    waveformDiv.style.display = 'none';
}
function clear() {//update
    ws.send(JSON.stringify({"action": "clear"}));
}

const recordButton = document.getElementById('start_button');
recordButton.onclick = () => {
    record_audio();
    
}

function record_audio() {//update
    if (!isRecording) {
        recorder = Recorder({type:"mp3", sampleRate:44100, bitRate:128, onProcess:function(buffers,powerLevel,bufferDuration,bufferSampleRate,newBufferIdx,asyncEnd){
            wave&&wave.input(buffers[buffers.length-1],powerLevel,bufferSampleRate);
        }});
        recorder.open(function(){
            isRecording = true;
            recorder.start();
            audioPlayer.style.display = 'none';
            waveformDiv.style.display = ''; 
            recordButton.style.filter = "invert(18%) sepia(66%) saturate(5808%) hue-rotate(338deg) brightness(91%) contrast(125%)";
        },function(msg,isUserNotAllow){
            alert("请允许浏览器获取麦克风录音权限");
            console.log((isUserNotAllow?"UserNotAllow, ":"")+"无法录音:"+msg);
        });
    }else {
        isRecording = false;
        recorder.stop(function(blob, duration){
            audioPlayer.style.display = '';
            waveformDiv.style.display = 'none';
            blobToDataURI(blob, function(audio_base64_data){
                audio_base64 = audio_base64_data;
                // document.getElementById('audioPlayer').src = URL.createObjectURL(blob);
                recorder.close();
                recorder=null;
                // 移动 audio 到暂存区
                audioPlayer.src = audio_base64;
                // sendMessage();
            });
        },function(msg){
            alert("录音失败");
            console.log("录音失败:"+msg);
            recorder.close();
            recorder=null;
        });
        recordButton.style.filter = null;
    }
}