channelkit 1.0.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.
- package/LICENSE +21 -0
- package/README.md +829 -0
- package/config.example.yaml +37 -0
- package/dist/api/middleware/auth.d.ts +14 -0
- package/dist/api/middleware/auth.d.ts.map +1 -0
- package/dist/api/middleware/auth.js +130 -0
- package/dist/api/middleware/auth.js.map +1 -0
- package/dist/api/routes/config.d.ts +4 -0
- package/dist/api/routes/config.d.ts.map +1 -0
- package/dist/api/routes/config.js +794 -0
- package/dist/api/routes/config.js.map +1 -0
- package/dist/api/routes/dashboard.d.ts +4 -0
- package/dist/api/routes/dashboard.d.ts.map +1 -0
- package/dist/api/routes/dashboard.js +89 -0
- package/dist/api/routes/dashboard.js.map +1 -0
- package/dist/api/routes/inbound.d.ts +4 -0
- package/dist/api/routes/inbound.d.ts.map +1 -0
- package/dist/api/routes/inbound.js +293 -0
- package/dist/api/routes/inbound.js.map +1 -0
- package/dist/api/routes/logs.d.ts +4 -0
- package/dist/api/routes/logs.d.ts.map +1 -0
- package/dist/api/routes/logs.js +49 -0
- package/dist/api/routes/logs.js.map +1 -0
- package/dist/api/routes/mcp.d.ts +4 -0
- package/dist/api/routes/mcp.d.ts.map +1 -0
- package/dist/api/routes/mcp.js +100 -0
- package/dist/api/routes/mcp.js.map +1 -0
- package/dist/api/routes/restart.d.ts +4 -0
- package/dist/api/routes/restart.d.ts.map +1 -0
- package/dist/api/routes/restart.js +11 -0
- package/dist/api/routes/restart.js.map +1 -0
- package/dist/api/routes/send.d.ts +4 -0
- package/dist/api/routes/send.d.ts.map +1 -0
- package/dist/api/routes/send.js +66 -0
- package/dist/api/routes/send.js.map +1 -0
- package/dist/api/routes/settings.d.ts +4 -0
- package/dist/api/routes/settings.d.ts.map +1 -0
- package/dist/api/routes/settings.js +133 -0
- package/dist/api/routes/settings.js.map +1 -0
- package/dist/api/routes/tunnel.d.ts +4 -0
- package/dist/api/routes/tunnel.d.ts.map +1 -0
- package/dist/api/routes/tunnel.js +209 -0
- package/dist/api/routes/tunnel.js.map +1 -0
- package/dist/api/routes/twilio.d.ts +4 -0
- package/dist/api/routes/twilio.d.ts.map +1 -0
- package/dist/api/routes/twilio.js +138 -0
- package/dist/api/routes/twilio.js.map +1 -0
- package/dist/api/routes/update.d.ts +4 -0
- package/dist/api/routes/update.d.ts.map +1 -0
- package/dist/api/routes/update.js +42 -0
- package/dist/api/routes/update.js.map +1 -0
- package/dist/api/server.d.ts +52 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +415 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/types.d.ts +61 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +3 -0
- package/dist/api/types.js.map +1 -0
- package/dist/channels/base.d.ts +15 -0
- package/dist/channels/base.d.ts.map +1 -0
- package/dist/channels/base.js +20 -0
- package/dist/channels/base.js.map +1 -0
- package/dist/channels/email/gmail.d.ts +36 -0
- package/dist/channels/email/gmail.d.ts.map +1 -0
- package/dist/channels/email/gmail.js +351 -0
- package/dist/channels/email/gmail.js.map +1 -0
- package/dist/channels/email/index.d.ts +3 -0
- package/dist/channels/email/index.d.ts.map +1 -0
- package/dist/channels/email/index.js +8 -0
- package/dist/channels/email/index.js.map +1 -0
- package/dist/channels/email/resend.d.ts +29 -0
- package/dist/channels/email/resend.d.ts.map +1 -0
- package/dist/channels/email/resend.js +155 -0
- package/dist/channels/email/resend.js.map +1 -0
- package/dist/channels/endpoint/index.d.ts +21 -0
- package/dist/channels/endpoint/index.d.ts.map +1 -0
- package/dist/channels/endpoint/index.js +80 -0
- package/dist/channels/endpoint/index.js.map +1 -0
- package/dist/channels/sms/index.d.ts +37 -0
- package/dist/channels/sms/index.d.ts.map +1 -0
- package/dist/channels/sms/index.js +163 -0
- package/dist/channels/sms/index.js.map +1 -0
- package/dist/channels/telegram/index.d.ts +24 -0
- package/dist/channels/telegram/index.d.ts.map +1 -0
- package/dist/channels/telegram/index.js +231 -0
- package/dist/channels/telegram/index.js.map +1 -0
- package/dist/channels/voice/index.d.ts +62 -0
- package/dist/channels/voice/index.d.ts.map +1 -0
- package/dist/channels/voice/index.js +286 -0
- package/dist/channels/voice/index.js.map +1 -0
- package/dist/channels/whatsapp/index.d.ts +31 -0
- package/dist/channels/whatsapp/index.d.ts.map +1 -0
- package/dist/channels/whatsapp/index.js +383 -0
- package/dist/channels/whatsapp/index.js.map +1 -0
- package/dist/cli/commands/demo.d.ts +4 -0
- package/dist/cli/commands/demo.d.ts.map +1 -0
- package/dist/cli/commands/demo.js +55 -0
- package/dist/cli/commands/demo.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +254 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/install-skill.d.ts +4 -0
- package/dist/cli/commands/install-skill.d.ts.map +1 -0
- package/dist/cli/commands/install-skill.js +60 -0
- package/dist/cli/commands/install-skill.js.map +1 -0
- package/dist/cli/commands/send.d.ts +5 -0
- package/dist/cli/commands/send.d.ts.map +1 -0
- package/dist/cli/commands/send.js +46 -0
- package/dist/cli/commands/send.js.map +1 -0
- package/dist/cli/commands/start.d.ts +5 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +129 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/helpers.d.ts +26 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +120 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +282 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/wizards/channel.d.ts +4 -0
- package/dist/cli/wizards/channel.d.ts.map +1 -0
- package/dist/cli/wizards/channel.js +285 -0
- package/dist/cli/wizards/channel.js.map +1 -0
- package/dist/cli/wizards/provision.d.ts +4 -0
- package/dist/cli/wizards/provision.d.ts.map +1 -0
- package/dist/cli/wizards/provision.js +213 -0
- package/dist/cli/wizards/provision.js.map +1 -0
- package/dist/cli/wizards/service.d.ts +5 -0
- package/dist/cli/wizards/service.d.ts.map +1 -0
- package/dist/cli/wizards/service.js +212 -0
- package/dist/cli/wizards/service.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/parser.d.ts +6 -0
- package/dist/config/parser.d.ts.map +1 -0
- package/dist/config/parser.js +37 -0
- package/dist/config/parser.js.map +1 -0
- package/dist/config/types.d.ts +170 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +3 -0
- package/dist/config/types.js.map +1 -0
- package/dist/core/apiServer.d.ts +2 -0
- package/dist/core/apiServer.d.ts.map +1 -0
- package/dist/core/apiServer.js +7 -0
- package/dist/core/apiServer.js.map +1 -0
- package/dist/core/groupStore.d.ts +19 -0
- package/dist/core/groupStore.d.ts.map +1 -0
- package/dist/core/groupStore.js +48 -0
- package/dist/core/groupStore.js.map +1 -0
- package/dist/core/logger.d.ts +42 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +142 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/messageHandler.d.ts +15 -0
- package/dist/core/messageHandler.d.ts.map +1 -0
- package/dist/core/messageHandler.js +309 -0
- package/dist/core/messageHandler.js.map +1 -0
- package/dist/core/restart.d.ts +3 -0
- package/dist/core/restart.d.ts.map +1 -0
- package/dist/core/restart.js +35 -0
- package/dist/core/restart.js.map +1 -0
- package/dist/core/router.d.ts +56 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +168 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/tunnel.d.ts +16 -0
- package/dist/core/tunnel.d.ts.map +1 -0
- package/dist/core/tunnel.js +99 -0
- package/dist/core/tunnel.js.map +1 -0
- package/dist/core/types.d.ts +54 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/updater.d.ts +44 -0
- package/dist/core/updater.d.ts.map +1 -0
- package/dist/core/updater.js +264 -0
- package/dist/core/updater.js.map +1 -0
- package/dist/core/webhook.d.ts +26 -0
- package/dist/core/webhook.d.ts.map +1 -0
- package/dist/core/webhook.js +224 -0
- package/dist/core/webhook.js.map +1 -0
- package/dist/dashboard/assets/browser-D_-rzKir.js +8 -0
- package/dist/dashboard/assets/index-CNa084vI.js +88 -0
- package/dist/dashboard/assets/index-CRvIEyjF.css +1 -0
- package/dist/dashboard/index.html +17 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +551 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +6 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +45 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +197 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +16 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +502 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/media/formatter.d.ts +12 -0
- package/dist/media/formatter.d.ts.map +1 -0
- package/dist/media/formatter.js +147 -0
- package/dist/media/formatter.js.map +1 -0
- package/dist/media/processor.d.ts +33 -0
- package/dist/media/processor.d.ts.map +1 -0
- package/dist/media/processor.js +145 -0
- package/dist/media/processor.js.map +1 -0
- package/dist/media/stt.d.ts +16 -0
- package/dist/media/stt.d.ts.map +1 -0
- package/dist/media/stt.js +298 -0
- package/dist/media/stt.js.map +1 -0
- package/dist/media/tts.d.ts +19 -0
- package/dist/media/tts.d.ts.map +1 -0
- package/dist/media/tts.js +135 -0
- package/dist/media/tts.js.map +1 -0
- package/dist/onboarding/index.d.ts +28 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +144 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +14 -0
- package/dist/paths.js.map +1 -0
- package/dist/provisioning/twilio.d.ts +51 -0
- package/dist/provisioning/twilio.d.ts.map +1 -0
- package/dist/provisioning/twilio.js +175 -0
- package/dist/provisioning/twilio.js.map +1 -0
- package/echo-server.js +163 -0
- package/package.json +79 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AI Data Formatter: transforms message text using AI providers.
|
|
4
|
+
*
|
|
5
|
+
* Uses a user-defined prompt to instruct the AI how to format/transform
|
|
6
|
+
* the incoming text (e.g. extract structured data, reformat, translate).
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.createFormatProvider = createFormatProvider;
|
|
10
|
+
function getApiKey(provider) {
|
|
11
|
+
const envMap = {
|
|
12
|
+
openai: 'OPENAI_API_KEY',
|
|
13
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
14
|
+
google: 'GOOGLE_API_KEY',
|
|
15
|
+
};
|
|
16
|
+
const envVar = envMap[provider];
|
|
17
|
+
const key = envVar ? process.env[envVar] : undefined;
|
|
18
|
+
if (!key) {
|
|
19
|
+
throw new Error(`Missing API key for format provider "${provider}". Set ${envVar} in settings or environment.`);
|
|
20
|
+
}
|
|
21
|
+
return key;
|
|
22
|
+
}
|
|
23
|
+
class OpenAIFormatter {
|
|
24
|
+
apiKey;
|
|
25
|
+
model;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.apiKey = getApiKey('openai');
|
|
28
|
+
this.model = config.model || 'gpt-4o-mini';
|
|
29
|
+
}
|
|
30
|
+
async format(text, prompt) {
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
const timer = setTimeout(() => controller.abort(), 30000);
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: {
|
|
37
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
38
|
+
'Content-Type': 'application/json',
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify({
|
|
41
|
+
model: this.model,
|
|
42
|
+
messages: [
|
|
43
|
+
{ role: 'system', content: prompt },
|
|
44
|
+
{ role: 'user', content: text },
|
|
45
|
+
],
|
|
46
|
+
temperature: 0,
|
|
47
|
+
}),
|
|
48
|
+
signal: controller.signal,
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
const err = await res.text();
|
|
52
|
+
throw new Error(`OpenAI ${res.status}: ${err.substring(0, 200)}`);
|
|
53
|
+
}
|
|
54
|
+
const data = await res.json();
|
|
55
|
+
return data.choices?.[0]?.message?.content?.trim() || text;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
class AnthropicFormatter {
|
|
63
|
+
apiKey;
|
|
64
|
+
model;
|
|
65
|
+
constructor(config) {
|
|
66
|
+
this.apiKey = getApiKey('anthropic');
|
|
67
|
+
this.model = config.model || 'claude-sonnet-4-20250514';
|
|
68
|
+
}
|
|
69
|
+
async format(text, prompt) {
|
|
70
|
+
const controller = new AbortController();
|
|
71
|
+
const timer = setTimeout(() => controller.abort(), 30000);
|
|
72
|
+
try {
|
|
73
|
+
const res = await fetch('https://api.anthropic.com/v1/messages', {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
headers: {
|
|
76
|
+
'x-api-key': this.apiKey,
|
|
77
|
+
'anthropic-version': '2023-06-01',
|
|
78
|
+
'Content-Type': 'application/json',
|
|
79
|
+
},
|
|
80
|
+
body: JSON.stringify({
|
|
81
|
+
model: this.model,
|
|
82
|
+
max_tokens: 4096,
|
|
83
|
+
system: prompt,
|
|
84
|
+
messages: [
|
|
85
|
+
{ role: 'user', content: text },
|
|
86
|
+
],
|
|
87
|
+
}),
|
|
88
|
+
signal: controller.signal,
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
const err = await res.text();
|
|
92
|
+
throw new Error(`Anthropic ${res.status}: ${err.substring(0, 200)}`);
|
|
93
|
+
}
|
|
94
|
+
const data = await res.json();
|
|
95
|
+
return data.content?.[0]?.text?.trim() || text;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
class GoogleFormatter {
|
|
103
|
+
apiKey;
|
|
104
|
+
model;
|
|
105
|
+
constructor(config) {
|
|
106
|
+
this.apiKey = getApiKey('google');
|
|
107
|
+
this.model = config.model || 'gemini-2.5-flash';
|
|
108
|
+
}
|
|
109
|
+
async format(text, prompt) {
|
|
110
|
+
const controller = new AbortController();
|
|
111
|
+
const timer = setTimeout(() => controller.abort(), 30000);
|
|
112
|
+
try {
|
|
113
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${this.model}:generateContent?key=${this.apiKey}`;
|
|
114
|
+
const res = await fetch(url, {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers: { 'Content-Type': 'application/json' },
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
systemInstruction: { parts: [{ text: prompt }] },
|
|
119
|
+
contents: [{ parts: [{ text }] }],
|
|
120
|
+
}),
|
|
121
|
+
signal: controller.signal,
|
|
122
|
+
});
|
|
123
|
+
if (!res.ok) {
|
|
124
|
+
const err = await res.text();
|
|
125
|
+
throw new Error(`Google ${res.status}: ${err.substring(0, 200)}`);
|
|
126
|
+
}
|
|
127
|
+
const data = await res.json();
|
|
128
|
+
return data.candidates?.[0]?.content?.parts?.[0]?.text?.trim() || text;
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
clearTimeout(timer);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function createFormatProvider(config) {
|
|
136
|
+
switch (config.provider) {
|
|
137
|
+
case 'openai':
|
|
138
|
+
return new OpenAIFormatter(config);
|
|
139
|
+
case 'anthropic':
|
|
140
|
+
return new AnthropicFormatter(config);
|
|
141
|
+
case 'google':
|
|
142
|
+
return new GoogleFormatter(config);
|
|
143
|
+
default:
|
|
144
|
+
throw new Error(`Unknown format provider: ${config.provider}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/media/formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MediaProcessor: handles STT/TTS/AI-formatting for the message pipeline
|
|
3
|
+
*
|
|
4
|
+
* Inbound: voice message → STT → AI format → adds text to UnifiedMessage
|
|
5
|
+
* Outbound: webhook returns { voice: true } → TTS → sends audio
|
|
6
|
+
*/
|
|
7
|
+
import { ServiceConfig } from '../config/types';
|
|
8
|
+
import { UnifiedMessage, WebhookResponse } from '../core/types';
|
|
9
|
+
export interface InboundResult {
|
|
10
|
+
/** Whether AI formatting was applied to the message text */
|
|
11
|
+
formatApplied?: boolean;
|
|
12
|
+
/** Original message text before formatting (only set when formatting changed it) */
|
|
13
|
+
formatOriginalText?: string;
|
|
14
|
+
/** If formatting failed, the error message — signals the request should be cancelled */
|
|
15
|
+
formatError?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Process inbound message:
|
|
19
|
+
* 1. If audio + STT configured → transcribe to text
|
|
20
|
+
* 2. If format configured → run AI formatting on text
|
|
21
|
+
* Mutates the message in place. Returns format processing info.
|
|
22
|
+
*/
|
|
23
|
+
export declare function processInbound(message: UnifiedMessage, serviceConfig: ServiceConfig): Promise<InboundResult>;
|
|
24
|
+
export interface OutboundResult {
|
|
25
|
+
response: WebhookResponse;
|
|
26
|
+
ttsError?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Process outbound response: if TTS is configured on the service, synthesize audio.
|
|
30
|
+
* Returns the response (with media buffer on success) and any TTS error.
|
|
31
|
+
*/
|
|
32
|
+
export declare function processOutbound(response: WebhookResponse, serviceConfig: ServiceConfig): Promise<OutboundResult>;
|
|
33
|
+
//# sourceMappingURL=processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../../src/media/processor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA4ChE,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAkDlH;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAmBD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAqBtH"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MediaProcessor: handles STT/TTS/AI-formatting for the message pipeline
|
|
4
|
+
*
|
|
5
|
+
* Inbound: voice message → STT → AI format → adds text to UnifiedMessage
|
|
6
|
+
* Outbound: webhook returns { voice: true } → TTS → sends audio
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.processInbound = processInbound;
|
|
10
|
+
exports.processOutbound = processOutbound;
|
|
11
|
+
const stt_1 = require("./stt");
|
|
12
|
+
const tts_1 = require("./tts");
|
|
13
|
+
const formatter_1 = require("./formatter");
|
|
14
|
+
const cache = {
|
|
15
|
+
stt: new Map(),
|
|
16
|
+
tts: new Map(),
|
|
17
|
+
format: new Map(),
|
|
18
|
+
};
|
|
19
|
+
function getSTT(config) {
|
|
20
|
+
if (!config.stt)
|
|
21
|
+
return null;
|
|
22
|
+
const key = `${config.stt.provider}:${config.stt.language || ''}`;
|
|
23
|
+
if (!cache.stt.has(key)) {
|
|
24
|
+
cache.stt.set(key, (0, stt_1.createSTTProvider)(config.stt));
|
|
25
|
+
}
|
|
26
|
+
return cache.stt.get(key);
|
|
27
|
+
}
|
|
28
|
+
function getTTS(config) {
|
|
29
|
+
if (!config.tts)
|
|
30
|
+
return null;
|
|
31
|
+
const key = `${config.tts.provider}:${config.tts.voice || ''}`;
|
|
32
|
+
if (!cache.tts.has(key)) {
|
|
33
|
+
cache.tts.set(key, (0, tts_1.createTTSProvider)(config.tts));
|
|
34
|
+
}
|
|
35
|
+
return cache.tts.get(key);
|
|
36
|
+
}
|
|
37
|
+
function getFormatter(config) {
|
|
38
|
+
if (!config.format)
|
|
39
|
+
return null;
|
|
40
|
+
const key = `${config.format.provider}:${config.format.model || 'default'}`;
|
|
41
|
+
if (!cache.format.has(key)) {
|
|
42
|
+
cache.format.set(key, (0, formatter_1.createFormatProvider)(config.format));
|
|
43
|
+
}
|
|
44
|
+
return cache.format.get(key);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Process inbound message:
|
|
48
|
+
* 1. If audio + STT configured → transcribe to text
|
|
49
|
+
* 2. If format configured → run AI formatting on text
|
|
50
|
+
* Mutates the message in place. Returns format processing info.
|
|
51
|
+
*/
|
|
52
|
+
async function processInbound(message, serviceConfig) {
|
|
53
|
+
const result = {};
|
|
54
|
+
// Step 1: STT — transcribe audio to text
|
|
55
|
+
if (message.type === 'audio' && serviceConfig.stt && message.media?.buffer) {
|
|
56
|
+
const stt = getSTT(serviceConfig);
|
|
57
|
+
if (stt) {
|
|
58
|
+
try {
|
|
59
|
+
const mimetype = message.media.mimetype || 'audio/ogg';
|
|
60
|
+
console.log(`[stt] Transcribing message ${message.id} (${mimetype}, ${message.media.buffer.length} bytes)...`);
|
|
61
|
+
const transcript = await stt.transcribe(message.media.buffer, mimetype, serviceConfig.stt.language);
|
|
62
|
+
if (transcript) {
|
|
63
|
+
message.text = transcript;
|
|
64
|
+
console.log(`[stt] Transcribed: "${transcript.substring(0, 80)}${transcript.length > 80 ? '...' : ''}"`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.log(`[stt] Empty transcription for message ${message.id}`);
|
|
68
|
+
}
|
|
69
|
+
// Clear media buffer after transcription unless forward_audio is enabled
|
|
70
|
+
if (!serviceConfig.stt.forward_audio) {
|
|
71
|
+
delete message.media;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error(`[stt] Transcription failed for message ${message.id}:`, err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Step 2: AI formatting — transform text using configured prompt
|
|
80
|
+
if (serviceConfig.format && message.text) {
|
|
81
|
+
const formatter = getFormatter(serviceConfig);
|
|
82
|
+
if (formatter) {
|
|
83
|
+
try {
|
|
84
|
+
console.log(`[format] Formatting message ${message.id} with ${serviceConfig.format.provider}...`);
|
|
85
|
+
const originalText = message.text;
|
|
86
|
+
const formatted = await formatter.format(message.text, serviceConfig.format.prompt);
|
|
87
|
+
if (formatted) {
|
|
88
|
+
console.log(`[format] Result: "${formatted.substring(0, 80)}${formatted.length > 80 ? '...' : ''}"`);
|
|
89
|
+
message.text = formatted;
|
|
90
|
+
result.formatApplied = true;
|
|
91
|
+
result.formatOriginalText = originalText;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
const errMsg = err?.message || String(err);
|
|
96
|
+
console.error(`[format] Formatting failed for message ${message.id}:`, errMsg);
|
|
97
|
+
result.formatError = errMsg.substring(0, 300);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
/** Strip messaging formatting characters so TTS reads clean text. */
|
|
104
|
+
function stripFormatting(text) {
|
|
105
|
+
return text
|
|
106
|
+
.replace(/\*([^*]+)\*/g, '$1') // *bold*
|
|
107
|
+
.replace(/_([^_]+)_/g, '$1') // _italic_
|
|
108
|
+
.replace(/~([^~]+)~/g, '$1') // ~strikethrough~
|
|
109
|
+
.replace(/```[\s\S]*?```/g, '') // ```code blocks```
|
|
110
|
+
.replace(/`([^`]+)`/g, '$1') // `inline code`
|
|
111
|
+
.replace(/^>\s?/gm, '') // > blockquote
|
|
112
|
+
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // [link text](url)
|
|
113
|
+
.replace(/!\[([^\]]*)\]\([^)]+\)/g, '$1') // 
|
|
114
|
+
.replace(/^#{1,6}\s+/gm, '') // # headings
|
|
115
|
+
.replace(/^[-*+]\s+/gm, '') // bullet lists
|
|
116
|
+
.replace(/^\d+\.\s+/gm, '') // numbered lists
|
|
117
|
+
.trim();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Process outbound response: if TTS is configured on the service, synthesize audio.
|
|
121
|
+
* Returns the response (with media buffer on success) and any TTS error.
|
|
122
|
+
*/
|
|
123
|
+
async function processOutbound(response, serviceConfig) {
|
|
124
|
+
// Synthesize when TTS is configured on the service, unless the webhook explicitly opted out (voice: false)
|
|
125
|
+
if (response.voice === false || !response.text || !serviceConfig.tts)
|
|
126
|
+
return { response };
|
|
127
|
+
const tts = getTTS(serviceConfig);
|
|
128
|
+
if (!tts)
|
|
129
|
+
return { response };
|
|
130
|
+
try {
|
|
131
|
+
const ttsText = stripFormatting(response.text);
|
|
132
|
+
console.log(`[tts] Synthesizing: "${ttsText.substring(0, 80)}${ttsText.length > 80 ? '...' : ''}"`);
|
|
133
|
+
const { buffer, mimetype } = await tts.synthesize(ttsText, serviceConfig.tts.voice);
|
|
134
|
+
console.log(`[tts] Synthesized ${buffer.length} bytes (${mimetype})`);
|
|
135
|
+
return {
|
|
136
|
+
response: { ...response, media: { buffer, mimetype } },
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
console.error(`[tts] Synthesis failed:`, err);
|
|
141
|
+
const errMsg = err?.message || String(err);
|
|
142
|
+
return { response, ttsError: errMsg.substring(0, 300) };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.js","sourceRoot":"","sources":["../../src/media/processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Speech-to-Text providers for ChannelKit
|
|
3
|
+
*/
|
|
4
|
+
export interface STTProvider {
|
|
5
|
+
transcribe(audio: Buffer, mimetype: string, language?: string): Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
export interface STTConfig {
|
|
8
|
+
provider: 'google' | 'whisper' | 'deepgram';
|
|
9
|
+
language?: string;
|
|
10
|
+
alternative_languages?: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Create an STT provider instance
|
|
14
|
+
*/
|
|
15
|
+
export declare function createSTTProvider(config: STTConfig): STTProvider;
|
|
16
|
+
//# sourceMappingURL=stt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stt.d.ts","sourceRoot":"","sources":["../../src/media/stt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACjF;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AA+QD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,CAWhE"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Speech-to-Text providers for ChannelKit
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.createSTTProvider = createSTTProvider;
|
|
40
|
+
// Env var convention: <PROVIDER>_STT_API_KEY
|
|
41
|
+
function getApiKey(provider) {
|
|
42
|
+
const key = process.env[`${provider.toUpperCase()}_STT_API_KEY`]
|
|
43
|
+
|| process.env[`${provider.toUpperCase()}_API_KEY`];
|
|
44
|
+
if (!key) {
|
|
45
|
+
throw new Error(`Missing API key for STT provider "${provider}". Set ${provider.toUpperCase()}_STT_API_KEY or ${provider.toUpperCase()}_API_KEY environment variable.`);
|
|
46
|
+
}
|
|
47
|
+
return key;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Google Cloud Speech-to-Text (REST API)
|
|
51
|
+
* Supports both API key and Application Default Credentials (ADC).
|
|
52
|
+
* Priority: GOOGLE_STT_API_KEY > GOOGLE_API_KEY > ADC (gcloud auth)
|
|
53
|
+
*/
|
|
54
|
+
class GoogleSTT {
|
|
55
|
+
sttConfig;
|
|
56
|
+
apiKey;
|
|
57
|
+
constructor(sttConfig) {
|
|
58
|
+
this.sttConfig = sttConfig;
|
|
59
|
+
// API key is optional — fall back to ADC
|
|
60
|
+
this.apiKey = process.env.GOOGLE_STT_API_KEY
|
|
61
|
+
|| process.env.GOOGLE_API_KEY
|
|
62
|
+
|| null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get an access token from ADC (Application Default Credentials).
|
|
66
|
+
* Works when `gcloud auth application-default login` has been run,
|
|
67
|
+
* or when GOOGLE_APPLICATION_CREDENTIALS points to a service account JSON.
|
|
68
|
+
*/
|
|
69
|
+
async getAccessToken() {
|
|
70
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
71
|
+
const home = process.env.HOME || '~';
|
|
72
|
+
const candidates = [
|
|
73
|
+
process.env.GOOGLE_APPLICATION_CREDENTIALS,
|
|
74
|
+
`${home}/.config/google/stt-credentials.json`,
|
|
75
|
+
`${home}/.config/gcloud/application_default_credentials.json`,
|
|
76
|
+
].filter(Boolean);
|
|
77
|
+
const credPath = candidates.find(p => fs.existsSync(p));
|
|
78
|
+
if (!credPath) {
|
|
79
|
+
throw new Error(`Google STT: No API key and no ADC found. Either set GOOGLE_STT_API_KEY / GOOGLE_API_KEY, ` +
|
|
80
|
+
`or run "gcloud auth application-default login".`);
|
|
81
|
+
}
|
|
82
|
+
const fsSync = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
83
|
+
const creds = JSON.parse(fsSync.readFileSync(credPath, 'utf-8'));
|
|
84
|
+
// Service account JSON
|
|
85
|
+
if (creds.type === 'service_account') {
|
|
86
|
+
const jwt = await this.createServiceAccountJWT(creds);
|
|
87
|
+
return jwt;
|
|
88
|
+
}
|
|
89
|
+
// User credentials (from gcloud auth)
|
|
90
|
+
if (creds.type === 'authorized_user') {
|
|
91
|
+
const res = await fetch('https://oauth2.googleapis.com/token', {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
94
|
+
body: new URLSearchParams({
|
|
95
|
+
client_id: creds.client_id,
|
|
96
|
+
client_secret: creds.client_secret,
|
|
97
|
+
refresh_token: creds.refresh_token,
|
|
98
|
+
grant_type: 'refresh_token',
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
101
|
+
if (!res.ok)
|
|
102
|
+
throw new Error(`Failed to refresh Google token: ${res.status}`);
|
|
103
|
+
const data = await res.json();
|
|
104
|
+
return data.access_token;
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`Unsupported Google credential type: ${creds.type}`);
|
|
107
|
+
}
|
|
108
|
+
async createServiceAccountJWT(creds) {
|
|
109
|
+
const crypto = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
110
|
+
const now = Math.floor(Date.now() / 1000);
|
|
111
|
+
const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');
|
|
112
|
+
const payload = Buffer.from(JSON.stringify({
|
|
113
|
+
iss: creds.client_email,
|
|
114
|
+
scope: 'https://www.googleapis.com/auth/cloud-platform',
|
|
115
|
+
aud: 'https://oauth2.googleapis.com/token',
|
|
116
|
+
iat: now,
|
|
117
|
+
exp: now + 3600,
|
|
118
|
+
})).toString('base64url');
|
|
119
|
+
const signature = crypto.sign('RSA-SHA256', Buffer.from(`${header}.${payload}`), creds.private_key);
|
|
120
|
+
const jwt = `${header}.${payload}.${signature.toString('base64url')}`;
|
|
121
|
+
const res = await fetch('https://oauth2.googleapis.com/token', {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
124
|
+
body: new URLSearchParams({
|
|
125
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
126
|
+
assertion: jwt,
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
if (!res.ok)
|
|
130
|
+
throw new Error(`Failed to get service account token: ${res.status}`);
|
|
131
|
+
const data = await res.json();
|
|
132
|
+
return data.access_token;
|
|
133
|
+
}
|
|
134
|
+
async transcribe(audio, mimetype, language) {
|
|
135
|
+
const encoding = this.getEncoding(mimetype);
|
|
136
|
+
const langCode = language || this.sttConfig.language || 'en-US';
|
|
137
|
+
const config = {
|
|
138
|
+
encoding,
|
|
139
|
+
languageCode: langCode,
|
|
140
|
+
enableAutomaticPunctuation: true,
|
|
141
|
+
};
|
|
142
|
+
// WhatsApp Ogg/Opus files have sample rate 0 in the header, so always specify explicitly.
|
|
143
|
+
// WhatsApp voice notes are 16kHz; generic Opus is typically 48kHz.
|
|
144
|
+
config.sampleRateHertz = encoding === 'OGG_OPUS' ? 16000 : 16000;
|
|
145
|
+
// Auto language detection: add alternative languages
|
|
146
|
+
if (this.sttConfig.alternative_languages?.length) {
|
|
147
|
+
config.alternativeLanguageCodes = this.sttConfig.alternative_languages;
|
|
148
|
+
}
|
|
149
|
+
// Validate audio header
|
|
150
|
+
const magic = audio.slice(0, 4).toString('ascii');
|
|
151
|
+
if (encoding === 'OGG_OPUS' && magic !== 'OggS') {
|
|
152
|
+
console.warn(`[stt:google] Audio buffer does not start with OggS magic (got: ${magic}). Buffer may be corrupt.`);
|
|
153
|
+
}
|
|
154
|
+
const body = {
|
|
155
|
+
config,
|
|
156
|
+
audio: {
|
|
157
|
+
content: audio.toString('base64'),
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
// Use API key if available, otherwise ADC
|
|
161
|
+
let url;
|
|
162
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
163
|
+
if (this.apiKey) {
|
|
164
|
+
url = `https://speech.googleapis.com/v1/speech:recognize?key=${this.apiKey}`;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const token = await this.getAccessToken();
|
|
168
|
+
url = 'https://speech.googleapis.com/v1/speech:recognize';
|
|
169
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
170
|
+
}
|
|
171
|
+
console.log(`[stt:google] Request config: encoding=${encoding}, lang=${langCode}, audioBytes=${audio.length}, magic=${magic}`);
|
|
172
|
+
const res = await fetch(url, {
|
|
173
|
+
method: 'POST',
|
|
174
|
+
headers,
|
|
175
|
+
body: JSON.stringify(body),
|
|
176
|
+
});
|
|
177
|
+
if (!res.ok) {
|
|
178
|
+
const err = await res.text();
|
|
179
|
+
throw new Error(`Google STT error: ${res.status} ${err}`);
|
|
180
|
+
}
|
|
181
|
+
const data = await res.json();
|
|
182
|
+
const results = data.results || [];
|
|
183
|
+
if (!results.length) {
|
|
184
|
+
console.log(`[stt:google] No results returned. Response: ${JSON.stringify(data).slice(0, 500)}`);
|
|
185
|
+
}
|
|
186
|
+
return results
|
|
187
|
+
.map((r) => r.alternatives?.[0]?.transcript || '')
|
|
188
|
+
.join(' ')
|
|
189
|
+
.trim();
|
|
190
|
+
}
|
|
191
|
+
getEncoding(mimetype) {
|
|
192
|
+
if (mimetype.includes('opus') || mimetype.includes('ogg'))
|
|
193
|
+
return 'OGG_OPUS';
|
|
194
|
+
if (mimetype.includes('flac'))
|
|
195
|
+
return 'FLAC';
|
|
196
|
+
if (mimetype.includes('wav'))
|
|
197
|
+
return 'LINEAR16';
|
|
198
|
+
if (mimetype.includes('mp3') || mimetype.includes('mpeg'))
|
|
199
|
+
return 'MP3';
|
|
200
|
+
if (mimetype.includes('webm'))
|
|
201
|
+
return 'WEBM_OPUS';
|
|
202
|
+
return 'OGG_OPUS'; // default for voice messages
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* OpenAI Whisper API
|
|
207
|
+
*/
|
|
208
|
+
class WhisperSTT {
|
|
209
|
+
apiKey;
|
|
210
|
+
constructor() {
|
|
211
|
+
this.apiKey = getApiKey('openai');
|
|
212
|
+
}
|
|
213
|
+
async transcribe(audio, mimetype, language) {
|
|
214
|
+
const ext = this.getExtension(mimetype);
|
|
215
|
+
const formData = new FormData();
|
|
216
|
+
formData.append('file', new Blob([new Uint8Array(audio)], { type: mimetype }), `audio.${ext}`);
|
|
217
|
+
formData.append('model', 'whisper-1');
|
|
218
|
+
if (language) {
|
|
219
|
+
// Whisper expects ISO 639-1 (e.g. 'he', 'en'), not full locale
|
|
220
|
+
formData.append('language', language.split('-')[0]);
|
|
221
|
+
}
|
|
222
|
+
const res = await fetch('https://api.openai.com/v1/audio/transcriptions', {
|
|
223
|
+
method: 'POST',
|
|
224
|
+
headers: { 'Authorization': `Bearer ${this.apiKey}` },
|
|
225
|
+
body: formData,
|
|
226
|
+
});
|
|
227
|
+
if (!res.ok) {
|
|
228
|
+
const err = await res.text();
|
|
229
|
+
throw new Error(`Whisper STT error: ${res.status} ${err}`);
|
|
230
|
+
}
|
|
231
|
+
const data = await res.json();
|
|
232
|
+
return (data.text || '').trim();
|
|
233
|
+
}
|
|
234
|
+
getExtension(mimetype) {
|
|
235
|
+
if (mimetype.includes('ogg') || mimetype.includes('opus'))
|
|
236
|
+
return 'ogg';
|
|
237
|
+
if (mimetype.includes('mp3') || mimetype.includes('mpeg'))
|
|
238
|
+
return 'mp3';
|
|
239
|
+
if (mimetype.includes('wav'))
|
|
240
|
+
return 'wav';
|
|
241
|
+
if (mimetype.includes('webm'))
|
|
242
|
+
return 'webm';
|
|
243
|
+
if (mimetype.includes('flac'))
|
|
244
|
+
return 'flac';
|
|
245
|
+
return 'ogg';
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Deepgram STT API
|
|
250
|
+
*/
|
|
251
|
+
class DeepgramSTT {
|
|
252
|
+
apiKey;
|
|
253
|
+
constructor() {
|
|
254
|
+
this.apiKey = getApiKey('deepgram');
|
|
255
|
+
}
|
|
256
|
+
async transcribe(audio, mimetype, language) {
|
|
257
|
+
const params = new URLSearchParams({
|
|
258
|
+
model: 'nova-2',
|
|
259
|
+
punctuate: 'true',
|
|
260
|
+
});
|
|
261
|
+
if (language) {
|
|
262
|
+
params.set('language', language.split('-')[0]);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
params.set('detect_language', 'true');
|
|
266
|
+
}
|
|
267
|
+
const res = await fetch(`https://api.deepgram.com/v1/listen?${params}`, {
|
|
268
|
+
method: 'POST',
|
|
269
|
+
headers: {
|
|
270
|
+
'Authorization': `Token ${this.apiKey}`,
|
|
271
|
+
'Content-Type': mimetype,
|
|
272
|
+
},
|
|
273
|
+
body: audio,
|
|
274
|
+
});
|
|
275
|
+
if (!res.ok) {
|
|
276
|
+
const err = await res.text();
|
|
277
|
+
throw new Error(`Deepgram STT error: ${res.status} ${err}`);
|
|
278
|
+
}
|
|
279
|
+
const data = await res.json();
|
|
280
|
+
return (data.results?.channels?.[0]?.alternatives?.[0]?.transcript || '').trim();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Create an STT provider instance
|
|
285
|
+
*/
|
|
286
|
+
function createSTTProvider(config) {
|
|
287
|
+
switch (config.provider) {
|
|
288
|
+
case 'google':
|
|
289
|
+
return new GoogleSTT(config);
|
|
290
|
+
case 'whisper':
|
|
291
|
+
return new WhisperSTT();
|
|
292
|
+
case 'deepgram':
|
|
293
|
+
return new DeepgramSTT();
|
|
294
|
+
default:
|
|
295
|
+
throw new Error(`Unknown STT provider: ${config.provider}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=stt.js.map
|