koishi-plugin-chat-patch 3.0.2 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/vue/index.vue +60 -634
- package/client/web/dist/assets/AppIcon-DIku6-h0.png +0 -0
- package/client/web/dist/assets/AppIconDark-BYymN71t.png +0 -0
- package/client/web/dist/assets/CapacitorAppIcon-CSZwNhvi.png +0 -0
- package/client/web/dist/assets/CapacitorAppIconDark-BMvMOzsg.png +0 -0
- package/client/web/dist/assets/Chat-CTdyeaX2.css +1 -0
- package/client/web/dist/assets/Chat-DkZvD7d8.js +28 -0
- package/client/web/dist/assets/MealHungryPan-Beos3lRI.js +1 -0
- package/client/web/dist/assets/MsgBody-aZ4_aija.js +1 -0
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-CPZjRLp6.js +67 -0
- package/client/web/dist/assets/NapcatAppIcon-C7VOAkW9.png +0 -0
- package/client/web/dist/assets/Vue-lEhHouxB.png +0 -0
- package/client/web/dist/assets/append_darwin-CqBNU62J.css +1 -0
- package/client/web/dist/assets/append_full_vibrancy-j0D2LM9m.css +1 -0
- package/client/web/dist/assets/append_linux-uhxeBqeC.css +1 -0
- package/client/web/dist/assets/append_linux_vibrancy-COiZq8MS.css +1 -0
- package/client/web/dist/assets/append_napcat-DV8CAyAd.css +1 -0
- package/client/web/dist/assets/append_new-407Lo5_V.css +1 -0
- package/client/web/dist/assets/append_vibrancy-6FHctkOY.css +1 -0
- package/client/web/dist/assets/append_win32-srmD-78y.css +1 -0
- package/client/web/dist/assets/cakes-CxTVKdnK.svg +189 -0
- package/client/web/dist/assets/core-DhEqZVGG.js +1 -0
- package/client/web/dist/assets/event-Cadp6m6J.js +1 -0
- package/client/web/dist/assets/index-CPTXiemn.js +4045 -0
- package/client/web/dist/assets/index-Cg_esKB0.js +1 -0
- package/client/web/dist/assets/index-Cln012sP.css +1 -0
- package/client/web/dist/assets//346/226/271/346/255/243/345/226/265/345/221/234/344/275/223-CJKIKBn3.ttf +0 -0
- package/client/web/dist/assets//346/234/237/345/276/205-C90_OY60.png +0 -0
- package/client/web/dist/bcui/css/color-dark.css +35 -0
- package/client/web/dist/bcui/css/color-light.css +35 -0
- package/client/web/dist/bcui/css/style.css +468 -0
- package/client/web/dist/bcui/js/main.js +193 -0
- package/client/web/dist/css/append-dark.css +13 -0
- package/client/web/dist/css/append-light.css +13 -0
- package/client/web/dist/css/append-napcat-dark.css +14 -0
- package/client/web/dist/css/append-napcat-light.css +14 -0
- package/client/web/dist/favicon.ico +0 -0
- package/client/web/dist/img/icons/icon-for-fuck-apple.png +0 -0
- package/client/web/dist/img/icons/icon-maskable.png +0 -0
- package/client/web/dist/img/icons/icon.png +0 -0
- package/client/web/dist/img/icons/icon.svg +10 -0
- package/client/web/dist/index.html +22 -0
- package/client/web/dist/robots.txt +2 -0
- package/client/web/dist/sw.js +58 -0
- package/client/web/env.d.ts +56 -0
- package/client/web/index.html +21 -0
- package/client/web/package-lock.json +3419 -0
- package/client/web/package.json +62 -0
- package/client/web/public/bcui/css/color-dark.css +35 -0
- package/client/web/public/bcui/css/color-light.css +35 -0
- package/client/web/public/bcui/css/style.css +468 -0
- package/client/web/public/bcui/js/main.js +193 -0
- package/client/web/public/css/append-dark.css +13 -0
- package/client/web/public/css/append-light.css +13 -0
- package/client/web/public/css/append-napcat-dark.css +14 -0
- package/client/web/public/css/append-napcat-light.css +14 -0
- package/client/web/public/favicon.ico +0 -0
- package/client/web/public/img/icons/icon-for-fuck-apple.png +0 -0
- package/client/web/public/img/icons/icon-maskable.png +0 -0
- package/client/web/public/img/icons/icon.png +0 -0
- package/client/web/public/img/icons/icon.svg +10 -0
- package/client/web/public/robots.txt +2 -0
- package/client/web/public/sw.js +58 -0
- package/client/web/scripts/copy-bcui.mjs +17 -0
- package/client/web/src/App.vue +1127 -0
- package/client/web/src/assets/css/append/append_darwin.css +68 -0
- package/client/web/src/assets/css/append/append_full_vibrancy.css +290 -0
- package/client/web/src/assets/css/append/append_linux.css +125 -0
- package/client/web/src/assets/css/append/append_linux_vibrancy.css +22 -0
- package/client/web/src/assets/css/append/append_napcat.css +35 -0
- package/client/web/src/assets/css/append/append_new.css +843 -0
- package/client/web/src/assets/css/append/append_vibrancy.css +113 -0
- package/client/web/src/assets/css/append/append_win32.css +109 -0
- package/client/web/src/assets/css/append/mobile/append_mobile_horizontal.css +349 -0
- package/client/web/src/assets/css/append/mobile/append_mobile_vertical.css +96 -0
- package/client/web/src/assets/css/chat.css +2104 -0
- package/client/web/src/assets/css/msg.css +941 -0
- package/client/web/src/assets/css/options.css +811 -0
- package/client/web/src/assets/css/sys_notice.css +62 -0
- package/client/web/src/assets/css/view.css +2105 -0
- package/client/web/src/assets/font//346/226/271/346/255/243/345/226/265/345/221/234/344/275/223.ttf +0 -0
- package/client/web/src/assets/img/Vue.png +0 -0
- package/client/web/src/assets/img/cakes.svg +189 -0
- package/client/web/src/assets/img/icons/AppIcon.png +0 -0
- package/client/web/src/assets/img/icons/AppIconDark.png +0 -0
- package/client/web/src/assets/img/icons/CapacitorAppIcon.png +0 -0
- package/client/web/src/assets/img/icons/CapacitorAppIconDark.png +0 -0
- package/client/web/src/assets/img/icons/NapcatAppIcon.png +0 -0
- package/client/web/src/assets/img/icons/NapcatAppIconDark.png +0 -0
- package/client/web/src/assets/img/icons/exit.png +0 -0
- package/client/web/src/assets/img/icons/pen.png +0 -0
- package/client/web/src/assets/img/stars.svg +89 -0
- package/client/web/src/assets/img//346/234/237/345/276/205.png +0 -0
- package/client/web/src/assets/l10n/_About I10n.md +35 -0
- package/client/web/src/assets/l10n/_l10nconfig.json +7 -0
- package/client/web/src/assets/l10n/zh-CN.po +1941 -0
- package/client/web/src/assets/logo.png +0 -0
- package/client/web/src/assets/pathMap/LLOneBot.yaml +2 -0
- package/client/web/src/assets/pathMap/Lagrange.OneBot.yaml +180 -0
- package/client/web/src/assets/pathMap/NapCat.Onebot.yaml +224 -0
- package/client/web/src/assets/pathMap/SnowLuma.yaml +80 -0
- package/client/web/src/assets/qed.txt +1 -0
- package/client/web/src/components/AboutPan.vue +197 -0
- package/client/web/src/components/BulletinBody.vue +129 -0
- package/client/web/src/components/DepPan.vue +310 -0
- package/client/web/src/components/EmojiFace.vue +32 -0
- package/client/web/src/components/FacePan.vue +461 -0
- package/client/web/src/components/FileBody.vue +129 -0
- package/client/web/src/components/FileManager.vue +532 -0
- package/client/web/src/components/FriendBody.vue +54 -0
- package/client/web/src/components/GlobalSessionSearchBar.vue +301 -0
- package/client/web/src/components/History.vue +49 -0
- package/client/web/src/components/LazyLottie.vue +82 -0
- package/client/web/src/components/MergePan.vue +127 -0
- package/client/web/src/components/MsgBody.vue +1478 -0
- package/client/web/src/components/MusicPlayer.vue +549 -0
- package/client/web/src/components/NoticeBody.vue +168 -0
- package/client/web/src/components/QzonePermissionPan.vue +150 -0
- package/client/web/src/components/RawMsgRenderPreviewPan.vue +190 -0
- package/client/web/src/components/ThemeColorPickerPan.vue +420 -0
- package/client/web/src/components/TinySessionBody.vue +51 -0
- package/client/web/src/components/UmamiInfoPan.vue +1549 -0
- package/client/web/src/components/UpdatePan.vue +263 -0
- package/client/web/src/components/ViewerCom.vue +1360 -0
- package/client/web/src/components/VoiceMsg.vue +626 -0
- package/client/web/src/components/WelPan.vue +894 -0
- package/client/web/src/components/msg-body/.gitkeep +0 -0
- package/client/web/src/components/msg-component/JsonSegComp.vue +138 -0
- package/client/web/src/components/msg-component/XmlSegComp.vue +132 -0
- package/client/web/src/components/msg-component/jsonComp/AutoReply.vue +97 -0
- package/client/web/src/components/msg-component/jsonComp/Contact.lua.vue +129 -0
- package/client/web/src/components/msg-component/jsonComp/Feed.lua.vue +94 -0
- package/client/web/src/components/msg-component/jsonComp/Forum.vue +84 -0
- package/client/web/src/components/msg-component/jsonComp/Mannounce.vue +111 -0
- package/client/web/src/components/msg-component/jsonComp/Map.vue +52 -0
- package/client/web/src/components/msg-component/jsonComp/Miniapp.lua.vue +53 -0
- package/client/web/src/components/msg-component/jsonComp/Miniapp.vue +69 -0
- package/client/web/src/components/msg-component/jsonComp/Music.lua.vue +135 -0
- package/client/web/src/components/msg-component/jsonComp/Tuwen.lua.vue +56 -0
- package/client/web/src/components/notice-component/.gitkeep +0 -0
- package/client/web/src/components/notice-component/MealHungryPan.vue +119 -0
- package/client/web/src/components/tooltip/CustomFaceTooltip.vue +22 -0
- package/client/web/src/components/tooltip/Tooltip.vue +50 -0
- package/client/web/src/components/tooltip/Tooltips.vue +14 -0
- package/client/web/src/components/tooltip/UserInfoTooltip.vue +69 -0
- package/client/web/src/function/base.ts +238 -0
- package/client/web/src/function/connect.ts +2042 -0
- package/client/web/src/function/debug.ts +10 -0
- package/client/web/src/function/elements/information.ts +141 -0
- package/client/web/src/function/elements/system.ts +101 -0
- package/client/web/src/function/elements/vueComp.ts +62 -0
- package/client/web/src/function/favicon.ts +76 -0
- package/client/web/src/function/input.ts +69 -0
- package/client/web/src/function/model/emoji.ts +127 -0
- package/client/web/src/function/model/img.ts +150 -0
- package/client/web/src/function/model/msg-body.ts +51 -0
- package/client/web/src/function/msg.ts +2674 -0
- package/client/web/src/function/notify.ts +225 -0
- package/client/web/src/function/option.ts +749 -0
- package/client/web/src/function/satori-model.ts +818 -0
- package/client/web/src/function/satori.ts +325 -0
- package/client/web/src/function/sender.ts +178 -0
- package/client/web/src/function/tooltip.ts +49 -0
- package/client/web/src/function/utils/appUtil.ts +2288 -0
- package/client/web/src/function/utils/avatarUtil.ts +31 -0
- package/client/web/src/function/utils/backgroundUtil.ts +110 -0
- package/client/web/src/function/utils/linkViewUtil.ts +101 -0
- package/client/web/src/function/utils/localHistoryUtil.ts +517 -0
- package/client/web/src/function/utils/msgUtil.ts +1242 -0
- package/client/web/src/function/utils/pinyin.ts +141 -0
- package/client/web/src/function/utils/recordUtil.ts +187 -0
- package/client/web/src/function/utils/sessionUtil.ts +114 -0
- package/client/web/src/function/utils/systemUtil.ts +664 -0
- package/client/web/src/main.ts +91 -0
- package/client/web/src/pages/Chat.vue +3453 -0
- package/client/web/src/pages/Friends.vue +636 -0
- package/client/web/src/pages/Info.vue +717 -0
- package/client/web/src/pages/Messages.vue +875 -0
- package/client/web/src/pages/Options.vue +82 -0
- package/client/web/src/pages/Qzone.vue +1178 -0
- package/client/web/src/pages/chat-view/ChatDanmaku.vue +759 -0
- package/client/web/src/pages/chat-view/ChatGlagame.vue +642 -0
- package/client/web/src/pages/chat-view/ChatTerminal.vue +1044 -0
- package/client/web/src/pages/chat-view/SystemNotice.vue +171 -0
- package/client/web/src/pages/options/OptAccount.vue +107 -0
- package/client/web/src/pages/options/OptAddon.vue +185 -0
- package/client/web/src/pages/options/OptDev.vue +704 -0
- package/client/web/src/pages/options/OptFunction.vue +403 -0
- package/client/web/src/pages/options/OptInfo.vue +165 -0
- package/client/web/src/pages/options/OptView.vue +846 -0
- package/client/web/src/runtime/backend.ts +310 -0
- package/client/web/src/state/auth.ts +14 -0
- package/client/web/src/state/chat.ts +36 -0
- package/client/web/src/state/connection.ts +20 -0
- package/client/web/src/state/contact.ts +37 -0
- package/client/web/src/state/qzone.ts +18 -0
- package/client/web/src/state/sessionHistory.ts +25 -0
- package/client/web/src/state/settings.ts +18 -0
- package/client/web/src/state/sticker.ts +10 -0
- package/client/web/src/state/ui.ts +56 -0
- package/client/web/tsconfig.json +27 -0
- package/client/web/tsconfig.tsbuildinfo +1 -0
- package/client/web/vite.config.ts +33 -0
- package/dist/index.js +1 -12
- package/dist/style.css +1 -1
- package/lib/index.js +2070 -2077
- package/package.json +15 -2
- package/readme.md +0 -22
- package/src/bootstrap.ts +71 -0
- package/src/cache.ts +319 -0
- package/src/config.ts +23 -35
- package/src/database.ts +650 -0
- package/src/index.ts +27 -59
- package/src/media.ts +302 -0
- package/src/recorder.ts +175 -0
- package/src/self-message.ts +456 -0
- package/src/server.d.ts +26 -0
- package/src/types.ts +108 -48
- package/src/web.ts +712 -0
- package/client/vue/chat-logic.ts +0 -683
- package/client/vue/composables/useChatActions.ts +0 -61
- package/client/vue/composables/useChatData.ts +0 -185
- package/client/vue/composables/useImageCache.ts +0 -281
- package/client/vue/composables/useVideoCache.ts +0 -125
- package/client/vue/types.ts +0 -72
- package/lib/api-handlers.d.ts +0 -25
- package/lib/config.d.ts +0 -14
- package/lib/file-manager.d.ts +0 -124
- package/lib/index.d.ts +0 -17
- package/lib/logger.d.ts +0 -9
- package/lib/message-handler.d.ts +0 -35
- package/lib/types.d.ts +0 -57
- package/lib/utils.d.ts +0 -18
- package/src/api-handlers.ts +0 -646
- package/src/file-manager.ts +0 -1436
- package/src/message-handler.ts +0 -507
- package/src/utils.ts +0 -189
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<chat v-bind="$props">
|
|
4
|
+
<template #main-input-button>
|
|
5
|
+
<div style="cursor: pointer" @click="onRobotClick">
|
|
6
|
+
<font-awesome-icon v-if="!onChating" :icon="['fas', 'robot']" />
|
|
7
|
+
<font-awesome-icon v-else :icon="['fas', 'spinner']" spin />
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<template #chat-extra>
|
|
11
|
+
<div v-if="onLoading || dataList.length > 0" id="chat-extra" class="chat-extra">
|
|
12
|
+
<template v-if="dataList.length == 0">
|
|
13
|
+
<div class="ss-card load">
|
|
14
|
+
<font-awesome-icon :icon="['fas', 'spinner']" spin />
|
|
15
|
+
</div>
|
|
16
|
+
<div v-if="debug" id="chatHistory" class="ss-card chat-history">
|
|
17
|
+
<span>{{ chatHistory }}</span>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
<div v-else class="options">
|
|
21
|
+
<div v-for="(item, index) in dataList" :key="index"
|
|
22
|
+
@click="selectChoice(item)">
|
|
23
|
+
{{ item }}
|
|
24
|
+
</div>
|
|
25
|
+
<div class="controller">
|
|
26
|
+
<font-awesome-icon
|
|
27
|
+
:icon="['fas', 'xmark']"
|
|
28
|
+
@click="onLoading = false; dataList = []" />
|
|
29
|
+
<font-awesome-icon
|
|
30
|
+
:icon="['fas', 'rotate']"
|
|
31
|
+
@click="dataList = []; onRobotClick()" />
|
|
32
|
+
</div>
|
|
33
|
+
<div v-if="debug" id="chatHistory" class="ss-card chat-history chat-history-ex">
|
|
34
|
+
<span>{{ chatHistory }}</span>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
</chat>
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script lang="ts" setup>
|
|
44
|
+
import z from 'zod'
|
|
45
|
+
|
|
46
|
+
import { v4 as uuid } from 'uuid'
|
|
47
|
+
import { streamText, tool } from 'ai'
|
|
48
|
+
import { ref, toRaw, watch, onMounted } from 'vue'
|
|
49
|
+
import { get, optDefault } from '../../function/option'
|
|
50
|
+
import { Logger, LogType, PopInfo, PopType } from '../../function/base'
|
|
51
|
+
import { getViewTime } from '../../function/utils/systemUtil'
|
|
52
|
+
import { getMsgRawTxt } from '../../function/utils/msgUtil'
|
|
53
|
+
import { createOpenAICompatible } from '@ai-sdk/openai-compatible'
|
|
54
|
+
import { useAuthStore } from '../../state/auth'
|
|
55
|
+
import { useChatStore } from '../../state/chat'
|
|
56
|
+
import {
|
|
57
|
+
registerExtraOptionCard,
|
|
58
|
+
registerExtraOptionItem,
|
|
59
|
+
} from '../../function/option'
|
|
60
|
+
|
|
61
|
+
import Chat from '../Chat.vue'
|
|
62
|
+
|
|
63
|
+
defineOptions({ name: 'ChatGlagame' })
|
|
64
|
+
|
|
65
|
+
const authStore = useAuthStore()
|
|
66
|
+
const chatStore = useChatStore()
|
|
67
|
+
|
|
68
|
+
const props = defineProps<{
|
|
69
|
+
chat: any
|
|
70
|
+
list: any[]
|
|
71
|
+
imgView: any
|
|
72
|
+
}>()
|
|
73
|
+
|
|
74
|
+
const debug = import.meta.env.DEV
|
|
75
|
+
const onLoading = ref(false)
|
|
76
|
+
const onChating = ref(false)
|
|
77
|
+
const dataList = ref<string[]>([])
|
|
78
|
+
const chatHistory = ref('')
|
|
79
|
+
|
|
80
|
+
const sessionMessageList = ref<{[key: number]: { role: 'user' | 'assistant' | 'system', content: string }[] }>({})
|
|
81
|
+
const sessionTokenUsage = ref<{[key: number]: number}>({})
|
|
82
|
+
|
|
83
|
+
function getCurrentMessages() {
|
|
84
|
+
const chatId = chatStore.chatInfo.show.id
|
|
85
|
+
if (!sessionMessageList.value[chatId]) {
|
|
86
|
+
sessionMessageList.value[chatId] = []
|
|
87
|
+
}
|
|
88
|
+
return sessionMessageList.value[chatId]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 初始化会话消息,包括基础提示词、账号信息、会话信息和历史消息等;如果已经有消息了则不重复初始化。
|
|
93
|
+
* 返回值表示是否进行了初始化(即是否发送了初始消息)。
|
|
94
|
+
*/
|
|
95
|
+
async function initChat() {
|
|
96
|
+
if (getCurrentMessages().length == 0) {
|
|
97
|
+
// 初始化基础提示词
|
|
98
|
+
getCurrentMessages().push({
|
|
99
|
+
role: 'system',
|
|
100
|
+
content: get('glagame_prompt') || optDefault.glagame_prompt,
|
|
101
|
+
})
|
|
102
|
+
getCurrentMessages().push({
|
|
103
|
+
role: 'system',
|
|
104
|
+
content: `好感度功能:
|
|
105
|
+
- 你可以通过调用 updateFavorability 工具来更新其他用户对自己的好感度数值,数值范围 -100 ~ 100。
|
|
106
|
+
- 你可以通过调用 getFavorability 工具来获取其他用户对自己的好感度数值,数值范围 -100 ~ 100,可能为 null 表示没有相关数据。
|
|
107
|
+
- 好感度值可参与对话语气、关注度、选项内容等生成,但请避免过度依赖好感度数值进行生成,以免出现数值异常时的异常表现。
|
|
108
|
+
- 你可以随时更新好感度数值来记录其他用户对自己的态度变化,但请只在出现明确对话行为时调用工具进行更新,不要为了记录而频繁调用工具进行更新。`
|
|
109
|
+
})
|
|
110
|
+
getCurrentMessages().push({
|
|
111
|
+
role: 'system',
|
|
112
|
+
content: `最终规则:
|
|
113
|
+
- 在没有明确要求调用工具时,请尽量不要调用工具。
|
|
114
|
+
- 在需要提供选项时,请直接提供选项内容,而不是解释说明或建议内容。
|
|
115
|
+
- 在你不知道要如何提供选项时,宁可不调用工具,也不要编造内容进行调用。`,
|
|
116
|
+
})
|
|
117
|
+
// 获取账号信息
|
|
118
|
+
getCurrentMessages().push({
|
|
119
|
+
role: 'system',
|
|
120
|
+
content: `当前账号信息:ID ${authStore.loginInfo.uin},昵称 ${authStore.loginInfo.nickname}`,
|
|
121
|
+
})
|
|
122
|
+
// 获取会话信息
|
|
123
|
+
getCurrentMessages().push({
|
|
124
|
+
role: 'system',
|
|
125
|
+
content: `当前会话基本信息:会话 ID ${chatStore.chatInfo.show.id},会话名称 ${chatStore.chatInfo.show.name},会话类型 ${chatStore.chatInfo.show.type}`,
|
|
126
|
+
})
|
|
127
|
+
if (props.list.length > 0) {
|
|
128
|
+
// 获取 20 条历史消息
|
|
129
|
+
const historyMessages = props.list.slice(-20)
|
|
130
|
+
let msgStrs = ''
|
|
131
|
+
historyMessages.forEach((msg: any) => {
|
|
132
|
+
msgStrs += getMessageDetail(msg) + '\n'
|
|
133
|
+
})
|
|
134
|
+
getCurrentMessages().push({
|
|
135
|
+
role: 'system',
|
|
136
|
+
content: '当前会话历史消息(仅展示最近 20 条):\n```json' + msgStrs + '\n```',
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const success = await sendMessage()
|
|
141
|
+
|
|
142
|
+
if (!success) {
|
|
143
|
+
new PopInfo().add(PopType.ERR, '初始消息分析失败,AI 功能可能无法正常工作')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return true
|
|
147
|
+
}
|
|
148
|
+
return false
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 粗略估算当前会话 token 数(按字符数近似)
|
|
152
|
+
function estimateTokens(messages: { role: 'user' | 'assistant' | 'system', content: string }[]) {
|
|
153
|
+
const totalChars = messages.reduce((sum, msg) => sum + (msg.content?.length || 0), 0)
|
|
154
|
+
// 这里使用简单近似:约 3 个字符 ≈ 1 token
|
|
155
|
+
return Math.ceil(totalChars / 3)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 根据 token 窗口进行会话压缩;优先使用实际 totalTokens,其次使用粗略估算
|
|
159
|
+
async function compactMessagesIfNeeded(messages: { role: 'user' | 'assistant' | 'system', content: string }[], actualTokens?: number) {
|
|
160
|
+
const maxTokens = Number(get('glagame_max_tokens')) || 6000
|
|
161
|
+
const estimatedTokens = estimateTokens(messages)
|
|
162
|
+
const currentTokens = typeof actualTokens === 'number' && actualTokens > 0 ? actualTokens : estimatedTokens
|
|
163
|
+
|
|
164
|
+
if (currentTokens <= maxTokens) return
|
|
165
|
+
|
|
166
|
+
const chatId = chatStore.chatInfo.show.id
|
|
167
|
+
|
|
168
|
+
const systemMessages = messages.filter(msg => msg.role === 'system')
|
|
169
|
+
const otherMessages = messages.filter(msg => msg.role !== 'system')
|
|
170
|
+
|
|
171
|
+
// 至少保留最近的一些对话消息,避免摘要过于粗糙
|
|
172
|
+
const keepTailCount = 8
|
|
173
|
+
if (otherMessages.length <= keepTailCount) return
|
|
174
|
+
|
|
175
|
+
const tail = otherMessages.slice(-keepTailCount)
|
|
176
|
+
const toSummarize = otherMessages.slice(0, otherMessages.length - keepTailCount)
|
|
177
|
+
|
|
178
|
+
if (!toSummarize.length) return
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const summaryText = await summarizeMessages(toSummarize)
|
|
182
|
+
const summaryMessage = {
|
|
183
|
+
role: 'system' as const,
|
|
184
|
+
content: '以下是此前对话的摘要,用于帮助你继续后续对话:\n' + summaryText,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
sessionMessageList.value[chatId] = [
|
|
188
|
+
...systemMessages,
|
|
189
|
+
summaryMessage,
|
|
190
|
+
...tail,
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
new Logger().info('会话已根据 token 窗口进行摘要压缩')
|
|
194
|
+
} catch (error) {
|
|
195
|
+
new Logger().error(error as unknown as Error, '会话摘要压缩失败,暂不进行压缩')
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function summarizeMessages(messages: { role: 'user' | 'assistant' | 'system', content: string }[]) {
|
|
200
|
+
const openaiCompatible = createOpenAICompatible({
|
|
201
|
+
name: 'glagame summarize: ' + chatStore.chatInfo.show.name,
|
|
202
|
+
baseURL: get('openai_api') || '',
|
|
203
|
+
headers: {
|
|
204
|
+
Authorization: `Bearer ${get('openai_token') || ''}`,
|
|
205
|
+
},
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const summaryMessages = [
|
|
209
|
+
{
|
|
210
|
+
role: 'system' as const,
|
|
211
|
+
content: '你是一个会话总结助手,请在不丢失关键信息的前提下,尽量简短地用中文总结下面对话的核心内容、重要背景和未完成的任务。不要输出多余说明。',
|
|
212
|
+
},
|
|
213
|
+
...messages,
|
|
214
|
+
]
|
|
215
|
+
|
|
216
|
+
const response = streamText({
|
|
217
|
+
model: openaiCompatible(get('openai_model') || 'gpt-4o'),
|
|
218
|
+
messages: summaryMessages,
|
|
219
|
+
} as any)
|
|
220
|
+
|
|
221
|
+
let fullResponse = ''
|
|
222
|
+
let jsonErrorMessage = ''
|
|
223
|
+
|
|
224
|
+
for await (const part of response.fullStream as any) {
|
|
225
|
+
const curPart = part as any
|
|
226
|
+
if (curPart?.text) {
|
|
227
|
+
fullResponse += curPart.text
|
|
228
|
+
}
|
|
229
|
+
if (!jsonErrorMessage && curPart?.error) {
|
|
230
|
+
if (typeof curPart.error === 'string') {
|
|
231
|
+
jsonErrorMessage = curPart.error
|
|
232
|
+
} else {
|
|
233
|
+
jsonErrorMessage = curPart.error?.message || JSON.stringify(curPart.error)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const responseText = fullResponse.trim()
|
|
239
|
+
if (!jsonErrorMessage && responseText.startsWith('{')) {
|
|
240
|
+
try {
|
|
241
|
+
const jsonData = JSON.parse(responseText)
|
|
242
|
+
if (jsonData?.error) {
|
|
243
|
+
if (typeof jsonData.error === 'string') {
|
|
244
|
+
jsonErrorMessage = jsonData.error
|
|
245
|
+
} else {
|
|
246
|
+
jsonErrorMessage = jsonData.error?.message || JSON.stringify(jsonData.error)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} catch {
|
|
250
|
+
// ignore JSON parse error, keep raw text
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (jsonErrorMessage) {
|
|
255
|
+
throw new Error(jsonErrorMessage)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return fullResponse.trim()
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function onRobotClick() {
|
|
262
|
+
if(onLoading.value) {
|
|
263
|
+
onLoading.value = false
|
|
264
|
+
dataList.value = []
|
|
265
|
+
} else {
|
|
266
|
+
onLoading.value = true
|
|
267
|
+
dataList.value = []
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if(!await initChat()) {
|
|
271
|
+
sendMessage().then(() => {
|
|
272
|
+
onLoading.value = false
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function getMessageDetail(chatMessage: any) {
|
|
278
|
+
return JSON.stringify({
|
|
279
|
+
id: chatMessage.messageId,
|
|
280
|
+
time: getViewTime(chatMessage.time),
|
|
281
|
+
sender: {
|
|
282
|
+
id: chatMessage.sender.id,
|
|
283
|
+
nickname: chatMessage.sender.nickname,
|
|
284
|
+
},
|
|
285
|
+
content: getMsgRawTxt(chatMessage),
|
|
286
|
+
replyMessages: chatMessage.message?.map((msg: any) => {
|
|
287
|
+
if(msg.type === 'reply') {
|
|
288
|
+
return msg.id
|
|
289
|
+
}
|
|
290
|
+
}) || [],
|
|
291
|
+
mentionUsers: chatMessage.message?.map((msg: any) => {
|
|
292
|
+
if(msg.type === 'at') {
|
|
293
|
+
return msg.qq
|
|
294
|
+
}
|
|
295
|
+
}) || [],
|
|
296
|
+
})
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async function sendMessage() {
|
|
300
|
+
const sessionId = uuid()
|
|
301
|
+
|
|
302
|
+
if(onChating.value) {
|
|
303
|
+
new PopInfo().add(PopType.INFO, '正在分析消息,请稍候...')
|
|
304
|
+
return false
|
|
305
|
+
}
|
|
306
|
+
onChating.value = true
|
|
307
|
+
chatHistory.value = ''
|
|
308
|
+
|
|
309
|
+
// 会话压缩(优先使用上一次请求的实际 token 统计)
|
|
310
|
+
const chatId = chatStore.chatInfo.show.id
|
|
311
|
+
const lastTokens = sessionTokenUsage.value[chatId]
|
|
312
|
+
await compactMessagesIfNeeded(getCurrentMessages(), lastTokens)
|
|
313
|
+
|
|
314
|
+
// 初始化 Provider
|
|
315
|
+
const openaiCompatible = createOpenAICompatible({
|
|
316
|
+
name: 'glagame chat: ' + chatStore.chatInfo.show.name,
|
|
317
|
+
baseURL: get('openai_api') || '',
|
|
318
|
+
headers: {
|
|
319
|
+
Authorization: `Bearer ${get('openai_token') || ''}`,
|
|
320
|
+
},
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
new Logger().add(LogType.DEBUG, '消息分析(' + sessionId + '):', toRaw(getCurrentMessages()))
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
const data = {
|
|
327
|
+
model: openaiCompatible(get('openai_model') || 'gpt-4o'),
|
|
328
|
+
messages: getCurrentMessages(),
|
|
329
|
+
tools: {
|
|
330
|
+
showChoices: tool({
|
|
331
|
+
description: 'Display reply options for interface display',
|
|
332
|
+
title: 'Display reply options',
|
|
333
|
+
inputSchema: z.object({
|
|
334
|
+
choices: z.array(z.string()).min(1).max(3).describe('选项列表,3 个'),
|
|
335
|
+
}),
|
|
336
|
+
execute: async (input) => {
|
|
337
|
+
const choices = input.choices
|
|
338
|
+
dataList.value = choices
|
|
339
|
+
onLoading.value = false
|
|
340
|
+
new Logger().add(LogType.DEBUG, '工具调用(' + sessionId + '):showChoices', choices)
|
|
341
|
+
}
|
|
342
|
+
}),
|
|
343
|
+
updateFavorability: tool({
|
|
344
|
+
description: 'Update the favorability value of the corresponding user, with a range of -100 ~ 100',
|
|
345
|
+
title: 'Update Favorability',
|
|
346
|
+
inputSchema: z.object({
|
|
347
|
+
id: z.number().describe('User ID'),
|
|
348
|
+
source: z.number().describe('Session ID the user comes from'),
|
|
349
|
+
value: z.number().min(-100).max(100).describe('Favorability value, range -100 ~ 100'),
|
|
350
|
+
}),
|
|
351
|
+
execute: async (input) => {
|
|
352
|
+
const { id, source, value } = input
|
|
353
|
+
new Logger().add(LogType.DEBUG, '工具调用(' + sessionId + '):updateFavorability', { id, source, value })
|
|
354
|
+
|
|
355
|
+
// TODO 好感存储相关功能
|
|
356
|
+
}
|
|
357
|
+
}),
|
|
358
|
+
getFavorability: tool({
|
|
359
|
+
description: 'Get the favorability value of the corresponding user, with a range of -100 ~ 100. May be null, indicating no related data.',
|
|
360
|
+
title: 'Get Favorability',
|
|
361
|
+
inputSchema: z.object({
|
|
362
|
+
id: z.number().describe('User ID'),
|
|
363
|
+
source: z.number().describe('Session ID the user comes from'),
|
|
364
|
+
}),
|
|
365
|
+
outputSchema: z.number().min(-100).max(100).nullable().describe('Favorability value, range -100 ~ 100, may be null'),
|
|
366
|
+
execute: async (input) => {
|
|
367
|
+
const { id, source } = input
|
|
368
|
+
new Logger().add(LogType.DEBUG, '工具调用(' + sessionId + '):getFavorability', { id, source })
|
|
369
|
+
|
|
370
|
+
// TODO 好感存储相关功能,暂时返回 0
|
|
371
|
+
return 0
|
|
372
|
+
}
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
} as any
|
|
376
|
+
|
|
377
|
+
const response = streamText(data)
|
|
378
|
+
let jsonErrorMessage = ''
|
|
379
|
+
for await (const part of response.fullStream) {
|
|
380
|
+
const curPart = part as any
|
|
381
|
+
if(curPart) {
|
|
382
|
+
switch(curPart.type) {
|
|
383
|
+
case 'reasoning-delta':
|
|
384
|
+
case 'text-delta':
|
|
385
|
+
chatHistory.value += curPart.text
|
|
386
|
+
if(debug) {
|
|
387
|
+
const chatHistoryEl = document.getElementById('chatHistory')
|
|
388
|
+
if(chatHistoryEl) {
|
|
389
|
+
chatHistoryEl.scrollTop = chatHistoryEl.scrollHeight
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
break
|
|
393
|
+
case 'finish':
|
|
394
|
+
if (curPart.totalUsage?.totalTokens) {
|
|
395
|
+
sessionTokenUsage.value[chatId] = curPart.totalUsage.totalTokens
|
|
396
|
+
new Logger().info('消息分析(' + sessionId + ')完成,token 消耗:' + curPart.totalUsage.totalTokens)
|
|
397
|
+
} else {
|
|
398
|
+
new Logger().info('消息分析(' + sessionId + ')完成,但未返回 token 统计')
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if(!jsonErrorMessage && curPart?.error) {
|
|
403
|
+
if(typeof curPart.error === 'string') {
|
|
404
|
+
jsonErrorMessage = curPart.error
|
|
405
|
+
} else {
|
|
406
|
+
jsonErrorMessage = curPart.error?.message || JSON.stringify(curPart.error)
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
onChating.value = false
|
|
412
|
+
|
|
413
|
+
const responseText = chatHistory.value.trim()
|
|
414
|
+
if(!jsonErrorMessage && responseText.startsWith('{')) {
|
|
415
|
+
try {
|
|
416
|
+
const jsonData = JSON.parse(responseText)
|
|
417
|
+
if(jsonData?.error) {
|
|
418
|
+
if(typeof jsonData.error === 'string') {
|
|
419
|
+
jsonErrorMessage = jsonData.error
|
|
420
|
+
} else {
|
|
421
|
+
jsonErrorMessage = jsonData.error?.message || JSON.stringify(jsonData.error)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
} catch {
|
|
425
|
+
// do nothing, keep fullResponse as is
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if(jsonErrorMessage) {
|
|
430
|
+
new Logger().error(new Error(jsonErrorMessage), '调用错误')
|
|
431
|
+
new PopInfo().add(PopType.ERR, '调用失败:' + jsonErrorMessage)
|
|
432
|
+
return false
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if(chatHistory.value.trim().length > 0) {
|
|
436
|
+
new Logger().add(LogType.INFO, '消息分析(' + sessionId + ')结果:', chatHistory.value.trim())
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
getCurrentMessages().push({
|
|
440
|
+
role: 'assistant',
|
|
441
|
+
content: chatHistory.value.trim(),
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
return true
|
|
445
|
+
} catch (error) {
|
|
446
|
+
onChating.value = false
|
|
447
|
+
|
|
448
|
+
new Logger().error(error as unknown as Error, '调用错误')
|
|
449
|
+
new PopInfo().add(PopType.ERR, '调用失败,请检查设置和网络连接')
|
|
450
|
+
return false
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function selectChoice(item: string) {
|
|
455
|
+
onLoading.value = false
|
|
456
|
+
dataList.value = []
|
|
457
|
+
|
|
458
|
+
const input = (document.getElementById( 'main-input') as HTMLTextAreaElement | HTMLInputElement) ??
|
|
459
|
+
(document.getElementById( 'main-input-ex') as HTMLTextAreaElement | HTMLInputElement)
|
|
460
|
+
if (input) {
|
|
461
|
+
input.value = item
|
|
462
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
463
|
+
input.focus()
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
onMounted(async () => {
|
|
468
|
+
registerExtraOptionCard({
|
|
469
|
+
id: 'ai',
|
|
470
|
+
title: 'AI 基础设置',
|
|
471
|
+
})
|
|
472
|
+
registerExtraOptionCard({
|
|
473
|
+
id: 'glagame',
|
|
474
|
+
title: '"Glagame" 聊天辅助',
|
|
475
|
+
})
|
|
476
|
+
registerExtraOptionItem('ai', {
|
|
477
|
+
id: 'openai_api',
|
|
478
|
+
icon: 'link',
|
|
479
|
+
label: 'OpenAI API 地址',
|
|
480
|
+
description: '只需要填写到 v1 即可,例如 https://openrouter.ai/api/v1',
|
|
481
|
+
type: 'input',
|
|
482
|
+
optionKey: 'openai_api',
|
|
483
|
+
defaultValue: '',
|
|
484
|
+
})
|
|
485
|
+
registerExtraOptionItem('ai', {
|
|
486
|
+
id: 'openai_token',
|
|
487
|
+
icon: 'key',
|
|
488
|
+
label: 'OpenAI Token',
|
|
489
|
+
description: '秘钥,明文存储请注意',
|
|
490
|
+
type: 'password',
|
|
491
|
+
optionKey: 'openai_token',
|
|
492
|
+
defaultValue: '',
|
|
493
|
+
})
|
|
494
|
+
registerExtraOptionItem('ai', {
|
|
495
|
+
id: 'openai_model',
|
|
496
|
+
icon: 'robot',
|
|
497
|
+
label: 'OpenAI 模型名称',
|
|
498
|
+
description: '模型名称,需支持工具调用和流式输出',
|
|
499
|
+
type: 'input',
|
|
500
|
+
optionKey: 'openai_model',
|
|
501
|
+
defaultValue: 'gpt-4o',
|
|
502
|
+
})
|
|
503
|
+
registerExtraOptionItem('glagame', {
|
|
504
|
+
id: 'glagame_max_tokens',
|
|
505
|
+
icon: 'cubes',
|
|
506
|
+
label: '上下文窗口(token)',
|
|
507
|
+
description: '超过时会自动进行摘要压缩',
|
|
508
|
+
type: 'input',
|
|
509
|
+
optionKey: 'glagame_max_tokens',
|
|
510
|
+
defaultValue: 2000,
|
|
511
|
+
})
|
|
512
|
+
registerExtraOptionItem('glagame', {
|
|
513
|
+
id: 'glagame_prompt',
|
|
514
|
+
icon: 'book',
|
|
515
|
+
label: '基础提示词',
|
|
516
|
+
description: 'AI 消息分析时的基础提示词',
|
|
517
|
+
type: 'input',
|
|
518
|
+
optionKey: 'glagame_prompt',
|
|
519
|
+
defaultValue: `你是一个对话辅助助手,你将根据历史的对话内容生成可供玩家可以选择用来直接回复的内容。
|
|
520
|
+
|
|
521
|
+
- 玩家默认是温和、体贴、日常向、有点小俏皮。
|
|
522
|
+
- **不要**为玩家本人的消息生成回复,玩家本人的消息仅供上下文参考。
|
|
523
|
+
- 若对话之间时间相隔较久,可自然应对(如"刚看到消息")。
|
|
524
|
+
- 避免引入与对话无关的新背景。
|
|
525
|
+
|
|
526
|
+
对话记录中含有玩家本人的消息,请根据提供的当前账号信息自行区分,可以适当模仿玩家的语言风格。`,
|
|
527
|
+
})
|
|
528
|
+
registerExtraOptionItem('glagame', {
|
|
529
|
+
id: 'glagame_favorability',
|
|
530
|
+
icon: 'heart',
|
|
531
|
+
label: '好感度功能',
|
|
532
|
+
description: '允许 AI 为聊天记录生成好感度数值',
|
|
533
|
+
type: 'switch',
|
|
534
|
+
optionKey: 'glagame_favorability',
|
|
535
|
+
defaultValue: false,
|
|
536
|
+
})
|
|
537
|
+
|
|
538
|
+
watch(() => props.list.length, async (newVal, oldVal) => {
|
|
539
|
+
if (newVal - oldVal == 1) {
|
|
540
|
+
getCurrentMessages().push({
|
|
541
|
+
role: 'user',
|
|
542
|
+
content: '```json\n' + getMessageDetail(
|
|
543
|
+
props.list[props.list.length - 1]) + '\n```',
|
|
544
|
+
})
|
|
545
|
+
}
|
|
546
|
+
})
|
|
547
|
+
})
|
|
548
|
+
</script>
|
|
549
|
+
|
|
550
|
+
<style scoped>
|
|
551
|
+
.chat-extra {
|
|
552
|
+
padding-top: 20px;
|
|
553
|
+
position: absolute;
|
|
554
|
+
width: 100%;
|
|
555
|
+
height: 100%;
|
|
556
|
+
display: flex;
|
|
557
|
+
flex-direction: column;
|
|
558
|
+
align-items: center;
|
|
559
|
+
justify-content: center;
|
|
560
|
+
pointer-events: all;
|
|
561
|
+
background: rgba(var(--color-card-rgb), 0.7);
|
|
562
|
+
}
|
|
563
|
+
.chat-extra .load {
|
|
564
|
+
display: flex;
|
|
565
|
+
align-items: center;
|
|
566
|
+
justify-content: center;
|
|
567
|
+
box-shadow: 0 0 5px var(--color-shader);
|
|
568
|
+
}
|
|
569
|
+
.chat-extra .chat-history {
|
|
570
|
+
max-height: 35vh;
|
|
571
|
+
overflow: scroll;
|
|
572
|
+
width: 60%;
|
|
573
|
+
white-space: pre-line;
|
|
574
|
+
font-size: 0.75rem !important;
|
|
575
|
+
color: var(--color-font-2);
|
|
576
|
+
margin-top: 20px;
|
|
577
|
+
}
|
|
578
|
+
.chat-extra .chat-history::-webkit-scrollbar {
|
|
579
|
+
display: none;
|
|
580
|
+
}
|
|
581
|
+
.chat-extra .chat-history-ex {
|
|
582
|
+
margin-top: -130px;
|
|
583
|
+
max-height: 20vh;
|
|
584
|
+
text-align: left !important;
|
|
585
|
+
line-height: unset !important;
|
|
586
|
+
}
|
|
587
|
+
.chat-extra .options {
|
|
588
|
+
flex-direction: column;
|
|
589
|
+
width: 100%;
|
|
590
|
+
align-items: center;
|
|
591
|
+
display: flex;
|
|
592
|
+
gap: 20px;
|
|
593
|
+
}
|
|
594
|
+
.chat-extra .options > div {
|
|
595
|
+
cursor: pointer;
|
|
596
|
+
border-radius: 7px;
|
|
597
|
+
box-shadow: 0 0 5px var(--color-shader);
|
|
598
|
+
background: var(--color-card);
|
|
599
|
+
padding: 10px;
|
|
600
|
+
width: 70%;
|
|
601
|
+
text-align: center;
|
|
602
|
+
line-height: 25px;
|
|
603
|
+
font-size: 0.8rem;
|
|
604
|
+
}
|
|
605
|
+
.chat-extra .options > div.controller {
|
|
606
|
+
background: unset;
|
|
607
|
+
box-shadow: unset;
|
|
608
|
+
}
|
|
609
|
+
.chat-extra .options svg {
|
|
610
|
+
margin: 10px;
|
|
611
|
+
cursor: pointer;
|
|
612
|
+
width: 15px;
|
|
613
|
+
height: 15px;
|
|
614
|
+
box-shadow: 0 0 5px var(--color-shader);
|
|
615
|
+
background: var(--color-card);
|
|
616
|
+
padding: 15px;
|
|
617
|
+
border-radius: 100%;
|
|
618
|
+
margin-top: 30px;
|
|
619
|
+
}
|
|
620
|
+
</style>
|
|
621
|
+
<style>
|
|
622
|
+
.glagame-api-config {
|
|
623
|
+
width: calc(100% - 10px);
|
|
624
|
+
max-height: 55vh;
|
|
625
|
+
overflow-y: scroll;
|
|
626
|
+
overflow-x: hidden;
|
|
627
|
+
padding-right: 10px;
|
|
628
|
+
}
|
|
629
|
+
.glagame-api-config label {
|
|
630
|
+
line-height: 25px;
|
|
631
|
+
}
|
|
632
|
+
.glagame-api-config input,
|
|
633
|
+
.glagame-api-config textarea {
|
|
634
|
+
color: var(--color-font);
|
|
635
|
+
width: calc(100% - 20px);
|
|
636
|
+
background: var(--color-card-1);
|
|
637
|
+
border: unset;
|
|
638
|
+
padding: 10px;
|
|
639
|
+
margin: 5px 0 10px 0;
|
|
640
|
+
border-radius: 7px;
|
|
641
|
+
}
|
|
642
|
+
</style>
|