|
|
@@ -12,10 +12,35 @@
|
|
|
<ElInput v-model="item.template" type="textarea" :autosize="{ min: 20 }"></ElInput>
|
|
|
<div class="mt-4">
|
|
|
<ElButton @click="save(i)" :loading="loading" type="primary">保存</ElButton>
|
|
|
+ <ElButton @click="test(i)" :loading="loading">测试</ElButton>
|
|
|
<ElButton @click="restore(i)" :disabled="loading">恢复默认</ElButton>
|
|
|
</div>
|
|
|
</el-tab-pane>
|
|
|
</el-tabs>
|
|
|
+ <br />
|
|
|
+ <br />
|
|
|
+ <div class="ml-32 flex text-sm text-neutral-600 dark:text-neutral-400">
|
|
|
+ <div class="">
|
|
|
+ 可用变量:<br />
|
|
|
+ days: 运行天数<br />
|
|
|
+ charactors: 角色列表<br />
|
|
|
+ total: 总人数<br />
|
|
|
+ alive: 存活人数<br />
|
|
|
+ dead: 死亡人数<br />
|
|
|
+ minHp: 最低生命值<br />
|
|
|
+ maxHp: 最高生命值<br />
|
|
|
+ avgHp: 平均生命值<br /><br />
|
|
|
+ 语法示例:
|
|
|
+ <code class="bg-neutral-300 dark:bg-neutral-700 px-2 py-1 rounded-sm"
|
|
|
+ ><% return alive > 5 ? '加入战斗情节' : '' %></code
|
|
|
+ ><br />
|
|
|
+ <br />
|
|
|
+ </div>
|
|
|
+ <div class="pl-8">
|
|
|
+ 测试变量:<br />
|
|
|
+ <json-viewer :value="testVarsFinal" :expand-depth="1" copyable boxed sort></json-viewer>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
<script setup>
|
|
|
@@ -24,6 +49,8 @@ import { onMounted, ref, watch } from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
import { Plus, Trash } from '@vicons/tabler'
|
|
|
import { ElMessageBox } from 'element-plus'
|
|
|
+import JsonViewer from 'vue-json-viewer'
|
|
|
+import {} from '@vicons/tabler'
|
|
|
const activeName = ref('')
|
|
|
const prompts = ref([])
|
|
|
const types = ref([])
|
|
|
@@ -61,6 +88,9 @@ onMounted(() => {
|
|
|
})
|
|
|
const loading = ref(false)
|
|
|
async function save(i) {
|
|
|
+ if (!test(i, false)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
try {
|
|
|
loading.value = true
|
|
|
await http.put('/prompt', prompts.value[i])
|
|
|
@@ -102,4 +132,126 @@ async function delType() {
|
|
|
ElMessage.error(error.message)
|
|
|
}
|
|
|
}
|
|
|
+const testVars = {
|
|
|
+ days: 4,
|
|
|
+ charactors: [
|
|
|
+ {
|
|
|
+ name: '约翰',
|
|
|
+ gender: '男',
|
|
|
+ age: '35',
|
|
|
+ occupation: '侦探',
|
|
|
+ personality: '1号',
|
|
|
+ background: '前警探,以侦破神秘犯罪而闻名',
|
|
|
+ hp: 0,
|
|
|
+ joinAt: '2023-10-10T16:00:00.000Z',
|
|
|
+ survival: 0,
|
|
|
+ dead: true,
|
|
|
+ avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/7laitqdb.png',
|
|
|
+ deadAt: '2023-10-15T16:00:00.000Z'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '艾米丽',
|
|
|
+ gender: '女',
|
|
|
+ age: '28',
|
|
|
+ occupation: '记者',
|
|
|
+ personality: '好奇心重',
|
|
|
+ background: '调查性记者,专注于揭露黑暗的秘密。',
|
|
|
+ hp: 0,
|
|
|
+ joinAt: '2023-10-10T16:00:00.000Z',
|
|
|
+ survival: 0,
|
|
|
+ dead: true,
|
|
|
+ avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/dgg7bxc6.png',
|
|
|
+ deadAt: '2023-10-14T16:00:00.000Z'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '威廉',
|
|
|
+ gender: '女',
|
|
|
+ age: '45',
|
|
|
+ occupation: '律师',
|
|
|
+ personality: '聪明的',
|
|
|
+ background: '非常成功的辩护律师,以为自己的客户获得无罪声誉而闻名。',
|
|
|
+ hp: 10,
|
|
|
+ joinAt: '2023-10-10T16:00:00.000Z',
|
|
|
+ survival: 0,
|
|
|
+ dead: false,
|
|
|
+ avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/slxskike.png'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '伊莎贝拉',
|
|
|
+ gender: '女',
|
|
|
+ age: '30',
|
|
|
+ occupation: '法医',
|
|
|
+ personality: '善于分析',
|
|
|
+ background: '具有DNA分析专业知识的法医科学家,解决了许多冷案。',
|
|
|
+ hp: 0,
|
|
|
+ joinAt: '2023-10-10T16:00:00.000Z',
|
|
|
+ survival: 0,
|
|
|
+ dead: true,
|
|
|
+ avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/oqqliuus.png',
|
|
|
+ deadAt: '2023-10-14T16:00:00.000Z'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '亚历山大',
|
|
|
+ gender: '男',
|
|
|
+ age: '40',
|
|
|
+ occupation: '心理学家',
|
|
|
+ personality: '富有洞察力的',
|
|
|
+ background: '著名心理学家,专长是犯罪心理分析。',
|
|
|
+ hp: 10,
|
|
|
+ joinAt: '2023-10-10T16:00:00.000Z',
|
|
|
+ survival: 0,
|
|
|
+ dead: false,
|
|
|
+ avatar: 'https://nebuai.oss-cn-hangzhou.aliyuncs.com/image/20231012/hqflwm6u.png'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+function evalPrompt(vars, template) {
|
|
|
+ vars.total = vars.charactors.length
|
|
|
+ vars.alive = vars.charactors.filter((i) => !i.dead).length
|
|
|
+ vars.dead = vars.charactors.filter((i) => i.dead).length
|
|
|
+ const hps = vars.charactors.filter((i) => i.hp > 0).map((i) => i.hp)
|
|
|
+ vars.minHp = hps.length > 0 ? Math.min(...hps) : 0
|
|
|
+ vars.maxHp = hps.length > 0 ? Math.max(...hps) : 0
|
|
|
+ vars.avgHp = hps.length > 0 ? hps.reduce((a, b) => a + b) / hps.length : 0
|
|
|
+ const reg = /<%([^%]*(?:%(?!>)[^%]*)*)%>/
|
|
|
+ while (reg.test(template)) {
|
|
|
+ template = template.replace(reg, function (match, $1) {
|
|
|
+ var func = new Function('days', 'charactors', 'total', 'alive', 'dead', 'minHp', 'maxHp', 'avgHp', $1)
|
|
|
+ return func(
|
|
|
+ vars.days,
|
|
|
+ vars.charactors,
|
|
|
+ vars.total,
|
|
|
+ vars.alive,
|
|
|
+ vars.dead,
|
|
|
+ vars.minHp,
|
|
|
+ vars.maxHp,
|
|
|
+ vars.avgHp
|
|
|
+ )
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ template,
|
|
|
+ vars
|
|
|
+ }
|
|
|
+}
|
|
|
+const testVarsFinal = evalPrompt(testVars, '<% return alive > 5 ? "加入战斗情节" : "" %>').vars
|
|
|
+function test(i, showResult = true) {
|
|
|
+ try {
|
|
|
+ const result = evalPrompt(testVars, prompts.value[i].template)
|
|
|
+ if (showResult) {
|
|
|
+ ElMessageBox.alert(`<p class="whitespace-pre-wrap">${result.template}</p>`, `测试结果`, {
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
+ customStyle: { maxWidth: '800px' }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ ElMessageBox.alert(`<p class="text-red-500">${error.message}</p>`, '测试失败', {
|
|
|
+ type: 'error',
|
|
|
+ dangerouslyUseHTMLString: true
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
</script>
|