diff --git a/ngapp/src/app/core/services/synthesis.service.ts b/ngapp/src/app/core/services/synthesis.service.ts index 7c2a281ae..39440cc22 100644 --- a/ngapp/src/app/core/services/synthesis.service.ts +++ b/ngapp/src/app/core/services/synthesis.service.ts @@ -49,6 +49,9 @@ export const voices = asVoice([ { name: "Colm", gender: "male", shortCode: "cmg", code: "ga_MU_cmg_nnmnkwii", dialect: "munster", algorithm: "dnn", }, ] as const); +// subset of voices that are confirmed to be working +export const functioningVoices = voices.slice(0,3); + // type defining an entry in the VoiceConfig array export type Voice = (typeof voices)[number]; diff --git a/ngapp/src/app/nav-bar/digital-reader/digital-reader.component.ts b/ngapp/src/app/nav-bar/digital-reader/digital-reader.component.ts index 58c6cbe6e..34d84e514 100644 --- a/ngapp/src/app/nav-bar/digital-reader/digital-reader.component.ts +++ b/ngapp/src/app/nav-bar/digital-reader/digital-reader.component.ts @@ -24,7 +24,8 @@ import { constructJSON } from '@phonlab-tcd/html2json'; import { objectUtil } from 'zod'; import config from '../anScealaiStoryCollectionsConf' -import { SynthesisService, Voice, voices } from 'app/core/services/synthesis.service'; +import { SynthesisService, Voice, functioningVoices } from 'app/core/services/synthesis.service'; +import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ selector: 'app-digital-reader', @@ -44,12 +45,12 @@ export class DigitalReaderComponent implements OnInit { //drStory: DigitalReaderStory; dialogRef: MatDialogRef; - dialectOptions:Array + //dialectOptions:Array adminCollectionOptions:Array = [] - defaultCollectionSelections:Object = {}; + defaultCollectionSelections:any = {}; storyState:string = ''; - @Output() isFirstDrStory = new EventEmitter(); + //@Output() isFirstDrStory = new EventEmitter(); constructor( public ts : TranslationService, @@ -59,16 +60,11 @@ export class DigitalReaderComponent implements OnInit { public http: HttpClient, private dialog: MatDialog, private synth: SynthesisService, - private _ngZone: NgZone,) { - this.dialectOptions = [this.ts.l.connacht, this.ts.l.munster, this.ts.l.ulster] - //console.log(adminStoryCollectionOpts) + private snackbar: MatSnackBar,) { + //this.dialectOptions = [this.ts.l.connacht, this.ts.l.munster, this.ts.l.ulster] console.log(this.ts.l) console.log(this.ts.l.adminStoryCollectionOpts) - /*for (let option in this.ts.l.adminStoryCollectionOpts) { - this.adminCollectionOptions.push(option); - this.defaultCollectionSelections[option] = false; - }*/ for (let option of config.adminStoryCollectionOpts) { //if (this.ts.l[option]) { @@ -76,126 +72,135 @@ export class DigitalReaderComponent implements OnInit { //} this.defaultCollectionSelections[option] = false; } - /*this.adminCollectionOptions = [ - this.ts.l.leaving_cert_stories, - this.ts.l.aesop_fables, - this.ts.l.other_stories, - this.ts.l.simple_versions_old_stories - ]*/ + } - updateSentenceNumbers(targetContainer:Element, startNumber:number) { - let tmp = targetContainer; - let number = startNumber; - while (tmp) { - tmp.setAttribute('sentNumber', number.toString()); - (tmp.querySelector('b') as Element).textContent = number.toString() + ' ' // setting the number element - number++; - tmp = tmp.nextElementSibling; - } - } + async ngOnInit() { + const user = this.auth.getUserDetails(); + if (!user) return; - test() { - console.log('input event fires anyway!') - } - - splitSentence(event:InputEvent) { - console.log(event) - const target:HTMLInputElement = event.target as HTMLInputElement; - - if (event.inputType==="insertLineBreak") { - event.preventDefault(); - const breakIndex:number = getSelection()?.anchorOffset; - const fullTextContent:string = target.textContent; - if (breakIndex > 0 && breakIndex < fullTextContent.length) { - const textPreSplit:string = fullTextContent?.slice(0, breakIndex); - const textPostSplit:string = fullTextContent?.slice(breakIndex, fullTextContent.length); - - console.log(textPreSplit); - console.log(textPostSplit); - - const localContainer = target.parentElement as Element; - const parentContainer = localContainer.parentElement as Element; - - target.textContent = textPostSplit; - - const newSentenceContainer = document.createElement('div'); - - const mergeButton = document.createElement('button'); - mergeButton.className="sentenceMerger" - mergeButton.textContent="merge" // TODO : change to use translation service - mergeButton.tabIndex = -1; - mergeButton.addEventListener('click', (event) => { - this.mergeSentences(event.target as Element); - }) - - const newNumberEl = document.createElement('b'); - const sentNumber = localContainer.getAttribute('sentNumber'); - newNumberEl.textContent = sentNumber + ' '; - - // create new editable element containing the segment before the break - const newSentencePreview = document.createElement('span'); - newSentencePreview.textContent = textPreSplit; - newSentencePreview.className = 'sentencePreview'; - newSentencePreview.contentEditable = "plaintext-only" - newSentencePreview.spellcheck = false; - - newSentencePreview.addEventListener('beforeinput', (event) => { - this.splitSentence(event); - }) - - newSentenceContainer.setAttribute('sentNumber', sentNumber.toString()) - newSentenceContainer.append(mergeButton); - newSentenceContainer.append(document.createElement('br')) - newSentenceContainer.append(newNumberEl); - newSentenceContainer.append(newSentencePreview); - - parentContainer.insertBefore(newSentenceContainer, localContainer); + // get logged-in user details + this.user = await firstValueFrom( this.userService.getUserById(user._id) ); + if (!this.user) return; - this.updateSentenceNumbers(localContainer, parseInt(sentNumber)+1); + console.log(this.user) + console.log(this) - } - } else { - console.log('disallowed!') - event.preventDefault(); - } + } + + updateSentenceNumbers(targetContainer:Element, startNumber:number) { + let tmp = targetContainer; + let number = startNumber; + while (tmp) { + tmp.setAttribute('sentNumber', number.toString()); + (tmp.querySelector('b') as Element).textContent = number.toString() + ' ' // setting the number element + number++; + tmp = tmp.nextElementSibling; } + } + + /*test() { + console.log('input event fires anyway!') + }*/ + + createMergeButton() { + const mergeButton = document.createElement('button'); + mergeButton.className="sentenceMerger"; + mergeButton.textContent="▲ merge ▼"; // TODO : change to use translation service + mergeButton.tabIndex = -1; + mergeButton.addEventListener('click', (event) => { + this.mergeSentences(event.target as Element); + }) + return mergeButton; + } + + createNumberEl(sentNumber:string) { + const newNumberEl = document.createElement('b'); + //const sentNumber = localContainer.getAttribute('sentNumber'); + newNumberEl.textContent = sentNumber + ' '; + return newNumberEl + } + + createSentencePreview(textContent:string) { + const newSentencePreview = document.createElement('span'); + newSentencePreview.textContent = textContent; + newSentencePreview.className = 'sentencePreview'; + newSentencePreview.contentEditable = "plaintext-only" + newSentencePreview.spellcheck = false; + + newSentencePreview.addEventListener('beforeinput', (event) => { + this.splitSentence(event); + }) + + return newSentencePreview; + } + + createSentencePreviewContainer(mergeButton:Element, newNumberEl:Element, newSentencePreview:Element, sentNumber:string) { + const newSentenceContainer = document.createElement('div'); + newSentenceContainer.setAttribute('sentNumber', sentNumber) + newSentenceContainer.append(mergeButton); + newSentenceContainer.append(document.createElement('br')) + newSentenceContainer.append(newNumberEl); + newSentenceContainer.append(newSentencePreview); + return newSentenceContainer; + } - mergeSentences(target:Element) { - const localContainer:Element = target.parentElement; - const currentSentence:Element = localContainer?.querySelector('.sentencePreview'); + splitSentence(event:InputEvent) { + + const target:Element = event.target as Element; - const previousLocalContainer:Element = localContainer?.previousElementSibling; + if (event.inputType==="insertLineBreak") { + event.preventDefault(); + const breakIndex:number = getSelection()?.anchorOffset as number; + const fullTextContent:string = target.textContent; + if (breakIndex > 0 && breakIndex < fullTextContent.length) { + const textPreSplit:string = fullTextContent?.slice(0, breakIndex); + const textPostSplit:string = fullTextContent?.slice(breakIndex, fullTextContent.length); - if (previousLocalContainer) { - const previousSentence:Element = previousLocalContainer.querySelector('.sentencePreview'); - const sentNumber = previousLocalContainer.getAttribute('sentNumber'); - console.log(sentNumber); + console.log(textPreSplit); + console.log(textPostSplit); - console.log(previousSentence?.textContent + currentSentence?.textContent); - localContainer.remove(); - previousSentence.textContent = previousSentence?.textContent + currentSentence?.textContent; + const localContainer = target.parentElement as Element; + const parentContainer = localContainer.parentElement as Element; - this.updateSentenceNumbers(previousLocalContainer, parseInt(sentNumber)); - } + target.textContent = textPostSplit; + + const mergeButton = this.createMergeButton(); + + const sentNumber:string = localContainer.getAttribute('sentNumber') as string; + const newNumberEl = this.createNumberEl(sentNumber); + + // create new editable element containing the segment before the break + const newSentencePreview = this.createSentencePreview(textPreSplit) + + const newSentenceContainer = this.createSentencePreviewContainer(mergeButton, newNumberEl, newSentencePreview, sentNumber); + + parentContainer.insertBefore(newSentenceContainer, localContainer); + + this.updateSentenceNumbers(localContainer, parseInt(sentNumber)+1); + + } + } else { + console.log('only return is allowed!') + event.preventDefault(); } + } - /*test2(target:HTMLInputElement) { - //(input)="this.style.height = ''; this.style.height = this.scrollHeight +'px'; console.log(this.style)" - target.style.height = target.scrollHeight +'px'; - }*/ + mergeSentences(target:Element) { + const localContainer:Element = target.parentElement as Element; + const currentSentence:Element = localContainer?.querySelector('.sentencePreview') as Element; - async ngOnInit() { - const user = this.auth.getUserDetails(); - if (!user) return; + const previousLocalContainer:Element = localContainer?.previousElementSibling as Element; - // get logged-in user details - this.user = await firstValueFrom( this.userService.getUserById(user._id) ); - if (!this.user) return; + if (previousLocalContainer) { + const previousSentence:Element = previousLocalContainer.querySelector('.sentencePreview') as Element; + const sentNumber:string = previousLocalContainer.getAttribute('sentNumber') as string; - console.log(this.user) - console.log(this) + localContainer.remove(); + previousSentence.textContent = (previousSentence?.textContent as string) + (currentSentence?.textContent as string); + this.updateSentenceNumbers(previousLocalContainer, parseInt(sentNumber)); + } } async convertDocxToHTML() { @@ -213,8 +218,29 @@ export class DigitalReaderComponent implements OnInit { } + synthesiseStory(storyId:string, sentenceSpans:NodeListOf) { + + for (let voice of functioningVoices) { + + for (let j=0;j { @@ -310,14 +333,6 @@ export class DigitalReaderComponent implements OnInit { return; } - // save the response object here - /*return { - title: res.title, - collections: collections, - thumbnail: thumbnail, - //story: story, - public: res.public - }*/ this.storyOptions = { title: res.title, collections: collections, @@ -326,6 +341,8 @@ export class DigitalReaderComponent implements OnInit { public: res.public } + this.snackbar.open(this.ts.l.enter_to_split_message, this.ts.l.okay, {duration: 6000}); + /* Temporarily commented out for testing if (this.convertedHTMLDoc) { //console.log(this.convertedHTMLDoc) @@ -395,7 +412,8 @@ export class DigitalReaderComponent implements OnInit { next: (response) => { console.log('a response was received') this.storyState = 'processed' - this.synthesiseStory(this.segmentedHTMLDoc, response.id); + //this.synthesiseStory(this.segmentedHTMLDoc, response.id); + this.synthesiseStory(response.id, this.segmentedHTMLDoc?.querySelectorAll('.sentence')); }, error: () => { alert("Not able to create a new story"); diff --git a/ngapp/src/app/nav-bar/nav-bar.module.ts b/ngapp/src/app/nav-bar/nav-bar.module.ts index 5e2596839..c5d80e1ac 100644 --- a/ngapp/src/app/nav-bar/nav-bar.module.ts +++ b/ngapp/src/app/nav-bar/nav-bar.module.ts @@ -12,6 +12,7 @@ import { MatDividerModule } from '@angular/material/divider'; import { FormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; import { NavBarRoutingModule } from './nav-bar-routing.module'; import { NavBarComponent } from './nav-bar/nav-bar.component'; @@ -68,7 +69,8 @@ import { FiosComponent } from './fios/fios.component'; MatDividerModule, FormsModule, MatInputModule, - MatFormFieldModule + //MatFormFieldModule, + MatSnackBarModule ] }) export class NavBarModule { } diff --git a/ngapp/src/app/translation.ts b/ngapp/src/app/translation.ts index 915eb31ce..a8e72e14f 100644 --- a/ngapp/src/app/translation.ts +++ b/ngapp/src/app/translation.ts @@ -245,6 +245,9 @@ const translations = { processing: { ga: 'Á phróiseáil', en: 'Processing' }, + enter_to_split_message: { + ga: "Brúigh ENTER laistigh d'abairt chun é a scoilteadh ina dhá", + en: 'Press ENTER within a sentence to split it in two' }, confirm_sentences: { ga: 'Ar dheimhnigh tú na habairtí atá thíos ?', en: 'Have you confirmed the below sentences?' },