@fonoster/apiserver 0.6.6 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/applications/createGetFnUtil.d.ts +1 -1
  2. package/dist/applications/getApplication.js +1 -3
  3. package/dist/applications/types.d.ts +1 -1
  4. package/dist/applications/utils/applicationWithEncodedStruct.js +20 -1
  5. package/dist/applications/utils/convertToApplicationData.js +1 -1
  6. package/dist/applications/utils/getApplicationValidationSchema.d.ts +3 -3
  7. package/dist/applications/utils/getApplicationValidationSchema.js +6 -3
  8. package/dist/applications/utils/prepareForValidation.js +1 -1
  9. package/dist/calls/ListCallsRequestSchema.d.ts +1 -4
  10. package/dist/calls/ListCallsRequestSchema.js +0 -4
  11. package/dist/calls/buildService.d.ts +2 -2
  12. package/dist/calls/buildService.js +6 -5
  13. package/dist/calls/createCall.d.ts +6 -4
  14. package/dist/calls/createCall.js +18 -8
  15. package/dist/calls/createFetchCalls.js +3 -7
  16. package/dist/calls/createFetchSingleCall.js +9 -2
  17. package/dist/calls/{trackCall.d.ts → makeTrackCall.d.ts} +3 -3
  18. package/dist/calls/makeTrackCall.js +67 -0
  19. package/dist/calls/runCallManager.js +12 -13
  20. package/dist/calls/types.d.ts +8 -42
  21. package/dist/calls/types.js +5 -38
  22. package/dist/core/seed.js +20 -0
  23. package/dist/core/services.d.ts +2 -2
  24. package/dist/envs.d.ts +0 -2
  25. package/dist/envs.js +1 -3
  26. package/dist/events/createInfluxDbPub.js +2 -1
  27. package/dist/events/mapCallDirectionToEnum.d.ts +3 -0
  28. package/dist/events/mapCallDirectionToEnum.js +37 -0
  29. package/dist/events/nats.js +5 -6
  30. package/dist/events/transformEvent.d.ts +2 -0
  31. package/dist/events/transformEvent.js +72 -0
  32. package/dist/index.js +4 -5
  33. package/dist/utils/index.d.ts +2 -0
  34. package/dist/utils/index.js +2 -0
  35. package/dist/utils/makeHandleDialEventsWithNats.d.ts +5 -0
  36. package/dist/{voice/handlers/StasisEnd.js → utils/makeHandleDialEventsWithNats.js} +10 -15
  37. package/dist/utils/makeHandleDialEventsWithVoiceClient.d.ts +5 -0
  38. package/dist/{voice/handlers/dial/handleDialEvents.js → utils/makeHandleDialEventsWithVoiceClient.js} +6 -17
  39. package/dist/utils/mapDialStatus.d.ts +3 -0
  40. package/dist/utils/mapDialStatus.js +38 -0
  41. package/dist/voice/VoiceClientImpl.d.ts +10 -1
  42. package/dist/voice/VoiceClientImpl.js +47 -7
  43. package/dist/voice/VoiceDispatcher.d.ts +6 -2
  44. package/dist/voice/VoiceDispatcher.js +50 -37
  45. package/dist/voice/connectToAri.js +3 -1
  46. package/dist/voice/createExternalMediaConfig.d.ts +3 -0
  47. package/dist/voice/createExternalMediaConfig.js +4 -1
  48. package/dist/voice/handlers/Answer.js +1 -1
  49. package/dist/voice/handlers/Hangup.js +1 -1
  50. package/dist/voice/handlers/Mute.js +1 -1
  51. package/dist/voice/handlers/Play.js +2 -2
  52. package/dist/voice/handlers/PlayDtmf.js +1 -1
  53. package/dist/voice/handlers/PlaybackControl.js +1 -1
  54. package/dist/voice/handlers/Record.js +2 -2
  55. package/dist/voice/handlers/Say.js +2 -2
  56. package/dist/voice/handlers/StreamGather.d.ts +3 -0
  57. package/dist/voice/handlers/StreamGather.js +66 -0
  58. package/dist/voice/handlers/Unmute.js +1 -1
  59. package/dist/voice/handlers/dial/Dial.js +10 -6
  60. package/dist/voice/handlers/gather/Gather.js +5 -4
  61. package/dist/voice/handlers/index.d.ts +12 -0
  62. package/dist/voice/handlers/index.js +46 -0
  63. package/dist/voice/handlers/{awaitForPlaybackFinished.js → utils/awaitForPlaybackFinished.js} +1 -1
  64. package/dist/voice/handlers/{awaitForRecordingFinished.js → utils/awaitForRecordingFinished.js} +1 -1
  65. package/dist/voice/handlers/utils/index.d.ts +3 -0
  66. package/dist/voice/handlers/utils/index.js +37 -0
  67. package/dist/voice/handlers/utils/isDtmf.d.ts +2 -0
  68. package/dist/voice/handlers/utils/isDtmf.js +24 -0
  69. package/dist/voice/integrations/findIntegrationsCredentials.d.ts +1 -1
  70. package/dist/voice/integrations/findIntegrationsCredentials.js +2 -1
  71. package/dist/voice/integrations/getSttConfig.d.ts +4 -2
  72. package/dist/voice/integrations/getSttConfig.js +4 -1
  73. package/dist/voice/integrations/getTtsConfig.d.ts +2 -1
  74. package/dist/voice/integrations/getTtsConfig.js +5 -1
  75. package/dist/voice/integrations/makeCreateContainer.js +1 -1
  76. package/dist/voice/integrations/types.d.ts +1 -1
  77. package/dist/voice/makeCreateVoiceClient.js +4 -10
  78. package/dist/voice/makeGetChannelVar.d.ts +2 -1
  79. package/dist/voice/makeGetChannelVar.js +13 -0
  80. package/dist/voice/stt/AbstractSpeechToText.d.ts +4 -3
  81. package/dist/voice/stt/Deepgram.d.ts +18 -0
  82. package/dist/voice/stt/Deepgram.js +156 -0
  83. package/dist/voice/stt/Google.d.ts +5 -6
  84. package/dist/voice/stt/Google.js +13 -13
  85. package/dist/voice/stt/SpeechToTextFactory.js +2 -0
  86. package/dist/voice/stt/types.d.ts +22 -10
  87. package/dist/voice/stt/types.js +7 -0
  88. package/dist/voice/tts/Deepgram.d.ts +25 -0
  89. package/dist/voice/tts/Deepgram.js +122 -0
  90. package/dist/voice/tts/Google.d.ts +2 -1
  91. package/dist/voice/tts/Google.js +7 -8
  92. package/dist/voice/tts/TextToSpeechFactory.js +2 -0
  93. package/dist/voice/types/ari.d.ts +2 -1
  94. package/dist/voice/types/ari.js +1 -0
  95. package/dist/voice/types/voice.d.ts +9 -1
  96. package/package.json +9 -8
  97. package/dist/calls/createTrackCallSubscriber.d.ts +0 -5
  98. package/dist/calls/createTrackCallSubscriber.js +0 -52
  99. package/dist/calls/trackCall.js +0 -63
  100. package/dist/voice/handlers/StasisEnd.d.ts +0 -4
  101. package/dist/voice/handlers/dial/handleDialEvents.d.ts +0 -5
  102. /package/dist/voice/handlers/{awaitForPlaybackFinished.d.ts → utils/awaitForPlaybackFinished.d.ts} +0 -0
  103. /package/dist/voice/handlers/{awaitForRecordingFinished.d.ts → utils/awaitForRecordingFinished.d.ts} +0 -0
  104. /package/dist/voice/handlers/{withErrorHandling.d.ts → utils/withErrorHandling.d.ts} +0 -0
  105. /package/dist/voice/handlers/{withErrorHandling.js → utils/withErrorHandling.js} +0 -0
