发布 v1.10 #5
@@ -578,6 +578,9 @@ watch(
|
|||||||
{ flush: 'post' },
|
{ flush: 'post' },
|
||||||
);
|
);
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
if (sending.value) {
|
||||||
|
stopSse();
|
||||||
|
}
|
||||||
if (bubbleListScrollElement.value) {
|
if (bubbleListScrollElement.value) {
|
||||||
bubbleListScrollElement.value.removeEventListener(
|
bubbleListScrollElement.value.removeEventListener(
|
||||||
'scroll',
|
'scroll',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { onBeforeUnmount, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { EasyFlowPanelModal } from '@easyflow/common-ui';
|
import { EasyFlowPanelModal } from '@easyflow/common-ui';
|
||||||
import { $t } from '@easyflow/locales';
|
import { $t } from '@easyflow/locales';
|
||||||
@@ -18,6 +18,16 @@ const rules = {
|
|||||||
};
|
};
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const stopStreaming = () => {
|
||||||
|
if (!loading.value) return;
|
||||||
|
sseClient.abort();
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDialog = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const data = {
|
const data = {
|
||||||
@@ -40,12 +50,28 @@ const handleSubmit = async () => {
|
|||||||
const delta = sseData.payload?.delta;
|
const delta = sseData.payload?.delta;
|
||||||
formData.value.prompt += delta;
|
formData.value.prompt += delta;
|
||||||
},
|
},
|
||||||
|
onError(error) {
|
||||||
|
loading.value = false;
|
||||||
|
console.error('提示词优化流式请求失败', error);
|
||||||
|
},
|
||||||
|
onFinished() {
|
||||||
|
loading.value = false;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handleReplace = () => {
|
const handleReplace = () => {
|
||||||
emit('success', formData.value.prompt);
|
emit('success', formData.value.prompt);
|
||||||
dialogVisible.value = false;
|
closeDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(dialogVisible, (visible) => {
|
||||||
|
if (!visible) {
|
||||||
|
stopStreaming();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(stopStreaming);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
open(botId: string, systemPrompt: string) {
|
open(botId: string, systemPrompt: string) {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
@@ -80,7 +106,7 @@ defineExpose({
|
|||||||
</ElForm>
|
</ElForm>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<ElButton @click="dialogVisible = false">
|
<ElButton @click="closeDialog">
|
||||||
{{ $t('button.cancel') }}
|
{{ $t('button.cancel') }}
|
||||||
</ElButton>
|
</ElButton>
|
||||||
<ElButton type="primary" @click="handleReplace" v-if="!loading">
|
<ElButton type="primary" @click="handleReplace" v-if="!loading">
|
||||||
|
|||||||
@@ -351,6 +351,9 @@ watch(
|
|||||||
);
|
);
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
if (sending.value || activeStreamSessionId.value) {
|
||||||
|
abortActiveStream();
|
||||||
|
}
|
||||||
window.removeEventListener('click', closeSessionContextMenu);
|
window.removeEventListener('click', closeSessionContextMenu);
|
||||||
window.removeEventListener('resize', closeSessionContextMenu);
|
window.removeEventListener('resize', closeSessionContextMenu);
|
||||||
window.removeEventListener('scroll', closeSessionContextMenu, true);
|
window.removeEventListener('scroll', closeSessionContextMenu, true);
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
|
|
||||||
let isCheckingUpdates = false;
|
let isCheckingUpdates = false;
|
||||||
let resumeCheckFrame: number | undefined;
|
let resumeCheckFrame: number | undefined;
|
||||||
|
let versionCheckController: AbortController | null = null;
|
||||||
|
const VERSION_CHECK_TIMEOUT_MS = 10_000;
|
||||||
const currentVersionTag = ref('');
|
const currentVersionTag = ref('');
|
||||||
const lastVersionTag = ref('');
|
const lastVersionTag = ref('');
|
||||||
const timer = ref<ReturnType<typeof setInterval>>();
|
const timer = ref<ReturnType<typeof setInterval>>();
|
||||||
@@ -37,6 +39,12 @@ const [UpdateNoticeModal, modalApi] = useEasyFlowModal({
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function getVersionTag() {
|
async function getVersionTag() {
|
||||||
|
const controller = new AbortController();
|
||||||
|
versionCheckController = controller;
|
||||||
|
const timeout = setTimeout(
|
||||||
|
() => controller.abort(),
|
||||||
|
VERSION_CHECK_TIMEOUT_MS,
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
location.hostname === 'localhost' ||
|
location.hostname === 'localhost' ||
|
||||||
@@ -48,14 +56,22 @@ async function getVersionTag() {
|
|||||||
cache: 'no-cache',
|
cache: 'no-cache',
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
redirect: 'manual',
|
redirect: 'manual',
|
||||||
|
signal: controller.signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
response.headers.get('etag') || response.headers.get('last-modified')
|
response.headers.get('etag') || response.headers.get('last-modified')
|
||||||
);
|
);
|
||||||
} catch {
|
} catch (error) {
|
||||||
console.error('Failed to fetch version tag');
|
if (!controller.signal.aborted) {
|
||||||
|
console.error('Failed to fetch version tag', error);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
if (versionCheckController === controller) {
|
||||||
|
versionCheckController = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,10 +88,21 @@ async function checkForUpdates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lastVersionTag.value !== versionTag && versionTag) {
|
if (lastVersionTag.value !== versionTag && versionTag) {
|
||||||
clearInterval(timer.value);
|
stop();
|
||||||
handleNotice(versionTag);
|
handleNotice(versionTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function runUpdateCheck() {
|
||||||
|
if (isCheckingUpdates) return;
|
||||||
|
isCheckingUpdates = true;
|
||||||
|
try {
|
||||||
|
await checkForUpdates();
|
||||||
|
} finally {
|
||||||
|
isCheckingUpdates = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleNotice(versionTag: string) {
|
function handleNotice(versionTag: string) {
|
||||||
currentVersionTag.value = versionTag;
|
currentVersionTag.value = versionTag;
|
||||||
modalApi.open();
|
modalApi.open();
|
||||||
@@ -89,7 +116,7 @@ function start() {
|
|||||||
|
|
||||||
// 每 checkUpdatesInterval(默认值为1) 分钟检查一次
|
// 每 checkUpdatesInterval(默认值为1) 分钟检查一次
|
||||||
timer.value = setInterval(
|
timer.value = setInterval(
|
||||||
checkForUpdates,
|
() => void runUpdateCheck(),
|
||||||
props.checkUpdatesInterval * 60 * 1000,
|
props.checkUpdatesInterval * 60 * 1000,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -108,13 +135,11 @@ function scheduleResumeCheck() {
|
|||||||
resumeCheckFrame = requestAnimationFrame(() => {
|
resumeCheckFrame = requestAnimationFrame(() => {
|
||||||
resumeCheckFrame = requestAnimationFrame(() => {
|
resumeCheckFrame = requestAnimationFrame(() => {
|
||||||
resumeCheckFrame = undefined;
|
resumeCheckFrame = undefined;
|
||||||
if (document.hidden || isCheckingUpdates) {
|
if (document.hidden) return;
|
||||||
return;
|
runUpdateCheck().finally(() => {
|
||||||
}
|
if (!document.hidden) {
|
||||||
isCheckingUpdates = true;
|
start();
|
||||||
checkForUpdates().finally(() => {
|
}
|
||||||
isCheckingUpdates = false;
|
|
||||||
start();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -130,11 +155,12 @@ function handleVisibilitychange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stop() {
|
function stop() {
|
||||||
if (timer.value === undefined) {
|
if (timer.value !== undefined) {
|
||||||
return;
|
clearInterval(timer.value);
|
||||||
|
timer.value = undefined;
|
||||||
}
|
}
|
||||||
clearInterval(timer.value);
|
versionCheckController?.abort();
|
||||||
timer.value = undefined;
|
versionCheckController = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ChatTimeTimelineItem } from '@easyflow/types';
|
import type { ChatTimeTimelineItem } from '@easyflow/types';
|
||||||
|
|
||||||
import { inject, ref } from 'vue';
|
import { inject, onBeforeUnmount, ref } from 'vue';
|
||||||
|
|
||||||
import { ChatTimeTimelineBuilder, uuid } from '@easyflow/utils';
|
import { ChatTimeTimelineBuilder, uuid } from '@easyflow/utils';
|
||||||
|
|
||||||
@@ -237,6 +237,12 @@ function normalizeSseRoundMeta(meta: any): SseRoundMeta {
|
|||||||
variantIndex,
|
variantIndex,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (btnLoading.value) {
|
||||||
|
stopSse();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let isCheckingUpdates = false;
|
let isCheckingUpdates = false;
|
||||||
|
let versionCheckController: AbortController | null = null;
|
||||||
|
const VERSION_CHECK_TIMEOUT_MS = 10_000;
|
||||||
const currentVersionTag = ref('');
|
const currentVersionTag = ref('');
|
||||||
const lastVersionTag = ref('');
|
const lastVersionTag = ref('');
|
||||||
const timer = ref<ReturnType<typeof setInterval>>();
|
const timer = ref<ReturnType<typeof setInterval>>();
|
||||||
@@ -36,6 +38,12 @@ const [UpdateNoticeModal, modalApi] = useEasyFlowModal({
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function getVersionTag() {
|
async function getVersionTag() {
|
||||||
|
const controller = new AbortController();
|
||||||
|
versionCheckController = controller;
|
||||||
|
const timeout = setTimeout(
|
||||||
|
() => controller.abort(),
|
||||||
|
VERSION_CHECK_TIMEOUT_MS,
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
location.hostname === 'localhost' ||
|
location.hostname === 'localhost' ||
|
||||||
@@ -47,14 +55,22 @@ async function getVersionTag() {
|
|||||||
cache: 'no-cache',
|
cache: 'no-cache',
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
redirect: 'manual',
|
redirect: 'manual',
|
||||||
|
signal: controller.signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
response.headers.get('etag') || response.headers.get('last-modified')
|
response.headers.get('etag') || response.headers.get('last-modified')
|
||||||
);
|
);
|
||||||
} catch {
|
} catch (error) {
|
||||||
console.error('Failed to fetch version tag');
|
if (!controller.signal.aborted) {
|
||||||
|
console.error('Failed to fetch version tag', error);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
if (versionCheckController === controller) {
|
||||||
|
versionCheckController = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,23 +87,35 @@ async function checkForUpdates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lastVersionTag.value !== versionTag && versionTag) {
|
if (lastVersionTag.value !== versionTag && versionTag) {
|
||||||
clearInterval(timer.value);
|
stop();
|
||||||
handleNotice(versionTag);
|
handleNotice(versionTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function runUpdateCheck() {
|
||||||
|
if (isCheckingUpdates) return;
|
||||||
|
isCheckingUpdates = true;
|
||||||
|
try {
|
||||||
|
await checkForUpdates();
|
||||||
|
} finally {
|
||||||
|
isCheckingUpdates = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleNotice(versionTag: string) {
|
function handleNotice(versionTag: string) {
|
||||||
currentVersionTag.value = versionTag;
|
currentVersionTag.value = versionTag;
|
||||||
modalApi.open();
|
modalApi.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
|
stop();
|
||||||
if (props.checkUpdatesInterval <= 0) {
|
if (props.checkUpdatesInterval <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每 checkUpdatesInterval(默认值为1) 分钟检查一次
|
// 每 checkUpdatesInterval(默认值为1) 分钟检查一次
|
||||||
timer.value = setInterval(
|
timer.value = setInterval(
|
||||||
checkForUpdates,
|
() => void runUpdateCheck(),
|
||||||
props.checkUpdatesInterval * 60 * 1000,
|
props.checkUpdatesInterval * 60 * 1000,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -96,18 +124,21 @@ function handleVisibilitychange() {
|
|||||||
if (document.hidden) {
|
if (document.hidden) {
|
||||||
stop();
|
stop();
|
||||||
} else {
|
} else {
|
||||||
if (!isCheckingUpdates) {
|
runUpdateCheck().finally(() => {
|
||||||
isCheckingUpdates = true;
|
if (!document.hidden) {
|
||||||
checkForUpdates().finally(() => {
|
|
||||||
isCheckingUpdates = false;
|
|
||||||
start();
|
start();
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function stop() {
|
function stop() {
|
||||||
clearInterval(timer.value);
|
if (timer.value !== undefined) {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
timer.value = undefined;
|
||||||
|
}
|
||||||
|
versionCheckController?.abort();
|
||||||
|
versionCheckController = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user