diff --git a/packages/live2d/src/components/Live2dChatWindow.tsx b/packages/live2d/src/components/Live2dChatWindow.tsx index b7a50e3..b4903c3 100644 --- a/packages/live2d/src/components/Live2dChatWindow.tsx +++ b/packages/live2d/src/components/Live2dChatWindow.tsx @@ -62,6 +62,7 @@ export class Live2dChatWindow extends DraggableUnoLitElement { private chatApi: ChatApi | null = null; private historyMessages: ChatMessage[] = []; private _hidePopoverTimer?: number; + private _chatRequestSeq = 0; connectedCallback(): void { super.connectedCallback(); @@ -83,8 +84,9 @@ export class Live2dChatWindow extends DraggableUnoLitElement { ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0", ].join(" "); - const sendButtonClass = - this._canSend && !this._isLoading + const sendButtonClass = this._isLoading + ? "bg-[#f97373] text-white shadow-[0_6px_16px_rgba(249,115,115,0.25)] hover:bg-[#ef4444]" + : this._canSend ? "bg-[#ffab5c] text-white shadow-[0_6px_16px_rgba(255,171,92,0.25)] hover:bg-[#ff9840]" : "bg-[#eee7de] text-slate-400 cursor-not-allowed"; @@ -109,13 +111,13 @@ export class Live2dChatWindow extends DraggableUnoLitElement { type="button" class="inline-flex h-8 w-8 flex-none items-center justify-center rounded-full border-none transition-colors ${sendButtonClass}" @click=${this.handleSend} - aria-label=${this._isLoading ? "发送中" : "发送消息"} + aria-label=${this._isLoading ? "停止生成" : "发送消息"} > ${ this._isLoading ? html` { - if (this._canSend && !this._isLoading) { + if (this._isLoading) { + this.stopMessage(); + return; + } + if (this._canSend) { void this.sendMessage(); } }; + private stopMessage(): void { + this._chatRequestSeq += 1; + this.chatApi?.abort(); + this._isLoading = false; + this._canSend = !!this._input?.value.length; + this.focusInput(); + } + private async sendMessage(): Promise { if (!this._input || !this._input.value || this._isLoading) { return; @@ -195,17 +209,20 @@ export class Live2dChatWindow extends DraggableUnoLitElement { this._canSend = false; this._isLoading = true; this.focusInput(); + const requestSeq = ++this._chatRequestSeq; try { await this.sendChatMessage(message, this.readStoredHistoryMessages()); } catch (error) { console.error("[Live2dChatWindow] Send message error:", error); } finally { - this._isLoading = false; - if (this._input) { - this._canSend = this._input.value.length > 0; + if (requestSeq === this._chatRequestSeq) { + this._isLoading = false; + if (this._input) { + this._canSend = this._input.value.length > 0; + } + this.focusInput(); } - this.focusInput(); } } @@ -273,6 +290,7 @@ export class Live2dChatWindow extends DraggableUnoLitElement { this._isLoading = true; this._canSend = false; this.focusInput(); + const requestSeq = ++this._chatRequestSeq; try { await this.sendChatMessage(resume.message, resume.historyMessages); } catch (error) { @@ -281,11 +299,13 @@ export class Live2dChatWindow extends DraggableUnoLitElement { error, ); } finally { - this._isLoading = false; - if (this._input) { - this._canSend = this._input.value.length > 0; + if (requestSeq === this._chatRequestSeq) { + this._isLoading = false; + if (this._input) { + this._canSend = this._input.value.length > 0; + } + this.focusInput(); } - this.focusInput(); } } diff --git a/src/main/java/run/halo/live2d/Live2dSettingProcess.java b/src/main/java/run/halo/live2d/Live2dSettingProcess.java index 17ded8d..006f487 100644 --- a/src/main/java/run/halo/live2d/Live2dSettingProcess.java +++ b/src/main/java/run/halo/live2d/Live2dSettingProcess.java @@ -30,8 +30,7 @@ public class Live2dSettingProcess implements Live2dSetting { private static final List TIPS_FIELDS = List.of( "firstOpenSite", "backSite", "backSiteTip", "copyContent", "copyContentTip", "openConsole", "openConsoleTip", "selectorTips", "tipsPath"); - private static final List ADVANCED_FIELDS = List.of( - "consoleShowStatu", "photoName", "live2dLocation"); + private static final List ADVANCED_FIELDS = List.of("consoleShowStatu", "photoName"); private static final List AI_CHAT_PUBLIC_FIELDS = List.of( "chunkTimeout", "showChatMessageTimeout", "autoContinuationMessageMinVisibleMs", "requestAcceptedMessage", "reasoningMessages", "reasoningMessageInterval", diff --git a/src/main/resources/extensions/settings.yaml b/src/main/resources/extensions/settings.yaml index 1a19018..7a929e5 100644 --- a/src/main/resources/extensions/settings.yaml +++ b/src/main/resources/extensions/settings.yaml @@ -117,11 +117,18 @@ spec: label: 打开控制台提示语 name: openConsoleTip value: "你是想要看看我的小秘密吗?" - - $formkit: repeater + - $formkit: array name: selectorTips label: 选择器提示语 help: 根据 CSS 选择器自定义 Live2d 呈现的文本(各主题选择器可能不同)。 value: [] + addLabel: 添加选择器提示语 + emptyText: 暂无选择器提示语 + itemLabels: + - type: text + label: $value.mouseAction + - type: text + label: $value.selector children: - $formkit: select name: mouseAction @@ -136,12 +143,17 @@ spec: name: selector label: CSS 选择器 validation: required - - $formkit: repeater + - $formkit: array name: messageTexts label: 提示语集合 help: 可以填写多个提示语,Live2d 将会随机选择一个 min: 1 value: [] + addLabel: 添加提示语 + emptyText: 暂无提示语 + itemLabels: + - type: text + label: $value.message children: - $formkit: text name: message @@ -234,11 +246,16 @@ spec: name: requestAcceptedMessage help: 用户发送消息后,Live2D 会立刻展示这条提示语,减少等待时的空白感 validation: String - - $formkit: repeater + - $formkit: array label: 思考中提示语 name: reasoningMessages help: 当模型正在返回思考内容但还没有可展示回复时,Live2D 会随机展示其中一条。思考时间较长时会自动切换 min: 1 + addLabel: 添加思考提示语 + emptyText: 暂无思考提示语 + itemLabels: + - type: text + label: $value.message children: - $formkit: text name: message @@ -317,11 +334,16 @@ spec: allowedExternalOrigins: [] allowNewTab: false children: - - $formkit: repeater + - $formkit: array name: allowedExternalOrigins label: 允许打开的外部站点 help: 仅填写 origin,例如 https://github.com。外链仍会默认请求访客确认。 value: [] + addLabel: 添加外部站点 + emptyText: 暂无外部站点 + itemLabels: + - type: text + label: $value.origin children: - $formkit: text name: origin @@ -365,11 +387,16 @@ spec: maxResponseChars: 4000 timeoutSeconds: 5 children: - - $formkit: repeater + - $formkit: array name: allowedOrigins label: 允许访问的 Origin help: 仅填写可信公网 Origin,例如 https://api.example.com。不会跟随重定向,也不会访问 localhost、内网或链路本地地址。 value: [] + addLabel: 添加 Origin + emptyText: 暂无 Origin + itemLabels: + - type: text + label: $value.origin children: - $formkit: text name: origin @@ -414,15 +441,6 @@ spec: name: photoName validation: required value: live2d - - $formkit: select - label: 看板娘位置 - name: live2dLocation - value: left - options: - - value: left - label: 屏幕左侧 - - value: right - label: 屏幕右侧 - $formkit: select help: 页面何时加载 Live2d。网站带宽有限时,可选择优先加载页面全部内容再加载 Live2d。 label: Live2d 加载时机