Thomas Fransolet 18e4240f0f RAG: pipeline d'ingestion, endpoints du guide IA, journalisation RGPD
Ingestion et indexation
- IIngestionService/IngestionService : chargement des collections filles par
  sous-type, un jeu de morceaux par langue, ChunkIndex continu.
- SectionIndexingInterceptor retenu comme unique déclencheur : les 5
  sous-contrôleurs totalisaient 30 SaveChanges et 0 Enqueue, donc ajouter des
  points d'intérêt à une carte ne réindexait rien.
- HTML retiré avant l'embedding et lignes trop longues recoupées : sans cela un
  article dépassait l'entrée max du modèle et emportait son lot de 50 morceaux.
- Gabarits de LanguageInit filtrés, DistinctBy(Text) avant le Take : ils
  occupaient les cinq premiers résultats d'une recherche en néerlandais.

Endpoints du guide IA
- GET /api/Ai/knowledge/{id} : agrégats sur ContentEmbedding, donc sur ce qui
  est réellement indexé — compter les sections publiées serait plus flatteur et faux.
- GET /api/Ai/insights/{id} : miroir de GuideIaInsights côté manager-app, c'est
  l'écran qui a fixé la forme pour que le job de thèmes la remplisse.

RGPD
- VisitorQuestion journalisée dans AiController.Chat. HasAnswer se déduit des
  sources du retrieval, pas du texte : un repli poli ressemble à une réponse.
  L'écriture n'échoue jamais la réponse au visiteur.
- VisitorQuestionPurgeService, 90 jours, actif sans condition de configuration :
  une durée écrite dans les CGU n'est pas un réglage commercial.

Corrections
- Updateinstance ne recopiait pas les quotas du nouveau plan.
- CheckQuota ne bloquait ni ne comptait à quota 0 — IA gratuite non comptée.
- StoragePath et SizeBytes renseignés à Create, types URL exclus.

dotnet build 0 erreur, dotnet test 130/130.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 10:48:10 +02:00

121 lines
3.8 KiB
C#

using Manager.DTOs;
using ManagerService.DTOs;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace ManagerService.Data
{
/// <summary>
/// Section Information
/// </summary>
[Index(nameof(InstanceId))]
public abstract class Section : IAuditableEntity
{
[Key]
[Required]
public string Id { get; set; }
[Required]
public string Label { get; set; } // Use in manager
[Required]
[Column(TypeName = "jsonb")]
public List<TranslationDTO> Title { get; set; }
[Column(TypeName = "jsonb")]
public List<TranslationDTO> Description { get; set; }
public int Order { get; set; }
[Required]
public string ConfigurationId { get; set; } // Parent id
public string ImageId { get; set; }
public string ImageSource { get; set; }
[Required]
public SectionType Type { get; set; }
[Required]
public bool IsSubSection { get; set; }
public string ParentId { get; set; } // only if it's an subsection
public DateTime DateCreation { get; set; }
public DateTime DateUpdate { get; set; }
[Required]
public string InstanceId { get; set; }
public bool IsBeacon { get; set; }
public int? BeaconId { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
public int? MeterZoneGPS { get; set; }
public bool IsActive { get; set; } = true;
/// <summary>
/// Texte de la section dans une langue, tel qu'il sera indexé pour le guide IA.
/// Rend une chaîne vide quand la section ne porte rien d'exploitable dans cette langue.
/// </summary>
/// <remarks>
/// Abstraite, et pas virtuelle avec un comportement par défaut : la collecte des
/// ressources vivait dans un switch centralisé, un nouveau sous-type n'obligeait
/// personne à le mettre à jour, et il est devenu faux en silence. Ici le compilateur
/// réclame l'implémentation.
/// </remarks>
public abstract string GetEmbeddableText(string language);
/// <summary>
/// Ids des ressources référencées par la section, pour l'export hors ligne.
/// <paramref name="language"/> null rend toutes les langues.
/// </summary>
public abstract IEnumerable<string> GetReferencedResourceIds(string language = null);
/// <summary>Titre et description, communs à tous les sous-types.</summary>
protected string BaseText(string language) =>
SectionText.JoinText(SectionText.Translate(Title, language), SectionText.Translate(Description, language));
/// <summary>Vignette de la section, commune à tous les sous-types.</summary>
protected IEnumerable<string> BaseResourceIds() => SectionText.ResourceId(ImageId);
public SectionDTO ToDTO()
{
return new SectionDTO()
{
id = Id,
label = Label,
title = Title,
description = Description,
isActive = IsActive,
order = Order,
type = Type,
imageId = ImageId,
imageSource = ImageSource,
configurationId = ConfigurationId,
isSubSection = IsSubSection,
parentId = ParentId,
dateCreation = DateCreation,
instanceId = InstanceId,
isBeacon = IsBeacon,
beaconId = BeaconId,
latitude = Latitude,
longitude = Longitude,
meterZoneGPS = MeterZoneGPS,
};
}
}
}