Skip to content

Commit ab87396

Browse files
authored
Merge pull request #148 from Cloud-Code-AI/147-add-tts-support-in-chrome-extension
147 add tts support in chrome extension
2 parents 8736de7 + ebef29b commit ab87396

File tree

3 files changed

+90
-3
lines changed

3 files changed

+90
-3
lines changed

extensions/chrome/src/helpers/executors.tsx

+52-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ const nodeExecutors = {
155155
truncatedPrompt,
156156
{
157157
temperature: node.nodeData?.temperature || 0.7,
158-
max_tokens: node.nodeData?.maxTokens || 2048
158+
max_tokens: node.nodeData?.maxTokens || 2048,
159+
system_prompt: node.nodeData?.systemPrompt
159160
}
160161
);
161162

@@ -215,6 +216,11 @@ const nodeExecutors = {
215216
'transcriptionAgent': async (node: WorkflowStep, input: any, params?: ExecuteWorkflowParams) => {
216217
try {
217218
console.debug("transcription-agent", node, input);
219+
220+
// Throw a specific error for speech transcription in Chrome extension
221+
throw new Error("Speech transcription models are not supported in the Chrome extension. Please use the web app version instead.");
222+
223+
// The code below will not execute due to the error above
218224
const browserAI = new BrowserAI();
219225

220226
await browserAI.loadModel(node.nodeData?.model || 'whisper-tiny-en', {
@@ -246,6 +252,51 @@ const nodeExecutors = {
246252
throw error;
247253
}
248254
},
255+
256+
'ttsAgent': async (node: WorkflowStep, input: any, params?: ExecuteWorkflowParams) => {
257+
try {
258+
console.debug("tts-agent", node, input);
259+
260+
// Throw a specific error for TTS in Chrome extension
261+
throw new Error("Text-to-speech models are not supported in the Chrome extension. Please use the web app version instead.");
262+
263+
// The code below will not execute due to the error above
264+
const browserAI = new BrowserAI();
265+
266+
await browserAI.loadModel(node.nodeData?.model || 'kokoro-tts', {
267+
onProgress: (progress: any) => {
268+
const progressPercent = progress.progress || 0;
269+
const eta = progress.eta || 0;
270+
params?.onModelLoadProgress?.(progressPercent * 100, eta);
271+
}
272+
});
273+
274+
// Extract text input
275+
if (!input) {
276+
throw new Error('No text input provided to TTS agent');
277+
}
278+
279+
// Generate speech
280+
const audioData = await browserAI.textToSpeech(input, {
281+
voice: node.nodeData?.voice || 'af_bella'
282+
});
283+
284+
// Create blob with proper MIME type
285+
const blob = new Blob([audioData], { type: 'audio/wav' });
286+
287+
// Create and store blob URL
288+
const audioUrl = URL.createObjectURL(blob);
289+
290+
return {
291+
success: true,
292+
output: audioUrl,
293+
log: `Text-to-speech generated successfully using ${node.nodeData?.model || 'bark-small'}`
294+
};
295+
} catch (error) {
296+
console.error('TTSAgent error:', error);
297+
throw error;
298+
}
299+
},
249300
};
250301

251302
export const executeWorkflow = async ({

extensions/chrome/src/popup/workflow-view.tsx

+37-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,27 @@ export function WorkflowView({ workflow, onBack }: WorkflowViewProps) {
5959
const [modelLoadProgress, setModelLoadProgress] = useState<number | null>(null);
6060
const [modelLoadEta, setModelLoadEta] = useState<number | null>(null);
6161

62+
// Add this function to check for unsupported nodes
63+
const hasUnsupportedNodes = () => {
64+
return nodes.some(node =>
65+
node.nodeType?.toLowerCase() === 'ttsagent' ||
66+
node.nodeType?.toLowerCase() === 'transcriptionagent'
67+
);
68+
};
69+
70+
// Get the unsupported node warning message
71+
const getUnsupportedWarningMessage = () => {
72+
const unsupportedTypes = nodes
73+
.filter(node =>
74+
node.nodeType?.toLowerCase() === 'ttsagent' ||
75+
node.nodeType?.toLowerCase() === 'transcriptionagent'
76+
)
77+
.map(node => node.nodeType?.toLowerCase() === 'ttsagent' ? 'Text-to-Speech' : 'Speech Transcription');
78+
79+
const uniqueTypes = [...new Set(unsupportedTypes)];
80+
return `${uniqueTypes.join(' and ')} ${uniqueTypes.length > 1 ? 'are' : 'is'} not supported in the Chrome extension. Please use the web app version instead.`;
81+
};
82+
6283
useEffect(() => {
6384
console.log('Workflow data received:', workflow);
6485
console.log('Initial nodes:', nodes);
@@ -71,6 +92,15 @@ export function WorkflowView({ workflow, onBack }: WorkflowViewProps) {
7192
fullNodeData: JSON.stringify(node.nodeData, null, 2)
7293
});
7394
});
95+
96+
// Show toast warning if workflow contains unsupported nodes
97+
if (hasUnsupportedNodes()) {
98+
toast({
99+
variant: "destructive",
100+
title: "Unsupported workflow",
101+
description: getUnsupportedWarningMessage()
102+
});
103+
}
74104
}, []);
75105

76106
// Update areAllInputsFilled function
@@ -273,7 +303,7 @@ export function WorkflowView({ workflow, onBack }: WorkflowViewProps) {
273303
<div className="flex items-center gap-8">
274304
<Button
275305
onClick={handleExecute}
276-
disabled={isExecuting || !areAllInputsFilled()}
306+
disabled={isExecuting || !areAllInputsFilled() || hasUnsupportedNodes()}
277307
className="flex items-center gap-2"
278308
>
279309
<Play className="h-4 w-4" />
@@ -283,6 +313,12 @@ export function WorkflowView({ workflow, onBack }: WorkflowViewProps) {
283313
</div>
284314

285315
<div className="flex-1 overflow-y-auto">
316+
{hasUnsupportedNodes() && (
317+
<div className="p-3 bg-destructive/10 text-destructive text-sm mb-2 mx-4 mt-4 rounded-md">
318+
<strong>Warning:</strong> {getUnsupportedWarningMessage()}
319+
</div>
320+
)}
321+
286322
{modelLoadProgress !== null && (
287323
<div className="p-2 bg-primary/10 text-primary text-sm sticky top-0 z-10">
288324
<div className="flex items-center gap-2">

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@browserai/browserai",
3-
"version": "1.0.29",
3+
"version": "1.0.30",
44
"private": false,
55
"description": "A library for running AI models directly in the browser",
66
"main": "dist/index.js",

0 commit comments

Comments
 (0)