generated from tailored/router-template
fix: 优化模块
This commit is contained in:
parent
512fe796b2
commit
8e04962cc1
@ -1,5 +1,5 @@
|
|||||||
import { config } from './common.ts';
|
import { config } from './common.ts';
|
||||||
import { runDemo } from '../tts-mix.ts';
|
import { runDemo, TtsMix } from '../tts-mix.ts';
|
||||||
const appId = config.APP_ID;
|
const appId = config.APP_ID;
|
||||||
const token = config.TOKEN;
|
const token = config.TOKEN;
|
||||||
|
|
||||||
@ -7,11 +7,50 @@ const token = config.TOKEN;
|
|||||||
const speaker = 'zh_female_roumeinvyou_emo_v2_mars_bigtts';
|
const speaker = 'zh_female_roumeinvyou_emo_v2_mars_bigtts';
|
||||||
const text = '明朝开国皇帝朱元璋也称这本书为,万物之根';
|
const text = '明朝开国皇帝朱元璋也称这本书为,万物之根';
|
||||||
const outputPath = 'videos/tts_mix.wav';
|
const outputPath = 'videos/tts_mix.wav';
|
||||||
|
const text2 =
|
||||||
|
'明朝开国皇帝朱元璋曾盛赞《道德经》为"万物之根",认为这部道家经典蕴含着治国安邦的至理。这位出身寒微的帝王在建立大明王朝后,深刻体会到老子"无为而治"的智慧,将其奉为治国圭臬。朱元璋不仅亲自批注《道德经》,更命翰林学士编修《御注道德经》,将其中"治大国若烹小鲜"等思想运用于轻徭薄赋的惠民政策中';
|
||||||
|
// 按15个字分割文本为数组
|
||||||
|
const text2Arr = [];
|
||||||
|
for (let i = 0; i < text2.length; i += 2) {
|
||||||
|
text2Arr.push(text2.slice(i, i + 2));
|
||||||
|
}
|
||||||
|
const sleep = async (ms = 1000) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(true);
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const mockSendText = (ttsMax: TtsMix) => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
for (let i = 0; i < text2Arr.length; i++) {
|
||||||
|
const text = text2Arr[i];
|
||||||
|
console.log('开始', i, text);
|
||||||
|
ttsMax.emitter.emit('text', text);
|
||||||
|
await sleep(10);
|
||||||
|
// console.log('完成', i, text);
|
||||||
|
}
|
||||||
|
ttsMax.emitter.emit('textEnd');
|
||||||
|
});
|
||||||
|
};
|
||||||
// tsx src/tts/provider/volcengine/test/mix.ts
|
// tsx src/tts/provider/volcengine/test/mix.ts
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
await runDemo(appId, token, speaker, text, outputPath);
|
try {
|
||||||
|
console.log('开始', appId, token);
|
||||||
|
// await runDemo(appId, token, speaker, text, outputPath);
|
||||||
|
const ttsMax = new TtsMix(appId, token);
|
||||||
|
setTimeout(() => {
|
||||||
|
mockSendText(ttsMax).then(() => {
|
||||||
console.log('完成');
|
console.log('完成');
|
||||||
|
});
|
||||||
|
}, 10000);
|
||||||
|
// await ttsMax.getVoiceDemo(speaker, text, outputPath);
|
||||||
|
|
||||||
|
await ttsMax.getVoiceDemo(speaker, '', outputPath, false);
|
||||||
|
console.log('完成');
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
@ -286,7 +286,7 @@ async function startSession(websocket: WebSocket, speaker: string, sessionId: st
|
|||||||
|
|
||||||
async function sendText(ws: WebSocket, speaker: string, text: string, sessionId: string): Promise<void> {
|
async function sendText(ws: WebSocket, speaker: string, text: string, sessionId: string): Promise<void> {
|
||||||
const header = new Header(PROTOCOL_VERSION, DEFAULT_HEADER_SIZE, FULL_CLIENT_REQUEST, MsgTypeFlagWithEvent, JSON_TYPE).asBytes();
|
const header = new Header(PROTOCOL_VERSION, DEFAULT_HEADER_SIZE, FULL_CLIENT_REQUEST, MsgTypeFlagWithEvent, JSON_TYPE).asBytes();
|
||||||
|
console.log('sendText=========', text);
|
||||||
const optional = new Optional(EVENT_TaskRequest, sessionId).asBytes();
|
const optional = new Optional(EVENT_TaskRequest, sessionId).asBytes();
|
||||||
const payload = getPayloadBytes('1234', EVENT_TaskRequest, text, speaker);
|
const payload = getPayloadBytes('1234', EVENT_TaskRequest, text, speaker);
|
||||||
return await sendEvent(ws, header, optional, payload);
|
return await sendEvent(ws, header, optional, payload);
|
||||||
@ -308,7 +308,20 @@ async function finishConnection(ws: WebSocket): Promise<void> {
|
|||||||
return await sendEvent(ws, header, optional, payload);
|
return await sendEvent(ws, header, optional, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runDemo(appId: string, token: string, speaker: string, text: string, outputPath: string, emitter?: EventEmitter): Promise<void> {
|
type RunOptions = {
|
||||||
|
id?: string;
|
||||||
|
autoEnd?: boolean;
|
||||||
|
};
|
||||||
|
export async function runDemo(
|
||||||
|
appId: string,
|
||||||
|
token: string,
|
||||||
|
speaker: string,
|
||||||
|
text: string,
|
||||||
|
outputPath: string,
|
||||||
|
emitter?: EventEmitter,
|
||||||
|
opts: RunOptions = {},
|
||||||
|
): Promise<void> {
|
||||||
|
const autoEnd = opts.autoEnd ?? true;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const wsHeader = {
|
const wsHeader = {
|
||||||
'X-Api-App-Key': appId,
|
'X-Api-App-Key': appId,
|
||||||
@ -320,6 +333,7 @@ export async function runDemo(appId: string, token: string, speaker: string, tex
|
|||||||
const url = 'wss://openspeech.bytedance.com/api/v3/tts/bidirection';
|
const url = 'wss://openspeech.bytedance.com/api/v3/tts/bidirection';
|
||||||
const ws = new WebSocket(url, { headers: wsHeader });
|
const ws = new WebSocket(url, { headers: wsHeader });
|
||||||
const filename = outputPath.split('/').pop() || '';
|
const filename = outputPath.split('/').pop() || '';
|
||||||
|
// 开始连接
|
||||||
let isBegin = true;
|
let isBegin = true;
|
||||||
const writeFileEmitter = (data: Buffer) => {
|
const writeFileEmitter = (data: Buffer) => {
|
||||||
const value: TTSWriteType = {
|
const value: TTSWriteType = {
|
||||||
@ -348,7 +362,19 @@ export async function runDemo(appId: string, token: string, speaker: string, tex
|
|||||||
let fileHandle: fs.FileHandle | null = null;
|
let fileHandle: fs.FileHandle | null = null;
|
||||||
let sessionId: string = '';
|
let sessionId: string = '';
|
||||||
let isFirstResponse = true;
|
let isFirstResponse = true;
|
||||||
|
let cacheText = '';
|
||||||
|
const emitOk = (id: string, code = 200) => {
|
||||||
|
emitter.emit(id, { code, msg: 'ok' });
|
||||||
|
};
|
||||||
|
emitter.on('text', async ({ text, id }) => {
|
||||||
|
await sendText(ws, speaker, text, sessionId);
|
||||||
|
emitOk(id);
|
||||||
|
});
|
||||||
|
emitter.on('textEnd', async ({ id }) => {
|
||||||
|
console.log('text end');
|
||||||
|
await finishSession(ws, sessionId);
|
||||||
|
emitOk(id);
|
||||||
|
});
|
||||||
ws.on('message', async (data) => {
|
ws.on('message', async (data) => {
|
||||||
try {
|
try {
|
||||||
const res = parserResponse(data as Buffer);
|
const res = parserResponse(data as Buffer);
|
||||||
@ -364,8 +390,10 @@ export async function runDemo(appId: string, token: string, speaker: string, tex
|
|||||||
}
|
}
|
||||||
if (res.optional.event === EVENT_SessionStarted && isFirstResponse) {
|
if (res.optional.event === EVENT_SessionStarted && isFirstResponse) {
|
||||||
isFirstResponse = false;
|
isFirstResponse = false;
|
||||||
await sendText(ws, speaker, text, sessionId);
|
console.log('start session', sessionId, autoEnd);
|
||||||
await finishSession(ws, sessionId);
|
emitter.emit('isConnect', sessionId);
|
||||||
|
text && (await sendText(ws, speaker, text, sessionId));
|
||||||
|
autoEnd && (await finishSession(ws, sessionId));
|
||||||
fileHandle = await fs.open(outputPath, 'w');
|
fileHandle = await fs.open(outputPath, 'w');
|
||||||
} else if (!isFirstResponse) {
|
} else if (!isFirstResponse) {
|
||||||
if (res.optional.event === EVENT_TTSResponse && res.header.messageType === AUDIO_ONLY_RESPONSE && res.payload && fileHandle) {
|
if (res.optional.event === EVENT_TTSResponse && res.header.messageType === AUDIO_ONLY_RESPONSE && res.payload && fileHandle) {
|
||||||
@ -413,11 +441,14 @@ export class TtsMix {
|
|||||||
appId: string;
|
appId: string;
|
||||||
token: string;
|
token: string;
|
||||||
emitter: EventEmitter;
|
emitter: EventEmitter;
|
||||||
|
isStart = false;
|
||||||
constructor(appId: string, token: string) {
|
constructor(appId: string, token: string) {
|
||||||
this.appId = appId;
|
this.appId = appId;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.emitter = new EventEmitter();
|
this.emitter = new EventEmitter();
|
||||||
|
this.emitter.on('isConnect', () => {
|
||||||
|
this.isStart = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获取语音
|
* 获取语音
|
||||||
@ -426,8 +457,32 @@ export class TtsMix {
|
|||||||
* @param outputPath 输出路径
|
* @param outputPath 输出路径
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async getVoiceDemo(speaker: string, text: string, outputPath: string): Promise<void> {
|
async getVoiceDemo(speaker: string, text: string, outputPath: string, autoEnd = true): Promise<void> {
|
||||||
return runDemo(this.appId, this.token, speaker, text, outputPath, this.emitter);
|
const id = nanoid();
|
||||||
|
const listenId = 'text' + id;
|
||||||
|
return runDemo(this.appId, this.token, speaker, text, outputPath, this.emitter, { autoEnd, id: listenId });
|
||||||
|
}
|
||||||
|
async isConnect() {
|
||||||
|
if (this.isStart) {
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.emitter.once('isConnect', resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async sendText(text: string): Promise<{ code?: number; msg?: string }> {
|
||||||
|
const id = nanoid();
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.emitter.once(id, resolve);
|
||||||
|
this.emitter.emit('text', { text, id });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async sendTextEnd() {
|
||||||
|
const id = nanoid();
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.emitter.once(id, resolve);
|
||||||
|
this.emitter.emit('textEnd', { id });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 写入文件的时候同步的流监听
|
* 写入文件的时候同步的流监听
|
||||||
|
Loading…
x
Reference in New Issue
Block a user