From 665052149919aaac3a2c66bba6f463f9f54bf92a Mon Sep 17 00:00:00 2001 From: dingyongliang Date: Thu, 30 Nov 2023 14:15:47 +0800 Subject: [PATCH] * add miniprogram chat page. --- lib/zin/wg/textarea/v1.php | 1 + module/ai/control.php | 14 +++ module/ai/css/miniprogramchat.ui.css | 86 +++++++++++++++++ module/ai/js/miniprogramchat.ui.js | 39 ++++++++ module/ai/lang/de.php | 10 +- module/ai/lang/en.php | 10 +- module/ai/lang/fr.php | 2 + module/ai/lang/zh-cn.php | 2 + module/ai/ui/miniprogramchat.html.php | 127 ++++++++++++++++++++++++++ module/ai/ui/square.html.php | 3 +- 10 files changed, 285 insertions(+), 9 deletions(-) create mode 100644 module/ai/css/miniprogramchat.ui.css create mode 100644 module/ai/js/miniprogramchat.ui.js create mode 100644 module/ai/ui/miniprogramchat.html.php diff --git a/lib/zin/wg/textarea/v1.php b/lib/zin/wg/textarea/v1.php index 15787c9254..5f1ccaf588 100644 --- a/lib/zin/wg/textarea/v1.php +++ b/lib/zin/wg/textarea/v1.php @@ -36,6 +36,7 @@ class textarea extends wg return h::textarea ( set($this->props->pick(array('name', 'id', 'class', 'required', 'placeholder', 'rows', 'cols', 'disabled'))), + set($this->getRestProps()), $this->prop('value'), $this->children() ); diff --git a/module/ai/control.php b/module/ai/control.php index 9bb5b1f06e..e1ad1e7566 100644 --- a/module/ai/control.php +++ b/module/ai/control.php @@ -135,6 +135,20 @@ class ai extends control $this->display(); } + /** + * Mini program chat. + * + * @param string $id + * @access public + * @return void + */ + public function miniProgramChat($id) + { + $this->view->miniProgram = $this->ai->getMiniProgramByID($id); + $this->view->fields = $this->ai->getMiniProgramFields($id); + $this->display(); + } + /** * Mini program square. * diff --git a/module/ai/css/miniprogramchat.ui.css b/module/ai/css/miniprogramchat.ui.css new file mode 100644 index 0000000000..0f80113812 --- /dev/null +++ b/module/ai/css/miniprogramchat.ui.css @@ -0,0 +1,86 @@ +.mini-program { + top: 66px; + right: 16px; + bottom: 16px; + left: 16px; + gap: 16px; +} + +.mini-program .detail { + flex-basis: 390px; + background: #fff; + display: flex; + flex-direction: column; +} + +.mini-program .detail .header { + padding: 24px 20px 20px 20px; + display: flex; + gap: 20px; + color: var(--color-slate-800); + flex: none; + border-bottom: 1px solid var(--color-gray-200); +} + +.mini-program .detail .header .program-avatar { + width: 46px; + height: 46px; + flex: none; +} + +.mini-program .detail .header .content { + flex: auto; +} + +.mini-program .detail .header .content .title { + font-size: 14px; + font-weight: 500; +} + +.mini-program .detail .header .content .desc { + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.mini-program .detail .body { + flex: auto; + display: flex; + flex-direction: column; + padding-top: 20px; + padding-left: 20px; + padding-right: 20px; +} + +.mini-program .detail .body .language-model { + display: flex; + justify-content: space-between; + align-items: center; + flex: none; +} + +.mini-program .detail .body .language-model .btn { + color: var(--color-slate-700); +} + +.mini-program .detail .body .language-model .btn:hover { + background: var(--color-gray-300); +} + +.mini-program .detail .body .form-container { + flex: auto; + overflow-y: auto; +} + +.mini-program .detail .footer { + padding: 20px 20px 24px 20px; + flex: none; +} + +.mini-program .chat { + flex: auto; + flex-basis: 67%; + background: #fff; +} diff --git a/module/ai/js/miniprogramchat.ui.js b/module/ai/js/miniprogramchat.ui.js new file mode 100644 index 0000000000..39009b1899 --- /dev/null +++ b/module/ai/js/miniprogramchat.ui.js @@ -0,0 +1,39 @@ +if(!window.aiMiniProgramChat) window.aiMiniProgramChat = {}; + +function getFormValue() +{ + /** + * @type {Map} + */ + const fieldValueMap = new Map(); + fieldNames.forEach(name => + { + const $field = $(`[data-name="${name}"]`); + if(!$field.hasClass('picker-box')) + { + fieldValueMap.set(name, $field.prop('value')); + } + else + { + fieldValueMap.set(name, $field.zui('picker').$.value); + } + }); + return fieldValueMap; +} + +function generatePrompt() +{ + let promptStr = prompt; + const map = getFormValue(); + map.forEach((value, key) => + { + promptStr = promptStr.replace(new RegExp(`\\s<${key}>\\s`, 'g'), value); + }); + return promptStr; +} + +window.aiMiniProgramChat.startAIChat = function() +{ + const promptStr = generatePrompt(); + console.log(promptStr); +}; diff --git a/module/ai/lang/de.php b/module/ai/lang/de.php index ab29484669..4087ed66ed 100644 --- a/module/ai/lang/de.php +++ b/module/ai/lang/de.php @@ -31,6 +31,7 @@ $lang->prompt->editedDate = 'Edited Date'; $lang->prompt->deleted = 'Deleted'; /* Lang for privs, keys are paired with privlang items. */ +$lang->ai->modelCurrent = 'Current Model'; $lang->ai->modelBrowse = 'Browse Models'; $lang->ai->modelEdit = 'Edit Models'; $lang->ai->modelTestConnection = 'Test Model Connection'; @@ -475,6 +476,10 @@ $lang->ai->miniPrograms->field->default = array( 'As a , I hope to in .' ); +$lang->ai->miniPrograms->field->emptyNameWarning = 'Field name cannot be empty'; +$lang->ai->miniPrograms->field->duplicatedNameWarning = 'Duplicate field name'; +$lang->ai->miniPrograms->field->emptyOptionWarning = 'Please configure at least one option'; + $lang->ai->miniPrograms->statuses = array( '' => 'all', 'draft' => 'unpublished', @@ -487,10 +492,7 @@ $lang->ai->miniPrograms->optionName = 'Option name'; $lang->ai->miniPrograms->promptTemplate = 'Prompt template'; $lang->ai->miniPrograms->fieldConfiguration = 'Field configuration'; $lang->ai->miniPrograms->summary = 'There are %s small programs on this page.'; - -$lang->ai->miniPrograms->field->emptyNameWarning = 'Field name cannot be empty'; -$lang->ai->miniPrograms->field->duplicatedNameWarning = 'Duplicate field name'; -$lang->ai->miniPrograms->field->emptyOptionWarning = 'Please configure at least one option'; +$lang->ai->miniPrograms->generate = 'Generate'; $lang->ai->models = new stdclass(); $lang->ai->models->title = 'Language Model Configuration'; diff --git a/module/ai/lang/en.php b/module/ai/lang/en.php index 099d9cb601..39b65d00fd 100644 --- a/module/ai/lang/en.php +++ b/module/ai/lang/en.php @@ -31,6 +31,7 @@ $lang->prompt->editedDate = 'Edited Date'; $lang->prompt->deleted = 'Deleted'; /* Lang for privs, keys are paired with privlang items. */ +$lang->ai->modelCurrent = 'Current Model'; $lang->ai->modelBrowse = 'Browse Models'; $lang->ai->modelEdit = 'Edit Models'; $lang->ai->modelTestConnection = 'Test Model Connection'; @@ -475,6 +476,10 @@ $lang->ai->miniPrograms->field->default = array( 'As a , I hope to in .' ); +$lang->ai->miniPrograms->field->emptyNameWarning = 'Field name cannot be empty'; +$lang->ai->miniPrograms->field->duplicatedNameWarning = 'Duplicate field name'; +$lang->ai->miniPrograms->field->emptyOptionWarning = 'Please configure at least one option'; + $lang->ai->miniPrograms->statuses = array( '' => 'all', 'draft' => 'unpublished', @@ -487,10 +492,7 @@ $lang->ai->miniPrograms->optionName = 'Option name'; $lang->ai->miniPrograms->promptTemplate = 'Prompt template'; $lang->ai->miniPrograms->fieldConfiguration = 'Field configuration'; $lang->ai->miniPrograms->summary = 'There are %s small programs on this page.'; - -$lang->ai->miniPrograms->field->emptyNameWarning = 'Field name cannot be empty'; -$lang->ai->miniPrograms->field->duplicatedNameWarning = 'Duplicate field name'; -$lang->ai->miniPrograms->field->emptyOptionWarning = 'Please configure at least one option'; +$lang->ai->miniPrograms->generate = 'Generate'; $lang->ai->models = new stdclass(); $lang->ai->models->title = 'Language Model Configuration'; diff --git a/module/ai/lang/fr.php b/module/ai/lang/fr.php index 921eae0407..39b65d00fd 100644 --- a/module/ai/lang/fr.php +++ b/module/ai/lang/fr.php @@ -31,6 +31,7 @@ $lang->prompt->editedDate = 'Edited Date'; $lang->prompt->deleted = 'Deleted'; /* Lang for privs, keys are paired with privlang items. */ +$lang->ai->modelCurrent = 'Current Model'; $lang->ai->modelBrowse = 'Browse Models'; $lang->ai->modelEdit = 'Edit Models'; $lang->ai->modelTestConnection = 'Test Model Connection'; @@ -491,6 +492,7 @@ $lang->ai->miniPrograms->optionName = 'Option name'; $lang->ai->miniPrograms->promptTemplate = 'Prompt template'; $lang->ai->miniPrograms->fieldConfiguration = 'Field configuration'; $lang->ai->miniPrograms->summary = 'There are %s small programs on this page.'; +$lang->ai->miniPrograms->generate = 'Generate'; $lang->ai->models = new stdclass(); $lang->ai->models->title = 'Language Model Configuration'; diff --git a/module/ai/lang/zh-cn.php b/module/ai/lang/zh-cn.php index 9ef6d0c83e..58bf380db1 100644 --- a/module/ai/lang/zh-cn.php +++ b/module/ai/lang/zh-cn.php @@ -31,6 +31,7 @@ $lang->prompt->editedDate = '编辑时间'; $lang->prompt->deleted = '是否已删除'; /* Lang for privs, keys are paired with privlang items. */ +$lang->ai->modelCurrent = '当前语言模型'; $lang->ai->modelBrowse = '浏览语言模型'; $lang->ai->modelEdit = '编辑语言模型'; $lang->ai->modelTestConnection = '测试连接'; @@ -491,6 +492,7 @@ $lang->ai->miniPrograms->optionName = '选项名称'; $lang->ai->miniPrograms->promptTemplate = '提词模板'; $lang->ai->miniPrograms->fieldConfiguration = '字段配置'; $lang->ai->miniPrograms->summary = '本页共 %s 个小程序。'; +$lang->ai->miniPrograms->generate = '生成'; $lang->ai->models = new stdclass(); $lang->ai->models->title = '语言模型配置'; diff --git a/module/ai/ui/miniprogramchat.html.php b/module/ai/ui/miniprogramchat.html.php new file mode 100644 index 0000000000..8886311450 --- /dev/null +++ b/module/ai/ui/miniprogramchat.html.php @@ -0,0 +1,127 @@ +prompt); + +$formGroups = array(); +$fieldNames = array(); +foreach($fields as $field) +{ + if($field->type === 'textarea') + { + $control = textarea( + set::rows(1), + set::name("field-{$field->id}"), + set::placeholder($field->placeholder), + setData('name', $field->name) + ); + } + elseif($field->type === 'radio') + { + $options = explode(',', $field->options); + $control = picker( + set::name("field-{$field->id}"), + set::items(array_combine($options, $options)), + setData('name', $field->name) + ); + } + elseif($field->type === 'checkbox') + { + $options = explode(',', $field->options); + $control = picker( + set::name("field-{$field->id}"), + set::items(array_combine($options, $options)), + set::multiple(true), + setData('name', $field->name) + ); + } + else + { + $control = input( + set::name("field-{$field->id}"), + set::placeholder($field->placeholder), + setData('name', $field->name) + ); + } + + $formGroups[] = formGroup( + set::label($field->name), + set::required($field->required === '1'), + $control + ); + + $fieldNames[] = $field->name; +} + +jsVar('fieldNames', $fieldNames); + +list($iconName, $iconTheme) = explode('-', $miniProgram->icon); + +div( + setClass('mini-program fixed flex'), + div( + setClass('detail col shadow-md'), + div( + setClass('header'), + div( + setClass('program-avatar center'), + setStyle(array('border' => "1px solid {$config->ai->miniPrograms->themeList[$iconTheme][1]}", 'background-color' => $config->ai->miniPrograms->themeList[$iconTheme][0])), + html($config->ai->miniPrograms->iconList[$iconName]) + ), + div( + setClass('content'), + div( + setClass('title pb-2'), + $miniProgram->name + ), + div( + setClass('desc'), + set::title($miniProgram->desc), + $miniProgram->desc + ) + ) + ), + div( + setClass('body'), + div( + setClass('language-model'), + div( + setClass('content flex gap-2.5'), + span( + setStyle(array('color' => 'var(--color-slate-700)')), + $lang->ai->modelCurrent + ), + span($lang->ai->miniPrograms->modelList[$miniProgram->model]), + ), + btn( + setClass('ghost'), + set::icon('trash'), + $lang->ai->chatReset + ), + ), + div( + setClass('form-container p-1'), + form( + set::grid(false), + set::actions(array()), + $formGroups + ), + ) + ), + div( + setClass('footer'), + btn( + setClass('primary block w-full'), + $lang->ai->miniPrograms->generate, + on::click('window.aiMiniProgramChat.startAIChat') + ) + ) + ), + div( + setClass('chat') + ) +); + +render(); diff --git a/module/ai/ui/square.html.php b/module/ai/ui/square.html.php index 731ddec55d..61e9003cac 100644 --- a/module/ai/ui/square.html.php +++ b/module/ai/ui/square.html.php @@ -66,7 +66,8 @@ $miniProgramCard = function($miniProgram) use ($categoryList, $collectedIDs) $star = in_array($miniProgram->id, $collectedIDs) ? 'star' : 'star-empty'; $delete = $star === 'star' ? 'true' : 'false'; - return div( + return a( + set::href(createLink('ai', 'miniProgramChat', "id={$miniProgram->id}#app=ai")), setClass('miniprogram-card'), div( setClass('program-content'),