bricks = window.bricks || {} bricks.LlmMsgAudio = class extends bricks.UpStreaming { constructor(opts){ super(opts); this.olddata = ''; this.data = ''; this.cn_p = ["。",",","!","?","\n"]; this.other_p = [".",",","!","?","\n"]; this.audio = AudioPlayer({}) } detectLanguage(text) { try { const detector = new Intl.LocaleDetector(); const locale = detector.detectLocaleOf(text); return locale.language; } catch (error) { console.error('无法检测语言:', error); return '未知'; } } send(data){ var newdata = data.slice(this.olddata.length); this.olddata = data; this.data += newdata; var lang = detectLaguage(this.data); var parts; if (lang='zh'){ parts = this.data.split(this.cn_p).filter(part => part.trim()!== ''); } else { parts = this.data.split(this.oter_p).filter(part => part.trim()!== ''); } for(var i=0;i0){ data.content = "```\\n" + this.received_reasoning_content + "\\n```\\n" + this.received_content; } else { data.content = this.received_content } var desc = bricks.apply_data(this.output_view, data); var w = await bricks.widgetBuild(desc, this.llmio); if (! w){ console.log('widgetBuild() return null, desc=', this.output_view, desc, 'data=', data); return; } w.set_css('llm_msg'); w.set_style('width', '100%'); this.filler.add_widget(w); this.filler.add_widget(this.estimate_w); if (data.logid){ this.logid = data.logid; if (this.estimate_url){ this.estimate_w.show(); } } } finish(){ if (this.upstreaming){ this.upstreaming.finish(); } } } bricks.LlmModel = class extends bricks.JsWidget { /* { icon: model: url: output_view: params: user_message_format: system_message_format: llm_message_format: use_session: input_from: textvoice: tts_url: response_mode:stream, sync or async } */ constructor(llmio, opts){ super(opts); this.llmio = llmio; } render_title(){ var w = new bricks.HBox({padding:'15px'}); w.bind('click', this.show_setup_panel.bind(this)) var img = new bricks.Svg({ rate:2, tip:this.opts.modelname, url:this.opts.icon||bricks_resource('imgs/llm.svg') }); // var txt = new bricks.Text({text:this.opts.modelname}); w.add_widget(img); // w.add_widget(txt); return w; } show_setup_panel(event){ } inputdata2uploaddata(data){ var d; if (data instanceof FormData){ d = bricks.formdata_copy(data); } else { d = objcopy(data); } if (data instanceof FormData){ d.append('model', this.opts.model) d.append('llmid', this.opts.llmid) } else { d.model = this.opts.model; d.llmid = this.opts.llmid; } return d; } async model_inputed(data){ var mout = new bricks.ModelOutput({ textvoice:this.textvoice, tts_url:this.tts_url, icon:this.opts.icon, response_mode: this.opts.response_mode, model:this.opts.model, modelname:this.opts.modelname, estimate_url:this.llmio.estimate_url, output_view:this.opts.output_view}); this.llmio.o_w.add_widget(mout); if (this.response_mode == 'stream' || this.response_mode == 'async') { var d = this.inputdata2uploaddata(data); var hr = new bricks.HttpResponseStream(); var resp = await hr.post(this.opts.url, {params:d}); await hr.handle_chunk(resp, this.chunk_response.bind(this, mout)); this.chunk_ended(); } else { var d = this.inputdata2uploaddata(data); console.log('data_inouted=', data, 'upload_data=', d); var hj = new bricks.HttpJson() var resp = await hj.post(this.opts.url, {params:d}); resp.content = bricks.escapeSpecialChars(resp.content) mout.update_data(resp); } } is_accept_source(source){ if (this.opts.input_from == source){ return true; } return false; } llm_msg_format(){ return this.llm_message_format || {role:'assistant', content:"${content}"} } chunk_response(mout, l){ try { var d = JSON.parse(l); } catch(e){ console.log(l, 'is not a json data'); return } if (! d.content || d.content == ''){ console.log(l, 'content is not null'); return; } d.content = bricks.escapeSpecialChars(d.content); mout.update_data(d); // console.log('stream data=', d); } chunk_ended(){ console.log('chunk end'); } } bricks.LlmIO = class extends bricks.VBox { /* options: { user_icon: list_models_url: input_fields: input_view: output_view: models: } models:[ { icon: model: modelnmae: url: params: use_session: system_prompt: user_parmpt: input_from: io_mode:stream, sync or async } ] */ constructor(opts){ super(opts); this.llmmodels = []; this.title_w = new bricks.HBox({cheight:3}); var bottom_box = new bricks.HBox({cheight:3}); this.i_w = new bricks.Svg({ rate:2, url:bricks_resource('imgs/input.svg'), margin:'14px', tip:'input data', css:'clickable' }); this.nm_w = new bricks.Svg({ rate:2, url:bricks_resource('imgs/add.svg'), margin:'14px', tip:'add new model', css:'clickable' }); bottom_box.add_widget(this.i_w); bottom_box.add_widget(this.nm_w); this.nm_w.bind('click', this.open_search_models.bind(this)); this.i_w.bind('click', this.open_input_widget.bind(this)); this.o_w = new bricks.Filler({overflow:'auto'}); this.add_widget(this.title_w); this.add_widget(this.o_w); if (this.models.length < 2 && this.tts_url){ this.textvoice = true; } this.add_widget(bottom_box); this.models.forEach( m =>{ this.show_added_model(m); }); } show_added_model(m){ if (this.textvoice){ m.textvoice = true; m.tts_url = this.tts_url; } var lm = new bricks.LlmModel(this, m); this.llmmodels.push(lm); var tw = lm.render_title(); this.title_w.add_widget(tw); } async open_search_models(event){ event.preventDefault(); event.stopPropagation(); var rect = this.showRectage(); var opts = { title:"select model", icon:bricks_resource('imgs/search.png'), auto_destroy:true, auto_open:true, auto_dismiss:false, movable:true, top:rect.top + 'px', left:rect.left + 'px', width: rect.right - rect.left + 'px', height: rect.bottom - rect.top + 'px' } var w = new bricks.PopupWindow(opts); var sopts = { data_url:this.list_models_url, data_params:{ mii:this.models[0].modelinstanceid, mti:this.models[0].modeltypeid }, data_method:'POST', col_cwidth: 24, record_view:{ widgettype:"VBox", options:{ cheight:20, css:"card" }, subwidgets:[ { widgettype:"Title4", options:{ text:"${name}" } }, { widgettype:"Filler", options:{ css:"scroll" }, subwidgets:[ { widgettype:"VBox", options:{ css:"subcard" }, subwidgets:[ { widgettype:"Text", options:{ text:"模型描述:${description}", wrap:true } }, { widgettype:"Text", options:{ text:"启用日期:${enable_date}" } } ] } ] } ] } }; var cols = new bricks.Cols(sopts); cols.bind('record_click', this.add_new_model.bind(this)); cols.bind('record_click', w.dismiss.bind(w)); w.add_widget(cols); w.open(); } async add_new_model(event){ event.preventDefault(); event.stopPropagation(); this.models.push(event.params); this.show_added_model(event.params); } async open_input_widget(event){ event.preventDefault(); event.stopPropagation(); var rect = this.showRectage(); var opts = { title:"input data", icon:bricks_resource('imgs/input.png'), auto_destroy:true, auto_open:true, auto_dismiss:false, movable:true, top:rect.top + 'px', left:rect.left + 'px', width: rect.right - rect.left + 'px', height: rect.bottom - rect.top + 'px' } var w = new bricks.PopupWindow(opts); var fopts = { fields:this.input_fields } var fw = new bricks.Form(fopts); fw.bind('submit', this.handle_input.bind(this)); fw.bind('submit', w.destroy.bind(w)); w.add_widget(fw); w.open(); } async handle_input(event){ var params = event.params; await this.show_input(params); for(var i=0;i