@mastra/voice-cloudflare
Version:
Mastra Cloudflare AI voice integration
338 lines (331 loc) • 10.3 kB
JavaScript
'use strict';
var Cloudflare = require('cloudflare');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
// ../../packages/_internal-core/dist/chunk-HDURQPU2.js
var RegisteredLogger = {
LLM: "LLM"};
var LogLevel = {
DEBUG: "debug",
INFO: "info",
WARN: "warn",
ERROR: "error"};
var MastraLogger = class {
name;
level;
transports;
constructor(options = {}) {
this.name = options.name || "Mastra";
this.level = options.level || LogLevel.ERROR;
this.transports = new Map(Object.entries(options.transports || {}));
}
getTransports() {
return this.transports;
}
trackException(_error, _metadata) {
}
async listLogs(transportId, params) {
if (!transportId || !this.transports.has(transportId)) {
return { logs: [], total: 0, page: params?.page ?? 1, perPage: params?.perPage ?? 100, hasMore: false };
}
return this.transports.get(transportId).listLogs?.(params) ?? {
logs: [],
total: 0,
page: params?.page ?? 1,
perPage: params?.perPage ?? 100,
hasMore: false
};
}
async listLogsByRunId({
transportId,
runId,
fromDate,
toDate,
logLevel,
filters,
page,
perPage
}) {
if (!transportId || !this.transports.has(transportId) || !runId) {
return { logs: [], total: 0, page: page ?? 1, perPage: perPage ?? 100, hasMore: false };
}
return this.transports.get(transportId).listLogsByRunId?.({ runId, fromDate, toDate, logLevel, filters, page, perPage }) ?? {
logs: [],
total: 0,
page: page ?? 1,
perPage: perPage ?? 100,
hasMore: false
};
}
};
var ConsoleLogger = class _ConsoleLogger extends MastraLogger {
component;
filter;
constructor(options = {}) {
super(options);
this.component = options.component;
this.filter = options.filter;
}
child(componentOrBindings) {
const component = typeof componentOrBindings === "string" ? componentOrBindings : componentOrBindings?.component ?? this.component;
return new _ConsoleLogger({
name: this.name,
level: this.level,
component,
filter: this.filter
});
}
shouldLog(level, message, args) {
if (!this.filter) return true;
try {
return this.filter({ component: this.component, level, message, args });
} catch (e) {
console.error(`[Logger] Filter error for component=${this.component} level=${level}:`, e);
return true;
}
}
prefix() {
return this.component ? `[${this.component}] ` : "";
}
debug(message, ...args) {
if (this.level === LogLevel.DEBUG && this.shouldLog(LogLevel.DEBUG, message, args)) {
console.info(`${this.prefix()}${message}`, ...args);
}
}
info(message, ...args) {
if ((this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.INFO, message, args)) {
console.info(`${this.prefix()}${message}`, ...args);
}
}
warn(message, ...args) {
if ((this.level === LogLevel.WARN || this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.WARN, message, args)) {
console.info(`${this.prefix()}${message}`, ...args);
}
}
error(message, ...args) {
if ((this.level === LogLevel.ERROR || this.level === LogLevel.WARN || this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.ERROR, message, args)) {
console.error(`${this.prefix()}${message}`, ...args);
}
}
async listLogs(_transportId, _params) {
return { logs: [], total: 0, page: _params?.page ?? 1, perPage: _params?.perPage ?? 100, hasMore: false };
}
async listLogsByRunId(_args) {
return { logs: [], total: 0, page: _args.page ?? 1, perPage: _args.perPage ?? 100, hasMore: false };
}
};
// ../../packages/_internal-core/dist/base/index.js
var MastraBase = class {
component = RegisteredLogger.LLM;
logger;
name;
#rawConfig;
constructor({
component,
name,
rawConfig
}) {
this.component = component || RegisteredLogger.LLM;
this.name = name;
this.#rawConfig = rawConfig;
this.logger = new ConsoleLogger({ name: `${this.component} - ${this.name}` });
}
/**
* Returns the raw storage configuration this primitive was created from,
* or undefined if it was created from code.
*/
toRawConfig() {
return this.#rawConfig;
}
/**
* Sets the raw storage configuration for this primitive.
* @internal
*/
__setRawConfig(rawConfig) {
this.#rawConfig = rawConfig;
}
/**
* Set the logger for the agent
* @param logger
*/
__setLogger(logger) {
this.logger = "child" in logger && typeof logger.child === "function" ? logger.child({ component: this.component }) : logger;
}
};
// ../../packages/_internals/voice/dist/chunk-NWNKSBZV.js
var MastraVoice = class extends MastraBase {
listeningModel;
speechModel;
speaker;
realtimeConfig;
constructor({ listeningModel, speechModel, speaker, realtimeConfig, name } = {}) {
super({
component: "VOICE",
name
});
this.listeningModel = listeningModel;
this.speechModel = speechModel;
this.speaker = speaker;
this.realtimeConfig = realtimeConfig;
}
/**
* Custom serialization for tracing/observability spans.
* Excludes `apiKey` from listeningModel / speechModel / realtimeConfig
* and any provider-specific state held by subclasses. Subclasses that
* need to expose additional non-sensitive fields can override.
*/
serializeForSpan() {
return {
component: "VOICE",
name: this.name,
speaker: this.speaker,
listeningModel: this.listeningModel ? { name: this.listeningModel.name } : void 0,
speechModel: this.speechModel ? { name: this.speechModel.name } : void 0,
realtimeModel: this.realtimeConfig?.model
};
}
updateConfig(_options) {
this.logger.debug("updateConfig not implemented by this voice provider");
}
/**
* Initializes a WebSocket or WebRTC connection for real-time communication
* @returns Promise that resolves when the connection is established
*/
async connect(_options) {
this.logger.debug("connect not implemented by this voice provider");
}
/**
* Relay audio data to the voice provider for real-time processing
* @param audioData Audio data to relay
*/
async send(_audioData) {
this.logger.debug("relay not implemented by this voice provider");
}
/**
* Trigger voice providers to respond
*/
async answer(_options) {
this.logger.debug("answer not implemented by this voice provider");
}
/**
* Equip the voice provider with instructions
* @param instructions Instructions to add
*/
addInstructions(_instructions) {
}
/**
* Equip the voice provider with tools
* @param tools Array of tools to add
*/
addTools(_tools) {
}
/**
* Disconnect from the WebSocket or WebRTC connection
*/
close() {
this.logger.debug("close not implemented by this voice provider");
}
/**
* Register an event listener
* @param event Event name (e.g., 'speaking', 'writing', 'error')
* @param callback Callback function that receives event data
*/
on(_event, _callback) {
this.logger.debug("on not implemented by this voice provider");
}
/**
* Remove an event listener
* @param event Event name (e.g., 'speaking', 'writing', 'error')
* @param callback Callback function to remove
*/
off(_event, _callback) {
this.logger.debug("off not implemented by this voice provider");
}
/**
* Get available speakers/voices
* @returns Array of available voice IDs and their metadata
*/
getSpeakers() {
this.logger.debug("getSpeakers not implemented by this voice provider");
return Promise.resolve([]);
}
/**
* Get available speakers/voices
* @returns Array of available voice IDs and their metadata
*/
getListener() {
this.logger.debug("getListener not implemented by this voice provider");
return Promise.resolve({ enabled: false });
}
};
var defaultListeningModel = {
model: "@cf/openai/whisper-large-v3-turbo",
apiKey: process.env.CLOUDFLARE_AI_API_KEY,
account_id: process.env.CLOUDFLARE_ACCOUNT_ID
};
var CloudflareVoice = class extends MastraVoice {
apiToken;
client = null;
binding;
constructor({
listeningModel,
binding
} = {}) {
super({
listeningModel: {
name: listeningModel?.model ?? defaultListeningModel.model,
apiKey: listeningModel?.apiKey ?? defaultListeningModel.apiKey
}
});
this.binding = binding;
if (!binding) {
this.apiToken = listeningModel?.apiKey || defaultListeningModel.apiKey;
if (!this.apiToken) {
throw new Error("CLOUDFLARE_AI_API_KEY must be set when not using bindings");
}
this.client = new Cloudflare__default.default({ apiToken: this.apiToken });
}
}
/**
* Checks if listening capabilities are enabled.
*
* @returns {Promise<{ enabled: boolean }>}
*/
async getListener() {
return { enabled: true };
}
async listen(audioStream, options) {
const chunks = [];
for await (const chunk of audioStream) {
if (typeof chunk === "string") {
chunks.push(Buffer.from(chunk));
} else {
chunks.push(chunk);
}
}
const audioBuffer = Buffer.concat(chunks);
const base64Audio = audioBuffer.toString("base64");
const model = options?.model || defaultListeningModel.model;
if (this.binding) {
const response = await this.binding.run(model, {
audio: base64Audio
});
return response.text;
} else if (this.client) {
const payload = { audio: base64Audio, account_id: options?.account_id || defaultListeningModel.account_id };
const response = await this.client.ai.run(model, payload);
return response.text;
} else {
throw new Error("Neither binding nor REST client is configured");
}
}
async speak() {
throw new Error("This feature is not yet implemented.");
}
async getSpeakers() {
throw new Error("This feature is not yet implemented.");
}
};
exports.CloudflareVoice = CloudflareVoice;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map