UNPKG

expo-edge-speech

Version:

Text-to-speech library for Expo using Microsoft Edge TTS service

206 lines (205 loc) 8.25 kB
"use strict"; /** * Common utility functions shared across the application. * Consolidated from duplicated implementations to maintain DRY principle. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.generateConnectionId = generateConnectionId; exports.generateTimestamp = generateTimestamp; exports.clampValue = clampValue; exports.generateSessionId = generateSessionId; exports.validateText = validateText; exports.validateSpeechParameters = validateSpeechParameters; exports.createSpeechError = createSpeechError; const Crypto = __importStar(require("expo-crypto")); const constants_1 = require("../constants"); /** * Generate unique connection ID using UUID v4 without dashes (32 character string) * Consolidated from duplicated implementations in connectionManager.ts, networkService.ts, and state.ts */ function generateConnectionId() { return Crypto.randomUUID().replace(/-/g, "").toLowerCase(); } /** * Generate RFC 3339 timestamp with microseconds * Used for message timestamps in Edge TTS protocol */ function generateTimestamp() { const now = new Date(); const isoString = now.toISOString(); // Add microseconds (always 000 since JavaScript doesn't have microsecond precision) return isoString.replace("Z", "000Z"); } /** * Clamp a numeric value between min and max bounds * @param value - The value to clamp * @param min - Minimum allowed value * @param max - Maximum allowed value * @returns Clamped value */ function clampValue(value, min, max) { return Math.max(min, Math.min(max, value)); } /** * Generate a unique session ID * @returns A unique session identifier */ function generateSessionId() { return Crypto.randomUUID(); } /** * Validate text input for speech synthesis * @param text - The text to validate * @returns Validation result */ function validateText(text) { const errors = []; if (!text || typeof text !== "string") { errors.push("Text must be a non-empty string"); } else if (text.length > constants_1.MAX_TEXT_LENGTH) { errors.push(`Text length (${text.length}) exceeds maximum allowed length (${constants_1.MAX_TEXT_LENGTH})`); } return { isValid: errors.length === 0, errors, warnings: [], }; } /** * Validate and normalize speech parameters * Consolidates validation logic from Speech.ts and ssmlUtils.ts * @param options - Speech options to validate * @param clampValues - Whether to clamp values to valid ranges (default: true) * @returns Validation result and normalized options */ function validateSpeechParameters(options, clampValues = true) { const errors = []; const warnings = []; const normalizedOptions = { ...options }; // Apply default values if (normalizedOptions.voice === undefined) { normalizedOptions.voice = constants_1.DEFAULT_VOICE; } if (normalizedOptions.rate === undefined) { normalizedOptions.rate = constants_1.PARAMETER_RANGES.rate.default; } if (normalizedOptions.pitch === undefined) { normalizedOptions.pitch = constants_1.PARAMETER_RANGES.pitch.default; } if (normalizedOptions.volume === undefined) { normalizedOptions.volume = constants_1.PARAMETER_RANGES.volume.default; } // Validate voice parameter (optional, but if provided, must be a non-empty string) if (options.voice !== undefined && (typeof options.voice !== "string" || options.voice.trim() === "")) { errors.push("Voice option, if provided, must be a non-empty string."); } // Validate and clamp rate parameter if (options.rate !== undefined) { if (typeof options.rate !== "number" || isNaN(options.rate)) { errors.push("Rate must be a valid number"); } else if (options.rate < constants_1.PARAMETER_RANGES.rate.min || // Use imported PARAMETER_RANGES options.rate > constants_1.PARAMETER_RANGES.rate.max) { if (clampValues) { normalizedOptions.rate = clampValue(options.rate, constants_1.PARAMETER_RANGES.rate.min, constants_1.PARAMETER_RANGES.rate.max); warnings.push(`Rate ${options.rate} clamped to ${normalizedOptions.rate}`); } else { errors.push(`Rate ${options.rate} is outside valid range ${constants_1.PARAMETER_RANGES.rate.min}-${constants_1.PARAMETER_RANGES.rate.max}`); } } } // Validate and clamp pitch parameter if (options.pitch !== undefined) { if (typeof options.pitch !== "number" || isNaN(options.pitch)) { errors.push("Pitch must be a valid number"); } else if (options.pitch < constants_1.PARAMETER_RANGES.pitch.min || // Use imported PARAMETER_RANGES options.pitch > constants_1.PARAMETER_RANGES.pitch.max) { if (clampValues) { normalizedOptions.pitch = clampValue(options.pitch, constants_1.PARAMETER_RANGES.pitch.min, constants_1.PARAMETER_RANGES.pitch.max); warnings.push(`Pitch ${options.pitch} clamped to ${normalizedOptions.pitch}`); } else { errors.push(`Pitch ${options.pitch} is outside valid range ${constants_1.PARAMETER_RANGES.pitch.min}-${constants_1.PARAMETER_RANGES.pitch.max}`); } } } // Validate and clamp volume parameter if (options.volume !== undefined) { if (typeof options.volume !== "number" || isNaN(options.volume)) { errors.push("Volume must be a valid number"); } else if (options.volume < constants_1.PARAMETER_RANGES.volume.min || // Use imported PARAMETER_RANGES options.volume > constants_1.PARAMETER_RANGES.volume.max) { if (clampValues) { normalizedOptions.volume = clampValue(options.volume, constants_1.PARAMETER_RANGES.volume.min, constants_1.PARAMETER_RANGES.volume.max); warnings.push(`Volume ${options.volume} clamped to ${normalizedOptions.volume}`); } else { errors.push(`Volume ${options.volume} is outside valid range ${constants_1.PARAMETER_RANGES.volume.min}-${constants_1.PARAMETER_RANGES.volume.max}`); } } } // Validate language parameter if (options.language !== undefined && typeof options.language !== "string") { errors.push("Language must be a string"); } return { result: { isValid: errors.length === 0, errors, warnings, }, normalizedOptions, }; } /** * Create a standardized SpeechError * @param name - Error name * @param message - Error message * @param code - Error code (optional) * @returns SpeechError object */ function createSpeechError(name, message, code) { return { name, message, code, }; }