blackboxify
Version:
BlackboxAI API client with OpenAI-compatible interface, streaming support, multiple auth accounts, and token pricing
107 lines (90 loc) • 3.24 kB
JavaScript
import { BlackboxError } from './errors.js';
// Simple word-based token estimation
function estimateTokens(text) {
if (!text) return 0;
// Split on whitespace and punctuation
const words = text.split(/[\s,.!?;:'"()\[\]{}|\\/<>]+/);
// Filter out empty strings and multiply by 1.3 for a conservative estimate
// Most language models use subword tokenization, so actual tokens are usually more than words
return Math.ceil(words.filter(w => w.length > 0).length * 1.3);
}
function calculateMessageTokens(messages) {
let total = 0;
for (const message of messages) {
// Add tokens for message metadata (role, etc.)
total += 4; // Approximate overhead per message
// Add tokens for content
if (message.content) {
total += estimateTokens(message.content);
}
// Add tokens for role
if (message.role) {
total += 1;
}
}
return total;
}
function calculateResponseTokens(response) {
if (!response || !response.choices || !response.choices[0]) return 0;
const choice = response.choices[0];
if (choice.message?.content) {
return estimateTokens(choice.message.content);
}
if (choice.delta?.content) {
return estimateTokens(choice.delta.content);
}
return 0;
}
function validateModel(modelId, configuredModels) {
// Check if model exists in configuration
const modelConfig = configuredModels[modelId];
if (!modelConfig) {
throw new BlackboxError(
'Invalid model',
`Model "${modelId}" is not configured. Available models: ${Object.keys(configuredModels).join(', ')}`
);
}
// Ensure required fields exist
if (!modelConfig.id) {
throw new BlackboxError(
'Invalid model configuration',
`Model "${modelId}" configuration is missing required 'id' field`
);
}
// Set default pricing if not specified
return {
...modelConfig,
input: modelConfig.input || 0,
output: modelConfig.output || 0
};
}
function calculateTokens(messages, modelConfig) {
const inputTokens = calculateMessageTokens(messages);
// Calculate estimated cost based on input tokens and model pricing
// Prices are per 1M tokens, so divide by 1M
const cost = (inputTokens * modelConfig.input) / 1_000_000;
return {
inputTokens,
cost
};
}
function updateResponseWithTokens(response, messages, modelConfig) {
const inputTokens = calculateMessageTokens(messages);
const completionTokens = calculateResponseTokens(response);
const totalTokens = inputTokens + completionTokens;
// Calculate cost based on both input and output tokens
// For blackboxai-default model, don't calculate cost
const inputCost = modelConfig.input ? (inputTokens * modelConfig.input) / 1_000_000 : 0;
const outputCost = modelConfig.output ? (completionTokens * modelConfig.output) / 1_000_000 : 0;
const totalCost = inputCost + outputCost;
return {
...response,
usage: {
prompt_tokens: inputTokens,
completion_tokens: completionTokens,
total_tokens: totalTokens,
cost: totalCost
}
};
}
export { validateModel, calculateTokens, updateResponseWithTokens };