Skip to content

Commit

Permalink
Merge pull request #7 from cadia-lvl/ssml
Browse files Browse the repository at this point in the history
Ssml
  • Loading branch information
staffanru authored Sep 19, 2022
2 parents 75e6baf + fd8105b commit c0b09cc
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 12 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.zip
2 changes: 2 additions & 0 deletions constants/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const CONTENT_COMMANDS = {
CHANGE_PLAYBACK_RATE: 'change_playback_rate',
GET_PLAYBACK_RATE: 'get_playback_rate',
UPDATE_VALUE: 'update_value',
PLAY_SSML: 'play_ssml',
};

const BACKGROUND_COMMANDS = {
Expand All @@ -29,6 +30,7 @@ const WEBRICE_KEYS = {
SUBSTITUTIONS: 'webrice_substitutions',
VOLUME: 'webrice_volume',
AWS_CREDS: 'webrice_aws_creds',
SSML_TEXT: 'webrice_ssml_text',
};

const BACKENDS = {
Expand Down
12 changes: 9 additions & 3 deletions content/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const settings = {
pitch_default: true,
subs: [],
text: '',
ssml: '',
};

// Sends messages to the background script
Expand Down Expand Up @@ -60,15 +61,15 @@ const getText = () => {
* Start playing audio. If needed setup and requesting of new audio is done.
* @returns SUCCESS or an error message
*/
const play = async () => {
const text = getText();
const play = async ({ ssml = false } = {}) => {
const text = ssml ? settings.ssml : getText();
if (player.sameTextAndVoice(text, settings.voice)) {
player.setPlaybackRate(settings.playbackRate);
player.play();
return 'SUCCESS';
}

const result = getRequestHeaderAndContent(text, settings);
const result = getRequestHeaderAndContent(text, settings, ssml);

if (result.requests.length == 0) {
return 'Unable to formulate tts requests.';
Expand Down Expand Up @@ -168,6 +169,9 @@ const updateSetting = (setting, value) => {
settings.volume = value;
player.setVolume(value);
break;
case WEBRICE_KEYS.SSML_TEXT:
settings.ssml = value;
break;
default:
break;
}
Expand Down Expand Up @@ -202,6 +206,8 @@ const commandHandler = async (message) => {
const { setting, value } = message.settings;
updateSetting(setting, value);
break;
case CONTENT_COMMANDS.PLAY_SSML:
return await play({ ssml: false });
default:
console.log(`WebRice extension: Unknown command -> ${message.command}`);
break;
Expand Down
40 changes: 34 additions & 6 deletions content/fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,26 @@ const normalizeText = (text, specialTrim = false) => {
* Normalizes the text and outputs an array of tts requests
* @param {string} text text to normalize for tts
* @param {object} settings eventual settings that might be used to change voice
* @param {boolean} ssml default false, turns on SSML settings for the request
* @returns an array of requests, {url, content}
*/
const getRequestHeaderAndContent = (text, settings) => {
const getRequestHeaderAndContent = (text, settings, ssml = false) => {
const audioType = 'mp3';
const voiceName = settings?.voice ? settings.voice : DEFAULT_VOICE;
const awsVoice = AWS_VOICES.includes(settings?.voice);

if (ssml) {
const ssml = `<speak>${text}</speak>`;
const request = awsVoice
? awsRequest(ssml, audioType, voiceName, true)
: tiroRequest(ssml, audioType, voiceName, true);
return {
backend: awsVoice ? BACKENDS.POLLY : BACKENDS.TIRO,
requests: [request],
};
}
const specialTrim = SPECIAL_VOICES.includes(voiceName);
const normalizedTexts = normalizeText(text, specialTrim);
const awsVoice = AWS_VOICES.includes(settings?.voice);

const requests = normalizedTexts.map((text) => {
const request = awsVoice
Expand All @@ -72,7 +84,15 @@ const getRequestHeaderAndContent = (text, settings) => {
return { backend: awsVoice ? BACKENDS.POLLY : BACKENDS.TIRO, requests };
};

const tiroRequest = (text, audioType, voiceName) => {
/**
* Creates the Tiro tts request.
* @param {string} text The text that should be converted to TTS
* @param {string} audioType The wanted audio output type
* @param {string} voiceName The voice used for TTS
* @param {boolean} ssml If the request handles SSML or not
* @returns
*/
const tiroRequest = (text, audioType, voiceName, ssml = false) => {
const url = 'https://tts.tiro.is/v0/speech';

return {
Expand All @@ -92,13 +112,21 @@ const tiroRequest = (text, audioType, voiceName) => {
SampleRate: '16000',
SpeechMarkTypes: [],
Text: text,
TextType: 'text',
TextType: ssml ? 'ssml' : 'text',
VoiceId: voiceName,
}),
},
};
};

const awsRequest = (text, audioType, voiceName) => {
return pollyParams(text, audioType, voiceName);
/**
* Creates the AWS polly request.
* @param {string} text The text that should be converted to TTS
* @param {string} audioType The wanted audio output type
* @param {string} voiceName The voice used for TTS
* @param {boolean} ssml If the request handles SSML or not
* @returns
*/
const awsRequest = (text, audioType, voiceName, ssml = false) => {
return pollyParams(text, audioType, voiceName, ssml);
};
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "WebRICE",
"version": "1.0.3",
"version": "1.0.4",

"description": "Text to speech service for icelandic",
"homepage_url": "https://www.webrice.is",
Expand Down
5 changes: 5 additions & 0 deletions popup/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ details > summary {
margin-bottom: 0.25rem;
}

.small_margins {
margin-bottom: 0.25rem;
margin-top: 0.25rem;
}

.verification_item {
border-radius: 1rem;
background: white;
Expand Down
35 changes: 35 additions & 0 deletions popup/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,41 @@ <h3>Hljóðstyrkur</h3>
/>
</div>
</div>
<div class="webrice_more_item">
<details id="ssml_details">
<summary>SSML</summary>
<div class="webrice_flex_column gap_small">
<p small_margins>
Speech Synthesis Markup Language (SSML) gerir kleift að sérsníða
Text-To-Speech.
</p>
<h3 class="small_bottom_margin">Upplýsingar</h3>
<p class="small_margins">
Sjálfgefið bakendakerfi er veitt af Tiro og studd SSML merki og
dæmi má finna
<a href="https://tts.tiro.is/#tag/speech/paths/~1v0~1speech/post"
>hér</a
>.
</p>
<p id="help_aws" class="webrice_hide small_margins">
Fyrir Amazon Polly raddir (Karl, Dora) eru viðbótar SSML merki
studd. Dæmi og studd merki má finna
<a
href="https://docs.aws.amazon.com/polly/latest/dg/supportedtags.html"
>hér</a
>.
</p>
<p class="small_margins">
Sláðu inn SSML í textareitinn fyrir neðan og smelltu á
spilunarhnappinn ofan til að prófa.
</p>
<code>&lt;speak&gt;</code>
<textarea rows="10" id="webrice_ssml_text"></textarea>
<code>&lt;/speak&gt;</code>
<p id="ssml_error" class="webrice_hide small_margins"></p>
</div>
</details>
</div>
<div class="webrice_more_item">
<details>
<summary>TTS bakgrunnskerfi</summary>
Expand Down
45 changes: 44 additions & 1 deletion popup/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ const resetAWSCredsButton = document.getElementById('aws_reset_button');
const resetAWSCredsDiv = document.getElementById('aws_reset');
const doraRadio = document.getElementById('dora_aws');
const karlRadio = document.getElementById('karl_aws');
const helpAWS = document.getElementById('help_aws');
const SSMLText = document.getElementById('webrice_ssml_text');
const SSMLdetails = document.getElementById('ssml_details');

loadingIcon.style.display = 'none'; // start by hiding loading icon

Expand Down Expand Up @@ -101,7 +104,12 @@ const toggleLoad = () => {
*/
const onPlayClicked = async () => {
toggleLoad();
const result = await sendToContent('play clicked', CONTENT_COMMANDS.PLAY);
// If SSML section is open and the more container is visible => request TTS with SSML
const command =
SSMLdetails.open && !isHidden(moreContainer)
? CONTENT_COMMANDS.PLAY_SSML
: CONTENT_COMMANDS.PLAY;
const result = await sendToContent('play clicked', command);
toggleLoad();
return result;
};
Expand Down Expand Up @@ -168,6 +176,11 @@ const onRadioClicked = (e) => {
updateValue(WEBRICE_KEYS.VOICE, voice);
};

/**
* Updates a value both in storage and in content
* @param {string} key The key of the value to update
* @param {any} value The value that should be stored.
*/
const updateValue = (key, value) => {
saveToStorage(key, value);
updateContentValue(key, value);
Expand All @@ -190,10 +203,22 @@ const onPitchDefaultChanged = (e) => {
pitchSliderDiv.classList.remove('webrice_disabled');
};

/**
* Updates values when volume slider changes
* @param {event} e
*/
const onVolumeSliderChanged = (e) => {
updateValue(WEBRICE_KEYS.VOLUME, e.target.valueAsNumber);
};

/**
* Keeps the SSML values updated in storage and content
* @param {event} e
*/
const onSSMLTextChanged = (e) => {
updateValue(WEBRICE_KEYS.SSML_TEXT, e.target.value);
};

/**HTMLElement
* On the AWS form submit update the stored values
* @param {Event} e
Expand Down Expand Up @@ -225,16 +250,27 @@ const onAWSFormSubmit = async (e) => {
saveToStorage(WEBRICE_KEYS.AWS_CREDS, awsCreds);
};

/**
* Hides AWS credential input fields
*/
const hideAWSCreds = () => {
hide(awsForm);
show(resetAWSCredsDiv);
};

/**
* Displays the AWS Form and hides the rest button
*/
const onResetAWS = () => {
show(awsForm);
hide(resetAWSCredsDiv);
};

/**
* Used to initialize values from storage into the popup form
* @param {string} key
* @param {any} value
*/
const initialize = (key, value) => {
switch (key) {
case WEBRICE_KEYS.PITCH:
Expand Down Expand Up @@ -271,11 +307,17 @@ const initialize = (key, value) => {
hideAWSCreds();
show(doraRadio);
show(karlRadio);
show(helpAWS);
break;
}
break;
case WEBRICE_KEYS.VOICE:
updateContentValue(key, value);
break;
case WEBRICE_KEYS.SSML_TEXT:
SSMLText.value = value;
updateContentValue(key, value);
break;
default:
break;
}
Expand All @@ -301,6 +343,7 @@ pitchSlider.onchange = onPitchSliderChanged;
volumeSlider.oninput = onVolumeSliderChanged;
awsForm.onsubmit = onAWSFormSubmit;
resetAWSCredsButton.onclick = onResetAWS;
SSMLText.onkeyup = onSSMLTextChanged;

let initialVoice = await getFromStorage(WEBRICE_KEYS.VOICE);
if (!initialVoice) {
Expand Down
3 changes: 2 additions & 1 deletion utils/aws-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ const testAws = async (region, accessKeyId, secretAccessKey) => {
}
};

const pollyParams = (text, audioType, voice) => {
const pollyParams = (text, audioType, voice, ssml = false) => {
params = {
Engine: 'standard',
Text: text,
TextType: ssml ? 'ssml' : 'text',
OutputFormat: audioType,
VoiceId: voice,
};
Expand Down

0 comments on commit c0b09cc

Please sign in to comment.