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;
///
/// false = ce tour n'est pas une question posée par un visiteur, et ne doit donc
/// pas être journalisé dans VisitorQuestion. Deux cas aujourd'hui :
///
/// - le mode proactif, dont la « question » est une consigne que le
/// système s'écrit à lui-même (« Tu es un guide audio de musée. Le visiteur vient
/// d'entrer dans la zone X… ») ;
/// - l'aperçu de conversation du Guide IA, où c'est le gestionnaire qui
/// teste sa personnalité — sans quoi il pollue son propre rapport.
///
///
/// ⚠️ Les jetons restent comptés dans les deux cas : ils sont réellement consommés.
///
/// ⚠️ Défaut à true, et c'est délibéré : un client qui n'envoie pas le champ
/// journalise, ce qui est le bon comportement pour les apps visiteur déjà publiées.
///
public bool IsVisitorQuestion { get; set; } = true;
}
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; }
}
}