mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Set language/rate in prosody XML
This commit is contained in:
parent
e298a49169
commit
4f6d8cdfce
3 changed files with 47 additions and 20 deletions
|
|
@ -131,16 +131,20 @@ export type SSMLItem = {
|
|||
textItems: string[]
|
||||
}
|
||||
|
||||
export type VoiceOptions = {
|
||||
primary: string
|
||||
secondary: string
|
||||
export type SSMLOptions = {
|
||||
primaryVoice: string
|
||||
secondaryVoice: string
|
||||
rate: string
|
||||
language: string
|
||||
}
|
||||
|
||||
const startSsml = (element: Element, voices: VoiceOptions): string => {
|
||||
const startSsml = (element: Element, options: SSMLOptions): string => {
|
||||
const voice =
|
||||
element.nodeName === 'BLOCKQUOTE' ? voices.secondary : voices.primary
|
||||
element.nodeName === 'BLOCKQUOTE'
|
||||
? options.secondaryVoice
|
||||
: options.primaryVoice
|
||||
return `
|
||||
<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="${voice}"><prosody rate="0%" pitch="0%">
|
||||
<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="${options.language}"><voice name="${voice}"><prosody rate="${options.rate}" pitch="default">
|
||||
`
|
||||
}
|
||||
|
||||
|
|
@ -152,10 +156,7 @@ export const ssmlItemText = (item: SSMLItem): string => {
|
|||
return [item.open, ...item.textItems, item.close].join('')
|
||||
}
|
||||
|
||||
export const htmlToSsml = (
|
||||
html: string,
|
||||
voices: { primary: string; secondary: string }
|
||||
): SSMLItem[] => {
|
||||
export const htmlToSsml = (html: string, options: SSMLOptions): SSMLItem[] => {
|
||||
const dom = parseHTML(html)
|
||||
const body = dom.document.querySelector('#readability-page-1')
|
||||
if (!body) {
|
||||
|
|
@ -174,7 +175,7 @@ export const htmlToSsml = (
|
|||
|
||||
i = emitElement(textItems, node, true)
|
||||
items.push({
|
||||
open: startSsml(node, voices),
|
||||
open: startSsml(node, options),
|
||||
close: endSsml(),
|
||||
textItems: textItems,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -217,8 +217,10 @@ const synthesizeTextToSpeech = async (
|
|||
}
|
||||
} else {
|
||||
const ssmlItems = htmlToSsml(input.text, {
|
||||
primary: speechConfig.speechSynthesisVoiceName,
|
||||
secondary: 'en-US-GuyNeural',
|
||||
primaryVoice: speechConfig.speechSynthesisVoiceName,
|
||||
secondaryVoice: 'en-US-GuyNeural',
|
||||
language: speechConfig.speechSynthesisLanguage,
|
||||
rate: '1',
|
||||
})
|
||||
|
||||
for (const ssmlItem of Array.from(ssmlItems)) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
import 'mocha'
|
||||
import { expect } from 'chai'
|
||||
|
||||
import fs from 'fs'
|
||||
import { glob } from 'glob'
|
||||
import { htmlToSsml } from '../src/htmlToSsml'
|
||||
|
||||
describe('htmlToSsml', () => {
|
||||
const TEST_VOCIES = { primary: 'test-primary', secondary: 'test-secondary' }
|
||||
const TEST_OPTIONS = {
|
||||
primaryVoice: 'test-primary',
|
||||
secondaryVoice: 'test-secondary',
|
||||
language: 'en-US',
|
||||
rate: '1'
|
||||
}
|
||||
|
||||
describe('a simple html file', () => {
|
||||
it('should convert Html to SSML', async () => {
|
||||
|
|
@ -11,7 +19,7 @@ describe('htmlToSsml', () => {
|
|||
<div class="page" id="readability-page-1">
|
||||
<p data-omnivore-anchor-idx="1">this is some text</p>
|
||||
</div>
|
||||
`, TEST_VOCIES
|
||||
`, TEST_OPTIONS
|
||||
)
|
||||
const text = ssml[0].textItems.join('').trim()
|
||||
expect(text).to.equal(
|
||||
|
|
@ -29,7 +37,7 @@ this is in the first paragraph
|
|||
this is also in the first paragraph
|
||||
</p>
|
||||
</div>
|
||||
`, TEST_VOCIES
|
||||
`, TEST_OPTIONS
|
||||
)
|
||||
const text = ssml[0].textItems.join('').trim()
|
||||
expect(text).to.equal(
|
||||
|
|
@ -45,7 +53,7 @@ this is also in the first paragraph
|
|||
<blockquote>second</blockquote>
|
||||
<p>third</p>
|
||||
</div>
|
||||
`, TEST_VOCIES
|
||||
`, TEST_OPTIONS
|
||||
)
|
||||
const first = ssml[0].textItems.join('').trim()
|
||||
const second = ssml[1].textItems.join('').trim()
|
||||
|
|
@ -62,14 +70,30 @@ this is also in the first paragraph
|
|||
)
|
||||
|
||||
expect(ssml[0].open.trim()).to.equal(
|
||||
`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="test-primary"><prosody rate="0%" pitch="0%">`
|
||||
`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="test-primary"><prosody rate="1" pitch="default">`
|
||||
)
|
||||
expect(ssml[1].open.trim()).to.equal(
|
||||
`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="test-secondary"><prosody rate="0%" pitch="0%">`
|
||||
`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="test-secondary"><prosody rate="1" pitch="default">`
|
||||
)
|
||||
expect(ssml[2].open.trim()).to.equal(
|
||||
`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="test-primary"><prosody rate="0%" pitch="0%">`
|
||||
`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="test-primary"><prosody rate="1" pitch="default">`
|
||||
)
|
||||
})
|
||||
})
|
||||
// For local testing:
|
||||
// describe('readability test files', () => {
|
||||
// it('should convert Html to SSML without throwing', async () => {
|
||||
// const g = new glob.GlobSync('../readabilityjs/test/test-pages/*')
|
||||
// console.log('glob: ', glob)
|
||||
// for (const f of g.found) {
|
||||
// const readablePath = `${f}/expected.html`
|
||||
// if (!fs.existsSync(readablePath)) {
|
||||
// continue
|
||||
// }
|
||||
// const html = fs.readFileSync(readablePath, { encoding: 'utf-8' })
|
||||
// const ssmlItems = htmlToSsml(html, TEST_OPTIONS)
|
||||
// console.log('SSML ITEMS', ssmlItems)
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue