temp
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					videos
 | 
				
			||||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					[submodule "packages/video-tools"]
 | 
				
			||||||
 | 
						path = packages/video-tools
 | 
				
			||||||
 | 
						url = git@git.xiongxiao.me:kevisual/video-tools.git
 | 
				
			||||||
							
								
								
									
										23
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "@kevisual/batch-asr",
 | 
				
			||||||
 | 
					  "version": "0.0.1",
 | 
				
			||||||
 | 
					  "description": "",
 | 
				
			||||||
 | 
					  "main": "index.js",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "test": "echo \"Error: no test specified\" && exit 1"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "keywords": [],
 | 
				
			||||||
 | 
					  "author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
 | 
				
			||||||
 | 
					  "license": "MIT",
 | 
				
			||||||
 | 
					  "packageManager": "pnpm@10.12.1",
 | 
				
			||||||
 | 
					  "type": "module",
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@kevisual/types": "^0.0.10",
 | 
				
			||||||
 | 
					    "@kevisual/video-tools": "workspace:*",
 | 
				
			||||||
 | 
					    "@types/node": "^24.0.3"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "eventemitter3": "^5.0.1",
 | 
				
			||||||
 | 
					    "natural": "^8.1.0"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								packages/video-tools
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								packages/video-tools
									
									
									
									
									
										Submodule
									
								
							 Submodule packages/video-tools added at 767e436eb8
									
								
							
							
								
								
									
										5512
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5512
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										6
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					packages:
 | 
				
			||||||
 | 
					  - packages/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onlyBuiltDependencies:
 | 
				
			||||||
 | 
					  - esbuild
 | 
				
			||||||
 | 
					  - msw
 | 
				
			||||||
							
								
								
									
										130
									
								
								src/asr.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/asr.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					import { VideoWS, VideoWsResult } from '@kevisual/video-tools/src/asr/provider/funasr/ws.ts';
 | 
				
			||||||
 | 
					import net from 'node:net';
 | 
				
			||||||
 | 
					import path from 'node:path';
 | 
				
			||||||
 | 
					import fs from 'node:fs';
 | 
				
			||||||
 | 
					import natural from 'natural';
 | 
				
			||||||
 | 
					import { EventEmitter } from 'eventemitter3';
 | 
				
			||||||
 | 
					const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
 | 
				
			||||||
 | 
					const videoTestPath = path.join(process.cwd(), 'videos/my_speech_text.wav');
 | 
				
			||||||
 | 
					const audioTestPath = path.join(process.cwd(), 'videos/test.mp3');
 | 
				
			||||||
 | 
					const name = 'output-1746007775571.mp3';
 | 
				
			||||||
 | 
					const videoTestPath2 = path.join(process.cwd(), 'build', name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emitter = new EventEmitter();
 | 
				
			||||||
 | 
					const url = 'https://funasr.xiongxiao.me';
 | 
				
			||||||
 | 
					const local = 'wss://192.168.31.220:10095';
 | 
				
			||||||
 | 
					const ws = new VideoWS({
 | 
				
			||||||
 | 
					  url: url,
 | 
				
			||||||
 | 
					  mode: '2pass',
 | 
				
			||||||
 | 
					  wsOptions: {
 | 
				
			||||||
 | 
					    rejectUnauthorized: false,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  emitter,
 | 
				
			||||||
 | 
					  wav_format: 'wav',
 | 
				
			||||||
 | 
					  onConnect: async () => {
 | 
				
			||||||
 | 
					    console.log('WebSocket connected');
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					type BatchSenderOptions = {
 | 
				
			||||||
 | 
					  vws: VideoWS;
 | 
				
			||||||
 | 
					  files: string[];
 | 
				
			||||||
 | 
					  matchText?: string;
 | 
				
			||||||
 | 
					  emitter?: EventEmitter;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					class BatchSenderFiles {
 | 
				
			||||||
 | 
					  files: string[];
 | 
				
			||||||
 | 
					  vws: VideoWS;
 | 
				
			||||||
 | 
					  emitter: EventEmitter;
 | 
				
			||||||
 | 
					  constructor({ vws, files, matchText, emitter }: BatchSenderOptions) {
 | 
				
			||||||
 | 
					    this.files = files;
 | 
				
			||||||
 | 
					    this.vws = vws;
 | 
				
			||||||
 | 
					    this.emitter = emitter || vws.emitter;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  async init() {
 | 
				
			||||||
 | 
					    const isConnected = await this.vws.isConnected();
 | 
				
			||||||
 | 
					    if (!isConnected) {
 | 
				
			||||||
 | 
					      console.error('链接失败:', isConnected);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.send();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  waitOne() {
 | 
				
			||||||
 | 
					    return new Promise((resolve) => {
 | 
				
			||||||
 | 
					      this.vws.emitter.once('result', (data) => {
 | 
				
			||||||
 | 
					        resolve(data);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  async checkAudioFile(file: string) {
 | 
				
			||||||
 | 
					    const stats = fs.statSync(file);
 | 
				
			||||||
 | 
					    if (!stats.isFile()) {
 | 
				
			||||||
 | 
					      throw new Error(`File not found: ${file}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const ext = path.extname(file).toLowerCase();
 | 
				
			||||||
 | 
					    const validExtensions = ['.wav', '.mp3', '.flac', '.ogg', '.aac'];
 | 
				
			||||||
 | 
					    if (!validExtensions.includes(ext)) {
 | 
				
			||||||
 | 
					      throw new Error(`Invalid file type: ${ext}. Supported types are: ${validExtensions.join(', ')}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const fileSize = stats.size;
 | 
				
			||||||
 | 
					    if (fileSize === 0) {
 | 
				
			||||||
 | 
					      throw new Error(`File is empty: ${file}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const maxSize = 100 * 1024 * 1024; // 100 MB
 | 
				
			||||||
 | 
					    if (fileSize > maxSize) {
 | 
				
			||||||
 | 
					      throw new Error(`File size exceeds limit: ${fileSize} bytes. Maximum allowed size is ${maxSize} bytes.`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      file,
 | 
				
			||||||
 | 
					      ext,
 | 
				
			||||||
 | 
					      size: fileSize,
 | 
				
			||||||
 | 
					      isValid: true,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  async send() {
 | 
				
			||||||
 | 
					    const textList: { file: string; text: string }[] = [];
 | 
				
			||||||
 | 
					    for (const file of this.files) {
 | 
				
			||||||
 | 
					      let wav_format = 'wav';
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        const ck = await this.checkAudioFile(file);
 | 
				
			||||||
 | 
					        if (ck.ext !== '.wav') {
 | 
				
			||||||
 | 
					          wav_format = ck.ext.replace('.', '');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } catch (error) {
 | 
				
			||||||
 | 
					        console.error('Error checking file:', error);
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const data = fs.readFileSync(file);
 | 
				
			||||||
 | 
					      const wait = this.waitOne();
 | 
				
			||||||
 | 
					      await this.vws.sendBuffer(data, { wav_format });
 | 
				
			||||||
 | 
					      await sleep(1000);
 | 
				
			||||||
 | 
					      console.log('File sent:', file);
 | 
				
			||||||
 | 
					      const result: VideoWsResult = (await wait) as any;
 | 
				
			||||||
 | 
					      console.log('Result:', result.text);
 | 
				
			||||||
 | 
					      textList.push({ file, text: result.text });
 | 
				
			||||||
 | 
					      console.log('----------------------');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.emitter.emit('send-done', textList);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const batchSender = new BatchSenderFiles({
 | 
				
			||||||
 | 
					  vws: ws,
 | 
				
			||||||
 | 
					  // files: [audioTestPath],
 | 
				
			||||||
 | 
					  files: [videoTestPath, audioTestPath],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					batchSender.init();
 | 
				
			||||||
 | 
					batchSender.emitter.on('send-done', (data) => {
 | 
				
			||||||
 | 
					  const matchText = '在一无所知中,梦里的一天结束了一个新的轮回,便会开始。';
 | 
				
			||||||
 | 
					  const textList = data as { file: string; text: string }[];
 | 
				
			||||||
 | 
					  for (const item of textList) {
 | 
				
			||||||
 | 
					    const getText = item.text || '';
 | 
				
			||||||
 | 
					    const distance = natural.JaroWinklerDistance(getText, matchText);
 | 
				
			||||||
 | 
					    console.log(`File: ${item.file}, \nText: ${item.text}\nDistance: ${distance}`);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // console.log('Batch processing done:', data);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const server = net.createServer((socket) => {
 | 
				
			||||||
 | 
					  socket.on('data', (data) => {
 | 
				
			||||||
 | 
					    console.log('data', data);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					server.listen(10096);
 | 
				
			||||||
							
								
								
									
										18
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "extends": "@kevisual/types/json/backend.json",
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "baseUrl": ".",
 | 
				
			||||||
 | 
					    "typeRoots": [
 | 
				
			||||||
 | 
					      "./node_modules/@types",
 | 
				
			||||||
 | 
					      "./node_modules/@kevisual"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "paths": {
 | 
				
			||||||
 | 
					      "@/*": [
 | 
				
			||||||
 | 
					        "src/*"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": [
 | 
				
			||||||
 | 
					    "src/**/*",
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user