@@ -7,7 +7,7 @@ type IntegrationConfig = {
7
7
  type IntegrationsContainer = {
8
8
  ref: string;
9
9
  accessKeyId: string;
10
- appEndpoint: string;
10
+ endpoint: string;
11
11
  tts: AbstractTextToSpeech<unknown>;
12
12
  stt: AbstractSpeechToText<unknown>;
13
13
  };
@@ -43,24 +43,18 @@ function makeCreateVoiceClient(createContainer) {
43
43
  const { ari, event, channel } = params;
44
44
  const { id: sessionRef, caller } = event.channel;
45
45
  const { name: callerName, number: callerNumber } = caller;
46
- const getChannelVar = (0, makeGetChannelVar_1.makeGetChannelVar)(channel);
46
+ const getChannelVar = (0, makeGetChannelVar_1.makeGetChannelVarWithoutThrow)(channel);
47
47
  // Variables set by Asterisk's dialplan
48
48
  const appRef = (_a = (yield getChannelVar(types_1.ChannelVar.APP_REF))) === null || _a === void 0 ? void 0 : _a.value;
49
49
  const ingressNumber = ((_b = (yield getChannelVar(types_1.ChannelVar.INGRESS_NUMBER))) === null || _b === void 0 ? void 0 : _b.value) || "";
50
- const { accessKeyId, appEndpoint, tts, stt } = yield createContainer(appRef);
50
+ const { accessKeyId, endpoint, tts, stt } = yield createContainer(appRef);
51
51
  const sessionToken = yield createToken({ accessKeyId, appRef });
52
- let metadataStr;
53
- try {
54
- metadataStr = (_c = (yield getChannelVar(types_1.ChannelVar.METADATA))) === null || _c === void 0 ? void 0 : _c.value;
55
- }
56
- catch (e) {
57
- // Do nothing
58
- }
52
+ const metadataStr = (_c = (yield getChannelVar(types_1.ChannelVar.METADATA))) === null || _c === void 0 ? void 0 : _c.value;
59
53
  const config = {
60
54
  appRef,
61
55
  sessionRef,
62
56
  accessKeyId,
63
- appEndpoint,
57
+ endpoint,
64
58
  callerName,
65
59
  callerNumber,
66
60
  ingressNumber,
@@ -1,4 +1,5 @@
1
1
  import { Channel } from "ari-client";
2
2
  import { ChannelVar } from "./types";
3
3
  declare function makeGetChannelVar(channel: Channel): (variable: ChannelVar) => Promise<import("ari-client").Variable>;
4
- export { makeGetChannelVar };
4
+ declare function makeGetChannelVarWithoutThrow(channel: Channel): (variable: ChannelVar) => Promise<import("ari-client").Variable>;
5
+ export { makeGetChannelVar, makeGetChannelVarWithoutThrow };
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.makeGetChannelVar = makeGetChannelVar;
13
+ exports.makeGetChannelVarWithoutThrow = makeGetChannelVarWithoutThrow;
13
14
  const ChannelVarNotFoundError_1 = require("./ChannelVarNotFoundError");
14
15
  function makeGetChannelVar(channel) {
15
16
  return (variable) => __awaiter(this, void 0, void 0, function* () {
@@ -23,3 +24,15 @@ function makeGetChannelVar(channel) {
23
24
  }
24
25
  });
25
26
  }
27
+ function makeGetChannelVarWithoutThrow(channel) {
28
+ return (variable) => __awaiter(this, void 0, void 0, function* () {
29
+ try {
30
+ return yield channel.getChannelVar({
31
+ variable
32
+ });
33
+ }
34
+ catch (e) {
35
+ return null;
36
+ }
37
+ });
38
+ }
@@ -1,11 +1,12 @@
1
1
  import { Stream } from "stream";
2
2
  import * as z from "zod";
3
- import { SpeechResult, StreamSpeechResult, SttConfig } from "./types";
4
- declare abstract class AbstractSpeechToText<E, T extends SttConfig = SttConfig> {
3
+ import { SpeechResult, StreamSpeech, SttConfig } from "./types";
4
+ import { SpeechToText } from "../types";
5
+ declare abstract class AbstractSpeechToText<E, T extends SttConfig = SttConfig> implements SpeechToText {
5
6
  abstract readonly engineName: E;
6
7
  config: T;
7
8
  constructor(config: T);
8
- abstract streamTranscribe(stream: Stream): StreamSpeechResult;
9
+ abstract streamTranscribe(stream: Stream): StreamSpeech;
9
10
  abstract transcribe(stream: Stream): Promise<SpeechResult>;
10
11
  getName(): E;
11
12
  static getConfigValidationSchema(): z.Schema;
@@ -0,0 +1,18 @@
1
+ import { Stream } from "stream";
2
+ import * as z from "zod";
3
+ import { AbstractSpeechToText } from "./AbstractSpeechToText";
4
+ import { DeepgramSttConfig, SpeechResult, StreamSpeech } from "./types";
5
+ import { SpeechToText } from "../types";
6
+ declare const DeepgramClient: any;
7
+ declare const ENGINE_NAME = "stt.deepgram";
8
+ declare class Deepgram extends AbstractSpeechToText<typeof ENGINE_NAME> implements SpeechToText {
9
+ client: typeof DeepgramClient;
10
+ engineConfig: DeepgramSttConfig;
11
+ readonly engineName = "stt.deepgram";
12
+ constructor(config: DeepgramSttConfig);
13
+ streamTranscribe(stream: Stream): StreamSpeech;
14
+ transcribe(stream: Stream): Promise<SpeechResult>;
15
+ static getConfigValidationSchema(): z.Schema;
16
+ static getCredentialsValidationSchema(): z.Schema;
17
+ }
18
+ export { Deepgram, ENGINE_NAME };
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.ENGINE_NAME = exports.Deepgram = void 0;
36
+ /* eslint-disable @typescript-eslint/no-var-requires */
37
+ /*
38
+ * Copyright (C) 2024 by Fonoster Inc (https://fonoster.com)
39
+ * http://github.com/fonoster/fonoster
40
+ *
41
+ * This file is part of Fonoster
42
+ *
43
+ * Licensed under the MIT License (the "License");
44
+ * you may not use this file except in compliance with
45
+ * the License. You may obtain a copy of the License at
46
+ *
47
+ * https://opensource.org/licenses/MIT
48
+ *
49
+ * Unless required by applicable law or agreed to in writing, software
50
+ * distributed under the License is distributed on an "AS IS" BASIS,
51
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
52
+ * See the License for the specific language governing permissions and
53
+ * limitations under the License.
54
+ */
55
+ const stream_1 = require("stream");
56
+ const common_1 = require("@fonoster/common");
57
+ const logger_1 = require("@fonoster/logger");
58
+ const z = __importStar(require("zod"));
59
+ const AbstractSpeechToText_1 = require("./AbstractSpeechToText");
60
+ const types_1 = require("./types");
61
+ const { DeepgramClient, LiveTranscriptionEvents, createClient } = require("@deepgram/sdk"); // Why Deepgram :(
62
+ const ENGINE_NAME = "stt.deepgram";
63
+ exports.ENGINE_NAME = ENGINE_NAME;
64
+ const logger = (0, logger_1.getLogger)({ service: "apiserver", filePath: __filename });
65
+ class Deepgram extends AbstractSpeechToText_1.AbstractSpeechToText {
66
+ constructor(config) {
67
+ super(config);
68
+ this.engineName = ENGINE_NAME;
69
+ this.client = createClient(config.credentials.apiKey);
70
+ this.engineConfig = config;
71
+ }
72
+ streamTranscribe(stream) {
73
+ const connection = this.client.listen.live(buildTranscribeConfig(this.engineConfig.config));
74
+ const out = new stream_1.Stream();
75
+ connection.on(LiveTranscriptionEvents.Open, () => {
76
+ // WARNING: This is a workaround to keep the connection open while the system
77
+ // is playing a file which causes the stream to be paused. We need to look into why
78
+ // the stream is being paused.
79
+ const keepAliveInterval = setInterval(() => {
80
+ const keepAliveMsg = JSON.stringify({ type: "KeepAlive" });
81
+ connection.send(keepAliveMsg);
82
+ }, 3000);
83
+ stream.on("data", (chunk) => {
84
+ connection.send(chunk);
85
+ });
86
+ connection.on(LiveTranscriptionEvents.Transcript, (data) => {
87
+ if (!data.channel.alternatives[0].transcript || !data.speech_final) {
88
+ return;
89
+ }
90
+ out.emit("data", {
91
+ speech: data.channel.alternatives[0].transcript
92
+ });
93
+ });
94
+ connection.on(LiveTranscriptionEvents.Error, (err) => {
95
+ logger.warn("error on Deepgram connection", { err });
96
+ clearInterval(keepAliveInterval);
97
+ connection.destroy();
98
+ });
99
+ });
100
+ return out;
101
+ }
102
+ transcribe(stream) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ return new Promise((resolve, reject) => {
105
+ const connection = this.client.listen.live(buildTranscribeConfig(this.engineConfig.config));
106
+ stream.on("data", (chunk) => {
107
+ connection.send(chunk);
108
+ });
109
+ connection.on(LiveTranscriptionEvents.Open, () => {
110
+ connection.on(LiveTranscriptionEvents.Transcript, (data) => {
111
+ if (data.channel.alternatives[0].transcript && data.speech_final) {
112
+ const result = {
113
+ speech: data.channel.alternatives[0].transcript,
114
+ isFinal: true
115
+ };
116
+ resolve(result);
117
+ connection.destroy();
118
+ }
119
+ });
120
+ connection.on(LiveTranscriptionEvents.Error, (err) => {
121
+ logger.warn("error on Deepgram connection", { err });
122
+ reject(err);
123
+ });
124
+ });
125
+ stream.on("end", () => {
126
+ connection.destroy();
127
+ });
128
+ stream.on("error", (err) => {
129
+ connection.destroy();
130
+ reject(err);
131
+ });
132
+ });
133
+ });
134
+ }
135
+ static getConfigValidationSchema() {
136
+ return z.object({
137
+ languageCode: z.nativeEnum(common_1.VoiceLanguage).optional().nullable(),
138
+ model: z.nativeEnum(types_1.DeepgramModel).optional().nullable()
139
+ });
140
+ }
141
+ static getCredentialsValidationSchema() {
142
+ return z.object({
143
+ apiKey: z.string()
144
+ });
145
+ }
146
+ }
147
+ exports.Deepgram = Deepgram;
148
+ function buildTranscribeConfig(config) {
149
+ return {
150
+ model: config.model || types_1.DeepgramModel.NOVA_2_PHONECALL,
151
+ encoding: "linear16",
152
+ sample_rate: 16000,
153
+ language: config.languageCode || common_1.VoiceLanguage.EN_US,
154
+ smart_format: true
155
+ };
156
+ }
@@ -2,16 +2,15 @@ import { Stream } from "stream";
2
2
  import { SpeechClient } from "@google-cloud/speech";
3
3
  import * as z from "zod";
4
4
  import { AbstractSpeechToText } from "./AbstractSpeechToText";
5
- import { GoogleSttConfig, SpeechResult, StreamSpeechResult } from "./types";
5
+ import { GoogleSttConfig, SpeechResult, StreamSpeech } from "./types";
6
+ import { SpeechToText } from "../types";
6
7
  declare const ENGINE_NAME = "stt.google";
7
- declare class Google extends AbstractSpeechToText<typeof ENGINE_NAME> {
8
+ declare class Google extends AbstractSpeechToText<typeof ENGINE_NAME> implements SpeechToText {
8
9
  client: SpeechClient;
9
- config: GoogleSttConfig;
10
+ engineConfig: GoogleSttConfig;
10
11
  readonly engineName = "stt.google";
11
- protected readonly AUDIO_ENCODING = "LINEAR16";
12
- protected readonly SAMPLE_RATE_HERTZ = 16000;
13
12
  constructor(config: GoogleSttConfig);
14
- streamTranscribe(_: Stream): StreamSpeechResult;
13
+ streamTranscribe(_: Stream): StreamSpeech;
15
14
  transcribe(stream: Stream): Promise<SpeechResult>;
16
15
  static getConfigValidationSchema(): z.Schema;
17
16
  static getCredentialsValidationSchema(): z.Schema;
@@ -39,32 +39,32 @@ const z = __importStar(require("zod"));
39
39
  const AbstractSpeechToText_1 = require("./AbstractSpeechToText");
40
40
  const ENGINE_NAME = "stt.google";
41
41
  exports.ENGINE_NAME = ENGINE_NAME;
42
- const AUDIO_ENCODING = "LINEAR16";
43
- const SAMPLE_RATE_HERTZ = 16000;
44
42
  class Google extends AbstractSpeechToText_1.AbstractSpeechToText {
45
43
  constructor(config) {
46
44
  super(config);
47
45
  this.engineName = ENGINE_NAME;
48
- this.AUDIO_ENCODING = AUDIO_ENCODING;
49
- this.SAMPLE_RATE_HERTZ = SAMPLE_RATE_HERTZ;
50
46
  this.client = new speech_1.SpeechClient(config);
51
- this.config = Object.assign(Object.assign({}, config), { config: {
52
- encoding: AUDIO_ENCODING,
53
- sampleRateHertz: SAMPLE_RATE_HERTZ,
54
- interimResults: false,
55
- languageCode: config.languageCode
56
- } });
47
+ this.engineConfig = config;
57
48
  }
58
49
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
59
50
  streamTranscribe(_) {
60
51
  // Not implemented
61
- return null;
52
+ throw new Error("Stream Transcribe not implemented for Google Engine");
62
53
  }
63
54
  transcribe(stream) {
64
55
  return __awaiter(this, void 0, void 0, function* () {
56
+ const languageCode = this.engineConfig.config.languageCode || common_1.VoiceLanguage.EN_US;
57
+ const audioConfig = {
58
+ interimResults: false,
59
+ config: {
60
+ encoding: "LINEAR16",
61
+ sampleRateHertz: 16000,
62
+ languageCode
63
+ }
64
+ };
65
65
  return new Promise((resolve, reject) => {
66
66
  const recognizeStream = this.client
67
- .streamingRecognize(this.config)
67
+ .streamingRecognize(audioConfig)
68
68
  .on("error", (e) => reject(e))
69
69
  .on("data", (data) => {
70
70
  var _a;
@@ -86,7 +86,7 @@ class Google extends AbstractSpeechToText_1.AbstractSpeechToText {
86
86
  }
87
87
  static getConfigValidationSchema() {
88
88
  return z.object({
89
- languageCode: z.nativeEnum(common_1.VoiceLanguage)
89
+ languageCode: z.nativeEnum(common_1.VoiceLanguage).optional().nullable()
90
90
  });
91
91
  }
92
92
  static getCredentialsValidationSchema() {
@@ -20,6 +20,7 @@ exports.SpeechToTextFactory = void 0;
20
20
  * limitations under the License.
21
21
  */
22
22
  const logger_1 = require("@fonoster/logger");
23
+ const Deepgram_1 = require("./Deepgram");
23
24
  const Google_1 = require("./Google");
24
25
  const logger = (0, logger_1.getLogger)({ service: "apiserver", filePath: __filename });
25
26
  class SpeechToTextFactory {
@@ -39,3 +40,4 @@ exports.SpeechToTextFactory = SpeechToTextFactory;
39
40
  SpeechToTextFactory.engines = new Map();
40
41
  // Register engines
41
42
  SpeechToTextFactory.registerEngine(Google_1.ENGINE_NAME, Google_1.Google);
43
+ SpeechToTextFactory.registerEngine(Deepgram_1.ENGINE_NAME, Deepgram_1.Deepgram);
@@ -1,20 +1,23 @@
1
1
  import { VoiceLanguage } from "@fonoster/common/src/tts/types";
2
- type SttConfig = {
3
- languageCode: VoiceLanguage;
4
- };
2
+ declare enum DeepgramModel {
3
+ NOVA_2 = "nova-2",
4
+ NOVA_2_PHONECALL = "nova-2-phonecall",
5
+ NOVA_2_CONVERSATIONALAI = "nova-2-conversationalai"
6
+ }
5
7
  type SpeechResult = {
6
8
  speech: string;
7
9
  isFinal: boolean;
8
10
  };
9
- type StreamSpeechResult = {
11
+ type StreamSpeech = {
10
12
  on(events: string, callback: (result: SpeechResult) => void): void;
11
- close: () => void;
12
13
  };
13
- type GoogleSttConfig = SttConfig & {
14
+ type SttConfig = {
15
+ config: {
16
+ languageCode: VoiceLanguage;
17
+ };
18
+ };
19
+ type GoogleSttConfig = {
14
20
  config: {
15
- encoding: "LINEAR16";
16
- sampleRateHertz: 16000;
17
- interimResults: boolean;
18
21
  languageCode: VoiceLanguage;
19
22
  };
20
23
  credentials: {
@@ -22,4 +25,13 @@ type GoogleSttConfig = SttConfig & {
22
25
  private_key: string;
23
26
  };
24
27
  };
25
- export { SttConfig, SpeechResult, StreamSpeechResult, GoogleSttConfig };
28
+ type DeepgramSttConfig = {
29
+ config: {
30
+ languageCode: VoiceLanguage;
31
+ model: DeepgramModel;
32
+ };
33
+ credentials: {
34
+ apiKey: string;
35
+ };
36
+ };
37
+ export { SpeechResult, StreamSpeech, SttConfig, GoogleSttConfig, DeepgramSttConfig, DeepgramModel };
@@ -1,2 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeepgramModel = void 0;
4
+ var DeepgramModel;
5
+ (function (DeepgramModel) {
6
+ DeepgramModel["NOVA_2"] = "nova-2";
7
+ DeepgramModel["NOVA_2_PHONECALL"] = "nova-2-phonecall";
8
+ DeepgramModel["NOVA_2_CONVERSATIONALAI"] = "nova-2-conversationalai";
9
+ })(DeepgramModel || (exports.DeepgramModel = DeepgramModel = {}));
@@ -0,0 +1,25 @@
1
+ import * as z from "zod";
2
+ import { AbstractTextToSpeech } from "./AbstractTextToSpeech";
3
+ import { SynthOptions, TtsConfig } from "./types";
4
+ declare const DeepgramClient: any;
5
+ declare const ENGINE_NAME = "tts.deepgram";
6
+ type DeepgramTtsConfig = TtsConfig & {
7
+ [key: string]: Record<string, string>;
8
+ credentials: {
9
+ apiKey: string;
10
+ };
11
+ };
12
+ declare class Deepgram extends AbstractTextToSpeech<typeof ENGINE_NAME> {
13
+ client: typeof DeepgramClient;
14
+ engineConfig: DeepgramTtsConfig;
15
+ readonly engineName = "tts.deepgram";
16
+ protected readonly OUTPUT_FORMAT = "sln16";
17
+ protected readonly CACHING_FIELDS: string[];
18
+ protected readonly AUDIO_ENCODING: "linear16";
19
+ protected readonly SAMPLE_RATE_HERTZ = 16000;
20
+ constructor(config: DeepgramTtsConfig);
21
+ synthesize(text: string, options: SynthOptions): Promise<string>;
22
+ static getConfigValidationSchema(): z.Schema;
23
+ static getCredentialsValidationSchema(): z.Schema;
24
+ }
25
+ export { Deepgram, ENGINE_NAME };
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.ENGINE_NAME = exports.Deepgram = void 0;
36
+ /*
37
+ * Copyright (C) 2024 by Fonoster Inc (https://fonoster.com)
38
+ * http://github.com/fonoster/fonoster
39
+ *
40
+ * This file is part of Fonoster
41
+ *
42
+ * Licensed under the MIT License (the "License");
43
+ * you may not use this file except in compliance with
44
+ * the License. You may obtain a copy of the License at
45
+ *
46
+ * https://opensource.org/licenses/MIT
47
+ *
48
+ * Unless required by applicable law or agreed to in writing, software
49
+ * distributed under the License is distributed on an "AS IS" BASIS,
50
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
51
+ * See the License for the specific language governing permissions and
52
+ * limitations under the License.
53
+ */
54
+ const fs = __importStar(require("fs"));
55
+ const util = __importStar(require("util"));
56
+ const common_1 = require("@fonoster/common");
57
+ const logger_1 = require("@fonoster/logger");
58
+ const z = __importStar(require("zod"));
59
+ const AbstractTextToSpeech_1 = require("./AbstractTextToSpeech");
60
+ const isSsml_1 = require("./isSsml");
61
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
62
+ const { DeepgramClient, createClient } = require("@deepgram/sdk");
63
+ const ENGINE_NAME = "tts.deepgram";
64
+ exports.ENGINE_NAME = ENGINE_NAME;
65
+ const logger = (0, logger_1.getLogger)({ service: "apiserver", filePath: __filename });
66
+ class Deepgram extends AbstractTextToSpeech_1.AbstractTextToSpeech {
67
+ constructor(config) {
68
+ super(config);
69
+ this.engineName = ENGINE_NAME;
70
+ this.OUTPUT_FORMAT = "sln16";
71
+ this.CACHING_FIELDS = ["voice"];
72
+ this.AUDIO_ENCODING = "linear16";
73
+ this.SAMPLE_RATE_HERTZ = 16000;
74
+ this.client = createClient(config.credentials.apiKey);
75
+ this.engineConfig = config;
76
+ }
77
+ synthesize(text, options) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ logger.verbose(`synthesize [input: ${text}, isSsml=${(0, isSsml_1.isSsml)(text)} options: ${JSON.stringify(options)}]`);
80
+ const effectiveOptions = Object.assign(Object.assign({}, this.engineConfig), options);
81
+ const { voice } = this.engineConfig.config;
82
+ const filename = this.createFilename(text, effectiveOptions);
83
+ if (this.fileExists(this.getFullPathToFile(filename))) {
84
+ return this.getFilenameWithoutExtension(filename);
85
+ }
86
+ const response = yield this.client.speak.request({ text }, {
87
+ model: voice || common_1.DeepgramVoice.AURA_ASTERIA_EN,
88
+ encoding: this.AUDIO_ENCODING,
89
+ sample_rate: this.SAMPLE_RATE_HERTZ
90
+ });
91
+ const writeFile = util.promisify(fs.writeFile);
92
+ const audioBuffer = yield getAudioBuffer(yield response.getStream());
93
+ yield writeFile(this.getFullPathToFile(filename), audioBuffer, "binary");
94
+ return this.getFilenameWithoutExtension(filename);
95
+ });
96
+ }
97
+ static getConfigValidationSchema() {
98
+ return z.object({
99
+ voice: z.nativeEnum(common_1.DeepgramVoice)
100
+ });
101
+ }
102
+ static getCredentialsValidationSchema() {
103
+ return z.object({
104
+ apiKey: z.string()
105
+ });
106
+ }
107
+ }
108
+ exports.Deepgram = Deepgram;
109
+ // helper function to convert stream to audio buffer
110
+ const getAudioBuffer = (response) => __awaiter(void 0, void 0, void 0, function* () {
111
+ const reader = response.getReader();
112
+ const chunks = [];
113
+ // eslint-disable-next-line no-loops/no-loops, no-constant-condition
114
+ while (true) {
115
+ const { done, value } = yield reader.read();
116
+ if (done)
117
+ break;
118
+ chunks.push(value);
119
+ }
120
+ const dataArray = chunks.reduce((acc, chunk) => Uint8Array.from([...acc, ...chunk]), new Uint8Array(0));
121
+ return Buffer.from(dataArray.buffer);
122
+ });
@@ -12,11 +12,12 @@ type GoogleTtsConfig = TtsConfig & {
12
12
  };
13
13
  declare class Google extends AbstractTextToSpeech<typeof ENGINE_NAME> {
14
14
  client: TextToSpeechClient;
15
- config: GoogleTtsConfig;
15
+ engineConfig: GoogleTtsConfig;
16
16
  readonly engineName = "tts.google";
17
17
  protected readonly OUTPUT_FORMAT = "sln16";
18
18
  protected readonly CACHING_FIELDS: string[];
19
19
  protected readonly AUDIO_ENCODING: "LINEAR16";
20
+ protected readonly SAMPLE_RATE_HERTZ = 16000;
20
21
  constructor(config: GoogleTtsConfig);
21
22
  synthesize(text: string, options: SynthOptions): Promise<string>;
22
23
  static getConfigValidationSchema(): z.Schema;
@@ -61,8 +61,6 @@ const AbstractTextToSpeech_1 = require("./AbstractTextToSpeech");
61
61
  const isSsml_1 = require("./isSsml");
62
62
  const ENGINE_NAME = "tts.google";
63
63
  exports.ENGINE_NAME = ENGINE_NAME;
64
- const AUDIO_ENCODING = "LINEAR16";
65
- const SAMPLE_RATE_HERTZ = 16000;
66
64
  const logger = (0, logger_1.getLogger)({ service: "apiserver", filePath: __filename });
67
65
  class Google extends AbstractTextToSpeech_1.AbstractTextToSpeech {
68
66
  constructor(config) {
@@ -70,15 +68,16 @@ class Google extends AbstractTextToSpeech_1.AbstractTextToSpeech {
70
68
  this.engineName = ENGINE_NAME;
71
69
  this.OUTPUT_FORMAT = "sln16";
72
70
  this.CACHING_FIELDS = ["voice"];
73
- this.AUDIO_ENCODING = AUDIO_ENCODING;
71
+ this.AUDIO_ENCODING = "LINEAR16";
72
+ this.SAMPLE_RATE_HERTZ = 16000;
74
73
  this.client = new text_to_speech_1.TextToSpeechClient(config);
75
- this.config = config;
74
+ this.engineConfig = config;
76
75
  }
77
76
  synthesize(text, options) {
78
77
  return __awaiter(this, void 0, void 0, function* () {
79
78
  logger.verbose(`synthesize [input: ${text}, isSsml=${(0, isSsml_1.isSsml)(text)} options: ${JSON.stringify(options)}]`);
80
- const effectiveOptions = Object.assign(Object.assign({}, this.config), options);
81
- const { voice } = effectiveOptions;
79
+ const effectiveOptions = Object.assign(Object.assign({}, this.engineConfig), options);
80
+ const { voice } = this.engineConfig.config;
82
81
  const lang = `${voice.split("-")[0]}-${voice.split("-")[1]}`;
83
82
  const filename = this.createFilename(text, effectiveOptions);
84
83
  if (this.fileExists(this.getFullPathToFile(filename))) {
@@ -87,8 +86,8 @@ class Google extends AbstractTextToSpeech_1.AbstractTextToSpeech {
87
86
  const request = {
88
87
  input: (0, isSsml_1.isSsml)(text) ? { ssml: text } : { text },
89
88
  audioConfig: {
90
- audioEncoding: AUDIO_ENCODING,
91
- sampleRateHertz: SAMPLE_RATE_HERTZ
89
+ audioEncoding: this.AUDIO_ENCODING,
90
+ sampleRateHertz: this.SAMPLE_RATE_HERTZ
92
91
  },
93
92
  voice: {
94
93
  languageCode: lang,
@@ -21,6 +21,7 @@ exports.TextToSpeechFactory = void 0;
21
21
  */
22
22
  const logger_1 = require("@fonoster/logger");
23
23
  const Azure_1 = require("./Azure");
24
+ const Deepgram_1 = require("./Deepgram");
24
25
  const Google_1 = require("./Google");
25
26
  const logger = (0, logger_1.getLogger)({ service: "apiserver", filePath: __filename });
26
27
  class TextToSpeechFactory {
@@ -41,3 +42,4 @@ TextToSpeechFactory.engines = new Map();
41
42
  // Register engines
42
43
  TextToSpeechFactory.registerEngine(Google_1.ENGINE_NAME, Google_1.Google);
43
44
  TextToSpeechFactory.registerEngine(Azure_1.ENGINE_NAME, Azure_1.Azure);
45
+ TextToSpeechFactory.registerEngine(Deepgram_1.ENGINE_NAME, Deepgram_1.Deepgram);
@@ -16,6 +16,7 @@ declare enum ChannelVar {
16
16
  APP_REF = "APP_REF",
17
17
  APP_ENDPOINT = "APP_ENDPOINT",
18
18
  METADATA = "METADATA",
19
- CURRENT_BRIDGE = "CURRENT_BRIDGE"
19
+ CURRENT_BRIDGE = "CURRENT_BRIDGE",
20
+ FROM_EXTERNAL_MEDIA = "FROM_EXTERNAL_MEDIA"
20
21
  }
21
22
  export { AriEvent, ChannelVar };
@@ -40,4 +40,5 @@ var ChannelVar;
40
40
  ChannelVar["APP_ENDPOINT"] = "APP_ENDPOINT";
41
41
  ChannelVar["METADATA"] = "METADATA";
42
42
  ChannelVar["CURRENT_BRIDGE"] = "CURRENT_BRIDGE";
43
+ ChannelVar["FROM_EXTERNAL_MEDIA"] = "FROM_EXTERNAL_MEDIA";
43
44
  })(ChannelVar || (exports.ChannelVar = ChannelVar = {}));