@elizaos/capacitor-talkmode 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/ElizaosCapacitorTalkmode.podspec +18 -0
- package/android/build.gradle +46 -0
- package/android/src/main/AndroidManifest.xml +7 -0
- package/android/src/main/java/ai/eliza/plugins/talkmode/TalkModePlugin.kt +1202 -0
- package/dist/esm/definitions.d.ts +277 -0
- package/dist/esm/definitions.d.ts.map +1 -0
- package/dist/esm/definitions.js +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/web.d.ts +46 -0
- package/dist/esm/web.d.ts.map +1 -0
- package/dist/esm/web.js +201 -0
- package/dist/plugin.cjs.js +214 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +217 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/TalkModePlugin/TalkModePlugin.swift +1121 -0
- package/package.json +83 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@capacitor/core');
|
|
4
|
+
|
|
5
|
+
const loadWeb = () => Promise.resolve().then(function () { return web; }).then((m) => new m.TalkModeWeb());
|
|
6
|
+
const TalkMode = core.registerPlugin("TalkMode", {
|
|
7
|
+
web: loadWeb,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Web implementation of TalkMode plugin
|
|
12
|
+
*
|
|
13
|
+
* Uses Web Speech API for TTS with limited functionality compared to native.
|
|
14
|
+
* ElevenLabs streaming is not supported on web due to CORS limitations.
|
|
15
|
+
*/
|
|
16
|
+
class TalkModeWeb extends core.WebPlugin {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
this.config = {};
|
|
20
|
+
this.state = "idle";
|
|
21
|
+
this.statusText = "Off";
|
|
22
|
+
this.synthesis = null;
|
|
23
|
+
this.currentUtterance = null;
|
|
24
|
+
this.recognition = null;
|
|
25
|
+
this.enabled = false;
|
|
26
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
27
|
+
this.synthesis = window.speechSynthesis;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async start(options) {
|
|
31
|
+
if (options?.config) {
|
|
32
|
+
this.config = { ...this.config, ...options.config };
|
|
33
|
+
}
|
|
34
|
+
// Check for Web Speech API support
|
|
35
|
+
const SpeechRecognitionAPI = window.SpeechRecognition ||
|
|
36
|
+
window.webkitSpeechRecognition;
|
|
37
|
+
if (!SpeechRecognitionAPI) {
|
|
38
|
+
return {
|
|
39
|
+
started: false,
|
|
40
|
+
error: "Speech recognition not supported on this browser",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (!this.synthesis) {
|
|
44
|
+
console.warn("[TalkMode] Speech synthesis not available on web");
|
|
45
|
+
}
|
|
46
|
+
this.enabled = true;
|
|
47
|
+
this.setState("listening", "Listening");
|
|
48
|
+
// Initialize speech recognition
|
|
49
|
+
this.recognition = new SpeechRecognitionAPI();
|
|
50
|
+
this.recognition.continuous = true;
|
|
51
|
+
this.recognition.interimResults = true;
|
|
52
|
+
this.recognition.onresult = (event) => {
|
|
53
|
+
const result = event.results[event.results.length - 1];
|
|
54
|
+
const transcript = result[0].transcript;
|
|
55
|
+
const isFinal = result.isFinal;
|
|
56
|
+
this.notifyListeners("transcript", { transcript, isFinal });
|
|
57
|
+
if (isFinal && transcript.trim()) ;
|
|
58
|
+
};
|
|
59
|
+
this.recognition.onerror = (event) => {
|
|
60
|
+
this.notifyListeners("error", {
|
|
61
|
+
code: event.error,
|
|
62
|
+
message: event.message || event.error,
|
|
63
|
+
recoverable: event.error !== "not-allowed",
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
this.recognition.onend = () => {
|
|
67
|
+
if (this.enabled && this.state === "listening") {
|
|
68
|
+
// Restart recognition if still enabled
|
|
69
|
+
try {
|
|
70
|
+
this.recognition?.start();
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
74
|
+
if (!msg.includes("already started")) {
|
|
75
|
+
console.warn("[TalkMode] Failed to restart recognition:", msg);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
try {
|
|
81
|
+
this.recognition.start();
|
|
82
|
+
return { started: true };
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
const message = error instanceof Error ? error.message : "Failed to start";
|
|
86
|
+
return { started: false, error: message };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async stop() {
|
|
90
|
+
this.enabled = false;
|
|
91
|
+
this.recognition?.stop();
|
|
92
|
+
this.recognition = null;
|
|
93
|
+
this.synthesis?.cancel();
|
|
94
|
+
this.currentUtterance = null;
|
|
95
|
+
this.setState("idle", "Off");
|
|
96
|
+
}
|
|
97
|
+
async isEnabled() {
|
|
98
|
+
return { enabled: this.enabled };
|
|
99
|
+
}
|
|
100
|
+
async getState() {
|
|
101
|
+
return { state: this.state, statusText: this.statusText };
|
|
102
|
+
}
|
|
103
|
+
async updateConfig(options) {
|
|
104
|
+
this.config = { ...this.config, ...options.config };
|
|
105
|
+
}
|
|
106
|
+
async speak(options) {
|
|
107
|
+
if (!this.synthesis) {
|
|
108
|
+
return {
|
|
109
|
+
completed: false,
|
|
110
|
+
interrupted: false,
|
|
111
|
+
usedSystemTts: false,
|
|
112
|
+
error: "Speech synthesis not available",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Web can only use system TTS (no ElevenLabs due to CORS)
|
|
116
|
+
const text = options.text.trim();
|
|
117
|
+
if (!text) {
|
|
118
|
+
return { completed: true, interrupted: false, usedSystemTts: true };
|
|
119
|
+
}
|
|
120
|
+
this.setState("speaking", "Speaking");
|
|
121
|
+
this.notifyListeners("speaking", { text, isSystemTts: true });
|
|
122
|
+
return new Promise((resolve) => {
|
|
123
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
124
|
+
this.currentUtterance = utterance;
|
|
125
|
+
// Always set language — fallback to en-US if directive doesn't specify.
|
|
126
|
+
// Without this, the browser uses the system locale, which may read
|
|
127
|
+
// numbers in the wrong language (e.g., Chinese on a Chinese-locale system).
|
|
128
|
+
utterance.lang = options.directive?.language || "en-US";
|
|
129
|
+
// Apply directive settings if available
|
|
130
|
+
if (options.directive?.speed) {
|
|
131
|
+
utterance.rate = options.directive.speed;
|
|
132
|
+
}
|
|
133
|
+
utterance.onend = () => {
|
|
134
|
+
this.currentUtterance = null;
|
|
135
|
+
this.notifyListeners("speakComplete", { completed: true });
|
|
136
|
+
this.setState("listening", "Listening");
|
|
137
|
+
resolve({ completed: true, interrupted: false, usedSystemTts: true });
|
|
138
|
+
};
|
|
139
|
+
utterance.onerror = (event) => {
|
|
140
|
+
this.currentUtterance = null;
|
|
141
|
+
this.notifyListeners("speakComplete", { completed: false });
|
|
142
|
+
this.setState("idle", "Speech error");
|
|
143
|
+
resolve({
|
|
144
|
+
completed: false,
|
|
145
|
+
interrupted: event.error === "interrupted",
|
|
146
|
+
usedSystemTts: true,
|
|
147
|
+
error: event.error,
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
this.synthesis?.speak(utterance);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async stopSpeaking() {
|
|
154
|
+
if (this.synthesis && this.currentUtterance) {
|
|
155
|
+
this.synthesis.cancel();
|
|
156
|
+
this.currentUtterance = null;
|
|
157
|
+
return { interruptedAt: undefined };
|
|
158
|
+
}
|
|
159
|
+
return {};
|
|
160
|
+
}
|
|
161
|
+
async isSpeaking() {
|
|
162
|
+
return { speaking: this.synthesis?.speaking ?? false };
|
|
163
|
+
}
|
|
164
|
+
async checkPermissions() {
|
|
165
|
+
// Check microphone permission
|
|
166
|
+
let microphone = "prompt";
|
|
167
|
+
try {
|
|
168
|
+
const result = await navigator.permissions.query({
|
|
169
|
+
name: "microphone",
|
|
170
|
+
});
|
|
171
|
+
microphone = result.state;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// Permissions API may not support microphone query
|
|
175
|
+
}
|
|
176
|
+
// Check if speech recognition is supported
|
|
177
|
+
const SpeechRecognitionAPI = window.SpeechRecognition ||
|
|
178
|
+
window.webkitSpeechRecognition;
|
|
179
|
+
const speechRecognition = SpeechRecognitionAPI ? "prompt" : "not_supported";
|
|
180
|
+
return { microphone, speechRecognition };
|
|
181
|
+
}
|
|
182
|
+
async requestPermissions() {
|
|
183
|
+
// Request microphone permission by attempting to get user media
|
|
184
|
+
try {
|
|
185
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
186
|
+
stream.getTracks().forEach((track) => {
|
|
187
|
+
track.stop();
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Permission denied or error
|
|
192
|
+
}
|
|
193
|
+
return this.checkPermissions();
|
|
194
|
+
}
|
|
195
|
+
setState(state, statusText) {
|
|
196
|
+
const previousState = this.state;
|
|
197
|
+
this.state = state;
|
|
198
|
+
this.statusText = statusText;
|
|
199
|
+
this.notifyListeners("stateChange", {
|
|
200
|
+
state,
|
|
201
|
+
previousState,
|
|
202
|
+
statusText,
|
|
203
|
+
usingSystemTts: true,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
209
|
+
__proto__: null,
|
|
210
|
+
TalkModeWeb: TalkModeWeb
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
exports.TalkMode = TalkMode;
|
|
214
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.TalkModeWeb());\nexport const TalkMode = registerPlugin(\"TalkMode\", {\n web: loadWeb,\n});\n","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web implementation of TalkMode plugin\n *\n * Uses Web Speech API for TTS with limited functionality compared to native.\n * ElevenLabs streaming is not supported on web due to CORS limitations.\n */\nexport class TalkModeWeb extends WebPlugin {\n constructor() {\n super();\n this.config = {};\n this.state = \"idle\";\n this.statusText = \"Off\";\n this.synthesis = null;\n this.currentUtterance = null;\n this.recognition = null;\n this.enabled = false;\n if (typeof window !== \"undefined\" && window.speechSynthesis) {\n this.synthesis = window.speechSynthesis;\n }\n }\n async start(options) {\n if (options?.config) {\n this.config = { ...this.config, ...options.config };\n }\n // Check for Web Speech API support\n const SpeechRecognitionAPI = window.SpeechRecognition ||\n window.webkitSpeechRecognition;\n if (!SpeechRecognitionAPI) {\n return {\n started: false,\n error: \"Speech recognition not supported on this browser\",\n };\n }\n if (!this.synthesis) {\n console.warn(\"[TalkMode] Speech synthesis not available on web\");\n }\n this.enabled = true;\n this.setState(\"listening\", \"Listening\");\n // Initialize speech recognition\n this.recognition = new SpeechRecognitionAPI();\n this.recognition.continuous = true;\n this.recognition.interimResults = true;\n this.recognition.onresult = (event) => {\n const result = event.results[event.results.length - 1];\n const transcript = result[0].transcript;\n const isFinal = result.isFinal;\n this.notifyListeners(\"transcript\", { transcript, isFinal });\n if (isFinal && transcript.trim()) {\n // Note: Full talk mode flow would need Gateway plugin integration\n // For web, we just emit the transcript\n }\n };\n this.recognition.onerror = (event) => {\n this.notifyListeners(\"error\", {\n code: event.error,\n message: event.message || event.error,\n recoverable: event.error !== \"not-allowed\",\n });\n };\n this.recognition.onend = () => {\n if (this.enabled && this.state === \"listening\") {\n // Restart recognition if still enabled\n try {\n this.recognition?.start();\n }\n catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes(\"already started\")) {\n console.warn(\"[TalkMode] Failed to restart recognition:\", msg);\n }\n }\n }\n };\n try {\n this.recognition.start();\n return { started: true };\n }\n catch (error) {\n const message = error instanceof Error ? error.message : \"Failed to start\";\n return { started: false, error: message };\n }\n }\n async stop() {\n this.enabled = false;\n this.recognition?.stop();\n this.recognition = null;\n this.synthesis?.cancel();\n this.currentUtterance = null;\n this.setState(\"idle\", \"Off\");\n }\n async isEnabled() {\n return { enabled: this.enabled };\n }\n async getState() {\n return { state: this.state, statusText: this.statusText };\n }\n async updateConfig(options) {\n this.config = { ...this.config, ...options.config };\n }\n async speak(options) {\n if (!this.synthesis) {\n return {\n completed: false,\n interrupted: false,\n usedSystemTts: false,\n error: \"Speech synthesis not available\",\n };\n }\n // Web can only use system TTS (no ElevenLabs due to CORS)\n const text = options.text.trim();\n if (!text) {\n return { completed: true, interrupted: false, usedSystemTts: true };\n }\n this.setState(\"speaking\", \"Speaking\");\n this.notifyListeners(\"speaking\", { text, isSystemTts: true });\n return new Promise((resolve) => {\n const utterance = new SpeechSynthesisUtterance(text);\n this.currentUtterance = utterance;\n // Always set language — fallback to en-US if directive doesn't specify.\n // Without this, the browser uses the system locale, which may read\n // numbers in the wrong language (e.g., Chinese on a Chinese-locale system).\n utterance.lang = options.directive?.language || \"en-US\";\n // Apply directive settings if available\n if (options.directive?.speed) {\n utterance.rate = options.directive.speed;\n }\n utterance.onend = () => {\n this.currentUtterance = null;\n this.notifyListeners(\"speakComplete\", { completed: true });\n this.setState(\"listening\", \"Listening\");\n resolve({ completed: true, interrupted: false, usedSystemTts: true });\n };\n utterance.onerror = (event) => {\n this.currentUtterance = null;\n this.notifyListeners(\"speakComplete\", { completed: false });\n this.setState(\"idle\", \"Speech error\");\n resolve({\n completed: false,\n interrupted: event.error === \"interrupted\",\n usedSystemTts: true,\n error: event.error,\n });\n };\n this.synthesis?.speak(utterance);\n });\n }\n async stopSpeaking() {\n if (this.synthesis && this.currentUtterance) {\n this.synthesis.cancel();\n this.currentUtterance = null;\n return { interruptedAt: undefined };\n }\n return {};\n }\n async isSpeaking() {\n return { speaking: this.synthesis?.speaking ?? false };\n }\n async checkPermissions() {\n // Check microphone permission\n let microphone = \"prompt\";\n try {\n const result = await navigator.permissions.query({\n name: \"microphone\",\n });\n microphone = result.state;\n }\n catch {\n // Permissions API may not support microphone query\n }\n // Check if speech recognition is supported\n const SpeechRecognitionAPI = window.SpeechRecognition ||\n window.webkitSpeechRecognition;\n const speechRecognition = SpeechRecognitionAPI ? \"prompt\" : \"not_supported\";\n return { microphone, speechRecognition };\n }\n async requestPermissions() {\n // Request microphone permission by attempting to get user media\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach((track) => {\n track.stop();\n });\n }\n catch {\n // Permission denied or error\n }\n return this.checkPermissions();\n }\n setState(state, statusText) {\n const previousState = this.state;\n this.state = state;\n this.statusText = statusText;\n this.notifyListeners(\"stateChange\", {\n state,\n previousState,\n statusText,\n usingSystemTts: true,\n });\n }\n}\n"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
var capacitorTalkMode = (function (exports, core) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const loadWeb = () => Promise.resolve().then(function () { return web; }).then((m) => new m.TalkModeWeb());
|
|
5
|
+
const TalkMode = core.registerPlugin("TalkMode", {
|
|
6
|
+
web: loadWeb,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Web implementation of TalkMode plugin
|
|
11
|
+
*
|
|
12
|
+
* Uses Web Speech API for TTS with limited functionality compared to native.
|
|
13
|
+
* ElevenLabs streaming is not supported on web due to CORS limitations.
|
|
14
|
+
*/
|
|
15
|
+
class TalkModeWeb extends core.WebPlugin {
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
this.config = {};
|
|
19
|
+
this.state = "idle";
|
|
20
|
+
this.statusText = "Off";
|
|
21
|
+
this.synthesis = null;
|
|
22
|
+
this.currentUtterance = null;
|
|
23
|
+
this.recognition = null;
|
|
24
|
+
this.enabled = false;
|
|
25
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
26
|
+
this.synthesis = window.speechSynthesis;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async start(options) {
|
|
30
|
+
if (options?.config) {
|
|
31
|
+
this.config = { ...this.config, ...options.config };
|
|
32
|
+
}
|
|
33
|
+
// Check for Web Speech API support
|
|
34
|
+
const SpeechRecognitionAPI = window.SpeechRecognition ||
|
|
35
|
+
window.webkitSpeechRecognition;
|
|
36
|
+
if (!SpeechRecognitionAPI) {
|
|
37
|
+
return {
|
|
38
|
+
started: false,
|
|
39
|
+
error: "Speech recognition not supported on this browser",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (!this.synthesis) {
|
|
43
|
+
console.warn("[TalkMode] Speech synthesis not available on web");
|
|
44
|
+
}
|
|
45
|
+
this.enabled = true;
|
|
46
|
+
this.setState("listening", "Listening");
|
|
47
|
+
// Initialize speech recognition
|
|
48
|
+
this.recognition = new SpeechRecognitionAPI();
|
|
49
|
+
this.recognition.continuous = true;
|
|
50
|
+
this.recognition.interimResults = true;
|
|
51
|
+
this.recognition.onresult = (event) => {
|
|
52
|
+
const result = event.results[event.results.length - 1];
|
|
53
|
+
const transcript = result[0].transcript;
|
|
54
|
+
const isFinal = result.isFinal;
|
|
55
|
+
this.notifyListeners("transcript", { transcript, isFinal });
|
|
56
|
+
if (isFinal && transcript.trim()) ;
|
|
57
|
+
};
|
|
58
|
+
this.recognition.onerror = (event) => {
|
|
59
|
+
this.notifyListeners("error", {
|
|
60
|
+
code: event.error,
|
|
61
|
+
message: event.message || event.error,
|
|
62
|
+
recoverable: event.error !== "not-allowed",
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
this.recognition.onend = () => {
|
|
66
|
+
if (this.enabled && this.state === "listening") {
|
|
67
|
+
// Restart recognition if still enabled
|
|
68
|
+
try {
|
|
69
|
+
this.recognition?.start();
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
73
|
+
if (!msg.includes("already started")) {
|
|
74
|
+
console.warn("[TalkMode] Failed to restart recognition:", msg);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
try {
|
|
80
|
+
this.recognition.start();
|
|
81
|
+
return { started: true };
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const message = error instanceof Error ? error.message : "Failed to start";
|
|
85
|
+
return { started: false, error: message };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async stop() {
|
|
89
|
+
this.enabled = false;
|
|
90
|
+
this.recognition?.stop();
|
|
91
|
+
this.recognition = null;
|
|
92
|
+
this.synthesis?.cancel();
|
|
93
|
+
this.currentUtterance = null;
|
|
94
|
+
this.setState("idle", "Off");
|
|
95
|
+
}
|
|
96
|
+
async isEnabled() {
|
|
97
|
+
return { enabled: this.enabled };
|
|
98
|
+
}
|
|
99
|
+
async getState() {
|
|
100
|
+
return { state: this.state, statusText: this.statusText };
|
|
101
|
+
}
|
|
102
|
+
async updateConfig(options) {
|
|
103
|
+
this.config = { ...this.config, ...options.config };
|
|
104
|
+
}
|
|
105
|
+
async speak(options) {
|
|
106
|
+
if (!this.synthesis) {
|
|
107
|
+
return {
|
|
108
|
+
completed: false,
|
|
109
|
+
interrupted: false,
|
|
110
|
+
usedSystemTts: false,
|
|
111
|
+
error: "Speech synthesis not available",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// Web can only use system TTS (no ElevenLabs due to CORS)
|
|
115
|
+
const text = options.text.trim();
|
|
116
|
+
if (!text) {
|
|
117
|
+
return { completed: true, interrupted: false, usedSystemTts: true };
|
|
118
|
+
}
|
|
119
|
+
this.setState("speaking", "Speaking");
|
|
120
|
+
this.notifyListeners("speaking", { text, isSystemTts: true });
|
|
121
|
+
return new Promise((resolve) => {
|
|
122
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
123
|
+
this.currentUtterance = utterance;
|
|
124
|
+
// Always set language — fallback to en-US if directive doesn't specify.
|
|
125
|
+
// Without this, the browser uses the system locale, which may read
|
|
126
|
+
// numbers in the wrong language (e.g., Chinese on a Chinese-locale system).
|
|
127
|
+
utterance.lang = options.directive?.language || "en-US";
|
|
128
|
+
// Apply directive settings if available
|
|
129
|
+
if (options.directive?.speed) {
|
|
130
|
+
utterance.rate = options.directive.speed;
|
|
131
|
+
}
|
|
132
|
+
utterance.onend = () => {
|
|
133
|
+
this.currentUtterance = null;
|
|
134
|
+
this.notifyListeners("speakComplete", { completed: true });
|
|
135
|
+
this.setState("listening", "Listening");
|
|
136
|
+
resolve({ completed: true, interrupted: false, usedSystemTts: true });
|
|
137
|
+
};
|
|
138
|
+
utterance.onerror = (event) => {
|
|
139
|
+
this.currentUtterance = null;
|
|
140
|
+
this.notifyListeners("speakComplete", { completed: false });
|
|
141
|
+
this.setState("idle", "Speech error");
|
|
142
|
+
resolve({
|
|
143
|
+
completed: false,
|
|
144
|
+
interrupted: event.error === "interrupted",
|
|
145
|
+
usedSystemTts: true,
|
|
146
|
+
error: event.error,
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
this.synthesis?.speak(utterance);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async stopSpeaking() {
|
|
153
|
+
if (this.synthesis && this.currentUtterance) {
|
|
154
|
+
this.synthesis.cancel();
|
|
155
|
+
this.currentUtterance = null;
|
|
156
|
+
return { interruptedAt: undefined };
|
|
157
|
+
}
|
|
158
|
+
return {};
|
|
159
|
+
}
|
|
160
|
+
async isSpeaking() {
|
|
161
|
+
return { speaking: this.synthesis?.speaking ?? false };
|
|
162
|
+
}
|
|
163
|
+
async checkPermissions() {
|
|
164
|
+
// Check microphone permission
|
|
165
|
+
let microphone = "prompt";
|
|
166
|
+
try {
|
|
167
|
+
const result = await navigator.permissions.query({
|
|
168
|
+
name: "microphone",
|
|
169
|
+
});
|
|
170
|
+
microphone = result.state;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Permissions API may not support microphone query
|
|
174
|
+
}
|
|
175
|
+
// Check if speech recognition is supported
|
|
176
|
+
const SpeechRecognitionAPI = window.SpeechRecognition ||
|
|
177
|
+
window.webkitSpeechRecognition;
|
|
178
|
+
const speechRecognition = SpeechRecognitionAPI ? "prompt" : "not_supported";
|
|
179
|
+
return { microphone, speechRecognition };
|
|
180
|
+
}
|
|
181
|
+
async requestPermissions() {
|
|
182
|
+
// Request microphone permission by attempting to get user media
|
|
183
|
+
try {
|
|
184
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
185
|
+
stream.getTracks().forEach((track) => {
|
|
186
|
+
track.stop();
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Permission denied or error
|
|
191
|
+
}
|
|
192
|
+
return this.checkPermissions();
|
|
193
|
+
}
|
|
194
|
+
setState(state, statusText) {
|
|
195
|
+
const previousState = this.state;
|
|
196
|
+
this.state = state;
|
|
197
|
+
this.statusText = statusText;
|
|
198
|
+
this.notifyListeners("stateChange", {
|
|
199
|
+
state,
|
|
200
|
+
previousState,
|
|
201
|
+
statusText,
|
|
202
|
+
usingSystemTts: true,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
208
|
+
__proto__: null,
|
|
209
|
+
TalkModeWeb: TalkModeWeb
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
exports.TalkMode = TalkMode;
|
|
213
|
+
|
|
214
|
+
return exports;
|
|
215
|
+
|
|
216
|
+
})({}, capacitorExports);
|
|
217
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.TalkModeWeb());\nexport const TalkMode = registerPlugin(\"TalkMode\", {\n web: loadWeb,\n});\n","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web implementation of TalkMode plugin\n *\n * Uses Web Speech API for TTS with limited functionality compared to native.\n * ElevenLabs streaming is not supported on web due to CORS limitations.\n */\nexport class TalkModeWeb extends WebPlugin {\n constructor() {\n super();\n this.config = {};\n this.state = \"idle\";\n this.statusText = \"Off\";\n this.synthesis = null;\n this.currentUtterance = null;\n this.recognition = null;\n this.enabled = false;\n if (typeof window !== \"undefined\" && window.speechSynthesis) {\n this.synthesis = window.speechSynthesis;\n }\n }\n async start(options) {\n if (options?.config) {\n this.config = { ...this.config, ...options.config };\n }\n // Check for Web Speech API support\n const SpeechRecognitionAPI = window.SpeechRecognition ||\n window.webkitSpeechRecognition;\n if (!SpeechRecognitionAPI) {\n return {\n started: false,\n error: \"Speech recognition not supported on this browser\",\n };\n }\n if (!this.synthesis) {\n console.warn(\"[TalkMode] Speech synthesis not available on web\");\n }\n this.enabled = true;\n this.setState(\"listening\", \"Listening\");\n // Initialize speech recognition\n this.recognition = new SpeechRecognitionAPI();\n this.recognition.continuous = true;\n this.recognition.interimResults = true;\n this.recognition.onresult = (event) => {\n const result = event.results[event.results.length - 1];\n const transcript = result[0].transcript;\n const isFinal = result.isFinal;\n this.notifyListeners(\"transcript\", { transcript, isFinal });\n if (isFinal && transcript.trim()) {\n // Note: Full talk mode flow would need Gateway plugin integration\n // For web, we just emit the transcript\n }\n };\n this.recognition.onerror = (event) => {\n this.notifyListeners(\"error\", {\n code: event.error,\n message: event.message || event.error,\n recoverable: event.error !== \"not-allowed\",\n });\n };\n this.recognition.onend = () => {\n if (this.enabled && this.state === \"listening\") {\n // Restart recognition if still enabled\n try {\n this.recognition?.start();\n }\n catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes(\"already started\")) {\n console.warn(\"[TalkMode] Failed to restart recognition:\", msg);\n }\n }\n }\n };\n try {\n this.recognition.start();\n return { started: true };\n }\n catch (error) {\n const message = error instanceof Error ? error.message : \"Failed to start\";\n return { started: false, error: message };\n }\n }\n async stop() {\n this.enabled = false;\n this.recognition?.stop();\n this.recognition = null;\n this.synthesis?.cancel();\n this.currentUtterance = null;\n this.setState(\"idle\", \"Off\");\n }\n async isEnabled() {\n return { enabled: this.enabled };\n }\n async getState() {\n return { state: this.state, statusText: this.statusText };\n }\n async updateConfig(options) {\n this.config = { ...this.config, ...options.config };\n }\n async speak(options) {\n if (!this.synthesis) {\n return {\n completed: false,\n interrupted: false,\n usedSystemTts: false,\n error: \"Speech synthesis not available\",\n };\n }\n // Web can only use system TTS (no ElevenLabs due to CORS)\n const text = options.text.trim();\n if (!text) {\n return { completed: true, interrupted: false, usedSystemTts: true };\n }\n this.setState(\"speaking\", \"Speaking\");\n this.notifyListeners(\"speaking\", { text, isSystemTts: true });\n return new Promise((resolve) => {\n const utterance = new SpeechSynthesisUtterance(text);\n this.currentUtterance = utterance;\n // Always set language — fallback to en-US if directive doesn't specify.\n // Without this, the browser uses the system locale, which may read\n // numbers in the wrong language (e.g., Chinese on a Chinese-locale system).\n utterance.lang = options.directive?.language || \"en-US\";\n // Apply directive settings if available\n if (options.directive?.speed) {\n utterance.rate = options.directive.speed;\n }\n utterance.onend = () => {\n this.currentUtterance = null;\n this.notifyListeners(\"speakComplete\", { completed: true });\n this.setState(\"listening\", \"Listening\");\n resolve({ completed: true, interrupted: false, usedSystemTts: true });\n };\n utterance.onerror = (event) => {\n this.currentUtterance = null;\n this.notifyListeners(\"speakComplete\", { completed: false });\n this.setState(\"idle\", \"Speech error\");\n resolve({\n completed: false,\n interrupted: event.error === \"interrupted\",\n usedSystemTts: true,\n error: event.error,\n });\n };\n this.synthesis?.speak(utterance);\n });\n }\n async stopSpeaking() {\n if (this.synthesis && this.currentUtterance) {\n this.synthesis.cancel();\n this.currentUtterance = null;\n return { interruptedAt: undefined };\n }\n return {};\n }\n async isSpeaking() {\n return { speaking: this.synthesis?.speaking ?? false };\n }\n async checkPermissions() {\n // Check microphone permission\n let microphone = \"prompt\";\n try {\n const result = await navigator.permissions.query({\n name: \"microphone\",\n });\n microphone = result.state;\n }\n catch {\n // Permissions API may not support microphone query\n }\n // Check if speech recognition is supported\n const SpeechRecognitionAPI = window.SpeechRecognition ||\n window.webkitSpeechRecognition;\n const speechRecognition = SpeechRecognitionAPI ? \"prompt\" : \"not_supported\";\n return { microphone, speechRecognition };\n }\n async requestPermissions() {\n // Request microphone permission by attempting to get user media\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach((track) => {\n track.stop();\n });\n }\n catch {\n // Permission denied or error\n }\n return this.checkPermissions();\n }\n setState(state, statusText) {\n const previousState = this.state;\n this.state = state;\n this.statusText = statusText;\n this.notifyListeners(\"stateChange\", {\n state,\n previousState,\n statusText,\n usingSystemTts: true,\n });\n }\n}\n"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
|