chore(stage-ui): queue.ts renaming, tts "..." recognition, and something relates to next and afterNext (#355)
This commit is contained in:
@@ -8,7 +8,6 @@ export interface HandlerContext<T> {
|
||||
emit: (eventName: string, ...params: any[]) => void
|
||||
}
|
||||
|
||||
// FIXME: should be exported?
|
||||
export interface Events<T> {
|
||||
add: Array<(payload: T) => void>
|
||||
pick: Array<(payload: T) => void>
|
||||
@@ -23,7 +22,7 @@ export function useQueue<T>(options: {
|
||||
}) {
|
||||
const queue = ref<T[]>([]) as Ref<T[]>
|
||||
const isProcessing = ref(false)
|
||||
const internalEventHandler: Events<T> = {
|
||||
const internalEventListeners: Events<T> = {
|
||||
add: [],
|
||||
pick: [],
|
||||
processing: [],
|
||||
@@ -31,26 +30,26 @@ export function useQueue<T>(options: {
|
||||
processed: [],
|
||||
done: [],
|
||||
}
|
||||
const internalHandlerEventHandler: Record<string, Array<(...params: any[]) => void>> = {}
|
||||
const internalHandlerEventListeners: Record<string, Array<(...params: any[]) => void>> = {}
|
||||
|
||||
function on<E extends keyof Events<T>>(eventName: E, handler: Events<T>[E][number]) {
|
||||
internalEventHandler[eventName].push(handler as any)
|
||||
function on<E extends keyof Events<T>>(eventName: E, Listener: Events<T>[E][number]) {
|
||||
internalEventListeners[eventName].push(Listener as any)
|
||||
}
|
||||
|
||||
function emit<E extends keyof Events<T>>(eventName: E, ...params: Parameters<Events<T>[E][number]>) {
|
||||
const handlers = internalEventHandler[eventName] as Events<T>[E]
|
||||
const handlers = internalEventListeners[eventName] as Events<T>[E]
|
||||
handlers.forEach((handler) => {
|
||||
(handler as any)(...params)
|
||||
})
|
||||
}
|
||||
|
||||
function onHandlerEvent(eventName: string, handler: (...params: any[]) => void) {
|
||||
internalHandlerEventHandler[eventName] = internalHandlerEventHandler[eventName] || []
|
||||
internalHandlerEventHandler[eventName].push(handler)
|
||||
internalHandlerEventListeners[eventName] = internalHandlerEventListeners[eventName] || []
|
||||
internalHandlerEventListeners[eventName].push(handler)
|
||||
}
|
||||
|
||||
function emitHandlerEvent(eventName: string, ...params: any[]) {
|
||||
const handlers = internalHandlerEventHandler[eventName] || []
|
||||
const handlers = internalHandlerEventListeners[eventName] || []
|
||||
handlers.forEach((handler) => {
|
||||
handler(...params)
|
||||
})
|
||||
@@ -70,7 +69,8 @@ export function useQueue<T>(options: {
|
||||
return payload
|
||||
}
|
||||
|
||||
async function handleItem() {
|
||||
// Listener for item add / enqueue event
|
||||
async function addItemListener() {
|
||||
if (isProcessing.value)
|
||||
return
|
||||
|
||||
@@ -81,12 +81,19 @@ export function useQueue<T>(options: {
|
||||
isProcessing.value = true
|
||||
|
||||
for (const handler of options.handlers) {
|
||||
// If there is a need to register customised listener for processing event, then this line of code should be rewritten
|
||||
// handlers as the input parameter is only designed for the add event
|
||||
emit('processing', payload, handler)
|
||||
try {
|
||||
// Use handler to deal with the newly enqueued item
|
||||
const result = await handler({ data: payload, itemsToBeProcessed: () => queue.value.length, emit: emitHandlerEvent })
|
||||
// If there is a need to register customised listener for processing event, then this line of code should be rewritten
|
||||
// handlers as the input parameter is only designed for the add event
|
||||
emit('processed', payload, result, handler)
|
||||
}
|
||||
catch (err) {
|
||||
// If there is a need to register customised listener for processing event, then this line of code should be rewritten
|
||||
// handlers as the input parameter is only designed for the add event
|
||||
emit('error', payload, err as Error, handler)
|
||||
continue
|
||||
}
|
||||
@@ -97,11 +104,13 @@ export function useQueue<T>(options: {
|
||||
|
||||
// Process next item if any
|
||||
if (queue.value.length > 0)
|
||||
handleItem()
|
||||
addItemListener()
|
||||
}
|
||||
|
||||
on('add', handleItem)
|
||||
on('done', handleItem)
|
||||
on('add', addItemListener)
|
||||
// Lilia: I'm not sure why do we need to register handleItem to 'done', if queue is not empty, addItemListner will continue to call addItemListner. Calling this function again when 'done' event is triggered will only lead to payload = undefined (since queue is already empty) and return
|
||||
// Maybe leave 'done' event to be registered other customised listeners would be more reasonable
|
||||
// on('done', addItemListener)
|
||||
|
||||
return {
|
||||
add,
|
||||
|
||||
@@ -8,8 +8,8 @@ import { readGraphemeClusters } from 'clustr'
|
||||
export const TTS_FLUSH_INSTRUCTION = '\u200B'
|
||||
|
||||
const keptPunctuations = new Set('??!!')
|
||||
const hardPunctuations = new Set('.。??!!…⋯~~「」\n\t\r')
|
||||
const softPunctuations = new Set(',,、–—::;;《》')
|
||||
const hardPunctuations = new Set('.。??!!…⋯~~\n\t\r')
|
||||
const softPunctuations = new Set(',,、–—::;;《》「」')
|
||||
|
||||
export interface TTSInputChunk {
|
||||
text: string
|
||||
@@ -62,7 +62,7 @@ export async function* chunkTTSInput(input: string | ReaderLike, options?: TTSIn
|
||||
let current = await iterator.next()
|
||||
|
||||
while (!current.done) {
|
||||
const value = current.value
|
||||
let value = current.value
|
||||
|
||||
if (value.length > 1) {
|
||||
previousValue = value
|
||||
@@ -74,13 +74,15 @@ export async function* chunkTTSInput(input: string | ReaderLike, options?: TTSIn
|
||||
const hard = hardPunctuations.has(value)
|
||||
const soft = softPunctuations.has(value)
|
||||
const kept = keptPunctuations.has(value)
|
||||
let next: IteratorResult<string, any> | undefined
|
||||
let afterNext: IteratorResult<string, any> | undefined
|
||||
|
||||
if (flush || hard || soft) {
|
||||
switch (value) {
|
||||
case '.':
|
||||
case ',': {
|
||||
if (previousValue !== undefined && /\d/.test(previousValue)) {
|
||||
const next = await iterator.next()
|
||||
next = await iterator.next()
|
||||
if (!next.done && next.value && /\d/.test(next.value)) {
|
||||
// This dot could be a decimal point, so we skip it (don't fully skip! keep in tts input!)
|
||||
|
||||
@@ -92,9 +94,23 @@ export async function* chunkTTSInput(input: string | ReaderLike, options?: TTSIn
|
||||
// If we don't append value ("." or ","), we will lose the decimal point, and 2.5 will become 25, which hugely impacted the tts...
|
||||
buffer += value
|
||||
current = next
|
||||
next = undefined
|
||||
continue
|
||||
}
|
||||
}
|
||||
else if (value === '.') {
|
||||
// trying catch '...' and turn it into U+2026
|
||||
next = await iterator.next()
|
||||
if (!next.done && next.value && next.value === '.') {
|
||||
afterNext = await iterator.next()
|
||||
// If this is a '...' repalce the current value
|
||||
if (!afterNext.done && afterNext.value && afterNext.value === '.') {
|
||||
value = '…'
|
||||
next = undefined
|
||||
afterNext = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,22 +151,40 @@ export async function* chunkTTSInput(input: string | ReaderLike, options?: TTSIn
|
||||
}
|
||||
|
||||
previousValue = value
|
||||
current = await iterator.next()
|
||||
// If next had been read during decimal recognition or "..." recognition
|
||||
if (next !== undefined) {
|
||||
// If afterNext had also been read
|
||||
if (afterNext !== undefined) {
|
||||
// The only case that the program will come to this place is:
|
||||
// "x..y" and y is not a "." so "..." is not recognised
|
||||
// ".." is not a legal punctuation so ignored.
|
||||
// The first "." had been consumed during hard flush
|
||||
// next.value = second '.'
|
||||
// afterNext.value = 'y', so we just need to care about 'y'
|
||||
// In case 'y' is not just a useless blank. It's OK if 'y' is blank since we have `text = chunk.trim()`
|
||||
current = afterNext
|
||||
next = undefined
|
||||
afterNext = undefined
|
||||
}
|
||||
else {
|
||||
// Only next had been read
|
||||
// This is the case where "x.y" and x is a number but y is not
|
||||
// In case 'y' is not just a useless blank. It's OK if 'y' is blank since we have `text = chunk.trim()`
|
||||
current = next
|
||||
next = undefined
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No next nor afterNext, so run `iterator.next()`
|
||||
current = await iterator.next()
|
||||
}
|
||||
// No need to do anything with buffer, just jump to the next loop
|
||||
continue
|
||||
}
|
||||
|
||||
// If normal character enters, add it to the buffer and move to the next
|
||||
buffer += value
|
||||
// TODO: remove later
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug('current buffer: ', buffer)
|
||||
previousValue = value
|
||||
// For debugging why it stuck at "xxxx\u200B"
|
||||
const next = await iterator.next()
|
||||
// if (next.value ==='\u200B') {
|
||||
// console.debug("TTS_FLUSH get for the next value!")
|
||||
// } else {
|
||||
// console.debug("the next value: ", next.value)
|
||||
// }
|
||||
next = await iterator.next()
|
||||
current = next
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user