From ae710ddc1059b38ef45dcd71ca9720b29ca78030 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Mon, 17 Jun 2024 18:29:55 +0800 Subject: [PATCH] bugfix --- bricks/build.sh | 2 +- bricks/input.js | 3 + bricks/llm.js | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 bricks/llm.js diff --git a/bricks/build.sh b/bricks/build.sh index 2065a29..041bd66 100755 --- a/bricks/build.sh +++ b/bricks/build.sh @@ -6,7 +6,7 @@ SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \ tree.js multiple_state_image.js dynamiccolumn.js form.js message.js conform.js \ paging.js datagrid.js iframe.js \ floaticonbar.js miniform.js wterm.js dynamicaccordion.js \ - llm_dialog.js websocket.js datarow.js tabular.js " + llm_dialog.js llm.js websocket.js datarow.js tabular.js " echo ${SOURCES} cat ${SOURCES} > ../dist/bricks.js # uglifyjs --compress --mangle -- ../dist/bricks.js > ../dist/bricks.min.js diff --git a/bricks/input.js b/bricks/input.js index 848798f..9a585d2 100755 --- a/bricks/input.js +++ b/bricks/input.js @@ -645,6 +645,9 @@ bricks.UiCode =class extends bricks.UiType { if(event){ bricks.extend(params, event.params); } + await loadData(params); + } + async loadData(params){ var jcall = bricks.jcall; var d = await jcall(this.opts.dataurl, { diff --git a/bricks/llm.js b/bricks/llm.js new file mode 100644 index 0000000..42d787c --- /dev/null +++ b/bricks/llm.js @@ -0,0 +1,218 @@ +bricks = window.bricks || {} + +bricks.ModelOutput = class extends bricks.HBox { + /* { + icon: + output_view: + } + 完成模型输出的控件的初始化以及获得数据后的更新, 更新是的数据在流模式下,需要使用累积数据 + */ + constructor(opts){ + if(! opts){ + opts = {}; + } + opts.width = '100%'; + super(opts); + this.img = new bricks.Icon({rate:2,url:this.icon||bricks_resource('imgs/llm.png')}); + this.run = new bricks.BaseRunning({target:this}); + this.add_widget(img); + this.add_widget(this.run) + } + async update_data(data){ + this.run.stop_timepass(); + var w = await bricks.widgetBuild(this.output_view, this.llmio, data); + w.set_css('llm_msg'); + w.set_css('filler'); + this.clear_widgets(); + this.add+widget(img); + this.add_widget(w); + this.add_widget(new bricks.BlankIcon({rate:2, flexShrink:0})); + } +} + +bricks.LlmModel { + /* + { + icon: + model: + mapi: + url: + output_view: + params: + user_message_format: + system_message_format: + llm_message_format: + use_session: + input_from: + io_mode:stream, sync or async + } + */ + constructor(llmio, opts){ + this.opts = opts; + this.llmio = llmio; + if (opts.use_session){ + this.messages = []; + } + } + render_title(){ + var w = new bricks.HBox({}); + w.bind('click', this.show_setup_panel.bind(this)) + var img = new bricks.Icon({rate:2,url:this.icon||bricks_resource('imgs/llm.png')}); + var txt = new bricks.Text({text:this.model}); + this.add_widget(img); + this.add_widget(txt); + this.llmmodels.forEach(lm => { + var tw = ml.render_title(); + w.add_widget(tw); + } + return w; + } + model_inputed(data){ + var mout = new bricks.ModelOutput({icon:this.opts.icon, output_view:this.opts.output_view}); + this.llmio.o_w.add_widget(mout); + var fmt = this.opts.user_message_format || { role:'user', content:'${prompt}'}; + var umsg = bricks.apply_data(fmt, data); + var d = data; + if (this.messages){ + this.messages.push(umsg); + d = { + messages:this.messages, + mapi:this.mapi, + prompt:prompt, + model:this.model + } + } else { + d = bricks.extend({}, data); + d.model = this.model; + } + if (this.response_mode == 'stream') { + var hr = new bricks.HttpResponseStream(); + this.set_stream_data(); + var resp = await hr.post(this.url, {params:d}); + await hr.handle_chunk(resp, this.chunk_response.bind(this, mout)); + this.chunk_ended(mout); + } else { + var hj = new bricks.HttpJson() + var resp = await hj.post(this.url, {params:d}); + if (this.response_mode == 'sync'){ + mout.update_data(resp); + if (this.messages){ + var msg = this.llm_msg_format(); + var lmsg = bricks.apply_data(msg, resp); + this.messages.push(lmsg) + } + } else { + ; + } + } + } + is_acccept_source(source){ + if (this.opts.input_from == source){ + return true; + } + return false; + } + llm_msg_format(){ + return this.llm_message_format || {role:'assistant', content:"${content}"} + } + set_stream_data(data){ + if (! data){ + this.stream_data = null; + } + if (! this.stream_data){ + this.stream_data = data; + return; + } + var merge_field = this.opts.merge_field || 'content'; + this.stream_data[merge_field] += data[merge_field]; + } + chunk_response(l, mout){ + var d = JSON.parse(l); + if (! d.content || d.content == ''){ + return; + } + this.set_stream_data(d); + mout.update_data(this.stream_data); + } + chunk_ended(){ + if (! this.messages) return; + + var msg = this.llm_msg_format(); + txt = bricks.escapeSpecialChars(txt); + var merge_field = this.opts.merge_field || 'content'; + var txt = bricks.escapeSpecialChars(this.stream_data[merge_field]); + this.stream_data[merge_field] = txt; + var lmsg = bricks.apply_data(msg, this.stream_data); + this.messages.push(lmsg); + } +} +bircks.LlmIO = class extends bricks.VBox { + /* + options: + { + user_icon: + input_fields: + input_view: + output_view: + models: + } + models:[ + { + icon: + model: + mapi: + url: + params: + use_session: + system_prompt: + user_parmpt: + input_from: + io_mode:stream, sync or async + } + ] + */ + constructor(opts){ + super(opts); + this.llmmodels = []; + this.models.forEach( m =>{ + var lm = new bricks.LlmModel(this, m); + this.llmmodels.push(lm); + } + this.title_w = new bricks.HBox({cheight:2}); + this.i_w = new bricks.VBox({cheight:5}); + this.o_w = new bricks.Filler({}); + this.add_widget(this.title_w); + this.add_widget(this.o_w); + this.add_widget(this.i_w); + this.build_input(); + } + async handle_input(event){ + var params = event.params; + await this.show_input(params); + this.llmmodels.forEach(lm => { + if (lm.is_accept_source('userinput')){ + lm.model_inputed(params); + } + }) + } + async show_input(params){ + var box = new bricks.HBox({width:'100%'}); + var w = new bricks.widgetBuild(this.input_view, this.o_w, params); + w.set_css(this.msg_css||'user_msg'); + w.set_css('filler'); + var img = new bricks.Icon({rate:2,url:this.user_icon||bricks_resource('imgs/user.png')}); + box.add_widget(w); + box.add_widget(img); + this.o_w.add_widget(box); + } + build_input(){ + var fopts = { + fields:this.input_fields + }; + var fw = new bricks.Form(fopts); + fw.bind('submit', this.handle_input.bind(this)); + this.i_w.add_widget(fw); + } +} + +bricks.Factory.register('LlmIO', bricks.LlmIO);