Change PIN to 1451
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
295
apps/captain-mobile-v2/flutter/lib/providers/chat_provider.dart
Normal file
295
apps/captain-mobile-v2/flutter/lib/providers/chat_provider.dart
Normal file
@@ -0,0 +1,295 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../models/message.dart';
|
||||
import '../services/chat_service.dart';
|
||||
import '../providers/auth_provider.dart';
|
||||
|
||||
/// Chat provider for v3 API (dynamic Claude sessions)
|
||||
class ChatProvider with ChangeNotifier {
|
||||
final ChatService _chatService = ChatService();
|
||||
final List<Message> _messages = [];
|
||||
static const int _maxMessages = 500;
|
||||
|
||||
AuthProvider? _authProvider;
|
||||
StreamSubscription? _messageSubscription;
|
||||
StreamSubscription? _stateSubscription;
|
||||
StreamSubscription? _errorSubscription;
|
||||
|
||||
List<ChatSession> _sessions = [];
|
||||
ChatSession? _currentSession;
|
||||
bool _isProcessing = false;
|
||||
String? _error;
|
||||
|
||||
List<Message> get messages => List.unmodifiable(_messages);
|
||||
List<ChatSession> get sessions => List.unmodifiable(_sessions);
|
||||
ChatSession? get currentSession => _currentSession;
|
||||
bool get isProcessing => _isProcessing;
|
||||
bool get isConnected => _chatService.currentState == ChatConnectionState.connected;
|
||||
bool get isSessionConnected => _currentSession != null;
|
||||
ChatConnectionState get connectionState => _chatService.currentState;
|
||||
String? get error => _error;
|
||||
|
||||
void updateAuth(AuthProvider auth) {
|
||||
_authProvider = auth;
|
||||
_chatService.setToken(auth.token);
|
||||
|
||||
if (auth.isAuthenticated && !isConnected) {
|
||||
connect();
|
||||
} else if (!auth.isAuthenticated && isConnected) {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> connect() async {
|
||||
if (_authProvider?.token == null) return;
|
||||
|
||||
_chatService.setToken(_authProvider!.token);
|
||||
|
||||
_stateSubscription?.cancel();
|
||||
_stateSubscription = _chatService.connectionState.listen((state) {
|
||||
notifyListeners();
|
||||
});
|
||||
|
||||
_errorSubscription?.cancel();
|
||||
_errorSubscription = _chatService.errors.listen((error) {
|
||||
_error = error;
|
||||
notifyListeners();
|
||||
});
|
||||
|
||||
_messageSubscription?.cancel();
|
||||
_messageSubscription = _chatService.messages.listen(_handleMessage);
|
||||
|
||||
await _chatService.connect();
|
||||
}
|
||||
|
||||
void _handleMessage(Map<String, dynamic> data) {
|
||||
final type = data['type'];
|
||||
debugPrint('ChatProvider: type=$type');
|
||||
|
||||
switch (type) {
|
||||
// Initial state with sessions
|
||||
case 'init':
|
||||
final sessionsList = data['sessions'] as List<dynamic>?;
|
||||
if (sessionsList != null) {
|
||||
_sessions = sessionsList
|
||||
.map((s) => ChatSession.fromJson(s))
|
||||
.toList();
|
||||
}
|
||||
notifyListeners();
|
||||
break;
|
||||
|
||||
// Sessions list update
|
||||
case 'sessions_list':
|
||||
final sessionsList = data['sessions'] as List<dynamic>?;
|
||||
if (sessionsList != null) {
|
||||
_sessions = sessionsList
|
||||
.map((s) => ChatSession.fromJson(s))
|
||||
.toList();
|
||||
}
|
||||
notifyListeners();
|
||||
break;
|
||||
|
||||
// Session created (v3)
|
||||
case 'session_created':
|
||||
final sessionId = data['session_id'] as String?;
|
||||
final name = data['name'] as String?;
|
||||
if (sessionId != null) {
|
||||
final newSession = ChatSession(
|
||||
sessionId: sessionId,
|
||||
name: name ?? 'New Session',
|
||||
);
|
||||
_sessions.add(newSession);
|
||||
_messages.add(Message(
|
||||
role: 'system',
|
||||
content: 'Sesión creada: ${newSession.name}',
|
||||
));
|
||||
// Auto-connect to new session
|
||||
connectToSession(sessionId);
|
||||
}
|
||||
notifyListeners();
|
||||
break;
|
||||
|
||||
// Connected to session (v3)
|
||||
case 'session_connected':
|
||||
final sessionId = data['session_id'] as String?;
|
||||
final name = data['name'] as String?;
|
||||
if (sessionId != null) {
|
||||
_currentSession = _sessions.firstWhere(
|
||||
(s) => s.sessionId == sessionId,
|
||||
orElse: () => ChatSession(
|
||||
sessionId: sessionId,
|
||||
name: name ?? 'Session',
|
||||
),
|
||||
);
|
||||
_messages.clear();
|
||||
_messages.add(Message(
|
||||
role: 'system',
|
||||
content: 'Conectado a: ${_currentSession!.name}',
|
||||
));
|
||||
}
|
||||
notifyListeners();
|
||||
break;
|
||||
|
||||
// Output from Claude (v3)
|
||||
case 'output':
|
||||
final content = data['content'] as String? ?? '';
|
||||
if (content.isEmpty) break;
|
||||
|
||||
debugPrint('ChatProvider: OUTPUT "${content.substring(0, content.length > 50 ? 50 : content.length)}"');
|
||||
_isProcessing = true;
|
||||
|
||||
// Check if it's a progress indicator
|
||||
if (content.startsWith('procesando')) {
|
||||
// Update or create progress message
|
||||
if (_messages.isNotEmpty && _messages.last.role == 'assistant' && _messages.last.isStreaming == true) {
|
||||
final lastIndex = _messages.length - 1;
|
||||
_messages[lastIndex] = Message(
|
||||
role: 'assistant',
|
||||
content: content,
|
||||
isStreaming: true,
|
||||
);
|
||||
} else {
|
||||
_messages.add(Message(
|
||||
role: 'assistant',
|
||||
content: content,
|
||||
isStreaming: true,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Real content - replace progress or add new
|
||||
if (_messages.isNotEmpty && _messages.last.role == 'assistant' && _messages.last.isStreaming == true) {
|
||||
final lastIndex = _messages.length - 1;
|
||||
final lastContent = _messages[lastIndex].content;
|
||||
// If last message was progress, replace it. Otherwise append.
|
||||
if (lastContent.startsWith('procesando')) {
|
||||
_messages[lastIndex] = Message(
|
||||
role: 'assistant',
|
||||
content: content,
|
||||
isStreaming: true,
|
||||
);
|
||||
} else {
|
||||
// Append to existing response
|
||||
_messages[lastIndex] = Message(
|
||||
role: 'assistant',
|
||||
content: lastContent + content,
|
||||
isStreaming: true,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_messages.add(Message(
|
||||
role: 'assistant',
|
||||
content: content,
|
||||
isStreaming: true,
|
||||
));
|
||||
}
|
||||
}
|
||||
_trimMessages();
|
||||
notifyListeners();
|
||||
break;
|
||||
|
||||
// Response complete (v3)
|
||||
case 'done':
|
||||
_isProcessing = false;
|
||||
// Mark last assistant message as complete
|
||||
if (_messages.isNotEmpty && _messages.last.role == 'assistant') {
|
||||
final lastIndex = _messages.length - 1;
|
||||
_messages[lastIndex] = Message(
|
||||
role: 'assistant',
|
||||
content: _messages[lastIndex].content,
|
||||
isStreaming: false,
|
||||
);
|
||||
}
|
||||
notifyListeners();
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
_isProcessing = false;
|
||||
final errorMsg = data['message'] ?? data['content'] ?? 'Error';
|
||||
if (errorMsg.toString().isNotEmpty) {
|
||||
_error = errorMsg;
|
||||
_messages.add(Message(
|
||||
role: 'system',
|
||||
content: 'Error: $errorMsg',
|
||||
));
|
||||
}
|
||||
notifyListeners();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _trimMessages() {
|
||||
while (_messages.length > _maxMessages) {
|
||||
_messages.removeAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and connect to a new session
|
||||
void createSession(String name) {
|
||||
_chatService.createSession(name);
|
||||
}
|
||||
|
||||
/// Connect to an existing session
|
||||
void connectToSession(String sessionId) {
|
||||
_chatService.connectToSession(sessionId);
|
||||
}
|
||||
|
||||
/// Refresh sessions list
|
||||
void refreshSessions() {
|
||||
_chatService.listSessions();
|
||||
}
|
||||
|
||||
/// Send message to current session
|
||||
void sendMessage(String content) {
|
||||
if (content.trim().isEmpty) return;
|
||||
if (!isConnected) {
|
||||
_error = 'No conectado al servidor';
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
if (_currentSession == null) {
|
||||
_error = 'No hay sesión activa';
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
if (_isProcessing) {
|
||||
_error = 'Espera a que termine la respuesta anterior';
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
_messages.add(Message(
|
||||
role: 'user',
|
||||
content: content,
|
||||
));
|
||||
_trimMessages();
|
||||
_isProcessing = true;
|
||||
notifyListeners();
|
||||
|
||||
_chatService.sendMessage(content);
|
||||
}
|
||||
|
||||
void clearMessages() {
|
||||
_messages.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void clearError() {
|
||||
_error = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
_chatService.disconnect();
|
||||
_messageSubscription?.cancel();
|
||||
_stateSubscription?.cancel();
|
||||
_errorSubscription?.cancel();
|
||||
_currentSession = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
disconnect();
|
||||
_chatService.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user