mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-02-10 08:21:33 +00:00
Compare commits
13 Commits
v0.9.5-rc4
...
v0.9.5-rc9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea27b20ac5 | ||
|
|
96aa705378 | ||
|
|
5e51849839 | ||
|
|
44f69fa76d | ||
|
|
73c77bea71 | ||
|
|
babc0d0dbb | ||
|
|
6b8d0fe1a8 | ||
|
|
66bb466297 | ||
|
|
1933f4ec0b | ||
|
|
b1089a1ae9 | ||
|
|
93e06d887e | ||
|
|
b478e0ecd2 | ||
|
|
94d43d4b70 |
@@ -1146,6 +1146,13 @@ class CallSession extends Emitter {
|
||||
options: credential.options
|
||||
};
|
||||
}
|
||||
else if ('resemble' === vendor) {
|
||||
return {
|
||||
api_key: credential.api_key,
|
||||
resemble_tts_use_tls: credential.resemble_tts_use_tls,
|
||||
resemble_tts_uri: credential.resemble_tts_uri,
|
||||
};
|
||||
}
|
||||
else if ('inworld' === vendor) {
|
||||
return {
|
||||
api_key: credential.api_key,
|
||||
@@ -1963,6 +1970,17 @@ Duration=${duration} `
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.info({err, opts, callSid}, 'CallSession:updateCall - error updating call');
|
||||
const {writeAlerts} = this.srf.locals;
|
||||
try {
|
||||
writeAlerts({
|
||||
alert_type: 'error-updating-call',
|
||||
account_sid: this.accountSid,
|
||||
message: err.message,
|
||||
target_sid: callSid
|
||||
});
|
||||
} catch (err) {
|
||||
this.logger.error({err}, 'Error writing error-updating-call alert');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2367,6 +2385,7 @@ Duration=${duration} `
|
||||
const ep = await this._createMediaEndpoint({
|
||||
headers: {
|
||||
'X-Jambones-Call-ID': this.callId,
|
||||
'X-Call-Sid': this.callSid,
|
||||
},
|
||||
remoteSdp: this.req.body
|
||||
});
|
||||
|
||||
@@ -8,7 +8,8 @@ const CallSession = require('./call-session');
|
||||
|
||||
*/
|
||||
class ConfirmCallSession extends CallSession {
|
||||
constructor({logger, application, dlg, ep, tasks, callInfo, accountInfo, memberId, confName, rootSpan, req}) {
|
||||
// eslint-disable-next-line max-len
|
||||
constructor({logger, application, dlg, ep, tasks, callInfo, accountInfo, memberId, confName, rootSpan, req, tmpFiles}) {
|
||||
super({
|
||||
logger,
|
||||
application,
|
||||
@@ -24,6 +25,7 @@ class ConfirmCallSession extends CallSession {
|
||||
this.dlg = dlg;
|
||||
this.ep = ep;
|
||||
this.req = req;
|
||||
this.tmpFiles = tmpFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -673,7 +673,8 @@ class Conference extends Task {
|
||||
confName: this.confName,
|
||||
tasks,
|
||||
rootSpan: cs.rootSpan,
|
||||
req: cs.req
|
||||
req: cs.req,
|
||||
tmpFiles: cs.tmpFiles,
|
||||
});
|
||||
await this._playSession.exec();
|
||||
this._playSession = null;
|
||||
|
||||
@@ -1098,7 +1098,8 @@ class TaskDial extends Task {
|
||||
accountInfo: this.cs.accountInfo,
|
||||
tasks,
|
||||
rootSpan: this.cs.rootSpan,
|
||||
req: this.cs.req
|
||||
req: this.cs.req,
|
||||
tmpFiles: this.cs.tmpFiles,
|
||||
});
|
||||
await this._onHoldSession.exec();
|
||||
this._onHoldSession = null;
|
||||
|
||||
@@ -370,7 +370,8 @@ class TaskEnqueue extends Task {
|
||||
accountInfo: cs.accountInfo,
|
||||
tasks: tasksToRun,
|
||||
rootSpan: cs.rootSpan,
|
||||
req: cs.req
|
||||
req: cs.req,
|
||||
tmpFiles: cs.tmpFiles,
|
||||
});
|
||||
await this._playSession.exec();
|
||||
this._playSession = null;
|
||||
|
||||
@@ -72,7 +72,7 @@ class TaskListen extends Task {
|
||||
} catch (err) {
|
||||
this.logger.info(err, `TaskListen:exec - error ${this.url}`);
|
||||
}
|
||||
if (this.transcribeTask) this.transcribeTask.kill();
|
||||
if (this.transcribeTask) this.transcribeTask.kill(cs);
|
||||
this._removeListeners(ep);
|
||||
}
|
||||
|
||||
|
||||
@@ -452,6 +452,7 @@ class TaskSay extends TtsTask {
|
||||
.replace('playht_', 'playht.')
|
||||
.replace('cartesia_', 'cartesia.')
|
||||
.replace('rimelabs_', 'rimelabs.')
|
||||
.replace('resemble_', 'resemble.')
|
||||
.replace('inworld_', 'inworld.')
|
||||
.replace('verbio_', 'verbio.')
|
||||
.replace('elevenlabs_', 'elevenlabs.');
|
||||
@@ -517,6 +518,9 @@ const spanMapping = {
|
||||
'rimelabs.name_lookup_time_ms': 'name_lookup_ms',
|
||||
'rimelabs.connect_time_ms': 'connect_ms',
|
||||
'rimelabs.final_response_time_ms': 'final_response_ms',
|
||||
// Resemble
|
||||
'resemble.connect_time_ms': 'connect_ms',
|
||||
'resemble.final_response_time_ms': 'final_response_ms',
|
||||
// inworld
|
||||
'inworld.name_lookup_time_ms': 'name_lookup_ms',
|
||||
'inworld.connect_time_ms': 'connect_ms',
|
||||
|
||||
@@ -293,7 +293,18 @@ class TtsTask extends Task {
|
||||
vendor,
|
||||
language,
|
||||
characters: text.length,
|
||||
elapsedTime: rtt
|
||||
elapsedTime: rtt,
|
||||
servedFromCache,
|
||||
'id': this.id
|
||||
});
|
||||
}
|
||||
if (servedFromCache) {
|
||||
this.notifyStatus({
|
||||
event: 'synthesized-audio',
|
||||
vendor,
|
||||
language,
|
||||
servedFromCache,
|
||||
'id': this.id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,13 +281,17 @@ module.exports = (logger) => {
|
||||
|
||||
/* set stt options */
|
||||
logger.info(`starting amd for vendor ${vendor} and language ${language}`);
|
||||
const sttOpts = amd.setChannelVarsForStt({name: TaskName.Gather}, sttCredentials, language, {
|
||||
vendor,
|
||||
hints,
|
||||
enhancedModel: true,
|
||||
altLanguages: opts.recognizer?.altLanguages || [],
|
||||
initialSpeechTimeoutMs: opts.resolveTimeoutMs,
|
||||
});
|
||||
/* if opts contains recognizer object use that config for stt, otherwise use defaults */
|
||||
const rOpts = opts.recognizer ?
|
||||
opts.recognizer :
|
||||
{
|
||||
vendor,
|
||||
hints,
|
||||
enhancedModel: true,
|
||||
altLanguages: opts.recognizer?.altLanguages || [],
|
||||
initialSpeechTimeoutMs: opts.resolveTimeoutMs,
|
||||
};
|
||||
const sttOpts = amd.setChannelVarsForStt({name: TaskName.Gather}, sttCredentials, language, rOpts);
|
||||
|
||||
await ep.set(sttOpts).catch((err) => logger.info(err, 'Error setting channel variables'));
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class BackgroundTaskManager extends Emitter {
|
||||
this.logger.info(`stopping background task: ${type}`);
|
||||
task.removeAllListeners();
|
||||
task.span.end();
|
||||
task.kill();
|
||||
task.kill(this.cs);
|
||||
// Remove task from managed List
|
||||
this.tasks.delete(type);
|
||||
}
|
||||
|
||||
@@ -124,6 +124,12 @@ const speechMapper = (cred) => {
|
||||
obj.model_id = o.model_id;
|
||||
obj.options = o.options;
|
||||
}
|
||||
else if ('resemble' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = o.api_key;
|
||||
obj.resemble_tts_use_tls = o.resemble_tts_use_tls;
|
||||
obj.resemble_tts_uri = o.resemble_tts_uri;
|
||||
}
|
||||
else if ('inworld' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = o.api_key;
|
||||
|
||||
@@ -41,7 +41,7 @@ class HttpRequestor extends BaseRequestor {
|
||||
constructor(logger, account_sid, hook, secret) {
|
||||
super(logger, account_sid, hook, secret);
|
||||
|
||||
this.method = hook.method || 'POST';
|
||||
this.method = hook.method?.toUpperCase() || 'POST';
|
||||
this.authHeader = basicAuth(hook.username, hook.password);
|
||||
this.backoffMs = 500;
|
||||
|
||||
@@ -111,7 +111,7 @@ class HttpRequestor extends BaseRequestor {
|
||||
|
||||
const payload = params ? snakeCaseKeys(params, ['customerData', 'sip', 'env_vars', 'args']) : null;
|
||||
const url = hook.url || hook;
|
||||
const method = hook.method || 'POST';
|
||||
const method = hook.method?.toUpperCase() || 'POST';
|
||||
let buf = '';
|
||||
httpHeaders = {
|
||||
...httpHeaders,
|
||||
@@ -119,7 +119,7 @@ class HttpRequestor extends BaseRequestor {
|
||||
};
|
||||
|
||||
assert.ok(url, 'HttpRequestor:request url was not provided');
|
||||
assert.ok, (['GET', 'POST'].includes(method), `HttpRequestor:request method must be 'GET' or 'POST' not ${method}`);
|
||||
assert.ok(['GET', 'POST'].includes(method), `HttpRequestor:request method must be 'GET' or 'POST' not ${method}`);
|
||||
const startAt = process.hrtime();
|
||||
|
||||
/* if we have an absolute url, and it is ws then do a websocket connection */
|
||||
|
||||
@@ -401,7 +401,8 @@ class SingleDialer extends Emitter {
|
||||
accountInfo: this.accountInfo,
|
||||
tasks,
|
||||
rootSpan: this.rootSpan,
|
||||
req: this.req
|
||||
req: this.req,
|
||||
tmpFiles: cs.tmpFiles,
|
||||
});
|
||||
await cs.exec();
|
||||
|
||||
|
||||
@@ -101,8 +101,6 @@ class SttLatencyCalculator extends Emitter {
|
||||
}
|
||||
this.isRunning = false;
|
||||
this.logger.info('STT Latency Calculator stopped');
|
||||
} else {
|
||||
this.logger.warn('Latency calculator is not running, no VAD detection to stop');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +114,7 @@ class SttLatencyCalculator extends Emitter {
|
||||
return;
|
||||
}
|
||||
this._startVad();
|
||||
this.logger.info('STT Latency Calculator started');
|
||||
this.logger.debug('STT Latency Calculator started');
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
||||
@@ -785,12 +785,15 @@ module.exports = (logger) => {
|
||||
AWS_ACCESS_KEY_ID: sttCredentials.accessKeyId,
|
||||
AWS_SECRET_ACCESS_KEY: sttCredentials.secretAccessKey,
|
||||
AWS_REGION: sttCredentials.region,
|
||||
AWS_SECURITY_TOKEN: sttCredentials.securityToken
|
||||
AWS_SECURITY_TOKEN: sttCredentials.securityToken,
|
||||
AWS_SESSION_TOKEN: sttCredentials.sessionToken ? sttCredentials.sessionToken : sttCredentials.securityToken
|
||||
}),
|
||||
...(awsOptions.accessKey && {AWS_ACCESS_KEY_ID: awsOptions.accessKey}),
|
||||
...(awsOptions.secretKey && {AWS_SECRET_ACCESS_KEY: awsOptions.secretKey}),
|
||||
...(awsOptions.region && {AWS_REGION: awsOptions.region}),
|
||||
...(awsOptions.securityToken && {AWS_SECURITY_TOKEN: awsOptions.securityToken}),
|
||||
...(awsOptions.sessionToken && {AWS_SESSION_TOKEN: awsOptions.sessionToken ?
|
||||
awsOptions.sessionToken : awsOptions.securityToken}),
|
||||
...(awsOptions.languageModelName && {AWS_LANGUAGE_MODEL_NAME: awsOptions.languageModelName}),
|
||||
...(awsOptions.piiEntityTypes?.length && {AWS_PII_ENTITY_TYPES: awsOptions.piiEntityTypes.join(',')}),
|
||||
...(awsOptions.piiIdentifyEntities && {AWS_PII_IDENTIFY_ENTITIES: true}),
|
||||
@@ -891,6 +894,14 @@ module.exports = (logger) => {
|
||||
const deepgramUri = deepgramOptions.deepgramSttUri || sttCredentials.deepgram_stt_uri;
|
||||
const useTls = deepgramOptions.deepgramSttUseTls || sttCredentials.deepgram_stt_use_tls;
|
||||
|
||||
// DH (2025-08-11) entity_prompt is currently limited to 100 words
|
||||
const entityPrompt = deepgramOptions.entityPrompt ?
|
||||
deepgramOptions.entityPrompt
|
||||
.split(/\s+/)
|
||||
.slice(0, 100)
|
||||
.join(' ')
|
||||
: undefined;
|
||||
|
||||
/* default to a sensible model if not supplied */
|
||||
if (!model) {
|
||||
model = selectDefaultDeepgramModel(task, language);
|
||||
@@ -949,7 +960,9 @@ module.exports = (logger) => {
|
||||
...(deepgramOptions.fillerWords) &&
|
||||
{DEEPGRAM_SPEECH_FILLER_WORDS: deepgramOptions.fillerWords},
|
||||
...((Array.isArray(deepgramOptions.keyterms) && deepgramOptions.keyterms.length > 0) &&
|
||||
{DEEPGRAM_SPEECH_KEYTERMS: deepgramOptions.keyterms.join(',')})
|
||||
{DEEPGRAM_SPEECH_KEYTERMS: deepgramOptions.keyterms.join(',')}),
|
||||
...(deepgramOptions.mipOptOut && {DEEPGRAM_SPEECH_MIP_OPT_OUT: deepgramOptions.mipOptOut}),
|
||||
...(entityPrompt && {DEEPGRAM_SPEECH_ENTITY_PROMPT: entityPrompt}),
|
||||
};
|
||||
}
|
||||
else if ('deepgramriver' === vendor) {
|
||||
|
||||
5419
package-lock.json
generated
5419
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -27,14 +27,14 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-auto-scaling": "^3.549.0",
|
||||
"@aws-sdk/client-sns": "^3.549.0",
|
||||
"@jambonz/db-helpers": "^0.9.12",
|
||||
"@jambonz/db-helpers": "^0.9.16",
|
||||
"@jambonz/http-health-check": "^0.0.1",
|
||||
"@jambonz/mw-registrar": "^0.2.7",
|
||||
"@jambonz/realtimedb-helpers": "^0.8.13",
|
||||
"@jambonz/speech-utils": "^0.2.15",
|
||||
"@jambonz/realtimedb-helpers": "^0.8.15",
|
||||
"@jambonz/speech-utils": "^0.2.19",
|
||||
"@jambonz/stats-collector": "^0.1.10",
|
||||
"@jambonz/time-series": "^0.2.14",
|
||||
"@jambonz/verb-specifications": "^0.0.111",
|
||||
"@jambonz/verb-specifications": "^0.0.113",
|
||||
"@modelcontextprotocol/sdk": "^1.9.0",
|
||||
"@opentelemetry/api": "^1.8.0",
|
||||
"@opentelemetry/exporter-jaeger": "^1.23.0",
|
||||
|
||||
Reference in New Issue
Block a user