asterisk/voicebot-rt/app-gc-mlx-llm/utils.js

162 lines
5.1 KiB
JavaScript
Raw Permalink Normal View History

2024-12-10 19:47:02 +00:00
// ====================================
// Voice Bot Utilities
// Helper functions for text processing, metrics calculation,
// and pricing calculations for the voice bot system
// ====================================
const { encoding_for_model } = require('tiktoken');
const prices = require('./prices.json');
require('dotenv').config();
// ====================================
// Text Processing Functions
// ====================================
/**
* Checks if a string ends with a sentence terminator (., !, ?, or :)
* Used to determine when to send text for speech synthesis
* @param {string} text - The text to check
* @returns {boolean} - True if the text ends with a sentence terminator
*/
function matchesSentenceEnding(text) {
return /([.!?:]([\s]|$|\n))/.test(text);
}
/**
* Removes special characters and formatting markers from text
* Cleans up text before processing or displaying
* @param {string} text - The text to clean
* @returns {string} - Cleaned text
*/
function removeSpecialCharacters(text) {
return text
.replace(/[*#\n]/g, '') // Remove asterisks, hashtags, and newlines
.replace(/【\d+:\d+†[^】]+】/g, '') // Remove timestamp-like markers
.trim();
}
/**
* Calculates the duration of an audio buffer
* @param {Buffer} buffer - The audio buffer
* @param {number} sampleRate - The sample rate of the audio
* @param {number} channels - Number of audio channels
* @returns {number} - Duration in seconds
*/
function getAudioDuration(buffer, sampleRate, channels) {
const bytesPerSample = 2; // Assuming 16-bit audio
const totalBytes = buffer.length;
const duration = totalBytes / (sampleRate * channels * bytesPerSample);
return Math.ceil(duration);
}
/**
* Converts a hex string to a UUID format string
* @param {string} hex - The hex string to convert to UUID
* @returns {string} - Formatted UUID string
*/
function toUUID(hex) {
return hex.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5');
}
// ====================================
// Metrics and Pricing Calculator
// ====================================
/**
* Calculates various metrics and costs for processing text
* Handles different roles (system, user, assistant) with different pricing models
*
* @param {string} role - The role of the message (system, user, or assistant)
* @param {string} text - The text content to analyze
* @param {number} [wordsPerMinute=130] - Words per minute rate for duration calculation
* @param {number} [costPerWord=0.00001] - Cost per word
* @param {number} [costPerChar=0.0000075] - Cost per character
* @param {number} [costPerSecond=0.00025] - Cost per second of audio
* @returns {Object} - Object containing various metrics and costs
*/
function calculateMetricsAndPricing(
role,
text,
wordsPerMinute = 130,
costPerWord = 0.00001,
costPerChar = 0.0000075,
costPerSecond = 0.00025
) {
// Determine which model to use, fallback to gpt-3.5-turbo if specified model not in prices
const model = prices[process.env.OPENAI_MODEL || 'gpt-3.5-turbo']
? process.env.OPENAI_MODEL || 'gpt-3.5-turbo'
: 'gpt-4';
// Initialize tokenizer for the selected model
const encoder = encoding_for_model(model);
// Calculate basic metrics
const charCount = text.length;
const wordCount = text.trim().split(/\s+/).length;
const durationInSeconds = Math.ceil((wordCount / wordsPerMinute) * 60);
const tokenCount = encoder.encode(text).length;
// Calculate costs with precision
const costByWord = parseFloat((wordCount * costPerWord).toFixed(7));
const costByCharacter = parseFloat((charCount * costPerChar).toFixed(7));
const costBySecond = parseFloat((durationInSeconds * costPerSecond).toFixed(7));
const costByToken = parseFloat(
(tokenCount * prices[model][role === 'assistant' ? 'output' : 'input'] / 1000)
.toFixed(7)
);
// Free up encoder resources
encoder.free();
// Return appropriate metrics based on role
switch (role) {
case 'system':
return {
tokenCount,
costByToken,
model
};
case 'user':
return {
durationInSeconds,
tokenCount,
costBySecond,
costByToken,
model
};
case 'assistant':
return {
charCount,
tokenCount,
costByCharacter,
costByToken,
model
};
default:
// Return all metrics if role is not specified
return {
charCount,
wordCount,
tokenCount,
durationInSeconds,
costByWord,
costByCharacter,
costBySecond,
costByToken,
model
};
}
}
// Export utility functions
module.exports = {
removeSpecialCharacters,
matchesSentenceEnding,
calculateMetricsAndPricing,
getAudioDuration,
toUUID
};