feat: Intégration d'un assistant IA logisticien basé sur Gemini
- Ajout d'une Cloud Function `aiEquipmentProposal` utilisant le modèle Gemini avec function calling pour suggérer du matériel et des containers. - Implémentation de plusieurs outils (tools) côté serveur pour permettre à l'IA d'interagir avec Firestore : `search_equipment`, `check_availability_batch`, `get_past_events`, `search_event_reference` et `search_containers`. - Ajout de la dépendance `@google/generative-ai` dans le backend. - Création d'un service Flutter `AiEquipmentAssistantService` pour communiquer avec la nouvelle Cloud Function. - Ajout d'une interface de dialogue `AiEquipmentAssistantDialog` permettant aux utilisateurs de discuter avec l'IA pour affiner les propositions de matériel. - Intégration de l'assistant IA dans la section de gestion du matériel des événements (`EventAssignedEquipmentSection`). - Mise à jour de `DataService` avec de nouvelles méthodes de recherche et de vérification de disponibilité optimisées pour l'assistant. - Activation du mode développement et configuration des identifiants de test dans `env.dart`. - Optimisation des paramètres de la Cloud Function (timeout de 300s et 1GiB de RAM) pour supporter les traitements IA.
This commit is contained in:
@@ -77,7 +77,8 @@ class _EventAddEditPageState extends State<EventAddEditPage> {
|
||||
return;
|
||||
}
|
||||
|
||||
final success = await _controller.submitForm(context, existingEvent: widget.event);
|
||||
final success =
|
||||
await _controller.submitForm(context, existingEvent: widget.event);
|
||||
if (success && mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
@@ -158,21 +159,25 @@ class _EventAddEditPageState extends State<EventAddEditPage> {
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(isEditMode ? 'Modifier un événement' : 'Créer un événement'),
|
||||
title: Text(
|
||||
isEditMode ? 'Modifier un événement' : 'Créer un événement'),
|
||||
),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: (isMobile
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 12),
|
||||
child: _buildFormContent(isMobile),
|
||||
)
|
||||
: Card(
|
||||
elevation: 6,
|
||||
margin: const EdgeInsets.all(24),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(18)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 32),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 32, vertical: 32),
|
||||
child: _buildFormContent(isMobile),
|
||||
),
|
||||
)),
|
||||
@@ -186,15 +191,6 @@ class _EventAddEditPageState extends State<EventAddEditPage> {
|
||||
Widget _buildFormContent(bool isMobile) {
|
||||
return Consumer<EventFormController>(
|
||||
builder: (context, controller, child) {
|
||||
// Trouver le nom du type d'événement pour le passer au sélecteur d'options
|
||||
final selectedEventTypeIndex = controller.selectedEventTypeId != null
|
||||
? controller.eventTypes.indexWhere((et) => et.id == controller.selectedEventTypeId)
|
||||
: -1;
|
||||
final selectedEventType = selectedEventTypeIndex != -1
|
||||
? controller.eventTypes[selectedEventTypeIndex]
|
||||
: null;
|
||||
final selectedEventTypeName = selectedEventType?.name;
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
@@ -209,18 +205,22 @@ class _EventAddEditPageState extends State<EventAddEditPage> {
|
||||
selectedEventTypeId: controller.selectedEventTypeId,
|
||||
startDateTime: controller.startDateTime,
|
||||
endDateTime: controller.endDateTime,
|
||||
onEventTypeChanged: (typeId) => controller.onEventTypeChanged(typeId, context),
|
||||
onEventTypeChanged: (typeId) =>
|
||||
controller.onEventTypeChanged(typeId, context),
|
||||
onStartDateTimeChanged: controller.setStartDateTime,
|
||||
onEndDateTimeChanged: controller.setEndDateTime,
|
||||
onAnyFieldChanged: () {}, // Géré automatiquement par le contrôleur
|
||||
onAnyFieldChanged:
|
||||
() {}, // Géré automatiquement par le contrôleur
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
OptionSelectorWidget(
|
||||
eventType: controller.selectedEventTypeId, // Utilise l'ID au lieu du nom
|
||||
eventType: controller
|
||||
.selectedEventTypeId, // Utilise l'ID au lieu du nom
|
||||
selectedOptions: controller.selectedOptions,
|
||||
onChanged: controller.setSelectedOptions,
|
||||
onRemove: (optionId) {
|
||||
final newOptions = List<Map<String, dynamic>>.from(controller.selectedOptions);
|
||||
final newOptions = List<Map<String, dynamic>>.from(
|
||||
controller.selectedOptions);
|
||||
newOptions.removeWhere((o) => o['id'] == optionId);
|
||||
controller.setSelectedOptions(newOptions);
|
||||
},
|
||||
@@ -236,6 +236,7 @@ class _EventAddEditPageState extends State<EventAddEditPage> {
|
||||
endDate: controller.endDateTime,
|
||||
onChanged: controller.setAssignedEquipment,
|
||||
eventId: widget.event?.id,
|
||||
eventTypeId: controller.selectedEventTypeId,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
EventDetailsSection(
|
||||
@@ -247,7 +248,8 @@ class _EventAddEditPageState extends State<EventAddEditPage> {
|
||||
contactEmailController: controller.contactEmailController,
|
||||
contactPhoneController: controller.contactPhoneController,
|
||||
isMobile: isMobile,
|
||||
onAnyFieldChanged: () {}, // Géré automatiquement par le contrôleur
|
||||
onAnyFieldChanged:
|
||||
() {}, // Géré automatiquement par le contrôleur
|
||||
),
|
||||
EventStaffAndDocumentsSection(
|
||||
allUsers: controller.allUsers,
|
||||
@@ -290,9 +292,10 @@ class _EventAddEditPageState extends State<EventAddEditPage> {
|
||||
}
|
||||
},
|
||||
onSubmit: _submit,
|
||||
onSetConfirmed: !isEditMode ? () {
|
||||
} : null,
|
||||
onDelete: isEditMode ? _deleteEvent : null, // Ajout du callback de suppression
|
||||
onSetConfirmed: !isEditMode ? () {} : null,
|
||||
onDelete: isEditMode
|
||||
? _deleteEvent
|
||||
: null, // Ajout du callback de suppression
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user