Forward speech proxy text messages as strings

- Convert non-binary upstream Xunfei WebSocket messages to UTF-8 strings before forwarding them to browser clients.

- Export and test raw WebSocket data to text conversion for speech proxy forwarding.

- Log unparseable speech responses in the report editor instead of silently swallowing them.

- Update report editor, progress, and testing documentation for text-message forwarding.
This commit is contained in:
2026-05-02 06:39:23 +08:00
parent 13d8853532
commit 6bdb12678a
7 changed files with 17 additions and 9 deletions

View File

@@ -4,7 +4,7 @@ import type { RawData, WebSocket } from 'ws';
import Ws from 'ws';
import type { SafeUser } from '../auth/auth.types.js';
import { SettingsService } from '../settings/settings.service.js';
import { prepareXfIatFrame } from './xf-frame.js';
import { prepareXfIatFrame, rawDataToText } from './xf-frame.js';
@Injectable()
export class SpeechService {
@@ -24,9 +24,9 @@ export class SpeechService {
}
});
upstream.on('message', (data) => {
upstream.on('message', (data, isBinary) => {
if (client.readyState === Ws.OPEN) {
client.send(data);
client.send(isBinary ? data : rawDataToText(data));
}
});

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { prepareXfIatFrame } from './xf-frame.js';
import { prepareXfIatFrame, rawDataToText } from './xf-frame.js';
describe('prepareXfIatFrame', () => {
it('adds server-side app id and default business options to the first frame', () => {
@@ -28,4 +28,9 @@ describe('prepareXfIatFrame', () => {
it('keeps non-json payloads unchanged', () => {
expect(prepareXfIatFrame('not-json', 'test-app-id')).toBe('not-json');
});
it('converts websocket raw data to text for browser forwarding', () => {
expect(rawDataToText(Buffer.from('{"code":0}', 'utf8'))).toBe('{"code":0}');
expect(rawDataToText([Buffer.from('{"code"'), Buffer.from(':0}')])).toBe('{"code":0}');
});
});

View File

@@ -29,7 +29,7 @@ export const prepareXfIatFrame = (data: RawData | string, appId: string) => {
}
};
const rawDataToText = (data: RawData | string) => {
export const rawDataToText = (data: RawData | string) => {
if (typeof data === 'string') return data;
if (Buffer.isBuffer(data)) return data.toString('utf8');
if (Array.isArray(data)) return Buffer.concat(data).toString('utf8');