refactor: use @moeru/std (#226)
This commit is contained in:
@@ -25,7 +25,6 @@
|
||||
"@xsai/generate-text": "catalog:",
|
||||
"@xsai/shared-chat": "catalog:",
|
||||
"@xsai/stream-text": "catalog:",
|
||||
"defu": "^6.1.4",
|
||||
"es-toolkit": "^1.39.4",
|
||||
"vue": "^3.5.17"
|
||||
},
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
"@xsai/stream-text": "catalog:",
|
||||
"@xsai/utils-chat": "catalog:",
|
||||
"culori": "^4.0.1",
|
||||
"defu": "^6.1.4",
|
||||
"drizzle-kit": "^0.31.2",
|
||||
"drizzle-orm": "^0.44.2",
|
||||
"jszip": "^3.10.1",
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
"@xsai/stream-text": "catalog:",
|
||||
"@xsai/utils-chat": "catalog:",
|
||||
"culori": "^4.0.1",
|
||||
"defu": "^6.1.4",
|
||||
"driver.js": "^1.3.6",
|
||||
"drizzle-kit": "^0.31.2",
|
||||
"drizzle-orm": "^0.44.2",
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
"@guiiai/logg": "^1.0.10",
|
||||
"@proj-airi/server-shared": "workspace:^",
|
||||
"crossws": "^0.4.1",
|
||||
"defu": "^6.1.4",
|
||||
"h3": "^1.15.3",
|
||||
"listhen": "^1.9.0"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { WebSocketBaseEvent, WebSocketEvent, WebSocketEvents } from '@proj-
|
||||
|
||||
import { sleep } from '@moeru/std'
|
||||
import WebSocket from 'crossws/websocket'
|
||||
import { defu } from 'defu'
|
||||
|
||||
export interface ClientOptions<C = undefined> {
|
||||
url?: string
|
||||
@@ -17,7 +16,7 @@ export interface ClientOptions<C = undefined> {
|
||||
|
||||
export class Client<C = undefined> {
|
||||
private connected = false
|
||||
private opts: Required<ClientOptions<C>>
|
||||
private opts: Required<Omit<ClientOptions<C>, 'token'>> & Pick<ClientOptions<C>, 'token'>
|
||||
private websocket: WebSocket | undefined
|
||||
private eventListeners: Map<keyof WebSocketEvents<C>, Array<(data: WebSocketBaseEvent<any, any>) => void | Promise<void>>> = new Map()
|
||||
|
||||
@@ -25,17 +24,15 @@ export class Client<C = undefined> {
|
||||
private shouldClose = false
|
||||
|
||||
constructor(options: ClientOptions<C>) {
|
||||
this.opts = defu<Required<ClientOptions<C>>, Required<Omit<ClientOptions<C>, 'name' | 'token'>>[]>(
|
||||
options,
|
||||
{
|
||||
this.opts = {
|
||||
url: 'ws://localhost:6121/ws',
|
||||
possibleEvents: [],
|
||||
onError: () => { },
|
||||
onClose: () => { },
|
||||
autoConnect: true,
|
||||
autoReconnect: true,
|
||||
},
|
||||
)
|
||||
...options,
|
||||
}
|
||||
|
||||
if (this.opts.autoConnect) {
|
||||
try {
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
"@xsai/stream-text": "catalog:",
|
||||
"@xsai/tool": "catalog:",
|
||||
"culori": "^4.0.1",
|
||||
"defu": "^6.1.4",
|
||||
"gpuu": "^1.0.4",
|
||||
"jszip": "^3.10.1",
|
||||
"localforage": "^1.10.0",
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import type { RealTimeVADOptions } from '@ricky0123/vad-web'
|
||||
import type { MaybeRef } from '@vueuse/shared'
|
||||
|
||||
import { merge } from '@moeru/std'
|
||||
import { getDefaultRealTimeVADOptions, MicVAD } from '@ricky0123/vad-web'
|
||||
import { usePermission } from '@vueuse/core'
|
||||
import { tryOnMounted } from '@vueuse/shared'
|
||||
import { defu } from 'defu'
|
||||
import { onUnmounted, ref, toRef, unref, watch } from 'vue'
|
||||
|
||||
export function useMicVAD(deviceId: MaybeRef<ConstrainDOMString | undefined>, options?: Partial<RealTimeVADOptions> & { auto?: boolean }) {
|
||||
const opts = defu<Partial<RealTimeVADOptions> & { auto?: boolean }, Array<Omit<RealTimeVADOptions, 'stream'> & { auto?: boolean }>>(options ?? {}, {
|
||||
export function useMicVAD(deviceId: MaybeRef<ConstrainDOMString | undefined>, options: Partial<RealTimeVADOptions> & { auto?: boolean } = {}) {
|
||||
const opts = merge<Omit<RealTimeVADOptions, 'stream'> & { auto?: boolean }, Partial<RealTimeVADOptions> & { auto?: boolean }>({
|
||||
...getDefaultRealTimeVADOptions('v5'),
|
||||
preSpeechPadFrames: 30,
|
||||
positiveSpeechThreshold: 0.5, // default is 0.5
|
||||
negativeSpeechThreshold: 0.5 - 0.15, // default is 0.5 - 0.15
|
||||
minSpeechFrames: 30, // default is 9
|
||||
auto: true,
|
||||
})
|
||||
}, options)
|
||||
|
||||
const micVad = ref<MicVAD>()
|
||||
const microphoneAccess = usePermission('microphone')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { MessageEvents, MessageGenerate, ProgressMessageEvents } from '../libs/workers/types'
|
||||
|
||||
import { merge } from '@moeru/std'
|
||||
import { useWebWorker } from '@vueuse/core'
|
||||
import { defu } from 'defu'
|
||||
import { onUnmounted, ref, watch } from 'vue'
|
||||
|
||||
export interface UseWhisperOptions {
|
||||
@@ -16,7 +16,7 @@ export interface UseWhisperOptions {
|
||||
}
|
||||
|
||||
export function useWhisper(url: string, options?: Partial<UseWhisperOptions>) {
|
||||
const opts = defu<Partial<UseWhisperOptions>, UseWhisperOptions[]>(options, {
|
||||
const opts = merge<UseWhisperOptions>({
|
||||
onLoading: () => {},
|
||||
onInitiate: () => {},
|
||||
onProgress: () => {},
|
||||
@@ -25,7 +25,7 @@ export function useWhisper(url: string, options?: Partial<UseWhisperOptions>) {
|
||||
onStart: () => {},
|
||||
onUpdate: () => {},
|
||||
onComplete: () => {},
|
||||
})
|
||||
}, options)
|
||||
|
||||
const {
|
||||
post: whisperPost,
|
||||
|
||||
@@ -3,13 +3,13 @@ import type { Message, SystemMessage } from '@xsai/shared-chat'
|
||||
|
||||
import type { ChatAssistantMessage, ChatMessage, ChatSlices } from '../types/chat'
|
||||
|
||||
import { readableStreamToAsyncIterator } from '@moeru/std'
|
||||
import { defineStore, storeToRefs } from 'pinia'
|
||||
import { ref, toRaw } from 'vue'
|
||||
|
||||
import { useQueue } from '../composables'
|
||||
import { useLlmmarkerParser } from '../composables/llmmarkerParser'
|
||||
import { useLLM } from '../stores/llm'
|
||||
import { asyncIteratorFromReadableStream } from '../utils'
|
||||
import { useAiriCardStore } from './modules'
|
||||
|
||||
export interface ErrorMessage {
|
||||
@@ -175,7 +175,7 @@ export const useChatStore = defineStore('chat', () => {
|
||||
|
||||
let fullText = ''
|
||||
|
||||
for await (const textPart of asyncIteratorFromReadableStream(res.textStream, async v => v)) {
|
||||
for await (const textPart of readableStreamToAsyncIterator(res.textStream, async v => v)) {
|
||||
slicesQueue.add({
|
||||
type: 'text',
|
||||
text: textPart,
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './eye-motions'
|
||||
export * from './iterator'
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
export async function* asyncIteratorFromReadableStream<T, F = Uint8Array>(res: ReadableStream<F>, func: (value: F) => Promise<T>): AsyncGenerator<T, void, unknown> {
|
||||
// react js - TS2504: Type 'ReadableStream<Uint8Array>' must have a '[Symbol.asyncIterator]()' method that returns an async iterator - Stack Overflow
|
||||
// https://stackoverflow.com/questions/76700924/ts2504-type-readablestreamuint8array-must-have-a-symbol-asynciterator
|
||||
const reader = res.getReader()
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) {
|
||||
return
|
||||
}
|
||||
|
||||
yield func(value)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.releaseLock()
|
||||
}
|
||||
}
|
||||
Generated
+4
-19
@@ -7,7 +7,7 @@ settings:
|
||||
catalogs:
|
||||
default:
|
||||
'@moeru/std':
|
||||
specifier: ^0.1.0-beta.4
|
||||
specifier: 0.1.0-beta.4
|
||||
version: 0.1.0-beta.4
|
||||
'@proj-airi/drizzle-duckdb-wasm':
|
||||
specifier: ^0.4.28
|
||||
@@ -230,9 +230,6 @@ importers:
|
||||
'@xsai/stream-text':
|
||||
specifier: 'catalog:'
|
||||
version: 0.3.0-beta.5
|
||||
defu:
|
||||
specifier: ^6.1.4
|
||||
version: 6.1.4
|
||||
es-toolkit:
|
||||
specifier: ^1.39.4
|
||||
version: 1.39.4
|
||||
@@ -354,9 +351,6 @@ importers:
|
||||
culori:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
defu:
|
||||
specifier: ^6.1.4
|
||||
version: 6.1.4
|
||||
drizzle-kit:
|
||||
specifier: ^0.31.2
|
||||
version: 0.31.2
|
||||
@@ -643,9 +637,6 @@ importers:
|
||||
culori:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
defu:
|
||||
specifier: ^6.1.4
|
||||
version: 6.1.4
|
||||
driver.js:
|
||||
specifier: ^1.3.6
|
||||
version: 1.3.6
|
||||
@@ -897,9 +888,6 @@ importers:
|
||||
crossws:
|
||||
specifier: ^0.4.1
|
||||
version: 0.4.1
|
||||
defu:
|
||||
specifier: ^6.1.4
|
||||
version: 6.1.4
|
||||
h3:
|
||||
specifier: ^1.15.3
|
||||
version: 1.15.3
|
||||
@@ -1056,9 +1044,6 @@ importers:
|
||||
culori:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
defu:
|
||||
specifier: ^6.1.4
|
||||
version: 6.1.4
|
||||
gpuu:
|
||||
specifier: ^1.0.4
|
||||
version: 1.0.4
|
||||
@@ -1492,12 +1477,12 @@ importers:
|
||||
'@modelcontextprotocol/sdk':
|
||||
specifier: ^1.13.1
|
||||
version: 1.13.1
|
||||
'@moeru/std':
|
||||
specifier: 'catalog:'
|
||||
version: 0.1.0-beta.4
|
||||
'@proj-airi/server-sdk':
|
||||
specifier: ^0.6.1
|
||||
version: 0.6.1
|
||||
defu:
|
||||
specifier: ^6.1.4
|
||||
version: 6.1.4
|
||||
dotenv:
|
||||
specifier: ^16.5.0
|
||||
version: 16.5.0
|
||||
|
||||
+15
-15
@@ -7,22 +7,22 @@ packages:
|
||||
- '!**/dist/**'
|
||||
|
||||
catalog:
|
||||
'@moeru/std': ^0.1.0-beta.4
|
||||
'@moeru/std': 0.1.0-beta.4
|
||||
'@proj-airi/drizzle-duckdb-wasm': ^0.4.28
|
||||
'@xsai-ext/providers-cloud': &xsai ^0.3.0-beta.5
|
||||
'@xsai-ext/providers-local': *xsai
|
||||
'@xsai-ext/shared-providers': *xsai
|
||||
'@xsai/embed': *xsai
|
||||
'@xsai/generate-speech': *xsai
|
||||
'@xsai/generate-text': *xsai
|
||||
'@xsai/generate-transcription': *xsai
|
||||
'@xsai/model': *xsai
|
||||
'@xsai/shared': *xsai
|
||||
'@xsai/shared-chat': *xsai
|
||||
'@xsai/stream-text': *xsai
|
||||
'@xsai/tool': *xsai
|
||||
'@xsai/utils-chat': *xsai
|
||||
xsschema: *xsai
|
||||
'@xsai-ext/providers-cloud': ^0.3.0-beta.5
|
||||
'@xsai-ext/providers-local': ^0.3.0-beta.5
|
||||
'@xsai-ext/shared-providers': ^0.3.0-beta.5
|
||||
'@xsai/embed': ^0.3.0-beta.5
|
||||
'@xsai/generate-speech': ^0.3.0-beta.5
|
||||
'@xsai/generate-text': ^0.3.0-beta.5
|
||||
'@xsai/generate-transcription': ^0.3.0-beta.5
|
||||
'@xsai/model': ^0.3.0-beta.5
|
||||
'@xsai/shared': ^0.3.0-beta.5
|
||||
'@xsai/shared-chat': ^0.3.0-beta.5
|
||||
'@xsai/stream-text': ^0.3.0-beta.5
|
||||
'@xsai/tool': ^0.3.0-beta.5
|
||||
'@xsai/utils-chat': ^0.3.0-beta.5
|
||||
xsschema: ^0.3.0-beta.5
|
||||
|
||||
catalogs:
|
||||
rolldown-vite:
|
||||
|
||||
@@ -2,11 +2,11 @@ import type { Agent, Neuri } from 'neuri'
|
||||
|
||||
import type { ChatHistory } from './types'
|
||||
|
||||
import { withRetry } from '@moeru/std'
|
||||
import { agent } from 'neuri'
|
||||
import { system, user } from 'neuri/openai'
|
||||
|
||||
import { config as appConfig } from '../../composables/config'
|
||||
import { toRetriable } from '../../utils/helper'
|
||||
import { useLogger } from '../../utils/logger'
|
||||
import { generateChatAgentPrompt } from './adapter'
|
||||
|
||||
@@ -56,13 +56,12 @@ export async function generateChatResponse(
|
||||
return content
|
||||
}
|
||||
|
||||
const retriableHandler = toRetriable<any, string>(
|
||||
config.retryLimit ?? 3,
|
||||
config.delayInterval ?? 1000,
|
||||
handleCompletion,
|
||||
)
|
||||
const retryHandler = withRetry<any, string>(handleCompletion, {
|
||||
retry: config.retryLimit ?? 3,
|
||||
retryDelay: config.delayInterval ?? 1000,
|
||||
})
|
||||
|
||||
return await retriableHandler(c)
|
||||
return await retryHandler(c)
|
||||
})
|
||||
|
||||
if (!content) {
|
||||
|
||||
@@ -3,9 +3,9 @@ import type { Neuri, NeuriContext } from 'neuri'
|
||||
import type { Logger } from '../../utils/logger'
|
||||
import type { MineflayerWithAgents } from './types'
|
||||
|
||||
import { withRetry } from '@moeru/std'
|
||||
import { system, user } from 'neuri/openai'
|
||||
|
||||
import { toRetriable } from '../../utils/helper'
|
||||
import { handleLLMCompletion } from './completion'
|
||||
import { generateStatusPrompt } from './prompt'
|
||||
|
||||
@@ -29,11 +29,13 @@ export async function handleChatMessage(username: string, message: string, bot:
|
||||
[...bot.memory.chatHistory, system(statusPrompt)],
|
||||
async (c: NeuriContext) => {
|
||||
logger.log('handling response...')
|
||||
return toRetriable<NeuriContext, string>(
|
||||
3,
|
||||
1000,
|
||||
return withRetry<NeuriContext, string>(
|
||||
ctx => handleLLMCompletion(ctx, bot, logger),
|
||||
{ onError: err => logger.withError(err).log('error occurred') },
|
||||
{
|
||||
retry: 3,
|
||||
retryDelay: 1000,
|
||||
onError: err => logger.withError(err).log('error occurred'),
|
||||
},
|
||||
)(c)
|
||||
},
|
||||
)
|
||||
|
||||
@@ -4,8 +4,9 @@ import type { ChatCompletion, Message } from 'neuri/openai'
|
||||
import type { Logger } from '../../utils/logger'
|
||||
import type { LLMConfig, LLMResponse } from './types'
|
||||
|
||||
import { withRetry } from '@moeru/std'
|
||||
|
||||
import { config } from '../../composables/config'
|
||||
import { toRetriable } from '../../utils/helper'
|
||||
import { useLogger } from '../../utils/logger'
|
||||
|
||||
export abstract class BaseLLMHandler {
|
||||
@@ -39,10 +40,9 @@ export abstract class BaseLLMHandler {
|
||||
}
|
||||
|
||||
protected createRetryHandler<T>(handler: (context: NeuriContext) => Promise<T>) {
|
||||
return toRetriable<NeuriContext, T>(
|
||||
this.config.retryLimit ?? 3,
|
||||
this.config.delayInterval ?? 1000,
|
||||
handler,
|
||||
)
|
||||
return withRetry<NeuriContext, T>(handler, {
|
||||
retry: this.config.retryLimit ?? 3,
|
||||
retryDelay: this.config.delayInterval ?? 1000,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import type { Neuri, NeuriContext } from 'neuri'
|
||||
import type { Logger } from '../../utils/logger'
|
||||
import type { MineflayerWithAgents } from './types'
|
||||
|
||||
import { withRetry } from '@moeru/std'
|
||||
import { system, user } from 'neuri/openai'
|
||||
|
||||
import { toRetriable } from '../../utils/helper'
|
||||
import { handleLLMCompletion } from './completion'
|
||||
import { generateStatusPrompt } from './prompt'
|
||||
|
||||
@@ -29,10 +29,12 @@ export async function handleVoiceInput(event: any, bot: MineflayerWithAgents, ag
|
||||
logger.log('Plan executed successfully')
|
||||
|
||||
// Generate response
|
||||
const retryHandler = toRetriable<NeuriContext, string>(
|
||||
3,
|
||||
1000,
|
||||
const retryHandler = withRetry<NeuriContext, string>(
|
||||
ctx => handleLLMCompletion(ctx, bot, logger),
|
||||
{
|
||||
retry: 3,
|
||||
retryDelay: 1000,
|
||||
},
|
||||
)
|
||||
|
||||
const content = await agent.handleStateless(
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { sleep } from '@moeru/std'
|
||||
|
||||
/**
|
||||
* Returns a retirable anonymous function with configured retryLimit and delayInterval
|
||||
*
|
||||
* @param retryLimit Number of retry attempts
|
||||
* @param delayInterval Delay between retries in milliseconds
|
||||
* @param func Function to be called
|
||||
* @returns A wrapped function with the same signature as func
|
||||
*/
|
||||
export function toRetriable<A, R>(
|
||||
retryLimit: number,
|
||||
delayInterval: number,
|
||||
func: (...args: A[]) => Promise<R>,
|
||||
hooks?: {
|
||||
onError?: (err: unknown) => void
|
||||
},
|
||||
): (...args: A[]) => Promise<R> {
|
||||
let retryCount = 0
|
||||
return async function (args: A): Promise<R> {
|
||||
try {
|
||||
return await func(args)
|
||||
}
|
||||
catch (err) {
|
||||
if (hooks?.onError) {
|
||||
hooks.onError(err)
|
||||
}
|
||||
|
||||
if (retryCount < retryLimit) {
|
||||
retryCount++
|
||||
await sleep(delayInterval)
|
||||
return await toRetriable(retryLimit - retryCount, delayInterval, func)(args)
|
||||
}
|
||||
else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@
|
||||
"@browserbasehq/stagehand": "^2.3.1",
|
||||
"@guiiai/logg": "^1.0.10",
|
||||
"@modelcontextprotocol/sdk": "^1.13.1",
|
||||
"@moeru/std": "catalog:",
|
||||
"@proj-airi/server-sdk": "^0.6.1",
|
||||
"defu": "^6.1.4",
|
||||
"dotenv": "^16.5.0",
|
||||
"h3": "^1.15.3",
|
||||
"listhen": "^1.9.0",
|
||||
|
||||
@@ -4,7 +4,7 @@ import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
|
||||
import { defu } from 'defu'
|
||||
import { merge } from '@moeru/std'
|
||||
import { config as configDotenv } from 'dotenv'
|
||||
|
||||
import { logger } from '../utils/logger'
|
||||
@@ -72,7 +72,7 @@ export class ConfigManager {
|
||||
|
||||
// Use defu to deeply merge configurations
|
||||
// Values in fileConfig take precedence over this.config
|
||||
this.config = defu(fileConfig, this.config)
|
||||
this.config = merge(this.config, fileConfig)
|
||||
|
||||
logger.config.log(`Configuration loaded from ${filePath}`)
|
||||
}
|
||||
@@ -93,7 +93,7 @@ export class ConfigManager {
|
||||
*/
|
||||
updateConfig(newConfig: Partial<Config>): void {
|
||||
// Use defu to merge new configuration
|
||||
this.config = defu(newConfig, this.config)
|
||||
this.config = merge(this.config, newConfig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user