110 lines
3.8 KiB
Dart
110 lines
3.8 KiB
Dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
import 'package:trainhub_flutter/injection.dart';
|
|
import 'package:trainhub_flutter/domain/repositories/chat_repository.dart';
|
|
import 'package:trainhub_flutter/presentation/chat/chat_state.dart';
|
|
|
|
part 'chat_controller.g.dart';
|
|
|
|
@riverpod
|
|
class ChatController extends _$ChatController {
|
|
late ChatRepository _repo;
|
|
|
|
@override
|
|
Future<ChatState> build() async {
|
|
_repo = getIt<ChatRepository>();
|
|
final sessions = await _repo.getAllSessions();
|
|
return ChatState(sessions: sessions);
|
|
}
|
|
|
|
Future<void> createSession() async {
|
|
final session = await _repo.createSession();
|
|
final sessions = await _repo.getAllSessions();
|
|
state = AsyncValue.data(
|
|
ChatState(sessions: sessions, activeSession: session),
|
|
);
|
|
}
|
|
|
|
Future<void> loadSession(String id) async {
|
|
final session = await _repo.getSession(id);
|
|
if (session == null) return;
|
|
final messages = await _repo.getMessages(id);
|
|
final current = state.valueOrNull ?? const ChatState();
|
|
state = AsyncValue.data(
|
|
current.copyWith(activeSession: session, messages: messages),
|
|
);
|
|
}
|
|
|
|
Future<void> deleteSession(String id) async {
|
|
await _repo.deleteSession(id);
|
|
final sessions = await _repo.getAllSessions();
|
|
final current = state.valueOrNull ?? const ChatState();
|
|
state = AsyncValue.data(
|
|
current.copyWith(
|
|
sessions: sessions,
|
|
activeSession:
|
|
current.activeSession?.id == id ? null : current.activeSession,
|
|
messages: current.activeSession?.id == id ? [] : current.messages,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> sendMessage(String content) async {
|
|
final current = state.valueOrNull;
|
|
if (current == null) return;
|
|
String sessionId;
|
|
if (current.activeSession == null) {
|
|
final session = await _repo.createSession();
|
|
sessionId = session.id;
|
|
final sessions = await _repo.getAllSessions();
|
|
state = AsyncValue.data(
|
|
current.copyWith(sessions: sessions, activeSession: session),
|
|
);
|
|
} else {
|
|
sessionId = current.activeSession!.id;
|
|
}
|
|
await _repo.addMessage(
|
|
sessionId: sessionId,
|
|
role: 'user',
|
|
content: content,
|
|
);
|
|
final messagesAfterUser = await _repo.getMessages(sessionId);
|
|
state = AsyncValue.data(
|
|
state.valueOrNull!.copyWith(messages: messagesAfterUser, isTyping: true),
|
|
);
|
|
await Future<void>.delayed(const Duration(seconds: 1));
|
|
final String response = _getMockResponse(content);
|
|
await _repo.addMessage(
|
|
sessionId: sessionId,
|
|
role: 'assistant',
|
|
content: response,
|
|
);
|
|
final messagesAfterAi = await _repo.getMessages(sessionId);
|
|
if (messagesAfterAi.length <= 2) {
|
|
final title = content.length > 30
|
|
? '${content.substring(0, 30)}...'
|
|
: content;
|
|
await _repo.updateSessionTitle(sessionId, title);
|
|
}
|
|
final sessions = await _repo.getAllSessions();
|
|
state = AsyncValue.data(
|
|
state.valueOrNull!.copyWith(
|
|
messages: messagesAfterAi,
|
|
isTyping: false,
|
|
sessions: sessions,
|
|
),
|
|
);
|
|
}
|
|
|
|
String _getMockResponse(String input) {
|
|
final String lower = input.toLowerCase();
|
|
if (lower.contains('plan') || lower.contains('program')) {
|
|
return "I can help you design a training plan! What are your goals? Strength, hypertrophy, or endurance?";
|
|
} else if (lower.contains('squat') || lower.contains('bench')) {
|
|
return "Compound movements are great. Remember to maintain proper form. For squats, keep your chest up and knees tracking over toes.";
|
|
} else if (lower.contains('nutrition') || lower.contains('eat')) {
|
|
return "Nutrition is key. Aim for 1.6-2.2g of protein per kg of bodyweight if you're training hard.";
|
|
}
|
|
return "I'm your AI training assistant. How can I help you today?";
|
|
}
|
|
}
|