<div x-data="chatbot()" class="chatbot-container">
<div @click="toggle()" class="chatbot-toggle">
<i class="fas fa-robot text-white text-2xl"></i>
</div>
<div class="chatbot-window" :class="{'open': isOpen}" x-cloak>
<!-- Header -->
<div class="bg-gradient-to-r from-[#006633] to-[#008844] text-white p-4">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-white bg-opacity-20 rounded-full flex items-center justify-center">
<i class="fas fa-robot text-xl"></i>
</div>
<div>
<h3 class="font-semibold">IBUNAS.IA</h3>
<p class="text-xs text-green-100">Assistant juridique intelligent</p>
</div>
</div>
<button @click="toggle()" class="text-white hover:text-gray-200">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<!-- Messages -->
<div id="chatbot-messages" class="flex-1 overflow-y-auto p-4 bg-gray-50 space-y-4">
<template x-for="message in messages" :key="message.id">
<div :class="message.sender === 'user' ? 'flex justify-end' : 'flex justify-start'">
<div :class="message.sender === 'user'
? 'bg-[#006633] text-white rounded-2xl rounded-br-none'
: 'bg-white border border-gray-200 text-gray-800 rounded-2xl rounded-bl-none'"
class="max-w-[80%] px-4 py-2 shadow-sm">
<p class="text-sm" x-text="message.text"></p>
<p class="text-xs mt-1 opacity-70" x-text="new Date(message.timestamp).toLocaleTimeString()"></p>
</div>
</div>
</template>
<div x-show="isLoading" class="flex justify-start">
<div class="bg-white border border-gray-200 rounded-2xl rounded-bl-none px-4 py-3">
<div class="flex space-x-1">
<div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div>
<div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
<div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style="animation-delay: 0.4s"></div>
</div>
</div>
</div>
</div>
<!-- Input -->
<div class="p-4 bg-white border-t">
<form @submit.prevent="send()" class="flex space-x-2">
<input type="text"
x-model="currentMessage"
placeholder="Posez votre question..."
class="flex-1 border border-gray-300 rounded-xl px-4 py-2 focus:outline-none focus:border-[#006633] focus:ring-1 focus:ring-[#006633]">
<button type="submit"
:disabled="isLoading"
class="bg-gradient-to-r from-[#006633] to-[#008844] text-white px-4 py-2 rounded-xl hover:from-[#004d26] hover:to-[#006633] transition disabled:opacity-50">
<i class="fas fa-paper-plane"></i>
</button>
</form>
<div class="mt-2 text-xs text-gray-400 text-center">
<i class="fas fa-lightbulb mr-1"></i> Ex: "Rechercher la loi sur l'urbanisme" | "Derniers décrets"
</div>
</div>
</div>
</div>
<style>
.chatbot-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
}
.chatbot-toggle {
width: 60px;
height: 60px;
background: linear-gradient(135deg, #006633, #008844);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
transition: transform 0.3s ease;
}
.chatbot-toggle:hover {
transform: scale(1.1);
}
.chatbot-window {
position: absolute;
bottom: 80px;
right: 0;
width: 380px;
height: 500px;
background: white;
border-radius: 20px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
display: flex;
flex-direction: column;
overflow: hidden;
transition: all 0.3s ease;
opacity: 0;
transform: scale(0.8);
transform-origin: bottom right;
pointer-events: none;
}
.chatbot-window.open {
opacity: 1;
transform: scale(1);
pointer-events: all;
}
@media (max-width: 640px) {
.chatbot-window {
width: calc(100vw - 40px);
right: 0;
left: auto;
}
}
[x-cloak] {
display: none;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
.animate-bounce {
animation: bounce 0.6s infinite;
}
</style>
<script>
function chatbot() {
return {
isOpen: false,
isLoading: false,
currentMessage: '',
messages: [
{
id: 1,
sender: 'bot',
text: 'Bonjour ! Je suis IBUNAS.IA, votre assistant juridique intelligent. Je peux vous aider à rechercher des lois, décrets, arrêtés et vous informer sur les publications officielles. Comment puis-je vous aider ?',
timestamp: Date.now()
}
],
toggle() {
this.isOpen = !this.isOpen;
if (this.isOpen) {
this.$nextTick(() => {
this.scrollToBottom();
});
}
},
async send() {
if (!this.currentMessage.trim()) return;
if (this.isLoading) return;
// Ajouter le message de l'utilisateur
const userMessage = {
id: Date.now(),
sender: 'user',
text: this.currentMessage,
timestamp: Date.now()
};
this.messages.push(userMessage);
const question = this.currentMessage;
this.currentMessage = '';
this.isLoading = true;
this.$nextTick(() => {
this.scrollToBottom();
});
try {
// Appel à l'API
const response = await this.callAPI(question);
const botMessage = {
id: Date.now() + 1,
sender: 'bot',
text: response,
timestamp: Date.now()
};
this.messages.push(botMessage);
} catch (error) {
console.error('Erreur:', error);
const errorMessage = {
id: Date.now() + 1,
sender: 'bot',
text: "Désolé, une erreur s'est produite. Veuillez réessayer ou contacter l'administrateur.",
timestamp: Date.now()
};
this.messages.push(errorMessage);
} finally {
this.isLoading = false;
this.$nextTick(() => {
this.scrollToBottom();
});
}
},
async callAPI(question) {
// Configuration de l'API - À remplacer par votre URL réelle
const API_URL = '/api/chatbot'; // Remplacez par votre endpoint API
const API_KEY = 'votre-cle-api'; // Si nécessaire
// Simuler une réponse API pour la démonstration (à supprimer quand l'API est prête)
const reponsesSimulees = this.getSimulatedResponse(question);
if (reponsesSimulees) {
// Simuler un délai réseau
await new Promise(resolve => setTimeout(resolve, 1000));
return reponsesSimulees;
}
// Appel API réel
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-Key': API_KEY
},
body: JSON.stringify({
question: question,
context: this.getConversationContext()
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.reponse || data.message || data.text || "Je n'ai pas compris votre question. Pouvez-vous reformuler ?";
} catch (error) {
console.error('API Error:', error);
// Fallback vers la simulation si l'API échoue
return this.getSimulatedResponse(question) || "Désolé, je ne peux pas répondre pour le moment. Veuillez réessayer plus tard.";
}
},
getConversationContext() {
// Récupérer les 5 derniers messages pour le contexte
const lastMessages = this.messages.slice(-5);
return lastMessages.map(msg => ({
role: msg.sender === 'user' ? 'user' : 'assistant',
content: msg.text
}));
},
getSimulatedResponse(question) {
const q = question.toLowerCase();
// Réponses simulées basées sur le contenu du Journal Officiel
if (q.includes('bonjour') || q.includes('salut') || q.includes('coucou')) {
return "Bonjour ! Comment puis-je vous aider avec les publications du Journal Officiel aujourd'hui ?";
}
if (q.includes('loi') || q.includes('code')) {
if (q.includes('impôt') || q.includes('impots') || q.includes('fiscal')) {
return "📜 **Code général des impôts 2026**\n\nLe nouveau code général des impôts a été publié dans le JO n°2026-014 du 25 février 2026. Les principales modifications concernent :\n\n• Nouveau barème de l'IRPP\n• Réduction du taux de l'IS de 30% à 25%\n• Nouvelles exonérations pour les zones franches\n\nSouhaitez-vous plus de détails sur un article spécifique ?";
}
if (q.includes('investissement') || q.includes('investissements')) {
return "📜 **Loi sur les investissements n°2026-001**\n\nPubliée au JO du 15 janvier 2026, cette loi modifie le code des investissements. Les principaux avantages :\n\n• Exonération totale d'impôts pendant 5 ans\n• Réduction des droits de douane\n• Simplification des procédures administratives\n\nPuis-je vous aider à trouver des informations plus spécifiques ?";
}
if (q.includes('urbanisme') || q.includes('construction')) {
return "📜 **Code de l'urbanisme**\n\nLa version consolidée du code de l'urbanisme est disponible dans nos archives. Les dernières modifications datent de janvier 2026. Vous pouvez consulter :\n\n• Les règles de constructibilité\n• Les permis de construire\n• Les plans d'occupation des sols\n\nSouhaitez-vous que je recherche un article particulier ?";
}
return "📚 **Textes législatifs disponibles**\n\nNous avons plusieurs lois récentes :\n\n• Loi n°2026-001 sur les investissements\n• Loi n°2026-002 sur le blanchiment\n• Code général des impôts 2026\n• Code du travail révisé\n\nQuelle loi vous intéresse précisément ?";
}
if (q.includes('décret') || q.includes('decret') || q.includes('arrêté') || q.includes('arrete')) {
if (q.includes('nomination')) {
return "📋 **Décret n°2026-045/PR**\n\nPublié le 20 janvier 2026, ce décret porte nomination des membres du gouvernement. La composition complète est disponible dans le JO n°2026-013.\n\nSouhaitez-vous la liste complète des ministres ?";
}
if (q.includes('agence') || q.includes('numérique')) {
return "📋 **Décret n°2026-044/PR**\n\nCréation de l'Agence Nationale du Numérique (ANN) publiée dans le JO du 20 février 2026. L'agence est chargée de :\n\n• Coordonner la transformation numérique\n• Gérer les infrastructures TIC publiques\n• Promouvoir l'e-gouvernement";
}
return "📋 **Décrets et arrêtés récents**\n\nDernières publications :\n\n• Décret n°2026-045/PR - Nomination gouvernement\n• Décret n°2026-044/PR - Création ANN\n• Arrêté n°2026-089/MF - Modalités paiement impôts\n\nLequel souhaitez-vous consulter ?";
}
if (q.includes('journal officiel') || q.includes('jo') || q.includes('numéro') || q.includes('numero')) {
if (q.includes('2026-015') || q.includes('015')) {
return "📰 **Journal Officiel n°2026-015**\n\nPublié le 1er mars 2026, ce numéro contient :\n\n• 12 actes publiés\n• 5 institutions émetteurs\n• 1 234 consultations\n\nContenu principal :\n- Loi de finances rectificative\n- Décrets d'application\n- Appels d'offres\n\nSouhaitez-vous télécharger la version PDF ?";
}
if (q.includes('2026-014') || q.includes('014')) {
return "📰 **Journal Officiel n°2026-014**\n\nPublié le 25 février 2026 :\n\n• 8 actes publiés\n• Code général des impôts 2026\n• Arrêtés ministériels\n\nTéléchargement PDF disponible sur demande.";
}
if (q.includes('2026-013') || q.includes('013')) {
return "📰 **Journal Officiel n°2026-013**\n\nPublié le 20 février 2026 :\n\n• 15 actes publiés\n• Nominations gouvernementales\n• Création de l'Agence Nationale du Numérique\n• Textes réglementaires";
}
if (q.includes('2026-012') || q.includes('012')) {
return "📰 **Journal Officiel n°2026-012**\n\nPublié le 15 février 2026 :\n\n• 10 actes publiés\n• Lois sur les investissements\n• Réformes administratives";
}
return "📰 **Derniers numéros du Journal Officiel**\n\n• JO 2026-015 (01 Mars 2026) - 12 actes\n• JO 2026-014 (25 Fév 2026) - 8 actes\n• JO 2026-013 (20 Fév 2026) - 15 actes\n• JO 2026-012 (15 Fév 2026) - 10 actes\n\nQuel numéro souhaitez-vous consulter ?";
}
if (q.includes('appel') || q.includes('offre') || q.includes('marché') || q.includes('marche')) {
return "🏗️ **Appels d'offres en cours**\n\nDerniers appels d'offres publiés :\n\n1. **AO n°2026-001** - Construction nouvelle Présidence\n Date limite : 30/04/2026\n\n2. **AO n°2026-002** - Fourniture matériel informatique\n Date limite : 15/04/2026\n\n3. **Consultation** - Étude faisabilité port\n Date limite : 30/05/2026\n\nSouhaitez-vous plus de détails sur un appel d'offres spécifique ?";
}
if (q.includes('association') || q.includes('récépissé') || q.includes('recepisse')) {
return "🏢 **Associations**\n\nLes récépissés de déclaration d'associations sont publiés dans les JO. Tarifs :\n\n• Déclaration : 12 000 KMF\n• Modification statuts : 8 000 KMF\n• Dissolution : 5 000 KMF\n\nBesoin d'aide pour préparer votre dossier ?";
}
if (q.includes('foncier') || q.includes('terrain') || q.includes('propriété')) {
return "🏠 **Actes fonciers**\n\nLes réquisitions foncières et transactions immobilières sont publiées au JO. Tarifs :\n\n• Base : 15 000 KMF\n• +3 000 KMF / 300 caractères\n\nNous pouvons vous aider à publier votre annonce foncière.";
}
if (q.includes('abonnement') || q.includes('abonner') || q.includes('prix') || q.includes('tarif')) {
return "💳 **Nos offres d'abonnement**\n\n**Standard** : 50 000 KMF/an\n• Accès numéros complets PDF\n• Recherche par filtres\n• Textes isolés moins de 5 ans\n\n**Premium** : 90 000 KMF/an\n• Tout Standard +\n• Archives complètes depuis 1975\n• Recherche IA avancée\n• Alertes personnalisées\n\n**-20% sur la première année !**\n\nSouhaitez-vous vous abonner ?";
}
if (q.includes('contact') || q.includes('aide') || q.includes('support')) {
return "📞 **Nous contacter**\n\n• Email : contact@journalofficiel.km\n• Téléphone : +269 123 45 67\n• Horaires : Lundi-Vendredi 8h-17h\n\nNotre équipe vous répondra dans les meilleurs délais.";
}
if (q.includes('merci')) {
return "Avec plaisir ! N'hésitez pas si vous avez d'autres questions. Je suis là pour vous aider ! 🙏";
}
// Réponse par défaut
return "Je suis votre assistant pour le Journal Officiel de l'Union des Comores. Je peux vous aider à :\n\n• 📰 Consulter les derniers numéros du JO\n• 📜 Rechercher des lois, décrets et arrêtés\n• 🏗️ Trouver des appels d'offres\n• 💳 Vous informer sur les tarifs de publication\n• 📞 Vous orienter vers les services compétents\n\nQue puis-je faire pour vous aujourd'hui ?";
},
scrollToBottom() {
const container = document.getElementById('chatbot-messages');
if (container) {
container.scrollTop = container.scrollHeight;
}
}
}
}
</script>