diff --git a/bricks/binstreaming.js b/bricks/binstreaming.js new file mode 100644 index 0000000..3d696ac --- /dev/null +++ b/bricks/binstreaming.js @@ -0,0 +1,34 @@ +bricks = window.bricks || {}; + +bricks.UpStreaming = class extends bricks.JsWidget { + /* + { + "url": + } + */ + constructor(opts){ + super(opts); + } + async go(){ + this.body = new ReadableStream(this); + this.headers = new Headers(); + this.headers.append('Content-Type', + 'application/octet-stream'); + var resp = await fetch(this.url, { + method: 'POST', + headers: this.headers, + duplex: 'half', + body: this.body + }); + return resp + } + send(data){ + this.stream_ctlr.enqueue(data); + } + finish(){ + this.stream_ctlr.close(); + } + start(controller){ + this.stream_ctlr = controller; + } +} diff --git a/bricks/gobang.js b/bricks/gobang.js new file mode 100644 index 0000000..b9c46ac --- /dev/null +++ b/bricks/gobang.js @@ -0,0 +1,129 @@ +var bricks = window.bricks || {} + +bricks.GobangPoint = class extends bricks.Image { + /* + p_status: 0:empty, 1:black, 2:white + p_x: horontical position from 1 to 15 + p_y: verical position, from 1 to 15 + */ + constructor(opts){ + super(opts); + var url = this.calc_url(); + this.set_url(url); + this.bind('mouseover', this.set_current_position.bind(this, true)); + this.bind('mouseout', this.set_current_position.bind(this, false)); + } + set_current_position(flg, event){ + this.set_css('curpos', !flg); + } + + calc_url(){ + var one, two, st; + switch(this.p_status){ + case 0: + st = 'empty'; + break; + case 1: + st = 'black'; + break; + case 2: + st = 'white'; + break; + } + switch(this.p_y){ + case 1: + one = "t"; + break; + case 15: + one = "b"; + break; + default: + one = "c" + } + switch(this.p_x){ + case 1: + two = "l"; + break; + case 15: + two = "r"; + break; + default: + two = "c" + } + var name = 'imgs/' + one + two + '_' + st + '.png'; + // console.log(name, this.p_x, this.p_y, one, two); + return bricks_resource(name); + } + getValue(){ + return { + status:this.p_status, + x:this.p_x, + y:this.p_y + } + } + str(){ + return '(' + this.p_status + ',' + this.p_x + ',' + this.p_y + ')'; + } +} +bricks.Gobang = class extends bricks.VBox { + /* + player:{ + "name":"ttt", + "type":"user", "llm" + "url": + "delay":seconds + "params": + } + { + black_player:{} + white_player:{} + } + */ + constructor(opts){ + super(opts); + this.filler = new bricks.Filler({}); + this.add_widget(this.filler); + this.render_empty_area() + this.inform_go('black') + this.filler.bind('element_resize', this.resize_area.bind(this)); + } + resize_area(){ + var ele = this.filler.dom_element; + var siz = Math.min(ele.clientWidth, + ele.clientHeight)/ 15; + console.log(siz, ele.clientWidth, ele.clientHeight); + for(var i=0;i<15;i++){ + for(var j=0;j<15;j++){ + var w = this.area[i][j]; + w.set_style('width', siz+'px'); + w.set_style('height', siz+'px'); + } + } + } + inform_go(party){ + } + render_empty_area(){ + this.area = []; + var vbox = new bricks.VBox({}); + vbox.h_center(); + for (var i=1; i<=15; i++){ + var hbox = new bricks.HBox({}) + vbox.add_widget(hbox); + var l = []; + for (var j=1; j<=15; j++){ + var w = new bricks.GobangPoint({ + p_status:0, + tip: '(' + i + ',' + j + ')', + p_x: j, + p_y: i + }); + hbox.add_widget(w); + l.push(w); + } + this.area.push(l); + } + this.filler.add_widget(vbox); + } +} + +bricks.Factory.register('Gobang', bricks.Gobang); diff --git a/bricks/streaming_audio.js b/bricks/streaming_audio.js new file mode 100644 index 0000000..b3ea09d --- /dev/null +++ b/bricks/streaming_audio.js @@ -0,0 +1,79 @@ +var bricks = window.bricks || {}; + +bricks.StreamAudio = class extends bricks.VBox { + constructor(opts){ + opts.height = '100%'; + opts.name = opts.name || 'asr_text'; + super(opts); + this.button = new bricks.Button({label:'start'}); + this.filler = new bricks.Filler({}); + this.add_widget(this.button); + this.add_widget(this.filler); + this.text_w = new bricks.Text({text:' ', wrap:true}); + this.filler.add_widget(this.text_w); + this.button.bind('click', this.toggle_status.bind(this)); + } + toggle_status(){ + if (this.upstreaming){ + this.stop(); + } else { + this.start(); + } + } + start(){ + this.button.text_w.set_otext('stop'); + schedule_once(this._start.bind(this), 0.1); + } + async _start(){ + if (bricks.vad){ + await bricks.vad.stop(); + } + var f = this.handle_audio.bind(this); + this.vad = await vad.MicVAD.new({ + onSpeechEnd:(audio) => { + console.log(audio, this.vad); + this.handle_audio(audio); + } + }); + this.vad.start(); + bricks.vad = this; + this.upstreaming = new bricks.UpStreaming({url:this.url}); + this.resp_text = ''; + this.resp = await this.upstreaming.go(); + await this.recieve_data(); + } + stop(){ + this.button.text_w.set_otext('start'); + schedule_once(this._stop.bind(this), 0.1); + } + async _stop(){ + if (this.upstreaming){ + this.upstreaming.finish(); + this.upstreaming = null; + } + await this.vad.pause(); + bricks.vad = null; + } + async receive_data(){ + const reader = resp.body.getReader(); + const decoder = new TextDecoder('utf-8'); + var line = await reader.readline(); + while (line){ + try { + var d = JSON.parse(line); + this.text_w.set_text(d.content); + } catch(e){ + console.log(line, 'can not parse as a json'); + } + line = await reader.readline(); + } + } + handle_audio(audio){ + console.log('handle_audil() called', audio); + var b64audio = btoa(audio); + this.upstreaming.send(b64audio); + } +} + +bricks.Factory.register('StreamAudio', bricks.StreamAudio); +bricks.Factory.register('ASRText', bricks.StreamAudio);