refactor: have stage-ui dedicated (#11)

* tmp commit
* now it works
* fix: various of type and import issues
* refactor: move test
* refactor: rename with stage- prefix
* refactor: all monorepo packages
* refactor: fix all build
* refactor: fix missing dep
* fix: remove unnecessary deps
* fix: netlify publish
* fix: hf space deploy

---------

Co-authored-by: LemonNeko <chheese048@gmail.com>
This commit is contained in:
Neko
2025-01-09 20:41:53 +08:00
committed by GitHub
co-authored by LemonNeko
parent 1ba0588569
commit acf0d63ae0
161 changed files with 3168 additions and 1730 deletions
@@ -27,7 +27,7 @@ jobs:
HF_USERNAME: ${{ secrets.HF_USERNAME }} HF_USERNAME: ${{ secrets.HF_USERNAME }}
- run: |- - run: |-
git clone https://$HF_USERNAME:$HF_TOKEN@huggingface.co/spaces/moeru-ai/airi --depth 1 packages/stage/dist git clone https://$HF_USERNAME:$HF_TOKEN@huggingface.co/spaces/moeru-ai/airi --depth 1 packages/stage-web/dist
env: env:
HF_TOKEN: ${{ secrets.HF_TOKEN }} HF_TOKEN: ${{ secrets.HF_TOKEN }}
HF_USERNAME: ${{ secrets.HF_USERNAME }} HF_USERNAME: ${{ secrets.HF_USERNAME }}
@@ -87,7 +87,7 @@ jobs:
git push -f git push -f
- id: airi_diff - id: airi_diff
working-directory: ./packages/stage/dist working-directory: ./packages/stage-web/dist
run: |- run: |-
git lfs ls-files --all git lfs ls-files --all
git add . git add .
@@ -96,7 +96,7 @@ jobs:
fi fi
- if: steps.airi_diff.outputs.changes == 'true' - if: steps.airi_diff.outputs.changes == 'true'
working-directory: ./packages/stage/dist working-directory: ./packages/stage-web/dist
env: env:
HF_TOKEN: ${{ secrets.HF_TOKEN }} HF_TOKEN: ${{ secrets.HF_TOKEN }}
HF_USERNAME: ${{ secrets.HF_USERNAME }} HF_USERNAME: ${{ secrets.HF_USERNAME }}
+2
View File
@@ -8,6 +8,7 @@ words:
- airi - airi
- airi-vtuber - airi-vtuber
- Attributify - Attributify
- audioworklet
- Ayaka - Ayaka
- Bitstream - Bitstream
- bumpp - bumpp
@@ -55,6 +56,7 @@ words:
- logg - logg
- Maru - Maru
- micvad - micvad
- mkdist
- Morioki - Morioki
- Myriam - Myriam
- Neko - Neko
+13 -13
View File
@@ -1,7 +1,7 @@
{ {
"name": "airi-vtuber", "name": "airi-vtuber",
"type": "module", "type": "module",
"packageManager": "pnpm@9.15.2", "packageManager": "pnpm@9.15.3",
"description": "LLM powered virtual character", "description": "LLM powered virtual character",
"author": { "author": {
"name": "Neko Ayaka", "name": "Neko Ayaka",
@@ -28,27 +28,27 @@
"sizecheck": "npx vite-bundle-visualizer" "sizecheck": "npx vite-bundle-visualizer"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^3.12.1", "@antfu/eslint-config": "^3.13.0",
"@antfu/ni": "^0.23.2", "@antfu/ni": "^23.2.0",
"@cspell/dict-ru_ru": "^2.2.4", "@cspell/dict-ru_ru": "^2.2.4",
"@types/node": "^22.10.5", "@types/node": "^22.10.5",
"@unocss/eslint-config": "^0.65.3", "@unocss/eslint-config": "^0.65.4",
"@unocss/eslint-plugin": "^0.65.3", "@unocss/eslint-plugin": "^0.65.4",
"bumpp": "^9.9.2", "bumpp": "^9.10.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^9.17.0", "eslint": "^9.17.0",
"eslint-plugin-cypress": "^4.1.0", "eslint-plugin-cypress": "^4.1.0",
"eslint-plugin-format": "^0.1.3", "eslint-plugin-format": "^1.0.1",
"lint-staged": "^15.3.0", "lint-staged": "^15.3.0",
"pnpm": "^9.15.2", "pnpm": "^9.15.3",
"rollup": "^4.29.1", "rollup": "^4.30.1",
"simple-git-hooks": "^2.11.1", "simple-git-hooks": "^2.11.1",
"taze": "^0.18.0", "taze": "^18.1.0",
"typescript": "~5.7.2", "typescript": "~5.7.3",
"unbuild": "3.0.0-rc.11", "unbuild": "3.0.0-rc.11",
"unocss": "^0.65.3", "unocss": "^0.65.4",
"vite": "^6.0.7", "vite": "^6.0.7",
"vite-plugin-inspect": "^0.10.6", "vite-plugin-inspect": "^10.0.6",
"vitest": "^2.1.8" "vitest": "^2.1.8"
}, },
"workspaces": [ "workspaces": [
+5
View File
@@ -16,6 +16,11 @@
"directory": "packages/huggingspace" "directory": "packages/huggingspace"
}, },
"exports": { "exports": {
".": {
"types": "./dist/vite/index.d.ts",
"import": "./dist/vite/index.mjs",
"require": "./dist/vite/index.cjs"
},
"./vite": { "./vite": {
"types": "./dist/vite/index.d.ts", "types": "./dist/vite/index.d.ts",
"import": "./dist/vite/index.mjs", "import": "./dist/vite/index.mjs",
+3 -3
View File
@@ -2,7 +2,7 @@
"name": "@proj-airi/moonshine-web", "name": "@proj-airi/moonshine-web",
"type": "module", "type": "module",
"private": true, "private": true,
"packageManager": "pnpm@9.15.2", "packageManager": "pnpm@9.15.3",
"description": "Yet another WebGPU based STT + VAD with Moonshine model re-implemented", "description": "Yet another WebGPU based STT + VAD with Moonshine model re-implemented",
"author": { "author": {
"name": "Neko Ayaka", "name": "Neko Ayaka",
@@ -19,7 +19,7 @@
}, },
"dependencies": { "dependencies": {
"@tresjs/core": "^4.3.2", "@tresjs/core": "^4.3.2",
"@unocss/reset": "^0.65.3", "@unocss/reset": "^0.65.4",
"@vueuse/core": "^12.3.0", "@vueuse/core": "^12.3.0",
"@vueuse/motion": "^2.2.6", "@vueuse/motion": "^2.2.6",
"ofetch": "^1.4.1", "ofetch": "^1.4.1",
@@ -29,7 +29,7 @@
"devDependencies": { "devDependencies": {
"@huggingface/transformers": "^3.2.4", "@huggingface/transformers": "^3.2.4",
"@types/audioworklet": "^0.0.65", "@types/audioworklet": "^0.0.65",
"@types/three": "^0.171.0", "@types/three": "^0.172.0",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@webgpu/types": "^0.1.52", "@webgpu/types": "^0.1.52",
"hfup": "workspace:^", "hfup": "workspace:^",

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,36 @@
import { join, resolve } from 'node:path'
import { Download } from '@proj-airi/unplugin-download'
import { DownloadLive2DSDK } from '@proj-airi/unplugin-live2d-sdk'
import vue from '@vitejs/plugin-vue'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import unocss from 'unocss/vite'
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()],
},
preload: {
plugins: [externalizeDepsPlugin()],
},
renderer: {
optimizeDeps: {
exclude: [
'@proj-airi/stage-ui/*',
],
},
resolve: {
alias: {
'@renderer': resolve(join('src', 'renderer', 'src')),
'@proj-airi/stage-ui': resolve(join(import.meta.dirname, '..', 'stage-ui', 'dist')),
'@proj-airi/stage-ui/stores': resolve(join(import.meta.dirname, '..', 'stage-ui', 'dist', 'stores')),
},
},
plugins: [
vue(),
unocss(),
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'),
],
},
})
+121
View File
@@ -0,0 +1,121 @@
{
"name": "@proj-airi/stage-tamagotchi",
"version": "1.0.0",
"description": "An Electron application with Vue and TypeScript",
"author": "LemonNekoGH",
"homepage": "https://electron-vite.org",
"main": "./out/main/index.js",
"scripts": {
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"start": "electron-vite preview",
"dev": "electron-vite dev",
"build": "npm run typecheck && electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir",
"build:win": "npm run build && electron-builder --win",
"build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux"
},
"dependencies": {
"@11labs/client": "^0.0.4",
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^3.0.0",
"@formkit/auto-animate": "^0.8.2",
"@gcornut/valibot-json-schema": "^0.42.0",
"@huggingface/transformers": "^3.2.4",
"@pixi/app": "6",
"@pixi/constants": "6",
"@pixi/core": "6",
"@pixi/display": "6",
"@pixi/extensions": "6",
"@pixi/loaders": "6",
"@pixi/math": "6",
"@pixi/runner": "6",
"@pixi/settings": "6",
"@pixi/sprite": "6",
"@pixi/ticker": "6",
"@pixi/utils": "6",
"@pixiv/three-vrm": "^3.3.2",
"@pixiv/three-vrm-animation": "^3.3.2",
"@pixiv/three-vrm-core": "^3.3.2",
"@proj-airi/stage-ui": "workspace:^",
"@ricky0123/vad-web": "^0.0.22",
"@tresjs/cientos": "^4.0.3",
"@tresjs/core": "^4.3.2",
"@types/yauzl": "^2.10.3",
"@typeschema/valibot": "^0.14.0",
"@unhead/vue": "^1.11.15",
"@unocss/reset": "^0.65.4",
"@vueuse/core": "^12.3.0",
"@vueuse/head": "^2.0.0",
"@vueuse/shared": "^12.3.0",
"@xsai/generate-speech": "^0.0.24",
"@xsai/generate-text": "^0.0.24",
"@xsai/model": "^0.0.24",
"@xsai/providers": "^0.0.24",
"@xsai/shared-chat": "^0.0.24",
"@xsai/stream-text": "^0.0.24",
"defu": "^6.1.4",
"jszip": "^3.10.1",
"nprogress": "^0.2.0",
"ofetch": "^1.4.1",
"onnxruntime-web": "^1.20.1",
"pinia": "^2.3.0",
"pixi-filters": "^4.2.0",
"pixi-live2d-display": "^0.4.0",
"rehype-stringify": "^10.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.1",
"shiki": "^1.26.1",
"three": "^0.172.0",
"unified": "^11.0.5",
"valibot": "1.0.0-beta.9",
"vaul-vue": "^0.2.0",
"vue": "^3.5.13",
"vue-demi": "^0.14.10",
"vue-i18n": "^11.0.1",
"vue-router": "^4.5.0",
"yauzl": "^3.2.0",
"zod": "^3.24.1"
},
"devDependencies": {
"@electron-toolkit/tsconfig": "^1.0.1",
"@iconify-json/carbon": "^1.2.5",
"@iconify-json/eos-icons": "^1.2.2",
"@iconify-json/lucide": "^1.2.22",
"@iconify-json/mingcute": "^1.2.3",
"@iconify-json/solar": "^1.2.2",
"@iconify-json/svg-spinners": "^1.2.2",
"@intlify/unplugin-vue-i18n": "^6.0.3",
"@proj-airi/elevenlabs": "workspace:^",
"@proj-airi/unplugin-download": "workspace:^",
"@proj-airi/unplugin-live2d-sdk": "workspace:^",
"@shikijs/markdown-it": "^1.26.1",
"@types/markdown-it-link-attributes": "^3.0.5",
"@types/nprogress": "^0.2.3",
"@types/three": "^0.172.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vue-macros/volar": "^0.30.9",
"@vueuse/motion": "^2.2.6",
"electron": "^31.7.6",
"electron-builder": "^24.13.3",
"electron-vite": "^2.3.0",
"markdown-it-link-attributes": "^4.0.1",
"unocss-preset-animations": "^1.1.0",
"unocss-preset-shadcn": "^0.3.1",
"unocss-preset-theme": "^0.14.1",
"unplugin-auto-import": "^19.0.0",
"unplugin-vue-components": "^28.0.0",
"unplugin-vue-macros": "^2.13.7",
"unplugin-vue-markdown": "^28.0.0",
"unplugin-vue-router": "^0.10.9",
"vite-bundle-visualizer": "^1.2.1",
"vite-plugin-pwa": "^0.21.1",
"vite-plugin-vue-devtools": "^7.7.0",
"vite-plugin-vue-layouts": "^0.11.0",
"vite-plugin-webfont-dl": "^3.10.4",
"vue-tsc": "^2.2.0"
}
}
@@ -1,6 +1,5 @@
import { readFileSync } from 'node:fs'
import { join } from 'node:path' import { join } from 'node:path'
import { platform } from 'node:process' import { env, platform } from 'node:process'
import { electronApp, is, optimizer } from '@electron-toolkit/utils' import { electronApp, is, optimizer } from '@electron-toolkit/utils'
import { app, BrowserWindow, ipcMain, shell } from 'electron' import { app, BrowserWindow, ipcMain, shell } from 'electron'
import icon from '../../build/icon.png?asset' import icon from '../../build/icon.png?asset'
@@ -38,13 +37,8 @@ function createWindow(): void {
// HMR for renderer base on electron-vite cli. // HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production. // Load the remote URL for development or the local html file for production.
if (is.dev) { if (is.dev && env.ELECTRON_RENDERER_URL) {
// try to read port number from stage.dev.json mainWindow.loadURL(env.ELECTRON_RENDERER_URL)
const devFile = readFileSync(join(import.meta.dirname, '../../../stage/stage.dev.json'), 'utf-8')
const devInfo = JSON.parse(devFile) as { address: { address: string, family: string, port: number } }
mainWindow.loadURL(`http://localhost:${devInfo.address.port}`).catch((e) => {
console.error('Failed to load URL', e)
})
} }
else { else {
mainWindow.loadFile(join(import.meta.dirname, '..', '..', 'out', 'renderer', 'index.html')) mainWindow.loadFile(join(import.meta.dirname, '..', '..', 'out', 'renderer', 'index.html'))
@@ -0,0 +1,26 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>アイリ</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self';
script-src-elem 'self' 'unsafe-eval' https://cdn.jsdelivr.net/;
script-src 'self' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob:;
font-src 'self' https://fonts.gstatic.com/;
connect-src 'self' https://cdn.jsdelivr.net/ blob: https://openrouter.ai/"
/>
<script src="/assets/js/CubismSdkForWeb-5-r.1/Core/live2dcubismcore.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { WidgetStage } from '@proj-airi/stage-ui/components'
import { ref } from 'vue' import { ref } from 'vue'
import TamagotchiInteractiveArea from '../src/components/Layouts/TamagotchiInteractiveArea.vue' import InteractiveArea from './components/InteractiveArea.vue'
import Stage from '../src/components/Widgets/Stage.vue'
const dragDelay = ref(0) const dragDelay = ref(0)
const isDragging = ref(false) const isDragging = ref(false)
@@ -31,8 +31,8 @@ function handleMouseMove(event: MouseEvent) {
<template> <template>
<div relative max-h="[100vh]" max-w="[100vw]" p="2" flex="~ col" z-2 h-full overflow-hidden @mousedown="handleMouseDown" @mouseup="handleMouseUp" @mousemove="handleMouseMove" @mouseleave="handleMouseLeave"> <div relative max-h="[100vh]" max-w="[100vw]" p="2" flex="~ col" z-2 h-full overflow-hidden @mousedown="handleMouseDown" @mouseup="handleMouseUp" @mousemove="handleMouseMove" @mouseleave="handleMouseLeave">
<div relative h-full w-full items-end gap-2 class="view"> <div relative h-full w-full items-end gap-2 class="view">
<Stage h-full w-full flex-1 mb="<md:18" /> <WidgetStage h-full w-full flex-1 mb="<md:18" />
<TamagotchiInteractiveArea class="interaction-area block" pointer-events-none absolute bottom-0 w-full opacity-0 transition="opacity duration-250" /> <InteractiveArea class="interaction-area block" pointer-events-none absolute bottom-0 w-full opacity-0 transition="opacity duration-250" />
</div> </div>
</div> </div>
</template> </template>
@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { useMarkdown } from '@proj-airi/stage-ui/composables'
import { useChatStore } from '@proj-airi/stage-ui/stores'
import { useElementBounding, useScroll } from '@vueuse/core' import { useElementBounding, useScroll } from '@vueuse/core'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { nextTick, ref } from 'vue' import { nextTick, ref } from 'vue'
import { useMarkdown } from '../../composables/markdown'
import { useChatStore } from '../../stores/chat'
const chatHistoryRef = ref<HTMLDivElement>() const chatHistoryRef = ref<HTMLDivElement>()
@@ -1,18 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { BasicTextarea } from '@proj-airi/stage-ui/components'
import { useMicVAD } from '@proj-airi/stage-ui/composables'
// import { useAudioContext } from '../../stores/audio'
import { useChatStore, useSettings } from '@proj-airi/stage-ui/stores'
// import { useDevicesList } from '@vueuse/core' // import { useDevicesList } from '@vueuse/core'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { DrawerContent, DrawerPortal, DrawerRoot, DrawerTrigger } from 'vaul-vue' import { DrawerContent, DrawerPortal, DrawerRoot, DrawerTrigger } from 'vaul-vue'
import { onMounted, ref, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import TamagotchiChatHistory from './ChatHistory.vue'
import { useMicVAD } from '../../composables/micvad' import TamagotchiSettings from './Settings.vue'
// import { useAudioContext } from '../../stores/audio'
import { useChatStore } from '../../stores/chat'
import { useSettings } from '../../stores/settings'
import BasicTextarea from '../BasicTextarea.vue'
import TamagotchiChatHistory from '../Widgets/TamagotchiChatHistory.vue'
import TamagotchiSettings from '../Widgets/TamagotchiSettings.vue'
const messageInput = ref('') const messageInput = ref('')
const listening = ref(false) const listening = ref(false)
@@ -1,13 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Voice } from '../../constants/elevenlabs' import type { Voice } from '@proj-airi/stage-ui/constants'
import { voiceList } from '@proj-airi/stage-ui/constants'
import { useLLM, useSettings } from '@proj-airi/stage-ui/stores'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { onMounted, ref, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { voiceList } from '../../constants/elevenlabs'
import { useLLM } from '../../stores/llm'
import { useSettings } from '../../stores/settings'
const { t, locale } = useI18n() const { t, locale } = useI18n()
const settings = useSettings() const settings = useSettings()
@@ -3,7 +3,7 @@ import Tres from '@tresjs/core'
import { MotionPlugin } from '@vueuse/motion' import { MotionPlugin } from '@vueuse/motion'
import { createPinia } from 'pinia' import { createPinia } from 'pinia'
import { createApp } from 'vue' import { createApp } from 'vue'
import { i18n } from '../src/modules/i18n' import { createI18n } from 'vue-i18n'
import App from './App.vue' import App from './App.vue'
import '@unocss/reset/tailwind.css' import '@unocss/reset/tailwind.css'
@@ -12,6 +12,16 @@ import './main.css'
const pinia = createPinia() const pinia = createPinia()
// TODO: messages
const i18n = createI18n({
locale: 'en',
messages: {
en: {
hello: 'Hello, world!',
},
},
})
createApp(App) createApp(App)
.use(MotionPlugin) .use(MotionPlugin)
.use(autoAnimatePlugin) .use(autoAnimatePlugin)
@@ -0,0 +1,6 @@
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<object, object, any>
export default component
}
+7
View File
@@ -0,0 +1,7 @@
{
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.web.json" }
],
"files": []
}
@@ -4,5 +4,10 @@
"composite": true, "composite": true,
"types": ["electron-vite/node"] "types": ["electron-vite/node"]
}, },
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"] "include": [
"electron.vite.config.*",
"src/main/**/*",
"src/preload/**/*",
"../../vite-plugins/**/*"
]
} }
@@ -1,8 +1,13 @@
{ {
"extends": "@electron-toolkit/tsconfig/tsconfig.web.json", "extends": [
"@electron-toolkit/tsconfig/tsconfig.web.json",
"../../tsconfig.json"
],
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"baseUrl": ".", "baseUrl": ".",
"module": "ESNext",
"moduleResolution": "bundler",
"paths": { "paths": {
"@renderer/*": [ "@renderer/*": [
"src/renderer/src/*" "src/renderer/src/*"
@@ -10,7 +15,7 @@
} }
}, },
"include": [ "include": [
"src/renderer/src/env.d.ts", "src/renderer/src/shims.ts",
"src/renderer/src/**/*", "src/renderer/src/**/*",
"src/renderer/src/**/*.vue", "src/renderer/src/**/*.vue",
"src/preload/*.d.ts" "src/preload/*.d.ts"
+16
View File
@@ -0,0 +1,16 @@
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
entries: [
{ builder: 'mkdist', input: './src/components/', outDir: './dist/components', pattern: '**/*.vue', loaders: ['vue'] },
{ builder: 'mkdist', input: './src/components/', outDir: './dist/components', pattern: '**/*.ts', format: 'esm', loaders: ['js'] },
{ builder: 'mkdist', input: './src/stores/', outDir: './dist/stores', pattern: '**/*.ts', format: 'esm', loaders: ['js'] },
{ builder: 'mkdist', input: './src/constants/', outDir: './dist/constants', pattern: '**/*.ts', format: 'esm', loaders: ['js'] },
{ builder: 'mkdist', input: './src/composables/', outDir: './dist/composables', pattern: '**/*.ts', format: 'esm', loaders: ['js'] },
{ builder: 'mkdist', input: './src/utils/', outDir: './dist/utils', pattern: '**/*.ts', format: 'esm', loaders: ['js'] },
{ builder: 'mkdist', input: './src/libs/', outDir: './dist/libs', pattern: '**/*.ts', format: 'esm', loaders: ['js'] },
],
declaration: true,
sourcemap: true,
clean: true,
})
+54
View File
@@ -0,0 +1,54 @@
{
"name": "@proj-airi/stage-ui",
"type": "module",
"private": true,
"packageManager": "pnpm@9.15.3",
"description": "Shared core for stage",
"author": {
"name": "Neko Ayaka",
"email": "neko@ayaka.moe",
"url": "https://github.com/nekomeowww"
},
"license": "MIT",
"exports": {
"./constants": {
"types": "./dist/constants/index.d.ts",
"import": "./dist/constants/index.mjs"
},
"./components": {
"types": "./dist/components/index.d.ts",
"import": "./dist/components/index.mjs"
},
"./stores": {
"types": "./dist/stores/index.d.ts",
"import": "./dist/stores/index.mjs"
},
".": {
"types": "./dist/components/index.d.ts",
"import": "./dist/components/index.mjs"
},
"./composables": {
"types": "./dist/composables/index.d.ts",
"import": "./dist/composables/index.mjs"
},
"./utils": {
"types": "./dist/utils/index.d.ts",
"import": "./dist/utils/index.mjs"
},
"./libs": {
"types": "./dist/libs/index.d.ts",
"import": "./dist/libs/index.mjs"
}
},
"module": "./dist/components/index.mjs",
"types": "./dist/components/index.d.ts",
"files": [
"dist",
"package.json"
],
"scripts": {
"dev": "pnpm run stub",
"stub": "unbuild --stub",
"build": "unbuild"
}
}
+12
View File
@@ -0,0 +1,12 @@
export { default as BasicTextarea } from './BasicTextarea.vue'
export { default as Live2DViewer } from './Live2D/Viewer.vue'
export { default as SceneLive2D } from './Scenes/Live2D.vue'
export { default as SceneVRM } from './Scenes/VRM.vue'
export { default as TransitionVertical } from './TransitionVertical.vue'
export { default as VRMModel } from './VRM/Model.vue'
export { default as WidgetStage } from './Widgets/Stage.vue'
@@ -0,0 +1,7 @@
export * from './llmmarkerParser'
export * from './markdown'
export * from './micvad'
export * from './queue'
export * from './queues'
export * from './vrm'
export * from './whisper'
@@ -7,7 +7,8 @@ export interface HandlerContext<T> {
emit: (eventName: string, ...params: any[]) => void emit: (eventName: string, ...params: any[]) => void
} }
interface Events<T> { // FIXME: should be exported?
export interface Events<T> {
add: Array<(payload: T) => void> add: Array<(payload: T) => void>
pick: Array<(payload: T) => void> pick: Array<(payload: T) => void>
processing: Array<(payload: T, handler: (param: HandlerContext<T>) => Promise<any>) => void> processing: Array<(payload: T, handler: (param: HandlerContext<T>) => Promise<any>) => void>
@@ -108,3 +109,5 @@ export function useQueue<T>(options: {
queue, queue,
} }
} }
export type UseQueueReturn<T> = ReturnType<typeof useQueue<T>>
@@ -3,9 +3,9 @@ import { ref } from 'vue'
import { llmInferenceEndToken } from '../constants' import { llmInferenceEndToken } from '../constants'
import { EMOTION_VALUES } from '../constants/emotions' import { EMOTION_VALUES } from '../constants/emotions'
import { useQueue } from './queue' import { useQueue, type UseQueueReturn } from './queue'
export function useEmotionsMessageQueue(emotionsQueue: ReturnType<typeof useQueue<Emotion>>) { export function useEmotionsMessageQueue(emotionsQueue: UseQueueReturn<Emotion>) {
function splitEmotion(content: string) { function splitEmotion(content: string) {
for (const emotion of EMOTION_VALUES) { for (const emotion of EMOTION_VALUES) {
// doesn't include the emotion, continue // doesn't include the emotion, continue
@@ -102,7 +102,7 @@ export function useDelayMessageQueue() {
}) })
} }
export function useMessageContentQueue(ttsQueue: ReturnType<typeof useQueue<string>>) { export function useMessageContentQueue(ttsQueue: UseQueueReturn<string>) {
const processed = ref<string>('') const processed = ref<string>('')
return useQueue<string>({ return useQueue<string>({
@@ -0,0 +1,4 @@
export * from './animation'
export * from './core'
export * from './expression'
export * from './loader'
+5
View File
@@ -0,0 +1,5 @@
export const llmInferenceEndToken = '<|llm_inference_end|>'
export * from './elevenlabs'
export * from './emotions'
export * from './prompts/system-v2'
+3
View File
@@ -0,0 +1,3 @@
export * from './audio/manager'
export * from './workers/types'
export * from './workers/worker'
@@ -7,8 +7,8 @@ import { useI18n } from 'vue-i18n'
import { useLlmmarkerParser } from '../composables/llmmarkerParser' import { useLlmmarkerParser } from '../composables/llmmarkerParser'
import SystemPromptV2 from '../constants/prompts/system-v2' import SystemPromptV2 from '../constants/prompts/system-v2'
import { useLLM } from '../stores/llm' import { useLLM } from '../stores/llm'
import { useSettings } from '../stores/settings'
import { asyncIteratorFromReadableStream } from '../utils/iterator' import { asyncIteratorFromReadableStream } from '../utils/iterator'
import { useSettings } from './settings'
export const useChatStore = defineStore('chat', () => { export const useChatStore = defineStore('chat', () => {
const { stream } = useLLM() const { stream } = useLLM()
+4
View File
@@ -0,0 +1,4 @@
export * from './audio'
export * from './chat'
export * from './llm'
export * from './settings'
@@ -3,7 +3,6 @@ import { defineStore } from 'pinia'
import { computed, onMounted, ref, watch } from 'vue' import { computed, onMounted, ref, watch } from 'vue'
import { Voice } from '../constants/elevenlabs' import { Voice } from '../constants/elevenlabs'
import { i18n } from '../modules/i18n'
export const useSettings = defineStore('settings', () => { export const useSettings = defineStore('settings', () => {
const selectedAudioDevice = ref<MediaDeviceInfo>() const selectedAudioDevice = ref<MediaDeviceInfo>()
@@ -45,8 +44,6 @@ export const useSettings = defineStore('settings', () => {
} }
}) })
watch(language, value => i18n.global.locale.value = value)
return { return {
openAiApiKey, openAiApiKey,
openAiApiBaseURL, openAiApiBaseURL,
+1
View File
@@ -0,0 +1 @@
export * from './iterator'
@@ -2,18 +2,16 @@
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": [
"DOM",
"ESNext"
],
"baseUrl": ".", "baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "Bundler", "moduleResolution": "Bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": [ "types": [
"vitest", "vitest"
"vite/client",
"vite-plugin-vue-layouts/client",
"vite-plugin-pwa/client",
"unplugin-vue-macros/macros-global",
"unplugin-vue-router/client"
], ],
"allowJs": true, "allowJs": true,
"strict": true, "strict": true,
@@ -32,5 +30,8 @@
"@vue-macros/volar/define-slots" "@vue-macros/volar/define-slots"
] ]
}, },
"exclude": ["dist", "node_modules", "cypress"] "exclude": [
"dist",
"node_modules"
]
} }
@@ -1,5 +1,5 @@
[build] [build]
publish = "packages/stage/dist" publish = "packages/stage-web/dist"
command = "pnpm run packages:stub && pnpm run build" command = "pnpm run packages:stub && pnpm run build"
[build.environment] [build.environment]
@@ -1,8 +1,8 @@
{ {
"name": "@proj-airi/stage", "name": "@proj-airi/stage-web",
"type": "module", "type": "module",
"private": true, "private": true,
"packageManager": "pnpm@9.15.2", "packageManager": "pnpm@9.15.3",
"description": "LLM powered virtual character", "description": "LLM powered virtual character",
"author": { "author": {
"name": "Neko Ayaka", "name": "Neko Ayaka",
@@ -15,9 +15,7 @@
"dev": "vite", "dev": "vite",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview", "preview": "vite preview",
"typecheck": "vue-tsc --noEmit", "typecheck": "vue-tsc --noEmit"
"dev:tamagotchi": "vite --mode tamagotchi",
"build:tamagotchi": "vite build --mode tamagotchi"
}, },
"dependencies": { "dependencies": {
"@11labs/client": "^0.0.4", "@11labs/client": "^0.0.4",
@@ -39,29 +37,30 @@
"@pixiv/three-vrm": "^3.3.2", "@pixiv/three-vrm": "^3.3.2",
"@pixiv/three-vrm-animation": "^3.3.2", "@pixiv/three-vrm-animation": "^3.3.2",
"@pixiv/three-vrm-core": "^3.3.2", "@pixiv/three-vrm-core": "^3.3.2",
"@proj-airi/stage-ui": "workspace:^",
"@ricky0123/vad-web": "^0.0.22", "@ricky0123/vad-web": "^0.0.22",
"@tresjs/cientos": "^4.0.3", "@tresjs/cientos": "^4.0.3",
"@tresjs/core": "^4.3.2", "@tresjs/core": "^4.3.2",
"@types/yauzl": "^2.10.3", "@types/yauzl": "^2.10.3",
"@typeschema/valibot": "^0.14.0", "@typeschema/valibot": "^0.14.0",
"@unhead/vue": "^1.11.14", "@unhead/vue": "^1.11.15",
"@unocss/reset": "^0.65.3", "@unocss/reset": "^0.65.4",
"@vueuse/core": "^12.3.0", "@vueuse/core": "^12.3.0",
"@vueuse/head": "^2.0.0", "@vueuse/head": "^2.0.0",
"@vueuse/shared": "^12.3.0", "@vueuse/shared": "^12.3.0",
"@xsai/generate-speech": "^0.0.23", "@xsai/generate-speech": "^0.0.24",
"@xsai/generate-text": "^0.0.23", "@xsai/generate-text": "^0.0.24",
"@xsai/model": "^0.0.23", "@xsai/model": "^0.0.24",
"@xsai/providers": "^0.0.23", "@xsai/providers": "^0.0.24",
"@xsai/shared-chat": "^0.0.23", "@xsai/shared-chat": "^0.0.24",
"@xsai/stream-text": "^0.0.23", "@xsai/stream-text": "^0.0.24",
"defu": "^6.1.4", "defu": "^6.1.4",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"ofetch": "^1.4.1", "ofetch": "^1.4.1",
"onnxruntime-web": "^1.20.1", "onnxruntime-web": "^1.20.1",
"pinia": "^2.3.0", "pinia": "^2.3.0",
"pixi-filters": "^4", "pixi-filters": "^4.2.0",
"pixi-live2d-display": "^0.4.0", "pixi-live2d-display": "^0.4.0",
"rehype-stringify": "^10.0.1", "rehype-stringify": "^10.0.1",
"remark-parse": "^11.0.0", "remark-parse": "^11.0.0",
@@ -81,34 +80,36 @@
"devDependencies": { "devDependencies": {
"@iconify-json/carbon": "^1.2.5", "@iconify-json/carbon": "^1.2.5",
"@iconify-json/eos-icons": "^1.2.2", "@iconify-json/eos-icons": "^1.2.2",
"@iconify-json/lucide": "^1.2.21", "@iconify-json/lucide": "^1.2.22",
"@iconify-json/mingcute": "^1.2.3", "@iconify-json/mingcute": "^1.2.3",
"@iconify-json/solar": "^1.2.2", "@iconify-json/solar": "^1.2.2",
"@iconify-json/svg-spinners": "^1.2.2", "@iconify-json/svg-spinners": "^1.2.2",
"@intlify/unplugin-vue-i18n": "^6.0.3", "@intlify/unplugin-vue-i18n": "^6.0.3",
"@proj-airi/elevenlabs": "workspace:^", "@proj-airi/elevenlabs": "workspace:^",
"@proj-airi/unplugin-download": "workspace:^",
"@proj-airi/unplugin-live2d-sdk": "workspace:^",
"@shikijs/markdown-it": "^1.26.1", "@shikijs/markdown-it": "^1.26.1",
"@types/markdown-it-link-attributes": "^3.0.5", "@types/markdown-it-link-attributes": "^3.0.5",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@types/three": "^0.171.0", "@types/three": "^0.172.0",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@vue-macros/volar": "^0.30.8", "@vue-macros/volar": "^0.30.9",
"@vueuse/motion": "^2.2.6", "@vueuse/motion": "^2.2.6",
"hfup": "workspace:^", "hfup": "workspace:^",
"markdown-it-link-attributes": "^4.0.1", "markdown-it-link-attributes": "^4.0.1",
"unocss-preset-animations": "^1.1.0", "unocss-preset-animations": "^1.1.0",
"unocss-preset-shadcn": "^0.3.1", "unocss-preset-shadcn": "^0.3.1",
"unocss-preset-theme": "^0.14.1", "unocss-preset-theme": "^0.14.1",
"unplugin-auto-import": "^0.19.0", "unplugin-auto-import": "^19.0.0",
"unplugin-vue-components": "^0.28.0", "unplugin-vue-components": "^28.0.0",
"unplugin-vue-macros": "^2.13.6", "unplugin-vue-macros": "^2.13.7",
"unplugin-vue-markdown": "^0.28.0", "unplugin-vue-markdown": "^28.0.0",
"unplugin-vue-router": "^0.10.9", "unplugin-vue-router": "^0.10.9",
"vite-bundle-visualizer": "^1.2.1", "vite-bundle-visualizer": "^1.2.1",
"vite-plugin-pwa": "^0.21.1", "vite-plugin-pwa": "^0.21.1",
"vite-plugin-vue-devtools": "^7.6.8", "vite-plugin-vue-devtools": "^7.7.0",
"vite-plugin-vue-layouts": "^0.11.0", "vite-plugin-vue-layouts": "^0.11.0",
"vite-plugin-webfont-dl": "^3.10.3", "vite-plugin-webfont-dl": "^3.10.4",
"vue-tsc": "^2.2.0" "vue-tsc": "^2.2.0"
} }
} }

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+17
View File
@@ -0,0 +1,17 @@
<script setup lang="ts">
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
import { watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterView } from 'vue-router'
const i18n = useI18n()
const settings = useSettings()
watch(settings.language, () => {
i18n.locale = settings.language
})
</script>
<template>
<RouterView />
</template>

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 163 KiB

@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useAudioContext } from '@proj-airi/stage-ui/stores'
import { useDark, useElementBounding } from '@vueuse/core' import { useDark, useElementBounding } from '@vueuse/core'
import { onMounted, ref } from 'vue'
import { useAudioContext } from '../stores/audio' import { onMounted, ref } from 'vue'
const containerRef = ref<HTMLDivElement>() const containerRef = ref<HTMLDivElement>()
// https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode

Some files were not shown because too many files have changed in this diff Show More