|
|
|
@ -468,13 +468,15 @@
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<template
|
|
|
|
|
x-if="message.state == 'succeed' && !!window.speechSynthesis">
|
|
|
|
|
<template x-if="message.state == 'succeed' && !!window.speechSynthesis">
|
|
|
|
|
<div class="tts-message-btn" @click="handleTTSMessage(message.content)" title="Text to speech">
|
|
|
|
|
<svg fill="currentColor" viewBox="0 0 16 16">
|
|
|
|
|
<path d="M11.536 14.01A8.47 8.47 0 0 0 14.026 8a8.47 8.47 0 0 0-2.49-6.01l-.708.707A7.48 7.48 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303z"/>
|
|
|
|
|
<path d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.48 5.48 0 0 1 11.025 8a5.48 5.48 0 0 1-1.61 3.89z"/>
|
|
|
|
|
<path d="M10.025 8a4.5 4.5 0 0 1-1.318 3.182L8 10.475A3.5 3.5 0 0 0 9.025 8c0-.966-.392-1.841-1.025-2.475l.707-.707A4.5 4.5 0 0 1 10.025 8M7 4a.5.5 0 0 0-.812-.39L3.825 5.5H1.5A.5.5 0 0 0 1 6v4a.5.5 0 0 0 .5.5h2.325l2.363 1.89A.5.5 0 0 0 7 12zM4.312 6.39 6 5.04v5.92L4.312 9.61A.5.5 0 0 0 4 9.5H2v-3h2a.5.5 0 0 0 .312-.11"/>
|
|
|
|
|
<path
|
|
|
|
|
d="M11.536 14.01A8.47 8.47 0 0 0 14.026 8a8.47 8.47 0 0 0-2.49-6.01l-.708.707A7.48 7.48 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303z" />
|
|
|
|
|
<path
|
|
|
|
|
d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.48 5.48 0 0 1 11.025 8a5.48 5.48 0 0 1-1.61 3.89z" />
|
|
|
|
|
<path
|
|
|
|
|
d="M10.025 8a4.5 4.5 0 0 1-1.318 3.182L8 10.475A3.5 3.5 0 0 0 9.025 8c0-.966-.392-1.841-1.025-2.475l.707-.707A4.5 4.5 0 0 1 10.025 8M7 4a.5.5 0 0 0-.812-.39L3.825 5.5H1.5A.5.5 0 0 0 1 6v4a.5.5 0 0 0 .5.5h2.325l2.363 1.89A.5.5 0 0 0 7 12zM4.312 6.39 6 5.04v5.92L4.312 9.61A.5.5 0 0 0 4 9.5H2v-3h2a.5.5 0 0 0 .312-.11" />
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
@ -603,6 +605,7 @@
|
|
|
|
|
}
|
|
|
|
|
$scrollToBottomBtns[i].style.left = offsets[i];
|
|
|
|
|
}
|
|
|
|
|
this.$refs.input.addEventListener("paste", (e) => this.handlePaste(e));
|
|
|
|
|
this.$watch("input", () => this.autosizeInput(this.$refs.input));
|
|
|
|
|
new ResizeObserver(() => {
|
|
|
|
|
this.autoHeightChatPanel();
|
|
|
|
@ -679,7 +682,7 @@
|
|
|
|
|
/**
|
|
|
|
|
* @param {string} messageToUtter
|
|
|
|
|
*/
|
|
|
|
|
handleTTSMessage(messageToUtter) {
|
|
|
|
|
handleTTSMessage(messageToUtter) {
|
|
|
|
|
if (!!window.speechSynthesis) {
|
|
|
|
|
if (window.speechSynthesis.speaking || window.speechSynthesis.pending) {
|
|
|
|
|
window.speechSynthesis.cancel();
|
|
|
|
@ -770,6 +773,12 @@
|
|
|
|
|
event.target.value = "";
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async handlePaste(event) {
|
|
|
|
|
const files = Array.from(event.clipboardData.items).filter(v => v.type.startsWith('image/')).map(v => v.getAsFile());
|
|
|
|
|
const urls = await Promise.all(files.map(file => convertImageToDataURL(file)));
|
|
|
|
|
this.images.push(...urls);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateUrl() {
|
|
|
|
|
const newUrl = new URL(location.href);
|
|
|
|
|
const models = this.chats.map(v => v.model).join(",");
|
|
|
|
|