Latest state before reworking with cluade 4.6.

This commit is contained in:
2026-02-12 22:44:44 +00:00
parent b1387f4833
commit c745efd1d2
6 changed files with 565 additions and 570 deletions
+246
View File
@@ -0,0 +1,246 @@
/**
* SentenceQueueModule
* Manages the preparation pipeline for sentences, including TTS generation
*/
import { BaseModule } from './base-module.js';
class SentenceQueueModule extends BaseModule {
constructor() {
super('sentence-queue', 'Sentence Queue');
// Dependencies
this.dependencies = ['text-buffer', 'tts-factory', 'tts-player'];
// Queue state
this.sentenceQueue = [];
this.isProcessing = false;
this.onSentenceReadyCallback = null;
// Bind methods
this.bindMethods([
'initialize',
'addSentence',
'processNextSentence',
'setOnSentenceReady',
'completeSentence'
]);
}
/**
* Initialize the module
* @returns {Promise<boolean>} - Resolves with success status
*/
async initialize() {
try {
// Get dependencies
const textBuffer = this.getModule('text-buffer');
if (!textBuffer) {
console.error("SentenceQueue: TextBuffer dependency not found");
return false;
}
// Set up the text buffer to send sentences to this queue
textBuffer.setOnSentenceReady((sentence, callback) => {
this.addSentence(sentence, callback);
});
this.reportProgress(100, "Sentence queue ready");
return true;
} catch (error) {
console.error("Error initializing Sentence Queue:", error);
return false;
}
}
/**
* Set callback for when a sentence is ready for display
* @param {Function} callback - Function to call with prepared sentence
*/
setOnSentenceReady(callback) {
if (typeof callback === 'function') {
this.onSentenceReadyCallback = callback;
}
}
/**
* Add a sentence to the queue
* @param {string} sentence - Sentence to add
* @param {Function} callback - Callback to call when sentence is processed
*/
addSentence(sentence, callback) {
this.sentenceQueue.push({
text: sentence,
callback: callback
});
// Process the queue if not already processing
if (!this.isProcessing) {
this.processNextSentence();
}
}
/**
* Process the next sentence in the queue
*/
async processNextSentence() {
if (this.sentenceQueue.length === 0 || this.isProcessing) {
return;
}
this.isProcessing = true;
const item = this.sentenceQueue[0]; // Don't remove yet
try {
// Get TTS Factory
const ttsFactory = this.getModule('tts-factory');
if (!ttsFactory) {
console.error("SentenceQueue: TTSFactory dependency not found");
this.completeSentence(item, { success: false, reason: 'no_tts_factory' });
return;
}
// Create a speech metadata object
const speechMetadata = await this.prepareSpeechMetadata(item.text);
// If we have a callback for ready sentences, call it with the metadata
if (this.onSentenceReadyCallback) {
this.onSentenceReadyCallback(item.text, speechMetadata, () => {
// Remove from queue and process next
this.completeSentence(item, { success: true });
});
} else {
// No callback, just complete
this.completeSentence(item, { success: true });
}
} catch (error) {
console.error("Error processing sentence:", error);
this.completeSentence(item, { success: false, reason: error.message });
}
}
/**
* Prepare speech metadata for a sentence
* @param {string} text - Text to prepare speech for
* @returns {Promise<Object>} - Speech metadata object
*/
async prepareSpeechMetadata(text) {
const ttsFactory = this.getModule('tts-factory');
const ttsPlayer = this.getModule('tts-player');
if (!ttsFactory || !ttsPlayer) {
throw new Error("TTS dependencies not found");
}
// Check if TTS is enabled
const isTtsEnabled = ttsPlayer.isEnabled();
// If TTS is disabled, estimate duration based on character count
if (!isTtsEnabled) {
return this.estimateSpeechDuration(text);
}
try {
// Preload the speech to get metadata
const result = await ttsFactory.preloadSpeech(text);
if (!result.success) {
console.warn("SentenceQueue: Speech preload failed, using estimated duration");
return this.estimateSpeechDuration(text);
}
// Create a speech metadata object
return {
text: text,
duration: result.duration || this.estimateSpeechDuration(text).duration,
handler: ttsFactory.getActiveHandler() ? ttsFactory.getActiveHandler().id : null,
play: async () => {
return ttsFactory.speak(text);
},
stop: () => {
return ttsFactory.stop();
},
isTtsEnabled: isTtsEnabled
};
} catch (error) {
console.error("Error preparing speech metadata:", error);
return this.estimateSpeechDuration(text);
}
}
/**
* Estimate speech duration based on character count
* @param {string} text - Text to estimate duration for
* @returns {Object} - Speech metadata object with estimated duration
*/
estimateSpeechDuration(text) {
// Average reading speed is about 14-15 characters per second
// We'll use a slightly slower rate for TTS
const charactersPerSecond = 12;
const ttsPlayer = this.getModule('tts-player');
// Get the current speed setting if available
let speedMultiplier = 1.0;
if (ttsPlayer) {
const ttsFactory = this.getModule('tts-factory');
if (ttsFactory) {
// Get the current speed setting (typically 0.5-2.0)
const speed = ttsFactory.speed || 1.0;
speedMultiplier = speed;
}
}
// Calculate estimated duration in milliseconds
const charCount = text.length;
const durationSeconds = charCount / (charactersPerSecond * speedMultiplier);
const durationMs = Math.max(durationSeconds * 1000, 500); // Minimum 500ms
return {
text: text,
duration: durationMs,
handler: null,
play: async () => ({ success: false, reason: 'tts_disabled' }),
stop: () => true,
isTtsEnabled: false,
isEstimated: true
};
}
/**
* Complete processing of a sentence
* @param {Object} item - Queue item
* @param {Object} result - Processing result
*/
completeSentence(item, result) {
// Remove from queue
this.sentenceQueue.shift();
// Call the original callback
if (item.callback) {
item.callback(result);
}
// Reset processing flag
this.isProcessing = false;
// Process next sentence if any
if (this.sentenceQueue.length > 0) {
this.processNextSentence();
}
}
}
// Create the singleton instance
const SentenceQueue = new SentenceQueueModule();
// Export the module
export { SentenceQueue };
// Register with the module registry
if (window.moduleRegistry) {
window.moduleRegistry.register(SentenceQueue);
}
// Keep a reference in window for loader system
window.SentenceQueue = SentenceQueue;