refactor(stage-web): use workers dir

This commit is contained in:
Neko Ayaka
2025-07-03 18:59:26 +08:00
parent b77d24231b
commit 5d75d66f53
7 changed files with 84 additions and 10 deletions
@@ -4,9 +4,9 @@ import { FieldCheckbox, FieldRange, FieldSelect } from '@proj-airi/ui'
import { useDevicesList } from '@vueuse/core'
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import workletUrl from '../../../utils/vad/process.worklet?worker&url'
import workletUrl from '../../../workers/vad/process.worklet?worker&url'
import { createVAD, VADAudioManager } from '../../../utils/vad'
import { createVAD, VADAudioManager } from '../../../workers/vad'
const devices = useDevicesList({ constraints: { audio: true } })
const audioInputs = computed(() => devices.audioInputs.value)
+74
View File
@@ -0,0 +1,74 @@
import type { CommonRequestOptions } from '@xsai/shared'
import type { Message } from '@xsai/shared-chat'
import type { Infer, Schema } from 'xsschema'
import { generateText } from '@xsai/generate-text'
import { message } from '@xsai/utils-chat'
import { toJsonSchema, validate } from 'xsschema'
type SchemaOrString<S extends Schema | undefined | unknown> = S extends unknown ? string : S extends Schema ? Infer<S> : never
async function parseJSONFormat<S extends Schema, R extends SchemaOrString<S>>(content: string, options: { messages: Message[], apiKey?: string, baseURL: string, model: string } & Partial<CommonRequestOptions>, schema?: S, erroredValue?: string, errorMessage?: string): Promise<R> {
if (!schema)
return content as unknown as R
try {
let parsedContent: Infer<S>
let correctionPrompt = ''
if (erroredValue && errorMessage) {
correctionPrompt = `Previous response "${JSON.stringify(erroredValue)}" was invalid due to: ${JSON.stringify(errorMessage)}\n\n`
}
try {
parsedContent = JSON.parse(content)
}
catch (parseError) {
console.error('Error parsing JSON:', parseError, content)
options.messages.push(message.user(`
${correctionPrompt}The response was not valid JSON:
${JSON.stringify(content)}
Error: ${String(parseError)}
Please provide a corrected JSON response that matches the schema:
${JSON.stringify(await toJsonSchema(schema))}`))
const response = await call(options, schema)
return parseJSONFormat(response, options, schema, content, String(parseError))
}
// TODO: print validation issues
return await validate(schema, parsedContent) as R
}
catch (error) {
console.error('Error processing response:', error)
throw error
}
}
/**
* Processes user input and generates LLM response along with thought nodes.
*/
async function call<S extends Schema, R extends SchemaOrString<S>>(options: { messages: Message[], apiKey?: string, baseURL: string, model: string } & Partial<CommonRequestOptions>, schema?: S): Promise<R> {
if (schema != null) {
options.messages.push(message.user(`Your response must follow the following schema:
${JSON.stringify(await toJsonSchema(schema))}
Without any extra markups such as \`\`\` in markdown, or descriptions.`))
}
const response = await generateText({
baseURL: options.baseURL,
apiKey: options.apiKey,
model: options.model,
messages: options.messages,
})
return await parseJSONFormat<S, R>(response.text || '', options, schema)
}
export async function generateObject<S extends Schema, R extends SchemaOrString<S>>(options: { messages: Message[], model: string, apiKey?: string, baseURL: string } & Partial<CommonRequestOptions>, schema?: S): Promise<R> {
return await call(options, schema)
}
+3
View File
@@ -0,0 +1,3 @@
export function isPlatformTamagotchi() {
return import.meta.env.MODE === 'tamagotchi'
}
@@ -1,3 +1,5 @@
import type { PreTrainedModel } from '@huggingface/transformers'
import { AutoModel, Tensor } from '@huggingface/transformers'
// Default configuration parameters
@@ -41,7 +43,7 @@ export type VADEventCallback<K extends keyof VADEvents>
*/
export class VAD {
private config: VADConfig
private model: any
private model: PreTrainedModel | undefined
private state: Tensor
private sampleRateTensor: Tensor
private buffer: Float32Array
@@ -68,14 +70,9 @@ export class VAD {
this.config = { ...defaultConfig, ...userConfig }
// Create buffer based on max duration
this.buffer = new Float32Array(this.config.maxBufferDuration * this.config.sampleRate)
// Initialize state tensor for VAD model
this.state = new Tensor('float32', new Float32Array(2 * 1 * 128), [2, 1, 128])
// Sample rate tensor for the model
this.sampleRateTensor = new Tensor('int64', [this.config.sampleRate], [])
this.state = new Tensor('float32', new Float32Array(2 * 1 * 128), [2, 1, 128])
}
/**
@@ -215,7 +212,7 @@ export class VAD {
const input = new Tensor('float32', buffer, [1, buffer.length])
const { stateN, output } = await (this.inferenceChain = this.inferenceChain.then(() =>
this.model({
this.model?.({
input,
sr: this.sampleRateTensor,
state: this.state,