diff --git a/lib/Screens/GuideIa/guide_ia_screen.dart b/lib/Screens/GuideIa/guide_ia_screen.dart index 172b539..dc8a082 100644 --- a/lib/Screens/GuideIa/guide_ia_screen.dart +++ b/lib/Screens/GuideIa/guide_ia_screen.dart @@ -630,6 +630,10 @@ class _GuideIaScreenState extends State { instanceId: ctx.instanceId, appType: AppType.Web, language: _editingLanguage, + // ⚠️ C'est le gestionnaire qui teste sa personnalité, pas un visiteur qui pose une + // question : sans ce drapeau, chaque essai atterrissait dans son propre onglet + // « Ce que demandent vos visiteurs » et gonflait le bloc des questions sans réponse. + isVisitorQuestion: false, )); if (!mounted) return; setState(() { diff --git a/lib/Screens/Statistics/statistics_screen.dart b/lib/Screens/Statistics/statistics_screen.dart index 533619e..32d570d 100644 --- a/lib/Screens/Statistics/statistics_screen.dart +++ b/lib/Screens/Statistics/statistics_screen.dart @@ -202,8 +202,14 @@ class _StatisticsScreenState extends State { double _contentsPerVisit(StatsSummaryDTO stats) => stats.totalSessions == 0 ? 0 : _totalViews(stats) / stats.totalSessions; - int _voiceSessions(StatsSummaryDTO stats) => - stats.appTypeDistribution[AppType.Voice.name] ?? 0; + /// ⚠️ Lisait `appTypeDistribution['Voice']`, qui ne se remplira jamais : **le vocal + /// n'est pas une plateforme mais un mode d'interaction**. Un visiteur passe des + /// lunettes à l'écran dans une même session, or la distribution ne compte qu'une + /// entrée par session, tranchée sur l'événement le plus ancien — le chiffre aurait + /// dépendu de l'ordre dans lequel le visiteur a touché ses appareils. + /// + /// Le serveur expose désormais « sessions ayant utilisé le vocal », qui est vrai. + int _voiceSessions(StatsSummaryDTO stats) => stats.voiceSessions ?? 0; double _voiceShare(StatsSummaryDTO stats) => stats.totalSessions == 0 ? 0 diff --git a/manager_api_new/lib/model/ai_chat_request.dart b/manager_api_new/lib/model/ai_chat_request.dart index d1b8a16..337b2e2 100644 --- a/manager_api_new/lib/model/ai_chat_request.dart +++ b/manager_api_new/lib/model/ai_chat_request.dart @@ -21,7 +21,7 @@ class AiChatRequest { this.conversationId, this.history = const [], this.isVoice = false, - this.isAutoTriggered = false, + this.isVisitorQuestion = true, }); String? message; @@ -50,9 +50,11 @@ class AiChatRequest { /// true = interaction vocale (lunettes) — prompt audio-friendly, pas de navigation bool? isVoice; - /// true = tour déclenché par le système (mode proactif), pas demandé par le visiteur. - /// Le backend compte les jetons mais ne journalise pas la question : elle n'en est pas une. - bool? isAutoTriggered; + /// false = ce tour n'est pas une question de visiteur (prompt du mode proactif, ou + /// gestionnaire testant sa personnalité dans l'aperçu du Guide IA). Le backend compte + /// les jetons mais ne journalise rien. Défaut à true : ne pas envoyer le champ revient + /// à journaliser, ce qui est le bon comportement pour une app visiteur. + bool? isVisitorQuestion; @override bool operator ==(Object other) => @@ -117,7 +119,7 @@ class AiChatRequest { json[r'conversationId'] = null; } json[r'isVoice'] = this.isVoice ?? false; - json[r'isAutoTriggered'] = this.isAutoTriggered ?? false; + json[r'isVisitorQuestion'] = this.isVisitorQuestion ?? true; return json; } diff --git a/manager_api_new/lib/model/stats_summary_dto.dart b/manager_api_new/lib/model/stats_summary_dto.dart index bf5b073..aae3854 100644 --- a/manager_api_new/lib/model/stats_summary_dto.dart +++ b/manager_api_new/lib/model/stats_summary_dto.dart @@ -15,6 +15,7 @@ class StatsSummaryDTO { this.visitsByDay = const [], this.languageDistribution = const {}, this.appTypeDistribution = const {}, + this.voiceSessions, this.topPois = const [], this.topAgendaEvents = const [], this.quizStats = const [], @@ -30,6 +31,12 @@ class StatsSummaryDTO { List visitsByDay; Map languageDistribution; Map appTypeDistribution; + + /// Sessions ayant utilisé le vocal au moins une fois. Volontairement **hors** de + /// `appTypeDistribution` : le vocal est un mode d'interaction, pas une plateforme — + /// une même session mêle la voix et le tactile. + int? voiceSessions; + List topPois; List topAgendaEvents; List quizStats; @@ -52,6 +59,7 @@ class StatsSummaryDTO { appTypeDistribution: (json[r'appTypeDistribution'] is Map) ? (json[r'appTypeDistribution'] as Map).cast() : {}, + voiceSessions: (json[r'voiceSessions'] as num?)?.toInt(), topPois: PoiStatDTO.listFromJson(json[r'topPois']), topAgendaEvents: AgendaEventStatDTO.listFromJson(json[r'topAgendaEvents']), quizStats: QuizStatDTO.listFromJson(json[r'quizStats']),