Я все еще новичок в веб-разработке, и я создаю чат-бота, но я хочу сначала выполнить ответы с помощью googles-текста в речь, а затем воспроизвести звук на клиенте. Таким образом, клиент отправляет сообщение на сервер -> сервер создает ответ -> сервер отправляет сообщение в Google -> возвращает аудиоданные -> отправляет их клиенту -> клиент воспроизводит их. Я дошел до последнего шага, но теперь я не в себе.
Я занимался поиском в Google, и, похоже, есть много информации о воспроизведении аудио из двоичных данных, аудио контекстов и так далее, и я создал функцию, но она не работает. Вот что я сделал:
export const SendMessage: Client.Common.Footer.API.SendMessage = async message => {
const baseRoute = process.env.REACT_APP_BASE_ROUTE;
const port = process.env.REACT_APP_SERVER_PORT;
const audioContext = new AudioContext();
let audio: any;
const url = baseRoute + ":" + port + "/ChatBot";
console.log("%c Sending post request...", "background: #1fa67f; color: white", url, JSON.stringify(message));
let responseJson = await fetch(url, {
method: "POST",
mode: "cors",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(message)
});
let response = await responseJson.json();
await audioContext.decodeAudioData(
new ArrayBuffer(response.data.audio.data),
buffer => {
audio = buffer;
},
error => console.log("===ERROR===\n", error)
);
const source = audioContext.createBufferSource();
source.buffer = audio;
source.connect(audioContext.destination);
source.start(0);
console.log("%c Post response:", "background: #1fa67f; color: white", url, response);
};
Эта функция отправляет сообщение на сервер и возвращает ответное сообщение и аудиоданные. У меня есть своего рода двоичные данные в моем response.data.audio.data, но я получаю сообщение об ошибке, говорящее, что аудиоданные не могут быть декодированы (ошибка в методе decodeAudioData вызывает). Я знаю, что данные действительны, потому что на моем сервере я использую следующий код, чтобы превратить их в mp3-файл, который прекрасно воспроизводится:
const writeFile = util.promisify(fs.writeFile);
await writeFile("output/TTS.mp3", response.audioContent, "binary");
Я почти не знаю, как здесь обрабатываются двоичные данные, и что может быть не так. Нужно ли указывать дополнительные параметры для правильного декодирования двоичных данных? Как я узнаю что? Я хотел бы понять, что на самом деле здесь происходит, а не просто скопировать вставить какое-либо решение.
РЕДАКТИРОВАТЬ:
Так что, похоже, буфер массива создается неправильно. Если я выполню этот код:
console.log(response);
const audioBuffer = new ArrayBuffer(response.data.audio.data);
console.log("===audioBuffer===", audioBuffer);
audio = await audioContext.decodeAudioData(audioBuffer);
Ответ будет выглядеть так:
{message: "Message successfully sent.", status: 1, data: {…}}
message: "Message successfully sent."
status: 1
data:
message: "Sorry, I didn't understand your question, try rephrasing."
audio:
type: "Buffer"
data: Array(14304)
[0 … 9999]
[10000 … 14303]
length: 14304
__proto__: Array(0)
__proto__: Object
__proto__: Object
__proto__: Object
, но буфер записывается так:
===audioBuffer===
ArrayBuffer(0) {}
[[Int8Array]]: Int8Array []
[[Uint8Array]]: Uint8Array []
[[Int16Array]]: Int16Array []
[[Int32Array]]: Int32Array []
byteLength: 0
__proto__: ArrayBuffer
Ясно JS не понимает формат в моем объекте ответа, но это то, что я получил из API Google text в речь. Может быть, я неправильно отправляю сообщение с моего сервера? Как я уже говорил, на моем сервере следующий код превращает этот массив в файл mp3:
const writeFile = util.promisify(fs.writeFile);
await writeFile("output/TTS.mp3", response.audioContent, "binary");
return response.audioContent;
Где response.audioContent также отправляется клиенту следующим образом:
//in index.ts
...
const app = express();
app.use(bodyParser.json());
app.use(cors(corsOptions));
app.post("/TextToSpeech", TextToSpeechController);
...
//textToSpeech.ts
export const TextToSpeechController = async (req: Req<Server.API.TextToSpeech.RequestQuery>, res: Response) => {
let response: Server.API.TextToSpeech.ResponseBody = {
message: null,
status: CONSTANTS.STATUS.ERROR,
data: undefined
};
try {
console.log("===req.body===", req.body);
if (!req.body) throw new Error("No message recieved");
const audio = await TextToSpeech({ message: req.body.message });
response = {
message: "Audio file successfully created!",
status: CONSTANTS.STATUS.SUCCESS,
data: audio
};
res.send(response);
} catch (error) {
response = {
message: "Error converting text to speech: " + error.message,
status: CONSTANTS.STATUS.ERROR,
data: undefined
};
res.json(response);
}
};
...
Я нахожу странным, что на моем сервере response.audioContent записывается как:
===response.audioContent=== <Buffer ff f3 44 c4 00 00 00 03 48 01 40 00 00 f0
a3 0f fc 1a 00 11 e1 48 7f e0 e0 87 fc b8 88 40 1c 7f e0 4c 03 c1 d9 ef ff ec
3e 4c 02 c7 88 7f ff f9 ff ff ... >
Но на клиенте это
audio:
type: "Buffer"
data: Array(14304)
[0 … 9999]
[10000 … 14303]
length: 14304
__proto__: Array(0)
__proto__: Object
Я попытался передать response.data, response. data.audio и response.data.audio.data для нового ArrayBuffer (), но все они приводят к одному и тому же пустому буферу.