using ManagerService.Data; using System.Collections.Generic; namespace ManagerService.DTOs { public class AiChatRequest { public string Message { get; set; } public string InstanceId { get; set; } public AppType AppType { get; set; } public string ConfigurationId { get; set; } // null = scope instance, fourni = scope configuration public string Language { get; set; } /// /// GUID généré par le client, stable sur une session de conversation. /// History étant reconstruit côté client à chaque appel, c'est le seul moyen /// de relier deux questions d'un même visiteur côté serveur. /// Optionnel : un appel sans ConversationId reste valide, la ligne journalisée est isolée. /// public string ConversationId { get; set; } public List History { get; set; } = new(); /// /// true = interaction vocale (lunettes, assistant vocal). /// Le backend adapte le prompt : pas de markdown, pas de navigation, /// dates en toutes lettres, réponses courtes audio-friendly. /// public bool IsVoice { get; set; } = false; /// /// true = le tour a été déclenché par le système, pas demandé par le visiteur — /// c'est le cas du mode proactif, où l'approche d'un point d'intérêt fait parler /// le guide tout seul. /// /// ⚠️ Ces tours ne sont **pas journalisés** dans VisitorQuestion : leur /// « question » est une consigne que le système s'est écrite à lui-même /// (« Tu es un guide audio de musée. Le visiteur vient d'entrer dans la zone X… »), /// et l'onglet Guide IA existe pour montrer ce que les **humains** demandent. /// Leurs jetons, eux, restent comptés : ils sont réellement consommés. /// public bool IsAutoTriggered { get; set; } = false; } public class AiChatMessage { public string Role { get; set; } // "user" | "assistant" public string Content { get; set; } } public class AiCardDTO { public string Title { get; set; } public string Subtitle { get; set; } public string? Icon { get; set; } } public class NavigationActionDTO { public string SectionId { get; set; } public string SectionTitle { get; set; } public string SectionType { get; set; } public string? ImageUrl { get; set; } } public class AiChatResponse { public string Reply { get; set; } public List? Cards { get; set; } public NavigationActionDTO? Navigation { get; set; } /// /// false = le LLM ne s'attend pas à une réponse du visiteur (info pure, hors-sujet, politesse, beacon). /// Le front peut désactiver l'écoute automatique après le TTS. /// public bool ExpectsReply { get; set; } = true; public long TokensUsed { get; set; } /// /// Contenus sur lesquels la réponse s'appuie, relevés côté serveur à chaque appel de /// SearchKnowledge. Ils ne passent pas par le modèle : la règle « ne mentionne jamais /// les identifiants techniques » lui interdit précisément de les recopier. /// Destinés au client, pas au visiteur — c'est ce qui rend une réponse vérifiable /// quand un client conteste ce que dit son guide. /// public List? Sources { get; set; } } public class AiSourceDTO { public string ContentId { get; set; } public string ContentType { get; set; } /// Null hors document paginé. public int? PageNumber { get; set; } } public class AiTranslateRequest { public string Text { get; set; } public string SourceLang { get; set; } public List TargetLangs { get; set; } = new(); } public class AiTranslateResponse { public Dictionary Translations { get; set; } = new(); public long TokensUsed { get; set; } } }