mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-10-03 17:54:12 +00:00
main
* fix(gather): clear a finalized deepgram interim word so UtteranceEnd is not deferred forever The #1088 check defers UtteranceEnd while an interim word newer than last_word_end is pending. The marker was only cleared by a non-empty is_final, so an interim word that Deepgram later dropped (e.g. line noise, followed by an empty final) left it set: the gather waited for the caller to speak again and merged both utterances. Clear the marker on any Deepgram is_final result whose window (start + duration) covers it. A word that Deepgram carries into the next segment still defers UtteranceEnd. Port of jambonz/feature-server#223. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(gather): return the buffer when a deferred deepgram UtteranceEnd is satisfied Clearing the unprocessed-word marker only helps if the covering final arrives before UtteranceEnd. If it arrives after, UtteranceEnd has already been deferred and Deepgram sends no further UtteranceEnd until new speech, so the next utterance is still merged in. Remember a deferred UtteranceEnd, and when a later final clears the marker, return the buffered transcript once that final has been handled (setImmediate, since _onTranscription has early returns). Port of jambonz/feature-server#225. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(gather): only an empty final ends a gather early after a deferred UtteranceEnd A final with words means the caller resumed talking after the pause; Deepgram will send a new UtteranceEnd after those words, so keep the existing flow instead of cutting the caller off mid-sentence (or skipping the asrTimeout wait). Only a final that drops the pending word (empty) leaves nothing else to end the gather. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
fix(gather): clear a finalized deepgram interim word so UtteranceEnd is not deferred forever (#1588)
fix(gather): clear a finalized deepgram interim word so UtteranceEnd is not deferred forever (#1588)
jambonz-feature-server 
This application implements the core feature server of the jambones platform.
Note: If you are a developer looking to work on the code please read our how-to for that.
Configuration
Configuration is provided via environment variables:
| variable | meaning | required? |
|---|---|---|
| AWS_ACCESS_KEY_ID | aws access key id, used for TTS/STT as well SNS notifications | no |
| AWS_REGION | aws region | no |
| AWS_SECRET_ACCESS_KEY | aws secret access key, used per above | no |
| AWS_SNS_TOPIC_ARN | aws sns topic arn that scale-in lifecycle notifications will be published to | no |
| DRACHTIO_HOST | ip address of drachtio server (typically '127.0.0.1') | yes |
| DRACHTIO_PORT | listening port of drachtio server for control connections (typically 9022) | yes |
| DRACHTIO_SECRET | shared secret | yes |
| ENABLE_METRICS | if 1, metrics will be generated | no |
| ENCRYPTION_SECRET | secret for credential encryption(JWT_SECRET is deprecated) | yes |
| GOOGLE_APPLICATION_CREDENTIALS | path to gcp service key file | yes |
| HTTP_PORT | tcp port to listen on for API requests from jambonz-api-server | yes |
| HTTP_IP | IP Address for API requests from jambonz-api-server | no |
| JAMBONES_GATHER_EARLY_HINTS_MATCH | if true and hints are provided, gather will opportunistically review interim transcripts if possible to reduce ASR latency | no |
| JAMBONES_FREESWITCH | IP:port:secret for Freeswitch server (e.g. '127.0.0.1:8021:JambonzR0ck$' | yes |
| JAMBONES_HOLD_UNHOLD_EVENTS | if set, surface in-dialog hold/un-hold: emits a 'hold'/'unhold' event and, when sipRequestWithinDialogHook is configured, delivers it to the application. Disabled when unset | no |
| JAMBONES_LOGLEVEL | log level for application, 'info' or 'debug' | no |
| JAMBONES_MYSQL_HOST | mysql host | yes |
| JAMBONES_MYSQL_USER | mysql username | yes |
| JAMBONES_MYSQL_PASSWORD | mysql password | yes |
| JAMBONES_MYSQL_DATABASE | mysql data | yes |
| JAMBONES_MYSQL_CONNECTION_LIMIT | mysql connection limit | no |
| JAMBONES_NETWORK_CIDR | CIDR of private network that feature server is running in (e.g. '172.31.0.0/16') | yes |
| JAMBONES_REDIS_HOST | redis host | yes |
| JAMBONES_REDIS_PORT | redis port | yes |
| JAMBONES_SBCS | list of IP addresses (on the internal network) of SBCs, comma-separated | yes |
| STATS_HOST | ip address of metrics host (usually '127.0.0.1' since telegraf is installed locally | no |
| STATS_PORT | listening port for metrics host | no |
| STATS_PROTOCOL | 'tcp' or 'udp' | no |
| STATS_TELEGRAF | if 1, metrics will be generated in telegraf format | no |
| JAMBONZ_RECORD_WS_BASE_URL | recording websocket URL to send the recording audio | no |
| JAMBONZ_RECORD_WS_USERNAME | recording websocket username | no |
| JAMBONZ_RECORD_WS_PASSWORD | recording websocket password | no |
| ANCHOR_MEDIA_ALWAYS | keep media on media server | no |
| JAMBONZ_DISABLE_DIAL_PAI_HEADER | control P-Asserted-Identity header on B-Leg | no |
running under pm2
Typically, this application runs under pm2 using an ecosystem.config.js file similar to this:
module.exports = {
apps : [
{
name: 'jambonz-feature-server',
cwd: '/home/admin/apps/jambonz-feature-server',
script: 'app.js',
instance_var: 'INSTANCE_ID',
out_file: '/home/admin/.pm2/logs/jambonz-feature-server.log',
err_file: '/home/admin/.pm2/logs/jambonz-feature-server.log',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
GOOGLE_APPLICATION_CREDENTIALS: '/home/admin/credentials/gcp.json',
AWS_ACCESS_KEY_ID: 'XXXXXXXXXXXX',
AWS_SECRET_ACCESS_KEY: 'YYYYYYYYYYYYYYYYYYYYY',
AWS_REGION: 'us-west-1',
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_TELEGRAF: 1,
AWS_SNS_TOPIC_ARN: 'arn:aws:sns:us-west-1:xxxxxxxxxxx:terraform-20201107200347128600000002',
JAMBONES_NETWORK_CIDR: '172.31.0.0/16',
JAMBONES_MYSQL_HOST: 'aurora-cluster-jambonz.cluster-yyyyyyyyyyy.us-west-1.rds.amazonaws.com',
JAMBONES_MYSQL_USER: 'admin',
JAMBONES_MYSQL_PASSWORD: 'foobarbz',
JAMBONES_MYSQL_DATABASE: 'jambones',
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
JAMBONES_REDIS_HOST: 'jambonz.zzzzzzz.0001.usw1.cache.amazonaws.com',
JAMBONES_REDIS_PORT: 6379,
JAMBONES_LOGLEVEL: 'debug',
HTTP_PORT: 3000,
DRACHTIO_HOST: '127.0.0.1',
DRACHTIO_PORT: 9022,
DRACHTIO_SECRET: 'sharedsecret',
JAMBONES_SBCS: '172.31.32.10',
JAMBONES_FREESWITCH: '127.0.0.1:8021:sharedsecret'
}
}]
};
Running the test suite
Please see this.
Languages
JavaScript
99.9%