refactor: rename swift → cortex in code and documentation
Complete rename of "swift" terminology to "cortex" across the codebase: Code Changes: - Rename directories: lib/swift → lib/cortex, components/swift → components/cortex - Rename API routes: /api/swift/* → /api/cortex/* - Rename page routes: /epd/swift → /epd/cortex - Rename store: swift-store.ts → cortex-store.ts Type Renames: - SwiftIntent → CortexIntent - SwiftStore → CortexStore - useSwiftStore → useCortexStore - SwiftContext → CortexContext - useSwiftVoice → useCortexVoice Documentation Updates (docs/intent/): - Safety Net → Nudge (Layer 3 rename) - SafetySuggestion → NudgeSuggestion - evaluateSafetyNet → evaluateNudge - SWIFT_* feature flags → CORTEX_* - All path references updated to match new structure Files affected: 47 files, ~700 lines changed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
115
lib/cortex/use-cortex-voice.ts
Normal file
115
lib/cortex/use-cortex-voice.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Cortex Voice Hook
|
||||
*
|
||||
* Wraps useDeepgramStreaming for Cortex-specific voice input behavior.
|
||||
* Streams transcript directly to the command input.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useCortexStore } from '@/stores/cortex-store';
|
||||
import {
|
||||
useDeepgramStreaming,
|
||||
type TranscriptResult,
|
||||
} from '@/hooks/use-deepgram-streaming';
|
||||
|
||||
export interface UseCortexVoiceReturn {
|
||||
isRecording: boolean;
|
||||
isConnecting: boolean;
|
||||
isConnected: boolean;
|
||||
error: string | null;
|
||||
startRecording: () => Promise<void>;
|
||||
stopRecording: () => void;
|
||||
analyserNode: AnalyserNode | null;
|
||||
isBrowserSupported: boolean;
|
||||
}
|
||||
|
||||
export function useCortexVoice(): UseCortexVoiceReturn {
|
||||
const { setInputValue, setVoiceActive, inputValue } = useCortexStore();
|
||||
|
||||
// Track the base text (what was in input before recording started)
|
||||
const baseTextRef = useRef('');
|
||||
// Track interim transcript for replacement
|
||||
const lastInterimRef = useRef('');
|
||||
|
||||
const handleTranscript = useCallback(
|
||||
(result: TranscriptResult) => {
|
||||
const { transcript, isFinal } = result;
|
||||
|
||||
if (isFinal) {
|
||||
// Final transcript: append to base text and update base
|
||||
const newText = baseTextRef.current
|
||||
? `${baseTextRef.current} ${transcript}`
|
||||
: transcript;
|
||||
baseTextRef.current = newText;
|
||||
lastInterimRef.current = '';
|
||||
setInputValue(newText);
|
||||
} else {
|
||||
// Interim transcript: show as preview (replace previous interim)
|
||||
const previewText = baseTextRef.current
|
||||
? `${baseTextRef.current} ${transcript}`
|
||||
: transcript;
|
||||
setInputValue(previewText);
|
||||
lastInterimRef.current = transcript;
|
||||
}
|
||||
},
|
||||
[setInputValue]
|
||||
);
|
||||
|
||||
const handleError = useCallback(
|
||||
(error: Error) => {
|
||||
console.error('[CortexVoice] Error:', error.message);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const {
|
||||
status,
|
||||
isRecording,
|
||||
startRecording: startDeepgram,
|
||||
stopRecording: stopDeepgram,
|
||||
analyserNode,
|
||||
error,
|
||||
isBrowserSupported,
|
||||
} = useDeepgramStreaming({
|
||||
onTranscript: handleTranscript,
|
||||
onError: handleError,
|
||||
language: 'nl',
|
||||
model: 'nova-2',
|
||||
endpointingMs: 2000, // Shorter for command-style input
|
||||
});
|
||||
|
||||
const startRecording = useCallback(async () => {
|
||||
// Store current input as base text
|
||||
baseTextRef.current = inputValue;
|
||||
lastInterimRef.current = '';
|
||||
setVoiceActive(true);
|
||||
await startDeepgram();
|
||||
}, [inputValue, setVoiceActive, startDeepgram]);
|
||||
|
||||
const stopRecording = useCallback(() => {
|
||||
stopDeepgram();
|
||||
setVoiceActive(false);
|
||||
// Keep whatever text is in the input
|
||||
lastInterimRef.current = '';
|
||||
}, [stopDeepgram, setVoiceActive]);
|
||||
|
||||
// Sync voice active state with recording state
|
||||
useEffect(() => {
|
||||
if (!isRecording) {
|
||||
setVoiceActive(false);
|
||||
}
|
||||
}, [isRecording, setVoiceActive]);
|
||||
|
||||
return {
|
||||
isRecording,
|
||||
isConnecting: status === 'connecting' || status === 'reconnecting',
|
||||
isConnected: status === 'connected',
|
||||
error,
|
||||
startRecording,
|
||||
stopRecording,
|
||||
analyserNode,
|
||||
isBrowserSupported,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user