chore(*): use @moeru/std & cleanup code, rename

This commit is contained in:
Neko Ayaka
2025-06-23 15:34:07 +08:00
parent ae98a39d8a
commit 50e05b114b
28 changed files with 55 additions and 192 deletions
+2
View File
@@ -60,6 +60,8 @@ export default defineConfig({
DownloadLive2DSDK(),
Download('https://dist.ayaka.moe/live2d-models/hiyori_free_zh.zip', 'hiyori_free_zh.zip', 'assets/live2d/models'),
Download('https://dist.ayaka.moe/live2d-models/hiyori_pro_zh.zip', 'hiyori_pro_zh.zip', 'assets/live2d/models'),
Download('https://dist.ayaka.moe/vrm-models/VRoid-Hub/AvatarSample-A/AvatarSample_A.vrm', 'AvatarSample_A.vrm', 'assets/vrm/models/AvatarSample-A'),
Download('https://dist.ayaka.moe/vrm-models/VRoid-Hub/AvatarSample-B/AvatarSample_B.vrm', 'AvatarSample_B.vrm', 'assets/vrm/models/AvatarSample-B'),
],
server: {
watch: {
+2 -1
View File
@@ -2,7 +2,8 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>アイリ</title>
<title>AIRI</title>
<description>Open source attempt to create cyber companion</description>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" sizes="any" />
<link rel="shortcut icon" href="/favicon.ico" />
+1
View File
@@ -20,6 +20,7 @@
"@formkit/auto-animate": "^0.8.2",
"@huggingface/transformers": "^3.5.2",
"@llama-flow/core": "^0.4.4",
"@moeru/std": "0.1.0-beta.1",
"@pixiv/three-vrm": "^3.4.1",
"@pixiv/three-vrm-animation": "^3.4.1",
"@pixiv/three-vrm-core": "^3.4.1",
@@ -19,8 +19,8 @@ const dark = useDark()
<template v-else>
<img :src="Logo" h-8 w-8 class="theme-colored">
</template>
<div font-cute>
<span>アイリ</span>
<div translate-y="[2px]" font-semibold font-quicksand>
<span>AIRI</span>
</div>
</RouterLink>
</template>
+1 -4
View File
@@ -1,11 +1,8 @@
<script setup lang="ts">
import { sleep } from '@moeru/std'
import { useQueue } from '@proj-airi/stage-ui/composables/queue'
import { onMounted, ref } from 'vue'
function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
const temp = ref<string>('')
const audioQueue = useQueue<string>({
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { sleep } from '@moeru/std'
import { Textarea } from '@proj-airi/ui'
import { ref } from 'vue'
@@ -6,10 +7,6 @@ const messageInput = ref<string>('')
const processing = ref<boolean>(false)
const streamingMessage = ref({ content: '' })
async function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function onSendMessage() {
processing.value = true
@@ -9,10 +9,6 @@ const messageInput = ref<string>('')
const ttsProcessed = ref<string[]>([])
const processing = ref<boolean>(false)
// async function sleep(ms: number) {
// return new Promise(resolve => setTimeout(resolve, ms))
// }
const ttsQueue = useQueue<string>({
handlers: [
async (ctx) => {
+13 -77
View File
@@ -1,5 +1,3 @@
import { Buffer } from 'node:buffer'
import { cp, mkdir, writeFile } from 'node:fs/promises'
import { join, resolve } from 'node:path'
import { env } from 'node:process'
@@ -9,7 +7,6 @@ import { DownloadLive2DSDK } from '@proj-airi/unplugin-live2d-sdk/vite'
import { templateCompilerOptions } from '@tresjs/core'
import Vue from '@vitejs/plugin-vue'
import { LFS, SpaceCard } from 'hfup/vite'
import { ofetch } from 'ofetch'
import Unocss from 'unocss/vite'
import VueMacros from 'unplugin-vue-macros/vite'
import VueRouter from 'unplugin-vue-router/vite'
@@ -18,15 +15,18 @@ import { VitePWA } from 'vite-plugin-pwa'
import VueDevTools from 'vite-plugin-vue-devtools'
import Layouts from 'vite-plugin-vue-layouts'
import { exists } from '../../scripts/fs'
export default defineConfig({
optimizeDeps: {
exclude: [
// Internal Packages
'@proj-airi/stage-ui/*',
'@proj-airi/drizzle-duckdb-wasm',
'@proj-airi/drizzle-duckdb-wasm/*',
// Static Assets: Models, Images, etc.
'public/assets/*',
// Live2D SDK
'@framework/live2dcubismframework',
'@framework/math/cubismmatrix44',
'@framework/type/csmvector',
@@ -74,6 +74,7 @@ export default defineConfig({
VueRouter({
extensions: ['.vue', '.md'],
dts: resolve(import.meta.dirname, 'src/typed-router.d.ts'),
importMode: 'async',
}),
// https://github.com/JohnCampionJr/vite-plugin-vue-layouts
@@ -143,79 +144,11 @@ export default defineConfig({
DownloadLive2DSDK(),
Download('https://dist.ayaka.moe/live2d-models/hiyori_free_zh.zip', 'hiyori_free_zh.zip', 'assets/live2d/models'),
Download('https://dist.ayaka.moe/live2d-models/hiyori_pro_zh.zip', 'hiyori_pro_zh.zip', 'assets/live2d/models'),
{
name: 'vrm-models-sample-a',
async configResolved(config) {
const cacheDir = resolve(join(config.root, '.cache'))
const publicDir = resolve(join(config.root, 'public'))
try {
if (!(await exists(resolve(join(cacheDir, 'assets/vrm/models/AvatarSample-A'))))) {
await mkdir(join(cacheDir, 'assets/vrm/models/AvatarSample-A'), { recursive: true })
console.log('Downloading VRM Model - Avatar Sample A...')
const res = await ofetch('https://dist.ayaka.moe/vrm-models/VRoid-Hub/AvatarSample-A/AvatarSample_A.vrm', { responseType: 'arrayBuffer' })
console.log('Saving VRM Model - Avatar Sample A...')
await writeFile(join(cacheDir, 'assets/vrm/models/AvatarSample-A/AvatarSample_A.vrm'), Buffer.from(res))
console.log('VRM Model - Avatar Sample A downloaded and saved.')
}
if (!(await exists(resolve(join(publicDir, 'assets/vrm/models/AvatarSample-A'))))) {
await mkdir(join(publicDir, 'assets/vrm/models/AvatarSample-A'), { recursive: true }).catch(() => { })
await cp(join(cacheDir, 'assets/vrm/models/AvatarSample-A'), join(publicDir, 'assets/vrm/models/AvatarSample-A'), { recursive: true })
}
}
catch (err) {
console.error(err)
throw err
}
},
},
{
name: 'vrm-models-sample-b',
async configResolved(config) {
const cacheDir = resolve(join(config.root, '.cache'))
const publicDir = resolve(join(config.root, 'public'))
try {
if (!(await exists(resolve(join(cacheDir, 'assets/vrm/models/AvatarSample-B'))))) {
await mkdir(join(cacheDir, 'assets/vrm/models/AvatarSample-B'), { recursive: true })
console.log('Downloading VRM Model - Avatar Sample B...')
const res = await ofetch('https://dist.ayaka.moe/vrm-models/VRoid-Hub/AvatarSample-B/AvatarSample_B.vrm', { responseType: 'arrayBuffer' })
console.log('Saving VRM Model - Avatar Sample B...')
await writeFile(join(cacheDir, 'assets/vrm/models/AvatarSample-B/AvatarSample_B.vrm'), Buffer.from(res))
}
if (!(await exists(resolve(join(publicDir, 'assets/vrm/models/AvatarSample-B'))))) {
await mkdir(join(publicDir, 'assets/vrm/models/AvatarSample-B'), { recursive: true }).catch(() => { })
await cp(join(cacheDir, 'assets/vrm/models/AvatarSample-B'), join(publicDir, 'assets/vrm/models/AvatarSample-B'), { recursive: true })
}
}
catch (err) {
console.error(err)
throw err
}
},
},
Download('https://dist.ayaka.moe/vrm-models/VRoid-Hub/AvatarSample-A/AvatarSample_A.vrm', 'AvatarSample_A.vrm', 'assets/vrm/models/AvatarSample-A'),
Download('https://dist.ayaka.moe/vrm-models/VRoid-Hub/AvatarSample-B/AvatarSample_B.vrm', 'AvatarSample_B.vrm', 'assets/vrm/models/AvatarSample-B'),
// HuggingFace Spaces
LFS({
extraGlobs: [
'*.vrm',
'*.cmo3',
'*.png',
'*.jpg',
'*.jpeg',
'*.gif',
'*.webp',
'*.bmp',
],
}),
LFS({ extraGlobs: ['*.vrm', '*.cmo3', '*.png', '*.jpg', '*.jpeg', '*.gif', '*.webp', '*.bmp'] }),
SpaceCard({
title: 'アイリ VTuber',
emoji: '🧸',
@@ -224,7 +157,10 @@ export default defineConfig({
sdk: 'static',
pinned: false,
license: 'mit',
models: ['onnx-community/whisper-base'],
models: [
'onnx-community/whisper-base',
'onnx-community/silero-vad',
],
short_description: 'アイリ VTuber. LLM powered Live2D/VRM living character.',
}),
],
+3
View File
@@ -40,5 +40,8 @@
"@proj-airi/server-shared": "workspace:^",
"crossws": "^0.4.1",
"defu": "^6.1.4"
},
"devDependencies": {
"@moeru/std": "0.1.0-beta.1"
}
}
+1 -2
View File
@@ -1,10 +1,9 @@
import type { WebSocketBaseEvent, WebSocketEvent, WebSocketEvents } from '@proj-airi/server-shared/types'
import { sleep } from '@moeru/std'
import WebSocket from 'crossws/websocket'
import { defu } from 'defu'
import { sleep } from './utils'
export interface ClientOptions<C = undefined> {
url?: string
name: string
@@ -1,3 +0,0 @@
export function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}
-1
View File
@@ -1 +0,0 @@
export * from './concurrency'
+1
View File
@@ -104,6 +104,7 @@
},
"devDependencies": {
"@histoire/plugin-vue": "1.0.0-alpha.2",
"@moeru/std": "0.1.0-beta.1",
"@types/culori": "^4.0.0",
"@types/three": "^0.177.0",
"@unocss/reset": "^66.2.3",
+1 -4
View File
@@ -1,6 +1,7 @@
import type { Emotion } from '../constants/emotions'
import type { UseQueueReturn } from './queue'
import { sleep } from '@moeru/std'
import { ref } from 'vue'
import { llmInferenceEndToken } from '../constants'
@@ -86,10 +87,6 @@ export function useDelayMessageQueue() {
}
}
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}
return useQueue<string>({
handlers: [
async (ctx) => {
+16
View File
@@ -547,6 +547,9 @@ importers:
'@llama-flow/core':
specifier: ^0.4.4
version: 0.4.4(@modelcontextprotocol/sdk@1.13.0)(zod@3.25.67)
'@moeru/std':
specifier: 0.1.0-beta.1
version: 0.1.0-beta.1
'@pixiv/three-vrm':
specifier: ^3.4.1
version: 3.4.1(three@0.177.0)
@@ -909,6 +912,10 @@ importers:
defu:
specifier: ^6.1.4
version: 6.1.4
devDependencies:
'@moeru/std':
specifier: 0.1.0-beta.1
version: 0.1.0-beta.1
packages/server-shared: {}
@@ -1116,6 +1123,9 @@ importers:
'@histoire/plugin-vue':
specifier: 1.0.0-alpha.2
version: 1.0.0-alpha.2(histoire@1.0.0-alpha.2(@types/node@24.0.3)(bufferutil@4.0.9)(less@4.3.0)(lightningcss@1.30.1)(terser@5.17.6)(utf-8-validate@5.0.10)(vite@6.3.5(@types/node@24.0.3)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(terser@5.17.6)(tsx@4.20.3)(yaml@2.8.0)))(vite@6.3.5(@types/node@24.0.3)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(terser@5.17.6)(tsx@4.20.3)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
'@moeru/std':
specifier: 0.1.0-beta.1
version: 0.1.0-beta.1
'@types/culori':
specifier: ^4.0.0
version: 4.0.0
@@ -1300,6 +1310,9 @@ importers:
'@guiiai/logg':
specifier: ^1.0.10
version: 1.0.10
'@moeru/std':
specifier: 0.1.0-beta.1
version: 0.1.0-beta.1
'@proj-airi/server-sdk':
specifier: ^0.6.1
version: 0.6.1
@@ -1391,6 +1404,9 @@ importers:
'@guiiai/logg':
specifier: ^1.0.10
version: 1.0.10
'@moeru/std':
specifier: 0.1.0-beta.1
version: 0.1.0-beta.1
'@xsai-ext/providers-cloud':
specifier: 'catalog:'
version: 0.3.0-beta.4
-25
View File
@@ -1,25 +0,0 @@
import { stat } from 'node:fs/promises'
export async function exists(path: string) {
try {
await stat(path)
return true
}
catch (error) {
if (isENOENTError(error))
return false
throw error
}
}
export function isENOENTError(error: unknown): boolean {
if (!(error instanceof Error))
return false
if (!('code' in error))
return false
if (error.code !== 'ENOENT')
return false
return true
}
+1
View File
@@ -13,6 +13,7 @@
},
"dependencies": {
"@guiiai/logg": "^1.0.10",
"@moeru/std": "0.1.0-beta.1",
"@proj-airi/server-sdk": "^0.6.1",
"awilix": "^12.0.5",
"es-toolkit": "^1.39.3",
@@ -1,3 +1,4 @@
import { sleep } from '@moeru/std'
import { messages, system, user } from 'neuri/openai'
import { beforeAll, describe, expect, it } from 'vitest'
@@ -5,7 +6,6 @@ import { initBot, useBot } from '../../composables/bot'
import { config, initEnv } from '../../composables/config'
import { createNeuriAgent } from '../../composables/neuri'
import { generateActionAgentPrompt } from '../../libs/llm-agent/prompt'
import { sleep } from '../../utils/helper'
import { initLogger } from '../../utils/logger'
describe('actions agent', { timeout: 0 }, () => {
@@ -1,6 +1,7 @@
import type { Mineflayer } from '../../libs/mineflayer'
import { sleep } from '../../utils/helper'
import { sleep } from '@moeru/std'
import { useLogger } from '../../utils/logger'
import { breakBlockAt } from '../blocks'
import { goToPosition, moveAway } from '../movement'
@@ -3,10 +3,10 @@ import type { Block } from 'prismarine-block'
import type { Mineflayer } from '../../libs/mineflayer'
import { sleep } from '@moeru/std'
import pathfinder from 'mineflayer-pathfinder'
import { Vec3 } from 'vec3'
import { sleep } from '../../utils/helper'
import { useLogger } from '../../utils/logger'
import { getNearestBlock, makeItem } from '../../utils/mcdata'
import { goToPosition } from '../movement'
+1 -1
View File
@@ -3,9 +3,9 @@ import type { Item } from 'prismarine-item'
import type { Mineflayer } from '../libs/mineflayer'
import { sleep } from '@moeru/std'
import pathfinderModel from 'mineflayer-pathfinder'
import { sleep } from '../utils/helper'
import { isHostile } from '../utils/mcdata'
import { log } from './base'
import { getNearbyEntities, getNearestEntityWhere } from './world'
+1 -1
View File
@@ -2,11 +2,11 @@ import type { Entity } from 'prismarine-entity'
import type { Mineflayer } from '../libs/mineflayer'
import { sleep } from '@moeru/std'
import { randomInt } from 'es-toolkit'
import pathfinder from 'mineflayer-pathfinder'
import { Vec3 } from 'vec3'
import { sleep } from '../utils/helper'
import { useLogger } from '../utils/logger'
import { log } from './base'
import { getNearestBlock, getNearestEntityWhere } from './world'
+1 -1
View File
@@ -1,4 +1,4 @@
export const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
import { sleep } from '@moeru/std'
/**
* Returns a retirable anonymous function with configured retryLimit and delayInterval
+1
View File
@@ -26,6 +26,7 @@
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@grammyjs/files": "^1.1.1",
"@guiiai/logg": "^1.0.10",
"@moeru/std": "0.1.0-beta.1",
"@xsai-ext/providers-cloud": "catalog:",
"@xsai/embed": "catalog:",
"@xsai/generate-text": "catalog:",
@@ -3,12 +3,13 @@ import type { Message } from 'grammy/types'
import type { BotSelf } from '../../../types'
import { useLogg } from '@guiiai/logg'
import { sleep } from '@moeru/std'
import { parse } from 'best-effort-json-parser'
import { randomInt } from 'es-toolkit'
import { recordMessage } from '../../../models'
import { listJoinedChats } from '../../../models/chats'
import { cancellable, sleep } from '../../../utils/promise'
import { cancellable } from '../../../utils/promise'
export function parseMayStructuredMessage(responseText: string) {
const logger = useLogg('parseMayStructuredMessage').useGlobalConfig()
-25
View File
@@ -1,25 +0,0 @@
import { stat } from 'node:fs/promises'
export async function exists(path: string) {
try {
await stat(path)
return true
}
catch (error) {
if (isENOENTError(error))
return false
throw error
}
}
export function isENOENTError(error: unknown): boolean {
if (!(error instanceof Error))
return false
if (!('code' in error))
return false
if (error.code !== 'ENOENT')
return false
return true
}
@@ -1,9 +1,3 @@
export function sleep(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
export interface CancellablePromise<T> {
promise: Promise<T>
cancel: () => void
-27
View File
@@ -1,27 +0,0 @@
const timerMap = new Map()
export function setClockInterval(func: (...args: any[]) => any, interval: number) {
let start: number
let tick: number
let clockTimer: ReturnType<typeof setTimeout>
const timerId = Math.floor(Math.random() * 1e10)
const recurFunc = () => {
func()
const realExecuteTime = new Date().getTime()
if (!start) {
start = realExecuteTime
}
tick = tick || start
const diff = realExecuteTime - tick
tick += interval
// Since setTimeout is not accurate, we need to adjust the interval
clockTimer = setTimeout(recurFunc, interval - diff)
timerMap.set(timerId, clockTimer)
}
recurFunc()
return timerId
}