phonic
Version:
Phonic Node.js SDK
311 lines (303 loc) • 7.74 kB
JavaScript
// package.json
var version = "0.19.1";
// src/conversations/index.ts
var Conversations = class {
constructor(phonic) {
this.phonic = phonic;
}
async get(id) {
const response = await this.phonic.get(
`/conversations/${id}`
);
return response;
}
async getByExternalId({
project,
externalId
}) {
const queryString = new URLSearchParams({
...project !== void 0 && { project },
external_id: externalId
}).toString();
const response = await this.phonic.get(
`/conversations?${queryString}`
);
return response;
}
async list({
project,
durationMin,
durationMax,
startedAtMin,
startedAtMax
}) {
const queryString = new URLSearchParams({
...project !== void 0 && { project },
...durationMin !== void 0 && { duration_min: String(durationMin) },
...durationMax !== void 0 && { duration_max: String(durationMax) },
...startedAtMin !== void 0 && { started_at_min: startedAtMin },
...startedAtMax !== void 0 && { started_at_max: startedAtMax }
}).toString();
const response = await this.phonic.get(
`/conversations?${queryString}`
);
return response;
}
};
// src/sts/index.ts
import WebSocket from "ws";
// src/sts/twilio/index.ts
var Twilio = class {
constructor(phonic) {
this.phonic = phonic;
}
async outboundCall(params, config) {
const response = await this.phonic.post(
"/sts/twilio/outbound_call",
{
from_phone_number: params.from_phone_number,
to_phone_number: params.to_phone_number,
config
},
{
"X-Twilio-Account-Sid": params.account_sid,
"X-Twilio-Api-Key-Sid": params.api_key_sid,
"X-Twilio-Api-Key-Secret": params.api_key_secret
}
);
return response;
}
};
// src/sts/websocket.ts
var PhonicSTSWebSocket = class {
constructor(ws, config) {
this.ws = ws;
this.config = config;
this.buffer.push(
JSON.stringify({
type: "config",
...this.config
})
);
this.ws.onopen = () => {
for (const message of this.buffer) {
this.ws.send(message);
}
this.isOpen = true;
};
this.ws.onmessage = (event) => {
if (this.onMessageCallback === null) {
return;
}
if (typeof event.data !== "string") {
throw new Error("Received non-string message");
}
const dataObj = JSON.parse(
event.data
);
this.onMessageCallback(dataObj);
};
this.ws.onclose = (event) => {
if (this.onCloseCallback === null) {
return;
}
this.onCloseCallback(event);
};
this.ws.onerror = (event) => {
if (this.onErrorCallback === null) {
return;
}
this.onErrorCallback(event);
};
this.onMessage = this.onMessage.bind(this);
this.onClose = this.onClose.bind(this);
this.onError = this.onError.bind(this);
this.audioChunk = this.audioChunk.bind(this);
this.close = this.close.bind(this);
}
onMessageCallback = null;
onCloseCallback = null;
onErrorCallback = null;
buffer = [];
isOpen = false;
onMessage(callback) {
this.onMessageCallback = callback;
}
onClose(callback) {
this.onCloseCallback = callback;
}
onError(callback) {
this.onErrorCallback = callback;
}
audioChunk({ audio }) {
const audiochunkMessage = JSON.stringify({
type: "audio_chunk",
audio
});
if (this.isOpen) {
this.ws.send(audiochunkMessage);
} else {
this.buffer.push(audiochunkMessage);
}
}
updateSystemPrompt({ systemPrompt }) {
const updateSystemPromptMessage = JSON.stringify({
type: "update_system_prompt",
system_prompt: systemPrompt
});
if (this.isOpen) {
this.ws.send(updateSystemPromptMessage);
} else {
this.buffer.push(updateSystemPromptMessage);
}
}
setExternalId({ externalId }) {
const setExternalIdMessage = JSON.stringify({
type: "set_external_id",
external_id: externalId
});
if (this.isOpen) {
this.ws.send(setExternalIdMessage);
} else {
this.buffer.push(setExternalIdMessage);
}
}
close(code) {
this.ws.close(code ?? 1e3);
}
};
// src/sts/index.ts
var SpeechToSpeech = class {
constructor(phonic) {
this.phonic = phonic;
this.twilio = new Twilio(phonic);
}
twilio;
websocket(config) {
const wsBaseUrl = this.phonic.baseUrl.replace(/^http/, "ws");
const queryString = new URLSearchParams({
...this.phonic.__downstreamWebSocketUrl !== null && {
downstream_websocket_url: this.phonic.__downstreamWebSocketUrl
}
}).toString();
const phonicApiWsUrl = `${wsBaseUrl}/v1/sts/ws?${queryString}`;
const ws = new WebSocket(phonicApiWsUrl, {
headers: this.phonic.headers
});
return new PhonicSTSWebSocket(ws, config);
}
async outboundCall(toPhoneNumber, config) {
const response = await this.phonic.post(
"/sts/outbound_call",
{
to_phone_number: toPhoneNumber,
config
}
);
return response;
}
};
// src/voices/index.ts
var Voices = class {
constructor(phonic) {
this.phonic = phonic;
}
async list({ model }) {
const response = await this.phonic.get(
`/voices?model=${encodeURIComponent(model)}`
);
return response;
}
async get(id) {
const response = await this.phonic.get(
`/voices/${id}`
);
return response;
}
};
// src/phonic.ts
var defaultBaseUrl = "https://api.phonic.co";
var defaultUserAgent = `phonic-node:${version}`;
var Phonic = class {
constructor(apiKey, config) {
this.apiKey = apiKey;
if (typeof process === "undefined") {
throw new Error(
"Phonic SDK is intended to be used in Node.js environment."
);
}
if (!this.apiKey) {
throw new Error(
'API key is missing. Pass it to the constructor: `new Phonic("ph_...")`'
);
}
this.baseUrl = (config?.baseUrl ?? defaultBaseUrl).replace(/\/$/, "");
this.__downstreamWebSocketUrl = config?.__downstreamWebSocketUrl || null;
this.headers = {
Authorization: `Bearer ${this.apiKey}`,
"User-Agent": process.env.PHONIC_USER_AGENT || defaultUserAgent,
"Content-Type": "application/json",
...config?.headers
};
}
baseUrl;
__downstreamWebSocketUrl;
headers;
conversations = new Conversations(this);
voices = new Voices(this);
sts = new SpeechToSpeech(this);
async fetchRequest(path, options) {
try {
const { headers, ...restOptions } = options;
const response = await fetch(`${this.baseUrl}/v1${path}`, {
headers: {
...this.headers,
...headers
},
...restOptions
});
if (response.ok) {
const data = await response.json();
return { data, error: null };
}
try {
const data = await response.json();
const errorMessage = data.error.message || response.statusText;
return {
data: null,
error: {
message: errorMessage
}
};
} catch (error) {
return {
data: null,
error: {
message: response.statusText
}
};
}
} catch (error) {
console.error(error);
return {
data: null,
error: {
message: "Fetch request failed"
}
};
}
}
async get(path) {
return this.fetchRequest(path, { method: "GET" });
}
async post(path, body, headers) {
return this.fetchRequest(path, {
method: "POST",
body: JSON.stringify(body),
headers
});
}
};
export {
Phonic
};