- ChatbotV2.vue : Vue island, thread chat (input + messages bot/user), persistance sessionStorage, bandeau beta '120 fiches AEP, RAG-PE bientot', gestion erreurs 429/502/504 ; pas de streaming ni markdown V1 - /api/chatbot.ts : endpoint Astro server proxy POST vers CHATBOT_UPSTREAM (default https://aep.trans-former.fr/api/chatbot), timeout 25s, body { question, history } -> upstream classique chatbot AEP Mistral Small - astro.config.mjs : output 'server' + adapter @astrojs/node standalone (Astro 6 a supprime mode hybrid ; on opt-in prerender sur les pages) - Toutes les pages publiques (index, manifeste, manifeste/commander, a-propos, mentions-legales) ont 'export const prerender = true' - ColCentre.astro : remplace ChatbotPlaceholder par ChatbotV2 dans le tab - .env.example : ajoute CHATBOT_UPSTREAM (V1.5 = switch LightRAG-PE 1 ligne) Decision V1 : endpoint AEP /api/chatbot (classique, repond bien) au lieu de /api/chatbot-v2 qui retourne v2_ready=false ('base vectorielle en cours'). Bandeau beta reste valide ; switch v2 quand ready cote AEP via env var. Note PC8 deploy : Coolify doit booter avec 'node ./dist/server/entry.mjs' (SSR Node standalone) au lieu de servir dist/client/ static. Test end-to-end OK : SSR boot port 4399 + curl POST /api/chatbot -> reponse_texte 800+ chars de l'AEP backend.
94 lines
2.9 KiB
Plaintext
94 lines
2.9 KiB
Plaintext
---
|
|
// Centre - HAUT : tabs (Carte O mindmap | Chatbot RAG branche PC7).
|
|
// BAS : iframe carte AEP + scroll articles Substack (PC4).
|
|
import CarteOWrapper from '../vue/CarteOWrapper.vue';
|
|
import ChatbotV2 from '../vue/ChatbotV2.vue';
|
|
import IframeCarteAEP from './IframeCarteAEP.astro';
|
|
import ScrollArticles from './ScrollArticles.astro';
|
|
---
|
|
<div class="h-full grid grid-rows-2 gap-2 p-2">
|
|
<!-- HAUT 50% : tabs Carte O / Chatbot -->
|
|
<section class="border border-neutral-200 rounded flex flex-col overflow-hidden bg-white">
|
|
<nav role="tablist" aria-label="Vues centrales" class="flex border-b border-neutral-200 px-1 pt-1">
|
|
<button
|
|
type="button"
|
|
role="tab"
|
|
id="tab-mindmap"
|
|
aria-controls="panel-mindmap"
|
|
aria-selected="true"
|
|
data-tab="mindmap"
|
|
class="tab-btn px-3 py-2 text-sm border-b-2 border-neutral-900 font-medium text-neutral-900"
|
|
>
|
|
Carte O
|
|
</button>
|
|
<button
|
|
type="button"
|
|
role="tab"
|
|
id="tab-chatbot"
|
|
aria-controls="panel-chatbot"
|
|
aria-selected="false"
|
|
data-tab="chatbot"
|
|
class="tab-btn px-3 py-2 text-sm border-b-2 border-transparent text-neutral-500 hover:text-neutral-900"
|
|
>
|
|
Chatbot
|
|
</button>
|
|
</nav>
|
|
|
|
<div class="flex-1 overflow-hidden relative">
|
|
<div
|
|
id="panel-mindmap"
|
|
role="tabpanel"
|
|
aria-labelledby="tab-mindmap"
|
|
data-tab-panel="mindmap"
|
|
class="absolute inset-0"
|
|
>
|
|
<CarteOWrapper client:visible />
|
|
</div>
|
|
<div
|
|
id="panel-chatbot"
|
|
role="tabpanel"
|
|
aria-labelledby="tab-chatbot"
|
|
data-tab-panel="chatbot"
|
|
class="absolute inset-0 hidden"
|
|
>
|
|
<ChatbotV2 client:visible />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- BAS 50% : iframe carte AEP + scroll articles Substack (PC4) -->
|
|
<section class="border border-neutral-200 rounded overflow-y-auto bg-white">
|
|
<div class="h-full min-h-[60vh] md:min-h-[400px]">
|
|
<IframeCarteAEP />
|
|
</div>
|
|
<ScrollArticles />
|
|
</section>
|
|
</div>
|
|
|
|
<script>
|
|
// Tabs toggle.
|
|
const tabs = document.querySelectorAll<HTMLButtonElement>('[data-tab]');
|
|
const panels = document.querySelectorAll<HTMLElement>('[data-tab-panel]');
|
|
|
|
tabs.forEach((tab) => {
|
|
tab.addEventListener('click', () => {
|
|
const target = tab.dataset.tab;
|
|
if (!target) return;
|
|
|
|
tabs.forEach((t) => {
|
|
const active = t.dataset.tab === target;
|
|
t.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
t.classList.toggle('border-neutral-900', active);
|
|
t.classList.toggle('border-transparent', !active);
|
|
t.classList.toggle('font-medium', active);
|
|
t.classList.toggle('text-neutral-900', active);
|
|
t.classList.toggle('text-neutral-500', !active);
|
|
});
|
|
|
|
panels.forEach((p) => {
|
|
p.classList.toggle('hidden', p.dataset.tabPanel !== target);
|
|
});
|
|
});
|
|
});
|
|
</script>
|