Chat persistant pour la partie lore et la partie campagne pour chaque page / scène.....
All checks were successful
Build & Push Images / build (brain) (push) Successful in 52s
Build & Push Images / build (core) (push) Successful in 1m23s
Build & Push Images / build (web) (push) Successful in 1m26s

Correction du carroussel
Passage en v0.4.0
Correction du docker compose pour tout le temps utiliser le bon port que ce soit prod ou dev
This commit is contained in:
2026-04-21 23:35:43 +02:00
parent b0fe8de708
commit 49a82d05f7
45 changed files with 2153 additions and 202 deletions

View File

@@ -5,6 +5,7 @@ import com.loremind.domain.campaigncontext.ports.CampaignRepository;
import com.loremind.domain.generationcontext.CampaignStructuralContext;
import com.loremind.domain.generationcontext.ChatMessage;
import com.loremind.domain.generationcontext.ChatRequest;
import com.loremind.domain.generationcontext.ChatUsage;
import com.loremind.domain.generationcontext.LoreStructuralContext;
import com.loremind.domain.generationcontext.NarrativeEntityContext;
import com.loremind.domain.generationcontext.ports.AiChatProvider;
@@ -46,6 +47,7 @@ public class StreamChatForCampaignUseCaseTest {
private CampaignStructuralContext campaignCtx;
private List<ChatMessage> messages;
private Consumer<ChatUsage> onUsage;
private Consumer<String> onToken;
private Runnable onComplete;
private Consumer<Throwable> onError;
@@ -57,6 +59,7 @@ public class StreamChatForCampaignUseCaseTest {
.campaignName("X").campaignDescription("d")
.build();
messages = List.of();
onUsage = mock(Consumer.class);
onToken = mock(Consumer.class);
onComplete = mock(Runnable.class);
onError = mock(Consumer.class);
@@ -67,7 +70,7 @@ public class StreamChatForCampaignUseCaseTest {
when(campaignRepository.findById("missing")).thenReturn(Optional.empty());
assertThrows(IllegalArgumentException.class,
() -> useCase.execute("missing", null, null, messages, onToken, onComplete, onError));
() -> useCase.execute("missing", null, null, messages, onUsage, onToken, onComplete, onError));
verifyNoInteractions(aiChatProvider);
}
@@ -77,10 +80,10 @@ public class StreamChatForCampaignUseCaseTest {
when(campaignRepository.findById("c-1")).thenReturn(Optional.of(standalone));
when(campaignContextBuilder.build("c-1")).thenReturn(campaignCtx);
useCase.execute("c-1", null, null, messages, onToken, onComplete, onError);
useCase.execute("c-1", null, null, messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), eq(onToken), eq(onComplete), eq(onError));
verify(aiChatProvider).streamChat(captor.capture(), eq(onUsage), eq(onToken), eq(onComplete), eq(onError));
ChatRequest req = captor.getValue();
assertSame(campaignCtx, req.getCampaignContext());
assertNull(req.getLoreContext());
@@ -100,10 +103,10 @@ public class StreamChatForCampaignUseCaseTest {
when(campaignContextBuilder.build("c-1")).thenReturn(campaignCtx);
when(loreContextBuilder.buildOptional("lore-1")).thenReturn(Optional.of(loreCtx));
useCase.execute("c-1", null, null, messages, onToken, onComplete, onError);
useCase.execute("c-1", null, null, messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
assertSame(loreCtx, captor.getValue().getLoreContext());
}
@@ -115,10 +118,10 @@ public class StreamChatForCampaignUseCaseTest {
when(campaignContextBuilder.build("c-1")).thenReturn(campaignCtx);
when(loreContextBuilder.buildOptional("lore-ghost")).thenReturn(Optional.empty());
useCase.execute("c-1", null, null, messages, onToken, onComplete, onError);
useCase.execute("c-1", null, null, messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
assertNull(captor.getValue().getLoreContext());
// La requete doit tout de meme partir (pas d'exception).
}
@@ -133,10 +136,10 @@ public class StreamChatForCampaignUseCaseTest {
when(campaignContextBuilder.build("c-1")).thenReturn(campaignCtx);
when(narrativeEntityContextBuilder.build("scene", "s-1")).thenReturn(entity);
useCase.execute("c-1", "scene", "s-1", messages, onToken, onComplete, onError);
useCase.execute("c-1", "scene", "s-1", messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
assertSame(entity, captor.getValue().getNarrativeEntity());
}
@@ -146,10 +149,10 @@ public class StreamChatForCampaignUseCaseTest {
when(campaignRepository.findById("c-1")).thenReturn(Optional.of(standalone));
when(campaignContextBuilder.build("c-1")).thenReturn(campaignCtx);
useCase.execute("c-1", "scene", " ", messages, onToken, onComplete, onError);
useCase.execute("c-1", "scene", " ", messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
assertNull(captor.getValue().getNarrativeEntity());
verifyNoInteractions(narrativeEntityContextBuilder);
}

View File

@@ -2,6 +2,7 @@ package com.loremind.application.generationcontext;
import com.loremind.domain.generationcontext.ChatMessage;
import com.loremind.domain.generationcontext.ChatRequest;
import com.loremind.domain.generationcontext.ChatUsage;
import com.loremind.domain.generationcontext.LoreStructuralContext;
import com.loremind.domain.generationcontext.ports.AiChatProvider;
import com.loremind.domain.lorecontext.FieldType;
@@ -46,6 +47,7 @@ public class StreamChatForLoreUseCaseTest {
private LoreStructuralContext loreCtx;
private List<ChatMessage> messages;
private Consumer<ChatUsage> onUsage;
private Consumer<String> onToken;
private Runnable onComplete;
private Consumer<Throwable> onError;
@@ -58,6 +60,7 @@ public class StreamChatForLoreUseCaseTest {
.folders(Collections.emptyMap())
.build();
messages = List.of();
onUsage = mock(Consumer.class);
onToken = mock(Consumer.class);
onComplete = mock(Runnable.class);
onError = mock(Consumer.class);
@@ -67,10 +70,10 @@ public class StreamChatForLoreUseCaseTest {
void testExecute_NoPageId_SendsRequestWithoutPageContext() {
when(loreContextBuilder.build("lore-1")).thenReturn(loreCtx);
useCase.execute("lore-1", null, messages, onToken, onComplete, onError);
useCase.execute("lore-1", null, messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), eq(onToken), eq(onComplete), eq(onError));
verify(aiChatProvider).streamChat(captor.capture(), eq(onUsage), eq(onToken), eq(onComplete), eq(onError));
ChatRequest req = captor.getValue();
assertSame(loreCtx, req.getLoreContext());
assertNull(req.getPageContext());
@@ -81,10 +84,10 @@ public class StreamChatForLoreUseCaseTest {
void testExecute_BlankPageId_TreatedAsNoPage() {
when(loreContextBuilder.build("lore-1")).thenReturn(loreCtx);
useCase.execute("lore-1", " ", messages, onToken, onComplete, onError);
useCase.execute("lore-1", " ", messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
assertNull(captor.getValue().getPageContext());
verifyNoInteractions(pageRepository);
}
@@ -108,10 +111,10 @@ public class StreamChatForLoreUseCaseTest {
when(pageRepository.findById("p-1")).thenReturn(Optional.of(page));
when(templateRepository.findById("tpl-1")).thenReturn(Optional.of(tpl));
useCase.execute("lore-1", "p-1", messages, onToken, onComplete, onError);
useCase.execute("lore-1", "p-1", messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
ChatRequest req = captor.getValue();
assertNotNull(req.getPageContext());
assertEquals("Alice", req.getPageContext().getTitle());
@@ -130,10 +133,10 @@ public class StreamChatForLoreUseCaseTest {
when(loreContextBuilder.build("lore-1")).thenReturn(loreCtx);
when(pageRepository.findById("p-1")).thenReturn(Optional.of(page));
useCase.execute("lore-1", "p-1", messages, onToken, onComplete, onError);
useCase.execute("lore-1", "p-1", messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
var pageCtx = captor.getValue().getPageContext();
assertNotNull(pageCtx);
assertEquals("Orphan", pageCtx.getTitle());
@@ -153,10 +156,10 @@ public class StreamChatForLoreUseCaseTest {
when(pageRepository.findById("p-1")).thenReturn(Optional.of(page));
when(templateRepository.findById("tpl-ghost")).thenReturn(Optional.empty());
useCase.execute("lore-1", "p-1", messages, onToken, onComplete, onError);
useCase.execute("lore-1", "p-1", messages, onUsage, onToken, onComplete, onError);
ArgumentCaptor<ChatRequest> captor = ArgumentCaptor.forClass(ChatRequest.class);
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any());
verify(aiChatProvider).streamChat(captor.capture(), any(), any(), any(), any());
var pageCtx = captor.getValue().getPageContext();
assertEquals("?", pageCtx.getTemplateName());
assertTrue(pageCtx.getTemplateFields().isEmpty());
@@ -168,7 +171,7 @@ public class StreamChatForLoreUseCaseTest {
when(pageRepository.findById("missing")).thenReturn(Optional.empty());
assertThrows(IllegalArgumentException.class,
() -> useCase.execute("lore-1", "missing", messages, onToken, onComplete, onError));
() -> useCase.execute("lore-1", "missing", messages, onUsage, onToken, onComplete, onError));
verifyNoInteractions(aiChatProvider);
}
}