Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/commands/speech/synthesize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,9 @@ export default defineCommand({
if (flags.subtitles) body.subtitle_enable = true; // Correct API parameter name

if (flags.pronunciation) {
body.pronunciation_dict = (flags.pronunciation as string[]).map(p => {
const [from, to] = p.split('/');
return { tone: to || from!, text: from! };
});
body.pronunciation_dict = {
tone: flags.pronunciation as string[],
};
}

if (dryRun(config, body)) return;
Expand Down
2 changes: 1 addition & 1 deletion src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export interface SpeechRequest {
channel?: number;
};
language_boost?: string;
pronunciation_dict?: Array<{ tone: string; text: string }>;
pronunciation_dict?: { tone: string[] };
output_format?: 'url' | 'hex';
stream?: boolean;
subtitle_enable?: boolean; // Correct API parameter name (not 'subtitle')
Expand Down
99 changes: 99 additions & 0 deletions test/commands/speech/synthesize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,105 @@ describe('speech synthesize command', () => {
console.log = originalLog;
}
});

it('--pronunciation serializes multiple values with the API-compatible shape', async () => {
const config = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'json' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: true,
nonInteractive: true,
async: false,
};

const originalLog = console.log;
let output = '';
console.log = (msg: string) => { output += msg; };

try {
await synthesizeCommand.execute(config, {
text: '处理这个危险的情况。',
pronunciation: [
'处理/(chu3)(li3)',
'危险/dangerous',
],
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: true,
help: false,
nonInteractive: true,
async: false,
});

const parsed = JSON.parse(output);

// pronunciation_dict is an object with a tone string array — not the
// old array-of-{text,tone} shape — and each value is preserved verbatim
// (no splitting, trimming, or rewriting), covering both the pinyin form
// and the plain-replacement form shown in the official API docs.
expect(Array.isArray(parsed.request.pronunciation_dict)).toBe(false);
expect(parsed.request.pronunciation_dict).toEqual({
tone: [
'处理/(chu3)(li3)',
'危险/dangerous',
],
});
} finally {
console.log = originalLog;
}
});

it('--pronunciation with a single value serializes under tone', async () => {
const config = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'json' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: true,
nonInteractive: true,
async: false,
};

const originalLog = console.log;
let output = '';
console.log = (msg: string) => { output += msg; };

try {
await synthesizeCommand.execute(config, {
text: 'Omg, the real danger is not that computers start thinking.',
pronunciation: ['Omg/Oh my god'],
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: true,
help: false,
nonInteractive: true,
async: false,
});

const parsed = JSON.parse(output);

expect(parsed.request.pronunciation_dict).toEqual({
tone: ['Omg/Oh my god'],
});
} finally {
console.log = originalLog;
}
});
});

describe('speech synthesize format validation', () => {
Expand Down