Skip to content

Commit af5207e

Browse files
committed
cleanup
1 parent fd81206 commit af5207e

File tree

3 files changed

+175
-113
lines changed

3 files changed

+175
-113
lines changed

next/components/assembly-context.tsx

+27-24
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@ export const AssemblyContextProvider = ({
3838

3939
const sendAudio = (data: Blob) => {
4040
if (!transcriber) {
41-
console.warn("[AssemblyAI] No transcriber available");
41+
console.warn("[AssemblyContext] No transcriber available");
4242
return;
4343
}
4444
if (connectionState !== AssemblyConnectionState.OPEN) {
45-
console.warn("[AssemblyAI] Connection not open, state:", connectionState);
45+
console.warn(
46+
"[AssemblyContext] Connection not open, state:",
47+
connectionState
48+
);
4649
return;
4750
}
4851

@@ -51,47 +54,47 @@ export const AssemblyContextProvider = ({
5154
data
5255
.arrayBuffer()
5356
.then((buffer) => {
54-
console.log(
55-
"[AssemblyAI] Sending audio chunk, size:",
56-
buffer.byteLength,
57-
"bytes"
58-
);
57+
// console.log(
58+
// "[AssemblyContext] Sending audio chunk, size:",
59+
// buffer.byteLength,
60+
// "bytes"
61+
// );
5962
transcriber.sendAudio(buffer);
6063
})
6164
.catch((error) => {
62-
console.error("[AssemblyAI] Buffer conversion error:", error);
65+
console.error("[AssemblyContext] Buffer conversion error:", error);
6366
});
6467
} catch (error) {
65-
console.error("[AssemblyAI] Send error:", error);
68+
console.error("[AssemblyContext] Send error:", error);
6669
setConnectionState(AssemblyConnectionState.ERROR);
6770
}
6871
};
6972

7073
const connectToAssembly = async () => {
7174
if (transcriber) {
72-
console.log("[AssemblyAI] Already have a transcriber instance");
75+
console.log("[AssemblyContext] Already have a transcriber instance");
7376
return;
7477
}
7578

7679
if (connectionState === AssemblyConnectionState.CONNECTING) {
77-
console.log("[AssemblyAI] Connection already in progress");
80+
console.log("[AssemblyContext] Connection already in progress");
7881
return;
7982
}
8083

8184
let connectionTimeout: ReturnType<typeof setTimeout>;
8285

8386
try {
8487
setConnectionState(AssemblyConnectionState.CONNECTING);
85-
console.log("[AssemblyAI] Getting token...");
88+
console.log("[AssemblyContext] Getting token...");
8689
const token = await getAssemblyToken();
8790

8891
if (!token) {
89-
console.error("[AssemblyAI] Failed to get token");
92+
console.error("[AssemblyContext] Failed to get token");
9093
setConnectionState(AssemblyConnectionState.ERROR);
9194
return;
9295
}
9396

94-
console.log("[AssemblyAI] Creating transcriber...");
97+
console.log("[AssemblyContext] Creating transcriber...");
9598
const transcriberInstance = new RealtimeTranscriber({
9699
sampleRate: 16000,
97100
token,
@@ -106,61 +109,61 @@ export const AssemblyContextProvider = ({
106109

107110
// Set up event handlers before connecting
108111
transcriberInstance.on("open", () => {
109-
console.log("[AssemblyAI] Connection opened, transcriber ready");
112+
console.log("[AssemblyContext] Connection opened, transcriber ready");
110113
clearTimeout(connectionTimeout);
111114
setConnectionState(AssemblyConnectionState.OPEN);
112115
setTranscriber(transcriberInstance);
113116
});
114117

115118
transcriberInstance.on("close", () => {
116-
console.log("[AssemblyAI] Connection closed");
119+
console.log("[AssemblyContext] Connection closed");
117120
clearTimeout(connectionTimeout);
118121
setConnectionState(AssemblyConnectionState.CLOSED);
119122
setTranscriber(null);
120123
});
121124

122125
transcriberInstance.on("error", (error) => {
123-
console.error("[AssemblyAI] Connection error:", error);
126+
console.error("[AssemblyContext] Connection error:", error);
124127
clearTimeout(connectionTimeout);
125128
setConnectionState(AssemblyConnectionState.ERROR);
126129
setTranscriber(null);
127130
});
128131

129132
// Debug transcript events
130133
transcriberInstance.on("transcript", (transcript) => {
131-
console.log("[AssemblyAI] Got transcript:", transcript);
134+
if (!transcript.text || transcript.confidence === 0) return;
132135
});
133136

134137
transcriberInstance.on("transcript.partial", (transcript) => {
135-
console.log("[AssemblyAI] Got partial transcript:", transcript);
138+
if (!transcript.text || transcript.confidence === 0) return;
136139
});
137140

138141
transcriberInstance.on("transcript.final", (transcript) => {
139-
console.log("[AssemblyAI] Got final transcript:", transcript);
142+
if (!transcript.text || transcript.confidence === 0) return;
140143
});
141144

142145
// Set up a connection timeout
143146
connectionTimeout = setTimeout(() => {
144147
if (connectionState !== AssemblyConnectionState.OPEN) {
145-
console.error("[AssemblyAI] Connection timeout");
148+
console.error("[AssemblyContext] Connection timeout");
146149
transcriberInstance.close();
147150
setConnectionState(AssemblyConnectionState.ERROR);
148151
setTranscriber(null);
149152
}
150153
}, 10000);
151154

152-
console.log("[AssemblyAI] Attempting connection...");
155+
console.log("[AssemblyContext] Attempting connection...");
153156
await transcriberInstance.connect();
154157
} catch (error) {
155-
console.error("[AssemblyAI] Setup error:", error);
158+
console.error("[AssemblyContext] Setup error:", error);
156159
setConnectionState(AssemblyConnectionState.ERROR);
157160
setTranscriber(null);
158161
}
159162
};
160163

161164
const disconnectFromAssembly = () => {
162165
if (transcriber) {
163-
console.log("[AssemblyAI] Disconnecting...");
166+
console.log("[AssemblyContext] Disconnecting...");
164167
transcriber.close();
165168
setTranscriber(null);
166169
setConnectionState(AssemblyConnectionState.CLOSED);

next/components/assembly-view.tsx

+91-31
Original file line numberDiff line numberDiff line change
@@ -66,42 +66,99 @@ const AssemblyView: () => JSX.Element = () => {
6666
latencyHint: "interactive",
6767
});
6868

69-
// Create a MediaStreamSource from the microphone stream
70-
const source = audioContext.createMediaStreamSource(microphone.stream);
69+
const setupAudioProcessor = async () => {
70+
const source = audioContext.createMediaStreamSource(microphone.stream);
71+
let processor: AudioWorkletNode | ScriptProcessorNode;
7172

72-
// Create a ScriptProcessor to get raw PCM data
73-
// @ts-ignore - ScriptProcessor is deprecated but still works
74-
const processor = audioContext.createScriptProcessor(2048, 1, 1);
75-
76-
processor.onaudioprocess = (e) => {
77-
if (isPaused || !isConnected) return;
73+
try {
74+
// Try AudioWorklet first (modern browsers)
75+
if ("audioWorklet" in audioContext) {
76+
// Define processor code as a string
77+
const processorCode = `
78+
class PCMProcessor extends AudioWorkletProcessor {
79+
process(inputs, outputs) {
80+
const input = inputs[0];
81+
const inputChannel = input[0];
82+
83+
// Convert to 16-bit PCM
84+
const pcmData = new Int16Array(inputChannel.length);
85+
for (let i = 0; i < inputChannel.length; i++) {
86+
pcmData[i] = Math.min(1, Math.max(-1, inputChannel[i])) * 0x7FFF;
87+
}
88+
89+
// Post the PCM data back to the main thread
90+
this.port.postMessage(pcmData.buffer, [pcmData.buffer]);
91+
92+
return true;
93+
}
94+
}
95+
registerProcessor('pcm-processor', PCMProcessor);
96+
`;
97+
98+
// Create a blob URL for the processor code
99+
const blob = new Blob([processorCode], {
100+
type: "application/javascript",
101+
});
102+
const url = URL.createObjectURL(blob);
103+
104+
await audioContext.audioWorklet.addModule(url);
105+
URL.revokeObjectURL(url);
106+
107+
const workletNode = new AudioWorkletNode(
108+
audioContext,
109+
"pcm-processor"
110+
);
111+
workletNode.port.onmessage = (e: MessageEvent<ArrayBuffer>) => {
112+
if (isPaused || !isConnected) return;
113+
const blob = new Blob([e.data], { type: "audio/wav" });
114+
sendAudio(blob);
115+
};
116+
processor = workletNode;
117+
} else {
118+
// Fallback to ScriptProcessor (older browsers)
119+
console.log("[AssemblyAI] Using ScriptProcessor fallback");
120+
// @ts-ignore - ScriptProcessor is deprecated but needed for fallback
121+
const scriptNode = audioContext.createScriptProcessor(2048, 1, 1);
122+
scriptNode.onaudioprocess = (e: AudioProcessingEvent) => {
123+
if (isPaused || !isConnected) return;
124+
const inputData = e.inputBuffer.getChannelData(0);
125+
const pcmData = new Int16Array(inputData.length);
126+
for (let i = 0; i < inputData.length; i++) {
127+
pcmData[i] = Math.min(1, Math.max(-1, inputData[i])) * 0x7fff;
128+
}
129+
const blob = new Blob([pcmData], { type: "audio/wav" });
130+
sendAudio(blob);
131+
};
132+
processor = scriptNode;
133+
}
78134

79-
// Get raw PCM data
80-
const inputData = e.inputBuffer.getChannelData(0);
135+
// Connect the audio nodes
136+
source.connect(processor);
137+
if (!("audioWorklet" in audioContext)) {
138+
(processor as ScriptProcessorNode).connect(
139+
(audioContext as AudioContext).destination
140+
);
141+
}
81142

82-
// Convert to 16-bit PCM
83-
const pcmData = new Int16Array(inputData.length);
84-
for (let i = 0; i < inputData.length; i++) {
85-
pcmData[i] = Math.min(1, Math.max(-1, inputData[i])) * 0x7fff;
143+
// Store for cleanup
144+
mainRecorder.current = {
145+
stop: () => {
146+
processor.disconnect();
147+
source.disconnect();
148+
audioContext.close();
149+
},
150+
} as any;
151+
} catch (error) {
152+
console.error("[AssemblyAI] Audio processor setup failed:", error);
153+
// Fallback to ScriptProcessor if AudioWorklet fails
154+
if ("audioWorklet" in audioContext) {
155+
console.log("[AssemblyAI] Falling back to ScriptProcessor");
156+
setupAudioProcessor();
157+
}
86158
}
87-
88-
// Send as blob
89-
const blob = new Blob([pcmData], { type: "audio/wav" });
90-
sendAudio(blob);
91159
};
92160

93-
// Connect the audio nodes
94-
source.connect(processor);
95-
processor.connect(audioContext.destination);
96-
97-
// Store for cleanup
98-
mainRecorder.current = {
99-
stop: () => {
100-
processor.disconnect();
101-
source.disconnect();
102-
audioContext.close();
103-
},
104-
} as any;
161+
setupAudioProcessor();
105162

106163
return () => {
107164
if (mainRecorder.current) {
@@ -136,7 +193,7 @@ const AssemblyView: () => JSX.Element = () => {
136193
const transcriptHandler = (transcript: any) => {
137194
if (!transcript.text) return;
138195

139-
console.log("[AssemblyAI] transcript:", {
196+
console.log("[AssemblyView] transcript:", {
140197
type: transcript.message_type,
141198
text: transcript.text,
142199
confidence: transcript.confidence,
@@ -145,6 +202,9 @@ const AssemblyView: () => JSX.Element = () => {
145202
const isFinal = transcript.message_type === "FinalTranscript";
146203
const isPartial = transcript.message_type === "PartialTranscript";
147204

205+
// Filter out empty or low confidence transcripts
206+
if (!transcript.text || transcript.confidence === 0) return;
207+
148208
// Only handle final or partial transcripts
149209
if (!isFinal && !isPartial) return;
150210

0 commit comments

Comments
 (0)