mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-04-22 15:09:04 +00:00
图片解密再次优化
This commit is contained in:
@@ -4,7 +4,21 @@ import {
|
||||
registerBackgroundTask,
|
||||
updateBackgroundTask
|
||||
} from '../services/backgroundTaskMonitor'
|
||||
import type { BackgroundTaskSourcePage } from '../types/backgroundTask'
|
||||
import type { BackgroundTaskSourcePage, BackgroundTaskStatus } from '../types/backgroundTask'
|
||||
|
||||
interface BatchDecryptTaskControls {
|
||||
cancelable?: boolean
|
||||
resumable?: boolean
|
||||
onCancel?: () => void | Promise<void>
|
||||
onPause?: () => void | Promise<void>
|
||||
onResume?: () => void | Promise<void>
|
||||
}
|
||||
|
||||
interface BatchDecryptFinishOptions {
|
||||
status?: Extract<BackgroundTaskStatus, 'completed' | 'failed' | 'canceled'>
|
||||
detail?: string
|
||||
progressText?: string
|
||||
}
|
||||
|
||||
export interface BatchImageDecryptState {
|
||||
isBatchDecrypting: boolean
|
||||
@@ -16,9 +30,15 @@ export interface BatchImageDecryptState {
|
||||
sessionName: string
|
||||
taskId: string | null
|
||||
|
||||
startDecrypt: (total: number, sessionName: string, sourcePage?: BackgroundTaskSourcePage) => void
|
||||
startDecrypt: (
|
||||
total: number,
|
||||
sessionName: string,
|
||||
sourcePage?: BackgroundTaskSourcePage,
|
||||
controls?: BatchDecryptTaskControls
|
||||
) => void
|
||||
updateProgress: (current: number, total: number) => void
|
||||
finishDecrypt: (success: number, fail: number) => void
|
||||
setTaskStatus: (detail: string, progressText?: string, status?: BackgroundTaskStatus) => void
|
||||
finishDecrypt: (success: number, fail: number, options?: BatchDecryptFinishOptions) => void
|
||||
setShowToast: (show: boolean) => void
|
||||
setShowResultToast: (show: boolean) => void
|
||||
reset: () => void
|
||||
@@ -53,7 +73,7 @@ export const useBatchImageDecryptStore = create<BatchImageDecryptState>((set, ge
|
||||
sessionName: '',
|
||||
taskId: null,
|
||||
|
||||
startDecrypt: (total, sessionName, sourcePage = 'chat') => {
|
||||
startDecrypt: (total, sessionName, sourcePage = 'chat', controls) => {
|
||||
const previousTaskId = get().taskId
|
||||
if (previousTaskId) {
|
||||
taskProgressUpdateMeta.delete(previousTaskId)
|
||||
@@ -73,7 +93,11 @@ export const useBatchImageDecryptStore = create<BatchImageDecryptState>((set, ge
|
||||
title,
|
||||
detail: `正在解密图片(${normalizedProgress.current}/${normalizedProgress.total})`,
|
||||
progressText: `${normalizedProgress.current} / ${normalizedProgress.total}`,
|
||||
cancelable: false
|
||||
cancelable: controls?.cancelable !== false,
|
||||
resumable: controls?.resumable === true,
|
||||
onCancel: controls?.onCancel,
|
||||
onPause: controls?.onPause,
|
||||
onResume: controls?.onResume
|
||||
})
|
||||
taskProgressUpdateMeta.set(taskId, {
|
||||
lastAt: Date.now(),
|
||||
@@ -97,6 +121,7 @@ export const useBatchImageDecryptStore = create<BatchImageDecryptState>((set, ge
|
||||
const previousProgress = get().progress
|
||||
const normalizedProgress = clampProgress(current, total)
|
||||
const taskId = get().taskId
|
||||
let shouldCommitUi = true
|
||||
if (taskId) {
|
||||
const now = Date.now()
|
||||
const meta = taskProgressUpdateMeta.get(taskId)
|
||||
@@ -105,7 +130,9 @@ export const useBatchImageDecryptStore = create<BatchImageDecryptState>((set, ge
|
||||
const intervalReached = !meta || (now - meta.lastAt >= TASK_PROGRESS_UPDATE_MIN_INTERVAL_MS)
|
||||
const crossedBucket = !meta || bucket !== meta.lastBucket
|
||||
const isFinal = normalizedProgress.total > 0 && normalizedProgress.current >= normalizedProgress.total
|
||||
if (crossedBucket || intervalReached || isFinal) {
|
||||
const shouldPublish = crossedBucket || intervalReached || isFinal
|
||||
shouldCommitUi = shouldPublish
|
||||
if (shouldPublish) {
|
||||
updateBackgroundTask(taskId, {
|
||||
detail: `正在解密图片(${normalizedProgress.current}/${normalizedProgress.total})`,
|
||||
progressText: `${normalizedProgress.current} / ${normalizedProgress.total}`
|
||||
@@ -117,26 +144,38 @@ export const useBatchImageDecryptStore = create<BatchImageDecryptState>((set, ge
|
||||
})
|
||||
}
|
||||
}
|
||||
if (
|
||||
if (shouldCommitUi && (
|
||||
previousProgress.current !== normalizedProgress.current ||
|
||||
previousProgress.total !== normalizedProgress.total
|
||||
) {
|
||||
)) {
|
||||
set({
|
||||
progress: normalizedProgress
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
finishDecrypt: (success, fail) => {
|
||||
setTaskStatus: (detail, progressText, status) => {
|
||||
const taskId = get().taskId
|
||||
if (!taskId) return
|
||||
const normalizedDetail = String(detail || '').trim()
|
||||
if (!normalizedDetail) return
|
||||
updateBackgroundTask(taskId, {
|
||||
detail: normalizedDetail,
|
||||
progressText,
|
||||
status
|
||||
})
|
||||
},
|
||||
|
||||
finishDecrypt: (success, fail, options) => {
|
||||
const taskId = get().taskId
|
||||
const normalizedSuccess = Number.isFinite(success) ? Math.max(0, Math.floor(success)) : 0
|
||||
const normalizedFail = Number.isFinite(fail) ? Math.max(0, Math.floor(fail)) : 0
|
||||
if (taskId) {
|
||||
taskProgressUpdateMeta.delete(taskId)
|
||||
const status = normalizedSuccess > 0 || normalizedFail === 0 ? 'completed' : 'failed'
|
||||
const status = options?.status || (normalizedSuccess > 0 || normalizedFail === 0 ? 'completed' : 'failed')
|
||||
finishBackgroundTask(taskId, status, {
|
||||
detail: `图片批量解密完成:成功 ${normalizedSuccess},失败 ${normalizedFail}`,
|
||||
progressText: `成功 ${normalizedSuccess} / 失败 ${normalizedFail}`
|
||||
detail: options?.detail || `图片批量解密完成:成功 ${normalizedSuccess},失败 ${normalizedFail}`,
|
||||
progressText: options?.progressText || `成功 ${normalizedSuccess} / 失败 ${normalizedFail}`
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,27 @@
|
||||
import { create } from 'zustand'
|
||||
import {
|
||||
finishBackgroundTask,
|
||||
registerBackgroundTask,
|
||||
updateBackgroundTask
|
||||
} from '../services/backgroundTaskMonitor'
|
||||
import type { BackgroundTaskSourcePage, BackgroundTaskStatus } from '../types/backgroundTask'
|
||||
|
||||
export type BatchVoiceTaskType = 'transcribe' | 'decrypt'
|
||||
|
||||
interface BatchVoiceTaskControls {
|
||||
cancelable?: boolean
|
||||
resumable?: boolean
|
||||
onCancel?: () => void | Promise<void>
|
||||
onPause?: () => void | Promise<void>
|
||||
onResume?: () => void | Promise<void>
|
||||
}
|
||||
|
||||
interface BatchVoiceTaskFinishOptions {
|
||||
status?: Extract<BackgroundTaskStatus, 'completed' | 'failed' | 'canceled'>
|
||||
detail?: string
|
||||
progressText?: string
|
||||
}
|
||||
|
||||
export interface BatchTranscribeState {
|
||||
/** 是否正在批量转写 */
|
||||
isBatchTranscribing: boolean
|
||||
@@ -18,17 +38,44 @@ export interface BatchTranscribeState {
|
||||
/** 当前转写的会话名 */
|
||||
startTime: number
|
||||
sessionName: string
|
||||
taskId: string | null
|
||||
|
||||
// Actions
|
||||
startTranscribe: (total: number, sessionName: string, taskType?: BatchVoiceTaskType) => void
|
||||
startTranscribe: (
|
||||
total: number,
|
||||
sessionName: string,
|
||||
taskType?: BatchVoiceTaskType,
|
||||
sourcePage?: BackgroundTaskSourcePage,
|
||||
controls?: BatchVoiceTaskControls
|
||||
) => void
|
||||
updateProgress: (current: number, total: number) => void
|
||||
finishTranscribe: (success: number, fail: number) => void
|
||||
setTaskStatus: (detail: string, progressText?: string, status?: BackgroundTaskStatus) => void
|
||||
finishTranscribe: (success: number, fail: number, options?: BatchVoiceTaskFinishOptions) => void
|
||||
setShowToast: (show: boolean) => void
|
||||
setShowResult: (show: boolean) => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
export const useBatchTranscribeStore = create<BatchTranscribeState>((set) => ({
|
||||
const clampProgress = (current: number, total: number): { current: number; total: number } => {
|
||||
const normalizedTotal = Number.isFinite(total) ? Math.max(0, Math.floor(total)) : 0
|
||||
const normalizedCurrentRaw = Number.isFinite(current) ? Math.max(0, Math.floor(current)) : 0
|
||||
const normalizedCurrent = normalizedTotal > 0
|
||||
? Math.min(normalizedCurrentRaw, normalizedTotal)
|
||||
: normalizedCurrentRaw
|
||||
return { current: normalizedCurrent, total: normalizedTotal }
|
||||
}
|
||||
|
||||
const TASK_PROGRESS_UPDATE_MIN_INTERVAL_MS = 250
|
||||
const TASK_PROGRESS_UPDATE_MAX_STEPS = 100
|
||||
|
||||
const taskProgressUpdateMeta = new Map<string, { lastAt: number; lastBucket: number; step: number }>()
|
||||
|
||||
const calcProgressStep = (total: number): number => {
|
||||
if (total <= 0) return 1
|
||||
return Math.max(1, Math.floor(total / TASK_PROGRESS_UPDATE_MAX_STEPS))
|
||||
}
|
||||
|
||||
export const useBatchTranscribeStore = create<BatchTranscribeState>((set, get) => ({
|
||||
isBatchTranscribing: false,
|
||||
taskType: 'transcribe',
|
||||
progress: { current: 0, total: 0 },
|
||||
@@ -37,41 +84,151 @@ export const useBatchTranscribeStore = create<BatchTranscribeState>((set) => ({
|
||||
result: { success: 0, fail: 0 },
|
||||
sessionName: '',
|
||||
startTime: 0,
|
||||
taskId: null,
|
||||
|
||||
startTranscribe: (total, sessionName, taskType = 'transcribe') => set({
|
||||
isBatchTranscribing: true,
|
||||
taskType,
|
||||
showToast: true,
|
||||
progress: { current: 0, total },
|
||||
showResult: false,
|
||||
result: { success: 0, fail: 0 },
|
||||
sessionName,
|
||||
startTime: Date.now()
|
||||
}),
|
||||
startTranscribe: (total, sessionName, taskType = 'transcribe', sourcePage = 'chat', controls) => {
|
||||
const previousTaskId = get().taskId
|
||||
if (previousTaskId) {
|
||||
taskProgressUpdateMeta.delete(previousTaskId)
|
||||
finishBackgroundTask(previousTaskId, 'canceled', {
|
||||
detail: '已被新的语音批量任务替换',
|
||||
progressText: '已替换'
|
||||
})
|
||||
}
|
||||
|
||||
updateProgress: (current, total) => set({
|
||||
progress: { current, total }
|
||||
}),
|
||||
const normalizedProgress = clampProgress(0, total)
|
||||
const normalizedSessionName = String(sessionName || '').trim()
|
||||
const taskLabel = taskType === 'decrypt' ? '语音批量解密' : '语音批量转写'
|
||||
const title = normalizedSessionName
|
||||
? `${taskLabel}(${normalizedSessionName})`
|
||||
: taskLabel
|
||||
const taskId = registerBackgroundTask({
|
||||
sourcePage,
|
||||
title,
|
||||
detail: `正在准备${taskType === 'decrypt' ? '语音解密' : '语音转写'}任务...`,
|
||||
progressText: `${normalizedProgress.current} / ${normalizedProgress.total}`,
|
||||
cancelable: controls?.cancelable !== false,
|
||||
resumable: controls?.resumable === true,
|
||||
onCancel: controls?.onCancel,
|
||||
onPause: controls?.onPause,
|
||||
onResume: controls?.onResume
|
||||
})
|
||||
taskProgressUpdateMeta.set(taskId, {
|
||||
lastAt: Date.now(),
|
||||
lastBucket: 0,
|
||||
step: calcProgressStep(normalizedProgress.total)
|
||||
})
|
||||
|
||||
finishTranscribe: (success, fail) => set({
|
||||
isBatchTranscribing: false,
|
||||
showToast: false,
|
||||
showResult: true,
|
||||
result: { success, fail },
|
||||
startTime: 0
|
||||
}),
|
||||
set({
|
||||
isBatchTranscribing: true,
|
||||
taskType,
|
||||
showToast: false,
|
||||
progress: normalizedProgress,
|
||||
showResult: false,
|
||||
result: { success: 0, fail: 0 },
|
||||
sessionName: normalizedSessionName,
|
||||
startTime: Date.now(),
|
||||
taskId
|
||||
})
|
||||
},
|
||||
|
||||
updateProgress: (current, total) => {
|
||||
const previousProgress = get().progress
|
||||
const normalizedProgress = clampProgress(current, total)
|
||||
const taskId = get().taskId
|
||||
let shouldCommitUi = true
|
||||
if (taskId) {
|
||||
const now = Date.now()
|
||||
const meta = taskProgressUpdateMeta.get(taskId)
|
||||
const step = meta?.step || calcProgressStep(normalizedProgress.total)
|
||||
const bucket = Math.floor(normalizedProgress.current / step)
|
||||
const intervalReached = !meta || (now - meta.lastAt >= TASK_PROGRESS_UPDATE_MIN_INTERVAL_MS)
|
||||
const crossedBucket = !meta || bucket !== meta.lastBucket
|
||||
const isFinal = normalizedProgress.total > 0 && normalizedProgress.current >= normalizedProgress.total
|
||||
const shouldPublish = crossedBucket || intervalReached || isFinal
|
||||
shouldCommitUi = shouldPublish
|
||||
if (shouldPublish) {
|
||||
const taskVerb = get().taskType === 'decrypt' ? '解密语音' : '转写语音'
|
||||
updateBackgroundTask(taskId, {
|
||||
detail: `正在${taskVerb}(${normalizedProgress.current}/${normalizedProgress.total})`,
|
||||
progressText: `${normalizedProgress.current} / ${normalizedProgress.total}`
|
||||
})
|
||||
taskProgressUpdateMeta.set(taskId, {
|
||||
lastAt: now,
|
||||
lastBucket: bucket,
|
||||
step
|
||||
})
|
||||
}
|
||||
}
|
||||
if (shouldCommitUi && (
|
||||
previousProgress.current !== normalizedProgress.current ||
|
||||
previousProgress.total !== normalizedProgress.total
|
||||
)) {
|
||||
set({
|
||||
progress: normalizedProgress
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
setTaskStatus: (detail, progressText, status) => {
|
||||
const taskId = get().taskId
|
||||
if (!taskId) return
|
||||
const normalizedDetail = String(detail || '').trim()
|
||||
if (!normalizedDetail) return
|
||||
updateBackgroundTask(taskId, {
|
||||
detail: normalizedDetail,
|
||||
progressText,
|
||||
status
|
||||
})
|
||||
},
|
||||
|
||||
finishTranscribe: (success, fail, options) => {
|
||||
const taskId = get().taskId
|
||||
const normalizedSuccess = Number.isFinite(success) ? Math.max(0, Math.floor(success)) : 0
|
||||
const normalizedFail = Number.isFinite(fail) ? Math.max(0, Math.floor(fail)) : 0
|
||||
const taskType = get().taskType
|
||||
if (taskId) {
|
||||
taskProgressUpdateMeta.delete(taskId)
|
||||
const status = options?.status || (normalizedSuccess > 0 || normalizedFail === 0 ? 'completed' : 'failed')
|
||||
const taskLabel = taskType === 'decrypt' ? '语音批量解密' : '语音批量转写'
|
||||
finishBackgroundTask(taskId, status, {
|
||||
detail: options?.detail || `${taskLabel}完成:成功 ${normalizedSuccess},失败 ${normalizedFail}`,
|
||||
progressText: options?.progressText || `成功 ${normalizedSuccess} / 失败 ${normalizedFail}`
|
||||
})
|
||||
}
|
||||
|
||||
set({
|
||||
isBatchTranscribing: false,
|
||||
showToast: false,
|
||||
showResult: false,
|
||||
result: { success: normalizedSuccess, fail: normalizedFail },
|
||||
startTime: 0,
|
||||
taskId: null
|
||||
})
|
||||
},
|
||||
|
||||
setShowToast: (show) => set({ showToast: show }),
|
||||
setShowResult: (show) => set({ showResult: show }),
|
||||
|
||||
reset: () => set({
|
||||
isBatchTranscribing: false,
|
||||
taskType: 'transcribe',
|
||||
progress: { current: 0, total: 0 },
|
||||
showToast: false,
|
||||
showResult: false,
|
||||
result: { success: 0, fail: 0 },
|
||||
sessionName: '',
|
||||
startTime: 0
|
||||
})
|
||||
reset: () => {
|
||||
const taskId = get().taskId
|
||||
if (taskId) {
|
||||
taskProgressUpdateMeta.delete(taskId)
|
||||
finishBackgroundTask(taskId, 'canceled', {
|
||||
detail: '语音批量任务已重置',
|
||||
progressText: '已停止'
|
||||
})
|
||||
}
|
||||
set({
|
||||
isBatchTranscribing: false,
|
||||
taskType: 'transcribe',
|
||||
progress: { current: 0, total: 0 },
|
||||
showToast: false,
|
||||
showResult: false,
|
||||
result: { success: 0, fail: 0 },
|
||||
sessionName: '',
|
||||
startTime: 0,
|
||||
taskId: null
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user