diff --git a/bricks/audio.js b/bricks/audio.js index 0000ae0..b6d88b6 100644 --- a/bricks/audio.js +++ b/bricks/audio.js @@ -34,9 +34,44 @@ bricks.AudioPlayer = class extends bricks.JsWidget { if ( this.url ){ this.set_source(this.url); } + this.playlist = []; + } + get_status() { + var audio = this.audio; + if (audio.error) { + return "error"; + } + if (audio.ended) { + return "ended"; + } + if (audio.paused) { + return "paused"; + } + if (audio.readyState < 3) { + return "loading"; // 数据不足,可能在缓冲 + } + return "playing"; + } + + add_url(url){ + var status = this.get_status(); + switch(status){ + case 'error': + case 'ended': + this.set_source(url); + break; + default: + this.playlist.push(url); + break; + } } playended(e){ - this.dispatch('ended'); + if (this.playlist.length > 0) { + var url = this.playlist.shift(); + this.set_source(url); + } else { + this.dispatch('ended'); + } } set_stream_urls(response){ async function* dyn_urls(response) { diff --git a/bricks/llmout.js b/bricks/llmout.js new file mode 100644 index 0000000..8d3f5e1 --- /dev/null +++ b/bricks/llmout.js @@ -0,0 +1,96 @@ +var bricks = window.bricks || {}; + +/* +根据大模型返回数据自动构造显示内容 +大模型返回json格式数据,下面的属性可选 +reasoning_content:推理文本 +content:应答文本 +audio:语音url或base64语音 +video:视频url或base64视频 +image:如果是个数组,则多个图片url +*/ + +bricks.LlmOut = class extends bricks.VBox { + constructor(opts){ + super(opts); + this.rc_w = null; + this.c_w = null; + this.v_w = null; + this.i_w = null; + this.a_w = null; + this.images = []; + this.reasoning_content = ''; + this.content = ''; + } + + update(data){ + if (data.audiao){ + if (!this.a_w) { + this.a_w = new bricks.AudioPlay({ + width: '100%', + autoplay: true, + url: data.audio, + cheight:2 + }); + } else { + this.a_w.add_url(data.audio); + } + } + if (data.video){ + if (!this.v_w){ + this.v_w = mew bricks.VideoPlayer({ + width: '100%', + url: data.video, + autoplay: true + }); + } else { + this.v_w.add_url(data.video); + } + } + if (data.reasoning_content){ + this.reasoning_content += data.reasoning_content; + } + if (data.content){ + this.content += data.content; + } + if (data.image){ + if (Array.isArray(data.image){ + this.images.concat(data.image); + else { + this.images.push(data.image); + } + } + this.clear_widgets(); + if (this.reasoning_content.length) { + var txt = bricks.escapeSpecialChars('\n\n' + this.reasoning_content + '\n\n''); + this.rc_w = new bricks.MdWidget({ + mdtext: txt, + width: '100%' + }); + this.add_widget(this.rc_w); + } + if (this.reasoning_content.length) { + var txt = bricks.escapeSpecialChars(this.content); + this.c_w = new bricks.MdWidget({ + mdtext: txt, + width: '100%' + }); + this.add_widget(this.c_w); + } + if (this.v_w) { + this.add_widget(this.v_w); + } + if (this.a_w) { + this.add_widget(this.a_w); + } + if (this.images.length){ + this.images.forEach( i => { + var w = new bricks.Image({ + width: '100%', + url: i + }); + this.add_widget(w) + }); + } + } +}