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>
183 lines
6.4 KiB
C#
183 lines
6.4 KiB
C#
using Manager.DTOs;
|
|
using ManagerService.DTOs;
|
|
using ManagerService.Helpers;
|
|
using NetTopologySuite.Geometries;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
using System.Linq;
|
|
|
|
using static ManagerService.Data.SectionText;
|
|
|
|
namespace ManagerService.Data.SubSection
|
|
{
|
|
/// <summary>
|
|
/// Section map
|
|
/// </summary>
|
|
public class SectionMap : Section
|
|
{
|
|
public int MapZoom { get; set; } // Default = 18
|
|
public bool IsListViewEnabled { get; set; } = false;
|
|
public MapTypeApp? MapMapType { get; set; } // Default = Hybrid for Google
|
|
public MapTypeMapBox? MapTypeMapbox { get; set; } // Default = standard for MapBox
|
|
public MapProvider? MapMapProvider { get; set; } // Default = Google
|
|
public List<GeoPoint> MapPoints { get; set; }
|
|
public string MapResourceId { get; set; }
|
|
public Resource MapResource { get; set; } // Icon
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<CategorieDTO> MapCategories { get; set; }
|
|
public string MapCenterLatitude { get; set; } // Center on
|
|
public string MapCenterLongitude { get; set; } // Center on
|
|
|
|
|
|
public override string GetEmbeddableText(string language) =>
|
|
JoinText(new[] { BaseText(language) }
|
|
.Concat((MapCategories ?? new List<CategorieDTO>())
|
|
.OrderBy(c => c.order ?? 0)
|
|
.Select(c => Translate(c.label, language)))
|
|
.Concat((MapPoints ?? new List<GeoPoint>())
|
|
.Select(p => p.GetEmbeddableText(language)))
|
|
.ToArray());
|
|
|
|
public override IEnumerable<string> GetReferencedResourceIds(string language = null) =>
|
|
BaseResourceIds()
|
|
.Concat(ResourceId(MapResourceId))
|
|
.Concat((MapCategories ?? new List<CategorieDTO>())
|
|
.SelectMany(c => ResourceId(c.resourceDTO?.id)))
|
|
.Concat((MapPoints ?? new List<GeoPoint>())
|
|
.SelectMany(p => p.GetReferencedResourceIds()));
|
|
|
|
public MapDTO ToDTO()
|
|
{
|
|
return new MapDTO()
|
|
{
|
|
id = Id,
|
|
label = Label,
|
|
title = Title.ToList(),
|
|
description = Description.ToList(),
|
|
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,
|
|
zoom = MapZoom,
|
|
mapType = MapMapType,
|
|
mapTypeMapbox = MapTypeMapbox,
|
|
mapProvider = MapMapProvider,
|
|
iconResourceId = MapResourceId,
|
|
categories = MapCategories,
|
|
centerLatitude = MapCenterLatitude,
|
|
centerLongitude = MapCenterLongitude
|
|
};
|
|
}
|
|
}
|
|
|
|
public class GeoPoint
|
|
{
|
|
[Required]
|
|
public int? Id { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<TranslationDTO> Title { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<TranslationDTO> Description { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<ContentDTO> Contents { get; set; }
|
|
|
|
public int? CategorieId { get; set; }
|
|
|
|
public Geometry Geometry { get; set; }
|
|
|
|
public string PolyColor { get; set; } // color of the polyline or polygon
|
|
|
|
public string ImageResourceId { get; set; }
|
|
|
|
public string ImageUrl { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<TranslationDTO> Schedules { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<TranslationDTO> Prices { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<TranslationDTO> Phone { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<TranslationDTO> Email { get; set; }
|
|
|
|
[Required]
|
|
[Column(TypeName = "jsonb")]
|
|
public List<TranslationDTO> Site { get; set; }
|
|
|
|
public string? SectionMapId { get; set; }
|
|
|
|
[ForeignKey(nameof(SectionMapId))]
|
|
public SectionMap? SectionMap { get; set; }
|
|
|
|
public string? SectionEventId { get; set; }
|
|
|
|
[ForeignKey(nameof(SectionEventId))]
|
|
public SectionEvent? SectionEvent { get; set; }
|
|
|
|
public string GetEmbeddableText(string language) =>
|
|
JoinText(Translate(Title, language),
|
|
Translate(Description, language),
|
|
TranslateContents(Contents, language),
|
|
Translate(Schedules, language),
|
|
Translate(Prices, language),
|
|
Translate(Phone, language),
|
|
Translate(Email, language),
|
|
Translate(Site, language));
|
|
|
|
public IEnumerable<string> GetReferencedResourceIds() =>
|
|
ResourceId(ImageResourceId).Concat(ResourceIds(Contents));
|
|
|
|
public GeoPointDTO ToDTO()
|
|
{
|
|
return new GeoPointDTO
|
|
{
|
|
id = Id,
|
|
title = Title,
|
|
description = Description,
|
|
contents = Contents,
|
|
categorieId = CategorieId,
|
|
geometry = Geometry != null ? Geometry.ToDto() : null,
|
|
polyColor = PolyColor,
|
|
imageResourceId = ImageResourceId,
|
|
imageUrl = ImageUrl,
|
|
schedules = Schedules,
|
|
prices = Prices,
|
|
phone = Phone,
|
|
email = Email,
|
|
site = Site,
|
|
sectionMapId = SectionMapId,
|
|
sectionEventId = SectionEventId
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
// SectionMap "normal" comme avant => Via geopoints. Si il y a des guidedPath lié à la sectionMap alors il y a un parcours lié à la sectionMap, tu peux aussi avoir des geopoints classique mis là + des parcours. et aussi lier un guidedstep à un geopoint (pour le trigger et aussi pour "afficher plus")
|
|
|
|
}
|