mymuseum-visitapp/lib/Services/assistantService.dart
2026-07-17 15:23:12 +02:00

107 lines
3.4 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:manager_api_new/api.dart';
import 'package:mymuseum_visitapp/Models/visitContext.dart';
import 'package:mymuseum_visitapp/Models/AssistantResponse.dart';
class AssistantService {
final VisitAppContext visitAppContext;
/// Nombre maximum de messages conservés dans l'historique envoyé au backend.
final int maxHistory;
/// Durée d'inactivité après laquelle l'historique est automatiquement vidé.
/// null = pas de vidage automatique.
final Duration? inactivityTimeout;
final List<AiChatMessage> _history = [];
Timer? _inactivityTimer;
AssistantService({
required this.visitAppContext,
this.maxHistory = 10,
this.inactivityTimeout = const Duration(minutes: 5),
});
Future<AssistantResponse> chat({
required String message,
String? configurationId,
bool isVoice = false,
}) => chatWithAppType(message: message, configurationId: configurationId, isVoice: isVoice);
Future<AssistantResponse> chatWithAppType({
required String message,
String? configurationId,
AppType appType = AppType.Mobile,
bool isVoice = false,
}) async {
_resetInactivityTimer();
final request = AiChatRequest(
message: message,
instanceId: visitAppContext.instanceId,
appType: appType,
configurationId: configurationId,
language: visitAppContext.language?.toUpperCase() ?? 'FR',
history: List.from(_history),
isVoice: isVoice,
);
final response = await visitAppContext.clientAPI.aiApi!.aiChat(request);
if (response == null) {
throw Exception('Empty response from assistant');
}
debugPrint("AI raw response: reply='${response.reply}' navigation.sectionId='${response.navigation?.sectionId}' navigation.sectionTitle='${response.navigation?.sectionTitle}' navigation.sectionType='${response.navigation?.sectionType}' cards=${response.cards?.length}");
final result = AssistantResponse(
reply: response.reply ?? '',
cards: response.cards
?.map((c) => AiCard(
title: c.title ?? '',
subtitle: c.subtitle ?? '',
icon: c.icon,
))
.toList(),
navigation: response.navigation != null
? AssistantNavigationAction(
sectionId: response.navigation!.sectionId ?? '',
sectionTitle: response.navigation!.sectionTitle ?? '',
sectionType: response.navigation!.sectionType ?? '',
imageUrl: response.navigation!.imageUrl,
)
: null,
expectsReply: response.expectsReply ?? true,
);
_history.add(AiChatMessage(role: 'user', content: message));
_history.add(AiChatMessage(role: 'assistant', content: result.reply));
// Cap local — inutile de garder plus que maxHistory côté client
if (_history.length > maxHistory) {
_history.removeRange(0, _history.length - maxHistory);
}
return result;
}
void _resetInactivityTimer() {
if (inactivityTimeout == null) return;
_inactivityTimer?.cancel();
_inactivityTimer = Timer(inactivityTimeout!, () {
debugPrint('[AssistantService] Inactivity timeout — clearing history');
clearHistory();
});
}
void clearHistory() {
_history.clear();
_inactivityTimer?.cancel();
}
void dispose() {
_inactivityTimer?.cancel();
}
}