From 0e2de4142f7aea5c40b03c434059389a3d8ea47e Mon Sep 17 00:00:00 2001 From: Butterscotch! Date: Mon, 29 Jan 2024 05:29:25 -0500 Subject: [PATCH] Queue when current paragraph is too long --- .../MessageSystem/MessageQueueTests.cs | 44 ++++++ ButterSTT/MessageSystem/MessageQueue.cs | 131 +++++++++++++----- ButterSTT/TextProcessing/EnglishTextParser.cs | 2 +- 3 files changed, 138 insertions(+), 39 deletions(-) diff --git a/ButterSTT.Tests/MessageSystem/MessageQueueTests.cs b/ButterSTT.Tests/MessageSystem/MessageQueueTests.cs index e9f7186..64b1337 100644 --- a/ButterSTT.Tests/MessageSystem/MessageQueueTests.cs +++ b/ButterSTT.Tests/MessageSystem/MessageQueueTests.cs @@ -139,5 +139,49 @@ public void MaxDequeueTest() output.WriteLine($"Second message: \"{curMessage}\""); Assert.Equal($"queue system. {secondMessage}", curMessage); } + + [Fact()] + public void RealtimeAppendingTooLongTest() + { + var queue = new MessageQueue + { + MessageLength = 33, + WordTime = TimeSpan.Zero, + MaxWordsDequeued = int.MaxValue + }; + + // Initial message, fully completed + var firstMessage = "Testing the queue system."; + queue.CurParagraph = EnglishTextParser.ParseParagraph(firstMessage); + queue.FinishCurrentParagraph(); + + // Add a partial sentence to it + var secondMessage = "Second test "; + queue.CurParagraph = EnglishTextParser.ParseParagraph(secondMessage); + var curMessage = queue.GetCurrentMessage(); + output.WriteLine($"Appended message: \"{curMessage}\""); + Assert.Equal($"{firstMessage} Second-", curMessage); + } + + [Fact()] + public void RealtimeTooLongTest() + { + var queue = new MessageQueue + { + MessageLength = 18, + WordTime = TimeSpan.Zero, + MaxWordsDequeued = int.MaxValue + }; + + queue.CurParagraph = EnglishTextParser.ParseParagraph("Testing th"); + var curMessage = queue.GetCurrentMessage(); + output.WriteLine($"First message: \"{curMessage}\""); + Assert.Equal("Testing", curMessage); + + queue.CurParagraph = EnglishTextParser.ParseParagraph("Testing the queue system."); + curMessage = queue.GetCurrentMessage(); + output.WriteLine($"Second message: \"{curMessage}\""); + Assert.Equal("Testing the queue-", curMessage); + } } } diff --git a/ButterSTT/MessageSystem/MessageQueue.cs b/ButterSTT/MessageSystem/MessageQueue.cs index 71bc80f..98771fa 100644 --- a/ButterSTT/MessageSystem/MessageQueue.cs +++ b/ButterSTT/MessageSystem/MessageQueue.cs @@ -34,7 +34,7 @@ public void LimitParagraphIndex() } } - public void FinishCurrentParagraph() + public IEnumerable ParagraphWordEnumerator() { // Limit the index if length has changed since last known LimitParagraphIndex(); @@ -42,16 +42,24 @@ public void FinishCurrentParagraph() // Queue all words after the current displayed ones for (var s = CurIndex.sentence; s < CurParagraph.Sentences.Length; s++) { - var wordCount = CurParagraph.Sentences[s].Words.Length; - for (var w = CurIndex.word; w < wordCount; w++) + var sentence = CurParagraph.Sentences[s]; + for ( + var w = s <= CurIndex.sentence ? CurIndex.word : 0; + w < sentence.Words.Length; + w++ + ) { - var word = CurParagraph.Sentences[s].Words[w]; - WordQueue.Enqueue( - $"{word.Text}{(w + 1 >= wordCount && !word.Text.EndsWith(' ') ? " " : "")}" - ); + yield return sentence.Words[w].Text; } - // Reset word index to 0 for following sentences - CurIndex.word = 0; + } + } + + public void FinishCurrentParagraph() + { + // Queue all words after the current displayed ones + foreach (var word in ParagraphWordEnumerator()) + { + WordQueue.Enqueue(word); } // Reset states @@ -59,43 +67,43 @@ public void FinishCurrentParagraph() CurIndex = default; } - public string GetCurrentMessage() + public int ParagraphLengthFromIndex() => ParagraphWordEnumerator().Sum(w => w.Length); + + public void QueueParagraphToFit(int padding = 0) { - // Remove expired words if more space is needed - if (WordQueue.Count > 0 || CurParagraph.Length > 0) + // Limit the index if length has changed since last known + LimitParagraphIndex(); + + var paragraphLen = ParagraphLengthFromIndex(); + // Queue as few words after the current displayed ones + for (var s = CurIndex.sentence; s < CurParagraph.Sentences.Length; s++) { - var dequeueCount = 0; - while ( - dequeueCount++ < MaxWordsDequeued - && MessageWordQueue.TryPeek(out var expiredWord) - && DateTime.UtcNow >= expiredWord.ExpiryTime + var sentence = CurParagraph.Sentences[s]; + for ( + var w = s <= CurIndex.sentence ? CurIndex.word : 0; + w < sentence.Words.Length; + w++ ) { - CurMessageLength -= MessageWordQueue.Dequeue().Text.Length; - } - } + if (paragraphLen <= MessageLength - padding) + { + CurIndex = (s, w); + return; + } - // If there's no queue and there's new words to display - if (WordQueue.Count <= 0 && CurParagraph.Length > 0) - { - // Fit the whole current paragraph in the message if possible - if (CurParagraph.Length <= MessageLength - CurMessageLength) - { - return string.Concat( - string.Concat(MessageWordQueue.Select(w => w.Text)), - string.Concat( - CurParagraph.Sentences.SelectMany(x => x.Words, (x, y) => y.Text) - ) - ) - .Trim(); + var word = sentence.Words[w].Text; + WordQueue.Enqueue(word); + paragraphLen -= word.Length; } } + } - // Make sure there is enough room to fit a new word in the message and - // allow space for a dash after the current text if there is already more + private void ProgressWordQueue() + { + // Make sure there is enough room to fit a new word in the message while ( WordQueue.TryPeek(out var newWord) - && CurMessageLength + newWord.Length + (WordQueue.Count > 1 ? 1 : 0) < MessageLength + && CurMessageLength + newWord.Length < MessageLength ) { var word = WordQueue.Dequeue(); @@ -109,9 +117,56 @@ public string GetCurrentMessage() ); CurMessageLength += word.Length; } + } + + public string GetCurrentMessage() + { + // Remove expired words if more space is needed + if (WordQueue.Count > 0 || CurParagraph.Length > 0) + { + var dequeueCount = 0; + while ( + dequeueCount++ < MaxWordsDequeued + && MessageWordQueue.TryPeek(out var expiredWord) + && DateTime.UtcNow >= expiredWord.ExpiryTime + ) + { + CurMessageLength -= MessageWordQueue.Dequeue().Text.Length; + } + } + + if (CurParagraph.Length >= MessageLength) + { + // Queue with a padding of the max words times the average word length + QueueParagraphToFit(MaxWordsDequeued * 6); + } + + ProgressWordQueue(); + + var message = string.Concat(MessageWordQueue.Select(w => w.Text)); + + // If there's no queue and there's new words to display + if (WordQueue.Count <= 0 && CurParagraph.Length > 0) + { + var availableLength = MessageLength - CurMessageLength; + var totalTaken = 0; + var paragraph = string.Concat( + ParagraphWordEnumerator() + .TakeWhile(w => + { + if (totalTaken + w.Length <= availableLength) + { + totalTaken += w.Length; + return true; + } + else + return false; + }) + ); + return (message + paragraph).Trim() + (CurParagraph.Length > totalTaken ? "-" : ""); + } - var message = string.Concat(MessageWordQueue.Select(w => w.Text)).Trim(); - return $"{message}{(WordQueue.Count > 0 ? "-" : "")}"; + return message.Trim() + (WordQueue.Count > 0 ? "-" : ""); } } } diff --git a/ButterSTT/TextProcessing/EnglishTextParser.cs b/ButterSTT/TextProcessing/EnglishTextParser.cs index 7e376e1..f77e9bb 100644 --- a/ButterSTT/TextProcessing/EnglishTextParser.cs +++ b/ButterSTT/TextProcessing/EnglishTextParser.cs @@ -18,7 +18,7 @@ public static Sentence ParseSentence(string text) { Word[] words = WordOnlyCompleteKeepUrl() .Matches(text) - .Select(m => new Word(m.Value)) + .Select(m => new Word(m.Value.EndsWith(' ') ? m.Value : m.Value + " ")) .ToArray(); return new Sentence(words); }