ssml-builder-js 2.8.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -44,6 +44,7 @@ __export(src_exports, {
44
44
  buildPartialSsml: () => buildPartialSsml,
45
45
  buildSsml: () => buildSsml,
46
46
  extractSsmlText: () => extractSsmlText,
47
+ isValidAzureAudioDuration: () => isValidAzureAudioDuration,
47
48
  mapSsmlTextNodes: () => mapSsmlTextNodes,
48
49
  normalizeAzureLanguage: () => normalizeAzureLanguage,
49
50
  parseSsml: () => parseSsml,
@@ -85,7 +86,8 @@ var SSML_TAGS = {
85
86
  MSTTS_SILENCE: "mstts:silence",
86
87
  SILENCE: "silence",
87
88
  MSTTS_VISEME: "mstts:viseme",
88
- VISEME: "viseme"
89
+ VISEME: "viseme",
90
+ MSTTS_AUDIO_DURATION: "mstts:audioduration"
89
91
  };
90
92
  var SSML_ATTRS = {
91
93
  VERSION: "version",
@@ -214,6 +216,9 @@ function getAttributes(element) {
214
216
  case SSML_TAGS.VISEME:
215
217
  addAttribute(attributes, SSML_ATTRS.TYPE, element.typeValue ?? element.visemeType);
216
218
  break;
219
+ case SSML_TAGS.MSTTS_AUDIO_DURATION:
220
+ addAttribute(attributes, SSML_ATTRS.VALUE, element.value);
221
+ break;
217
222
  case SSML_TAGS.PARAGRAPH:
218
223
  case SSML_TAGS.SENTENCE:
219
224
  case SSML_TAGS.WORD:
@@ -238,6 +243,8 @@ function getTagName(element) {
238
243
  case SSML_TAGS.VISEME:
239
244
  case SSML_TAGS.MSTTS_VISEME:
240
245
  return SSML_TAGS.MSTTS_VISEME;
246
+ case SSML_TAGS.MSTTS_AUDIO_DURATION:
247
+ return SSML_TAGS.MSTTS_AUDIO_DURATION;
241
248
  case "element":
242
249
  case "custom":
243
250
  return element.name;
@@ -772,6 +779,12 @@ function convertElement(node) {
772
779
  if (typeValue !== void 0) element.typeValue = typeValue;
773
780
  return finishElement(element, node, attributes);
774
781
  }
782
+ case SSML_TAGS.MSTTS_AUDIO_DURATION: {
783
+ const element = { type: SSML_TAGS.MSTTS_AUDIO_DURATION };
784
+ const value = readAttribute(attributes, SSML_ATTRS.VALUE);
785
+ if (value !== void 0) element.value = value;
786
+ return finishElement(element, node, attributes);
787
+ }
775
788
  default: {
776
789
  const element = {
777
790
  name: node.name,
@@ -1046,93 +1059,126 @@ async function mapSsmlTextNodes(ssml, transform, options = {}) {
1046
1059
  return result + ssml.slice(cursor);
1047
1060
  }
1048
1061
 
1062
+ // packages/ssml-core/src/generated/azureVoiceDefinitions.ts
1063
+ var AZURE_VOICE_DEFINITIONS = [
1064
+ { name: "de-DE-ConradNeural", locale: "de-DE", styles: ["cheerful", "sad"] },
1065
+ { name: "de-DE-KatjaNeural", locale: "de-DE", styles: ["cheerful", "sad"] },
1066
+ { name: "en-US-AndrewNeural", locale: "en-US", styles: ["empathetic", "relieved"] },
1067
+ {
1068
+ name: "en-US-GuyNeural",
1069
+ locale: "en-US",
1070
+ styles: [
1071
+ "angry",
1072
+ "cheerful",
1073
+ "excited",
1074
+ "friendly",
1075
+ "hopeful",
1076
+ "newscast",
1077
+ "sad",
1078
+ "shouting",
1079
+ "terrified",
1080
+ "unfriendly",
1081
+ "whispering"
1082
+ ]
1083
+ },
1084
+ {
1085
+ name: "en-US-JennyMultilingualNeural",
1086
+ locale: "en-US",
1087
+ styles: [
1088
+ "cheerful",
1089
+ "empathetic",
1090
+ "excited",
1091
+ "friendly",
1092
+ "hopeful",
1093
+ "sad",
1094
+ "shouting",
1095
+ "terrified",
1096
+ "unfriendly",
1097
+ "whispering"
1098
+ ]
1099
+ },
1100
+ {
1101
+ name: "en-US-JennyNeural",
1102
+ locale: "en-US",
1103
+ styles: [
1104
+ "assistant",
1105
+ "chat",
1106
+ "customerservice",
1107
+ "newscast",
1108
+ "cheerful",
1109
+ "empathetic",
1110
+ "excited",
1111
+ "friendly",
1112
+ "hopeful",
1113
+ "sad",
1114
+ "shouting",
1115
+ "terrified",
1116
+ "unfriendly",
1117
+ "whispering"
1118
+ ]
1119
+ },
1120
+ { name: "es-ES-ElviraNeural", locale: "es-ES" },
1121
+ { name: "fil-PH-AngeloNeural", locale: "fil-PH" },
1122
+ { name: "fr-FR-DeniseNeural", locale: "fr-FR", styles: ["cheerful", "sad"] },
1123
+ { name: "fr-FR-HenriNeural", locale: "fr-FR", styles: ["cheerful", "sad"] },
1124
+ { name: "id-ID-GadisNeural", locale: "id-ID" },
1125
+ { name: "it-IT-ElsaNeural", locale: "it-IT", styles: ["cheerful", "sad"] },
1126
+ { name: "ja-JP-KeitaNeural", locale: "ja-JP", styles: ["chat"] },
1127
+ { name: "ja-JP-MayuNeural", locale: "ja-JP", styles: ["calm", "cheerful", "sad"] },
1128
+ { name: "ja-JP-NanamiNeural", locale: "ja-JP", styles: ["chat", "customerservice", "cheerful", "whispering", "sad"] },
1129
+ { name: "ko-KR-SunHiNeural", locale: "ko-KR", styles: ["cheerful", "sad"] },
1130
+ { name: "ms-MY-YasminNeural", locale: "ms-MY" },
1131
+ { name: "pt-BR-FranciscaNeural", locale: "pt-BR", styles: ["calm"] },
1132
+ {
1133
+ name: "ru-RU-SvetlanaNeural",
1134
+ locale: "ru-RU",
1135
+ styles: ["cheerful", "sad", "angry", "disgruntled", "embarrassed", "fearful"]
1136
+ },
1137
+ { name: "th-TH-PremwadeeNeural", locale: "th-TH" },
1138
+ { name: "vi-VN-HoaiMyNeural", locale: "vi-VN" },
1139
+ {
1140
+ name: "zh-CN-XiaoxiaoNeural",
1141
+ locale: "zh-CN",
1142
+ styles: [
1143
+ "assistant",
1144
+ "chat",
1145
+ "customerservice",
1146
+ "newscast",
1147
+ "cheerful",
1148
+ "empathetic",
1149
+ "excited",
1150
+ "friendly",
1151
+ "hopeful",
1152
+ "sad",
1153
+ "terrified",
1154
+ "whispering",
1155
+ "poetry-reading",
1156
+ "sports_commentary",
1157
+ "sports_commentary_excited",
1158
+ "story"
1159
+ ]
1160
+ },
1161
+ {
1162
+ name: "zh-CN-YunxiNeural",
1163
+ locale: "zh-CN",
1164
+ styles: [
1165
+ "narration-relaxed",
1166
+ "embarrassed",
1167
+ "fearful",
1168
+ "sad",
1169
+ "disgruntled",
1170
+ "serious",
1171
+ "angry",
1172
+ "depressed",
1173
+ "chat",
1174
+ "cheerful",
1175
+ "assistant"
1176
+ ]
1177
+ },
1178
+ { name: "zh-TW-HsiaoChenNeural", locale: "zh-TW" }
1179
+ ];
1180
+
1049
1181
  // packages/ssml-core/src/azureValidation.ts
1050
- var EXPRESS_AS_STYLES = {
1051
- "en-us-jennyneural": [
1052
- "assistant",
1053
- "chat",
1054
- "customerservice",
1055
- "newscast",
1056
- "cheerful",
1057
- "empathetic",
1058
- "excited",
1059
- "friendly",
1060
- "hopeful",
1061
- "sad",
1062
- "shouting",
1063
- "terrified",
1064
- "unfriendly",
1065
- "whispering"
1066
- ],
1067
- "en-us-guyneural": [
1068
- "angry",
1069
- "cheerful",
1070
- "excited",
1071
- "friendly",
1072
- "hopeful",
1073
- "newscast",
1074
- "sad",
1075
- "shouting",
1076
- "terrified",
1077
- "unfriendly",
1078
- "whispering"
1079
- ],
1080
- "en-us-jennymultilingualneural": [
1081
- "cheerful",
1082
- "empathetic",
1083
- "excited",
1084
- "friendly",
1085
- "hopeful",
1086
- "sad",
1087
- "shouting",
1088
- "terrified",
1089
- "unfriendly",
1090
- "whispering"
1091
- ],
1092
- "en-us-andrewneural": ["empathetic", "relieved"],
1093
- "ja-jp-mayuneural": ["calm", "cheerful", "sad"],
1094
- "ja-jp-nanamineural": ["chat", "customerservice", "cheerful", "whispering", "sad"],
1095
- "ja-jp-keitaneural": ["chat"],
1096
- "ko-kr-sunhineural": ["cheerful", "sad"],
1097
- "zh-cn-yunxineural": [
1098
- "narration-relaxed",
1099
- "embarrassed",
1100
- "fearful",
1101
- "sad",
1102
- "disgruntled",
1103
- "serious",
1104
- "angry",
1105
- "depressed",
1106
- "chat",
1107
- "cheerful",
1108
- "assistant"
1109
- ],
1110
- "zh-cn-xiaoxiaoneural": [
1111
- "assistant",
1112
- "chat",
1113
- "customerservice",
1114
- "newscast",
1115
- "cheerful",
1116
- "empathetic",
1117
- "excited",
1118
- "friendly",
1119
- "hopeful",
1120
- "sad",
1121
- "terrified",
1122
- "whispering",
1123
- "poetry-reading",
1124
- "sports_commentary",
1125
- "sports_commentary_excited",
1126
- "story"
1127
- ],
1128
- "fr-fr-deniseneural": ["cheerful", "sad"],
1129
- "fr-fr-henrineural": ["cheerful", "sad"],
1130
- "pt-br-franciscaneural": ["calm"],
1131
- "it-it-elsaneural": ["cheerful", "sad"],
1132
- "de-de-katjaneural": ["cheerful", "sad"],
1133
- "de-de-conradneural": ["cheerful", "sad"],
1134
- "ru-ru-svetlananeural": ["cheerful", "sad", "angry", "disgruntled", "embarrassed", "fearful"]
1135
- };
1136
1182
  var ALLOWED_BREAK_STRENGTHS = /* @__PURE__ */ new Set(["none", "x-weak", "weak", "medium", "strong", "x-strong"]);
1137
1183
  var ALLOWED_SAY_AS = /* @__PURE__ */ new Set([
1138
1184
  "characters",
@@ -1261,18 +1307,17 @@ function isSupportedProsodyRate(value) {
1261
1307
  const numericValue = Number(multiplier[1]);
1262
1308
  return numericValue >= 0.5 && numericValue <= 2;
1263
1309
  }
1310
+ function isValidAzureAudioDuration(value) {
1311
+ const trimmed = value.trim();
1312
+ const numeric = /^(\d+(?:\.\d+)?)(ms|s)$/.exec(trimmed);
1313
+ if (numeric) return Number(numeric[1]) > 0;
1314
+ const clock = /^(\d{2,}):([0-5]\d):([0-5]\d)(?:\.(\d{1,3}))?$/.exec(trimmed);
1315
+ if (!clock) return false;
1316
+ return Number(clock[1]) > 0 || Number(clock[2]) > 0 || Number(clock[3]) > 0 || Number(clock[4] ?? 0) > 0;
1317
+ }
1264
1318
  function attr(token, name) {
1265
1319
  return token.attributes.get(name.toLowerCase());
1266
1320
  }
1267
- var ADDITIONAL_VOICE_DEFINITIONS = [
1268
- { name: "zh-TW-HsiaoChenNeural", locale: "zh-TW" },
1269
- { name: "es-ES-ElviraNeural", locale: "es-ES" },
1270
- { name: "th-TH-PremwadeeNeural", locale: "th-TH" },
1271
- { name: "fil-PH-AngeloNeural", locale: "fil-PH" },
1272
- { name: "vi-VN-HoaiMyNeural", locale: "vi-VN" },
1273
- { name: "id-ID-GadisNeural", locale: "id-ID" },
1274
- { name: "ms-MY-YasminNeural", locale: "ms-MY" }
1275
- ];
1276
1321
  var DEFAULT_LANGUAGE_ALIASES = {
1277
1322
  "zh-CN": ["zh-Hans"],
1278
1323
  "zh-TW": ["zh-Hant"]
@@ -1335,10 +1380,7 @@ function definitionFromStyleMap(voiceName, styles) {
1335
1380
  }
1336
1381
  function normalizeVoiceCatalog(options) {
1337
1382
  const definitions = /* @__PURE__ */ new Map();
1338
- for (const [name, styles] of Object.entries(EXPRESS_AS_STYLES)) {
1339
- definitions.set(name.toLowerCase(), definitionFromStyleMap(name, styles));
1340
- }
1341
- for (const definition of ADDITIONAL_VOICE_DEFINITIONS) definitions.set(definition.name.toLowerCase(), definition);
1383
+ for (const definition of AZURE_VOICE_DEFINITIONS) definitions.set(definition.name.toLowerCase(), definition);
1342
1384
  for (const definition of options.voiceCatalog ?? []) definitions.set(definition.name.toLowerCase(), definition);
1343
1385
  for (const definition of options.voiceDefinitions ?? []) definitions.set(definition.name.toLowerCase(), definition);
1344
1386
  for (const definition of options.customVoiceDefinitions ?? [])
@@ -1475,6 +1517,18 @@ function validateElement(token, source, diagnostics, voiceName, options, voiceCa
1475
1517
  if (!value || !/^\d+(?:\.\d+)?(?:ms|s)$/.test(value.trim()))
1476
1518
  addDiagnostic(diagnostics, source, token.start, '<mstts:silence> requires a time-valued "value" attribute.');
1477
1519
  }
1520
+ if (name === "mstts:audioduration") {
1521
+ const value = attr(token, "value");
1522
+ if (!value || !isValidAzureAudioDuration(value))
1523
+ addDiagnostic(
1524
+ diagnostics,
1525
+ source,
1526
+ token.start,
1527
+ '<mstts:audioduration> requires a positive duration such as "10s", "5000ms", or "00:00:10".'
1528
+ );
1529
+ if (!token.selfClosing)
1530
+ addDiagnostic(diagnostics, source, token.start, "<mstts:audioduration> must be self-closing.");
1531
+ }
1478
1532
  if (name === "mstts:viseme") {
1479
1533
  const type = attr(token, "type");
1480
1534
  if (!type || !ALLOWED_VISEME_TYPES.has(type))
@@ -1765,6 +1819,7 @@ _options = new WeakMap();
1765
1819
  buildPartialSsml,
1766
1820
  buildSsml,
1767
1821
  extractSsmlText,
1822
+ isValidAzureAudioDuration,
1768
1823
  mapSsmlTextNodes,
1769
1824
  normalizeAzureLanguage,
1770
1825
  parseSsml,