2026-06-12 17:46:25 +08:00
|
|
|
import { defineConfig } from 'vite'
|
|
|
|
|
import react from '@vitejs/plugin-react'
|
2026-06-13 22:20:31 +08:00
|
|
|
import fs from 'fs'
|
|
|
|
|
import path from 'path'
|
|
|
|
|
|
|
|
|
|
const ortDistDir = path.resolve(__dirname, 'node_modules/onnxruntime-web/dist')
|
|
|
|
|
const vadDistDir = path.resolve(__dirname, 'node_modules/@ricky0123/vad-web/dist')
|
|
|
|
|
const publicDir = path.resolve(__dirname, 'public')
|
|
|
|
|
|
2026-06-14 21:24:11 +08:00
|
|
|
// 需要复制到 public 的 VAD 模型/工作线程
|
|
|
|
|
const vadFiles = [
|
2026-06-13 22:20:31 +08:00
|
|
|
{ src: vadDistDir, name: 'silero_vad_legacy.onnx' },
|
|
|
|
|
{ src: vadDistDir, name: 'silero_vad_v5.onnx' },
|
|
|
|
|
{ src: vadDistDir, name: 'vad.worklet.bundle.min.js' },
|
|
|
|
|
]
|
2026-06-12 17:46:25 +08:00
|
|
|
|
2026-06-14 21:24:11 +08:00
|
|
|
// 需要复制到 public 的 ONNX Runtime WASM 文件(生产环境需要)
|
|
|
|
|
const ortFiles = [
|
|
|
|
|
{ src: ortDistDir, name: 'ort-wasm-simd-threaded.mjs' },
|
|
|
|
|
{ src: ortDistDir, name: 'ort-wasm-simd-threaded.wasm' },
|
|
|
|
|
{ src: ortDistDir, name: 'ort-wasm-simd.mjs' },
|
|
|
|
|
{ src: ortDistDir, name: 'ort-wasm-simd.wasm' },
|
|
|
|
|
{ src: ortDistDir, name: 'ort-wasm.mjs' },
|
|
|
|
|
{ src: ortDistDir, name: 'ort-wasm.wasm' },
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
/** 把所需文件复制到 public 目录(不存在则复制) */
|
|
|
|
|
function copyAssetsToPublic() {
|
|
|
|
|
for (const { src, name } of [...vadFiles, ...ortFiles]) {
|
|
|
|
|
const srcFile = path.join(src, name)
|
|
|
|
|
const destFile = path.join(publicDir, name)
|
|
|
|
|
if (fs.existsSync(srcFile) && !fs.existsSync(destFile)) {
|
|
|
|
|
fs.copyFileSync(srcFile, destFile)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-12 17:46:25 +08:00
|
|
|
export default defineConfig({
|
2026-06-14 13:00:54 +08:00
|
|
|
server: {
|
|
|
|
|
proxy: {
|
|
|
|
|
'/ws': {
|
|
|
|
|
target: 'http://localhost:8080',
|
|
|
|
|
ws: true,
|
|
|
|
|
},
|
|
|
|
|
'/api': {
|
|
|
|
|
target: 'http://localhost:8080',
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-06-13 22:20:31 +08:00
|
|
|
plugins: [
|
|
|
|
|
react(),
|
|
|
|
|
{
|
|
|
|
|
name: 'serve-vad-assets',
|
2026-06-14 21:24:11 +08:00
|
|
|
// 1. 启动时将 VAD 模型 + ORT WASM 复制到 public
|
2026-06-13 22:20:31 +08:00
|
|
|
configResolved() {
|
2026-06-14 21:24:11 +08:00
|
|
|
copyAssetsToPublic()
|
2026-06-13 22:20:31 +08:00
|
|
|
},
|
2026-06-14 21:24:11 +08:00
|
|
|
// 2. 开发模式中间件:拦截 WASM 相关请求,确保 MIME 类型正确
|
2026-06-13 22:20:31 +08:00
|
|
|
configureServer(server) {
|
|
|
|
|
server.middlewares.use((req, res, next) => {
|
|
|
|
|
const url = req.url?.split('?')[0] ?? ''
|
2026-06-14 21:24:11 +08:00
|
|
|
const wasmMatch = url.match(/\/(ort-wasm[\w-]*\.(mjs|wasm))$/)
|
2026-06-13 22:20:31 +08:00
|
|
|
if (wasmMatch) {
|
|
|
|
|
const fileName = wasmMatch[1]
|
|
|
|
|
const filePath = path.join(ortDistDir, fileName)
|
|
|
|
|
if (fs.existsSync(filePath)) {
|
|
|
|
|
res.setHeader('Content-Type', fileName.endsWith('.wasm') ? 'application/wasm' : 'application/javascript')
|
|
|
|
|
res.setHeader('Cache-Control', 'no-cache')
|
|
|
|
|
res.end(fs.readFileSync(filePath))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
next()
|
|
|
|
|
})
|
|
|
|
|
},
|
2026-06-14 21:24:11 +08:00
|
|
|
// 3. 构建阶段确保所有资源都在 dist 中
|
|
|
|
|
writeBundle() {
|
|
|
|
|
const distDir = path.resolve(__dirname, 'dist')
|
|
|
|
|
for (const { src, name } of [...vadFiles, ...ortFiles]) {
|
|
|
|
|
const srcFile = path.join(src, name)
|
|
|
|
|
const destFile = path.join(distDir, name)
|
|
|
|
|
if (fs.existsSync(srcFile) && !fs.existsSync(destFile)) {
|
|
|
|
|
fs.copyFileSync(srcFile, destFile)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
2026-06-13 22:20:31 +08:00
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
})
|