Skip to content

Commit 7109d30

Browse files
authored
Merge pull request #114 from AGiXT/copilot/add-recording-feature-glasses
Toggle conversation recording via glasses right-side button with AGiXT summarization
2 parents 846fd7f + ff6a956 commit 7109d30

File tree

1 file changed

+89
-11
lines changed

1 file changed

+89
-11
lines changed

lib/services/ai_service.dart

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class AIService {
3636
Timer? _micTimer;
3737
bool _isBackgroundMode = false;
3838
bool _methodChannelInitialized = false;
39+
bool _isConversationRecording = false;
3940

4041
// WebSocket streaming state
4142
StreamSubscription<WebSocketMessage>? _messageSubscription;
@@ -163,11 +164,19 @@ class AIService {
163164
if ((state.status == VoiceInputStatus.complete ||
164165
state.status == VoiceInputStatus.stopped) &&
165166
state.audioData != null) {
166-
// Process the recorded audio
167-
_processRecordedAudio(state.audioData!, state.source);
167+
if (_isConversationRecording) {
168+
_isConversationRecording = false;
169+
_processConversationRecording(state.audioData!, state.source);
170+
} else {
171+
// Process the recorded audio
172+
_processRecordedAudio(state.audioData!, state.source);
173+
}
168174
} else if (state.status == VoiceInputStatus.stopped &&
169175
state.audioData == null) {
170176
// Recording stopped but no audio captured
177+
if (_isConversationRecording) {
178+
_isConversationRecording = false;
179+
}
171180
debugPrint('AIService: Recording stopped with no audio data');
172181
_isProcessing = false;
173182
_showErrorMessage('No audio captured');
@@ -516,6 +525,60 @@ class AIService {
516525
}
517526
}
518527

528+
/// Process a conversation recording: transcribe and send with summary prompt
529+
Future<void> _processConversationRecording(
530+
Uint8List audioData,
531+
VoiceInputSource? source,
532+
) async {
533+
debugPrint(
534+
'AIService: Processing conversation recording (${audioData.length} bytes from $source)');
535+
try {
536+
await _showProcessingMessage();
537+
538+
// Transcribe the audio
539+
debugPrint('AIService: Transcribing conversation audio...');
540+
String? transcription;
541+
if (_whisperService != null) {
542+
transcription = await _whisperService!.transcribe(audioData);
543+
} else {
544+
debugPrint('AIService: WhisperService is null, initializing...');
545+
await _initWhisperService();
546+
if (_whisperService != null) {
547+
transcription = await _whisperService!.transcribe(audioData);
548+
}
549+
}
550+
551+
if (transcription == null || transcription.isEmpty) {
552+
debugPrint('AIService: Conversation transcription failed or empty');
553+
await _showErrorMessage('Could not transcribe conversation');
554+
return;
555+
}
556+
557+
debugPrint('AIService: Conversation transcription: $transcription');
558+
559+
// Wrap transcription in a conversation summary prompt
560+
final prompt = 'The following is a transcription of a recorded '
561+
'conversation. Please:\n'
562+
'1. Summarize the conversation\n'
563+
'2. Extract potentially important notes and highlights\n'
564+
'3. Identify specific goals if mentioned\n'
565+
'4. List any action items\n\n'
566+
'Transcription:\n$transcription';
567+
568+
// Send to AGiXT
569+
await _sendMessageToAGiXT(prompt);
570+
} catch (e) {
571+
debugPrint('AIService: Error processing conversation recording: $e');
572+
await _showErrorMessage('Error processing conversation');
573+
await _audioPlayerService.stopStreaming();
574+
} finally {
575+
_isProcessing = false;
576+
if (_wakeWordService.isEnabled) {
577+
await _wakeWordService.resume();
578+
}
579+
}
580+
}
581+
519582
/// Output response to the appropriate device(s)
520583
Future<void> _outputResponse(String response) async {
521584
// Always display on glasses if connected
@@ -646,38 +709,50 @@ class AIService {
646709
_whisperService = await WhisperService.service();
647710
}
648711

649-
// Handle side button press to activate voice input and AI response
712+
// Handle side button press to toggle conversation recording
650713
Future<void> handleSideButtonPress() async {
714+
// Toggle: if already recording a conversation, stop and process
715+
if (_isConversationRecording) {
716+
debugPrint('AIService: Stopping conversation recording (second press)');
717+
await _showInfoMessage('Processing conversation...');
718+
await _voiceInputService.stopRecording();
719+
// Audio will be processed via _handleVoiceInputState callback
720+
return;
721+
}
722+
651723
if (_isProcessing) {
652724
debugPrint('Already processing a request');
653725
return;
654726
}
655727

656728
_isProcessing = true;
729+
_isConversationRecording = true;
657730
try {
658-
// Pause wake word detection during manual recording
731+
// Pause wake word detection during recording
659732
if (_wakeWordService.isEnabled) {
660733
await _wakeWordService.pause();
661734
}
662735

663736
// Use the voice input service to record from best available source
664737
final source = _voiceInputService.getBestAvailableSource();
665-
debugPrint('AIService: Starting recording from $source');
738+
debugPrint('AIService: Starting conversation recording from $source');
666739

667-
// Now show listening indicator since we're about to listen
668-
await _showListeningIndicator();
740+
// Show recording indicator
741+
await _showInfoMessage('Recording...');
669742

670-
// Start recording
743+
// Start recording with long duration - will be stopped manually by second press
671744
final success = await _voiceInputService.startRecording(
672-
maxDuration: const Duration(seconds: 5),
745+
maxDuration: const Duration(minutes: 30),
673746
);
674747

675748
if (!success) {
676-
// Fall back to original method if voice input service fails
677-
await _fallbackToOriginalRecording();
749+
_isConversationRecording = false;
750+
_isProcessing = false;
751+
await _showErrorMessage('Failed to start recording');
678752
}
679753
} catch (e) {
680754
debugPrint('Error handling side button press: $e');
755+
_isConversationRecording = false;
681756
_isProcessing = false;
682757
await _showErrorMessage('Failed to process voice input');
683758
}
@@ -1069,6 +1144,9 @@ class AIService {
10691144
/// Check if AIService is in background mode
10701145
bool get isBackgroundMode => _isBackgroundMode;
10711146

1147+
/// Check if currently recording a conversation
1148+
bool get isConversationRecording => _isConversationRecording;
1149+
10721150
/// Check if WebSocket is connected
10731151
bool get isWebSocketConnected => _webSocketService.isConnected;
10741152

0 commit comments

Comments
 (0)