fix(providers-transformers): progress support
Signed-off-by: Neko Ayaka <neko@ayaka.moe>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { InitiateProgressInfo, ProgressStatusInfo } from '@proj-airi/utils-transformers/types'
|
||||
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { embed } from '@xsai/embed'
|
||||
import { serialize } from 'superjson'
|
||||
@@ -6,6 +8,7 @@ import { onMounted, ref } from 'vue'
|
||||
|
||||
import { createTransformers } from '../../src'
|
||||
import embedWorkerURL from '../../src/worker?worker&url'
|
||||
import Progress from './components/Progress.vue'
|
||||
|
||||
const isDark = useDark()
|
||||
const toggleDark = useToggle(isDark)
|
||||
@@ -13,11 +16,33 @@ const toggleDark = useToggle(isDark)
|
||||
const modelId = ref('Xenova/all-MiniLM-L6-v2')
|
||||
const input = ref('Hello, world!')
|
||||
const results = ref<any>()
|
||||
const loadingItems = ref<(InitiateProgressInfo | ProgressStatusInfo)[]>([])
|
||||
|
||||
const transformersProvider = createTransformers({ embedWorkerURL })
|
||||
|
||||
onMounted(async () => {
|
||||
await transformersProvider.loadEmbed(modelId.value)
|
||||
await transformersProvider.loadEmbed(modelId.value, {
|
||||
onProgress: (progress) => {
|
||||
switch (progress.status) {
|
||||
case 'initiate':
|
||||
loadingItems.value.push(progress)
|
||||
break
|
||||
|
||||
case 'progress':
|
||||
loadingItems.value = loadingItems.value.map((item) => {
|
||||
if (item.file === progress.file) {
|
||||
return { ...item, ...progress }
|
||||
}
|
||||
return item
|
||||
})
|
||||
break
|
||||
|
||||
case 'done':
|
||||
// loadingItems.value = loadingItems.value.filter(item => item.file !== progress.file)
|
||||
break
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
async function execute() {
|
||||
@@ -55,6 +80,15 @@ async function execute() {
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="loadingItems.length > 0" class="w-[50%] flex flex-col gap-2">
|
||||
<Progress
|
||||
v-for="(item, index) of loadingItems"
|
||||
:key="index"
|
||||
:text="item.file"
|
||||
:percentage="'progress' in item ? item.progress || 0 : 0"
|
||||
:total="'total' in item ? item.total || 0 : 0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div grid grid-cols-2 gap-2>
|
||||
<div flex flex-col gap-2>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(defineProps<{
|
||||
text: string
|
||||
percentage: number
|
||||
total?: number
|
||||
}>(), {
|
||||
percentage: 0,
|
||||
})
|
||||
|
||||
function formatBytes(size?: number) {
|
||||
if (!size)
|
||||
size = 0
|
||||
|
||||
const i = size === 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
|
||||
return +((size / 1024 ** i).toFixed(2)) * 1 + ['B', 'kB', 'MB', 'GB', 'TB'][i]
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center justify-between whitespace-nowrap rounded-lg bg-violet-100 px-3 py-2 text-sm dark:bg-violet-900"
|
||||
:style="{ width: `${percentage}%` }"
|
||||
>
|
||||
<span>{{ text }}</span>
|
||||
<span>({{ percentage.toFixed(2) }}%{{ Number.isNaN(total) ? '' : ` of ${formatBytes(total)}` }})</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -15,6 +15,9 @@ export function createEmbedProvider<T extends string, T2 extends Omit<CommonRequ
|
||||
|
||||
function loadModel(model: (string & {}) | T, options: T2) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const onProgress = options.onProgress
|
||||
delete options.onProgress
|
||||
|
||||
try {
|
||||
const workerURL = new URL(createOptions.baseURL)
|
||||
|
||||
@@ -29,7 +32,7 @@ export function createEmbedProvider<T extends string, T2 extends Omit<CommonRequ
|
||||
reject(err)
|
||||
}
|
||||
|
||||
worker.onmessage = (event: MessageEvent<WorkerMessageEvent>) => {
|
||||
worker.addEventListener('message', (event: MessageEvent<WorkerMessageEvent>) => {
|
||||
switch (event.data.type) {
|
||||
case 'error':
|
||||
reject(event.data.data.error)
|
||||
@@ -42,13 +45,13 @@ export function createEmbedProvider<T extends string, T2 extends Omit<CommonRequ
|
||||
|
||||
break
|
||||
case 'progress':
|
||||
if (options.onProgress != null && typeof options.onProgress === 'function') {
|
||||
options.onProgress(event.data.data.progress)
|
||||
if (onProgress != null && typeof onProgress === 'function') {
|
||||
onProgress(event.data.data.progress)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -62,13 +65,18 @@ export function createEmbedProvider<T extends string, T2 extends Omit<CommonRequ
|
||||
return
|
||||
}
|
||||
|
||||
worker.addEventListener('error', (event: ErrorEvent) => {
|
||||
reject(event)
|
||||
})
|
||||
|
||||
let text: string = ''
|
||||
let body: any
|
||||
let body: LoadOptions & { input: string }
|
||||
|
||||
try {
|
||||
body = JSON.parse(init.body.toString())
|
||||
text = body.input
|
||||
delete body.input
|
||||
delete body.onProgress
|
||||
}
|
||||
catch (err) {
|
||||
reject(err)
|
||||
@@ -78,7 +86,7 @@ export function createEmbedProvider<T extends string, T2 extends Omit<CommonRequ
|
||||
let errored = false
|
||||
let resultDone = false
|
||||
|
||||
worker.onmessage = (event: MessageEvent<WorkerMessageEvent>) => {
|
||||
worker.addEventListener('message', (event: MessageEvent<WorkerMessageEvent>) => {
|
||||
switch (event.data.type) {
|
||||
case 'error':
|
||||
errored = true
|
||||
@@ -94,7 +102,7 @@ export function createEmbedProvider<T extends string, T2 extends Omit<CommonRequ
|
||||
resolve(new Response(encoder.encode(JSON.stringify(result))))
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!errored && !resultDone)
|
||||
worker.postMessage({ type: 'extract', data: { text, options: body as any } } satisfies WorkerMessageEvent)
|
||||
|
||||
Reference in New Issue
Block a user