File size: 8,517 Bytes
040db21
37619a6
040db21
23f07ff
 
b728b86
d510348
 
fe49da4
d510348
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
edad585
d510348
 
edad585
d510348
a5874c3
d510348
 
 
 
 
 
 
 
 
 
 
 
b728b86
edad585
d510348
 
b728b86
d510348
 
 
 
b728b86
 
d510348
 
 
 
 
 
 
 
 
 
 
 
b728b86
fe49da4
d510348
b728b86
d510348
 
 
b728b86
23f07ff
d510348
 
 
 
 
 
 
b728b86
fe49da4
d510348
 
 
 
 
 
 
 
fe49da4
d510348
 
 
 
 
 
 
 
 
 
 
 
 
 
23f07ff
d510348
 
b728b86
 
 
d510348
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68ce09b
d510348
 
 
 
 
 
 
 
 
 
 
 
b728b86
a5874c3
040db21
0d2d16d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mariam AI!</title>
    <!-- Tailwind CSS via CDN -->
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        /* Style personnalisé pour la barre de défilement (optionnel) */
        ::-webkit-scrollbar {
            width: 8px;
        }
        ::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 10px;
        }
        ::-webkit-scrollbar-thumb {
            background: #888;
            border-radius: 10px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background: #555;
        }
        /* Empêche le FOUC (Flash of Unstyled Content) */
        [x-cloak] { display: none !important; }
    </style>
    <!-- Alpine.js pour une interactivité simple (optionnel mais utile) -->
    <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen" x-data="{ processing: {{ 'true' if processing_message else 'false' }} }">

<div class="chat-container bg-white rounded-lg shadow-xl w-full max-w-3xl h-[90vh] flex flex-col" x-cloak>
    <!-- En-tête -->
    <div class="chat-header bg-gradient-to-r from-emerald-500 to-teal-600 text-white p-4 rounded-t-lg flex justify-between items-center">
        <h1 class="text-xl font-semibold">Mariam AI!</h1>
        <!-- Bouton pour effacer (optionnel mais utile) -->
        <form action="{{ url_for('clear_chat') }}" method="post" onsubmit="return confirm('Voulez-vous vraiment effacer la conversation ?');">
             <button type="submit" title="Effacer la conversation" class="text-white hover:text-red-300 transition duration-150">
                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12.576 0a48.108 48.108 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
                </svg>
            </button>
        </form>
    </div>

    <!-- Zone des messages -->
    <div class="chat-messages flex-grow overflow-y-auto p-4 md:p-6 space-y-4" id="chat-messages">
        {% for message in chat_history %}
            <div class="message flex {% if message.role == 'user' %}justify-end{% else %}justify-start{% endif %}">
                <div class="max-w-xs md:max-w-md lg:max-w-lg px-4 py-2 rounded-lg shadow {% if message.role == 'user' %}bg-emerald-500 text-white rounded-br-none{% else %}bg-gray-200 text-gray-800 rounded-bl-none{% endif %}">
                    <p class="text-sm break-words whitespace-pre-wrap">{{ message.text }}</p>
                </div>
            </div>
        {% endfor %}

        <!-- Indicateur de chargement -->
        <div x-show="processing" class="flex justify-center items-center py-4">
            <div class="animate-spin rounded-full h-6 w-6 border-b-2 border-emerald-500"></div>
            <span class="ml-2 text-gray-500 italic">
                {% if session.get('processing_web_search') %}
                Recherche web et génération en cours...
                {% else %}
                Génération de la réponse...
                {% endif %}
            </span>
        </div>
    </div>

    <!-- Affichage des erreurs -->
    {% if error %}
    <div class="error-message bg-red-100 border border-red-400 text-red-700 px-4 py-2 rounded-md mx-4 mb-2 text-sm">
        <strong>Erreur :</strong> {{ error }}
    </div>
    {% endif %}

    <!-- Zone de saisie et options -->
    <div class="chat-input-area border-t border-gray-200 p-4 bg-gray-50 rounded-b-lg">
        <form method="POST" action="{{ url_for('chat') }}" enctype="multipart/form-data" id="chat-form" @submit="processing = true">
            <!-- Options : Recherche Web & Upload -->
            <div class="options flex flex-col sm:flex-row justify-between items-center mb-3 gap-3 text-sm text-gray-600">
                 <label for="web_search_toggle" class="flex items-center cursor-pointer">
                    <input type="checkbox" id="web_search_toggle" name="web_search" value="true" {% if web_search_active %}checked{% endif %} class="mr-2 h-4 w-4 rounded border-gray-300 text-emerald-600 focus:ring-emerald-500">
                    Activer la recherche web
                </label>

                <label for="file_upload" class="flex items-center cursor-pointer bg-white border border-gray-300 rounded-md px-3 py-1 hover:bg-gray-50 transition duration-150">
                     <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2 text-gray-500">
                       <path stroke-linecap="round" stroke-linejoin="round" d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.122 2.122l7.81-7.81" />
                     </svg>
                    <span id="file-label-text">Joindre un fichier</span> (.jpg, .png, .pdf, .txt)
                    <input type="file" id="file_upload" name="file" class="hidden" accept=".jpg,.jpeg,.png,.pdf,.txt" onchange="updateFileLabel(this)">
                </label>
            </div>

            <!-- Champ de saisie et bouton envoyer -->
            <div class="flex items-center gap-2">
                <input type="text" name="prompt" id="prompt-input" placeholder="Posez votre question à Mariam..." required autofocus
                       class="flex-grow p-3 border border-gray-300 rounded-full focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-transparent transition duration-150"
                       :disabled="processing"> <!-- Désactivé pendant le traitement -->

                <button type="submit" id="send-button"
                        class="bg-emerald-500 hover:bg-emerald-600 text-white rounded-full p-3 focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-1 transition duration-150 disabled:opacity-50 disabled:cursor-not-allowed"
                        :disabled="processing"> <!-- Désactivé pendant le traitement -->
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
                      <path stroke-linecap="round" stroke-linejoin="round" d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
                    </svg>
                </button>
            </div>
        </form>
    </div>
</div>

<script>
    // Fonction pour faire défiler vers le bas
    function scrollToBottom() {
        const chatMessages = document.getElementById('chat-messages');
        chatMessages.scrollTop = chatMessages.scrollHeight;
    }

    // Fonction pour mettre à jour le label du fichier
    function updateFileLabel(input) {
        const fileLabel = document.getElementById('file-label-text');
        if (input.files && input.files.length > 0) {
            fileLabel.textContent = input.files[0].name;
        } else {
            fileLabel.textContent = 'Joindre un fichier';
        }
    }

    // Faire défiler vers le bas au chargement initial
    window.addEventListener('load', scrollToBottom);

    // Optionnel : Faire défiler après un léger délai pour s'assurer que tout est rendu (peut aider sur certains navigateurs)
    setTimeout(scrollToBottom, 100);

    // Optionnel : Si vous vouliez effacer le champ après envoi (ne fonctionne pas bien avec le rechargement de page standard)
    /*
    const chatForm = document.getElementById('chat-form');
    const promptInput = document.getElementById('prompt-input');
    chatForm.addEventListener('submit', function() {
        // Déjà géré par Alpine.js : document.getElementById('send-button').disabled = true;
        // Peut causer des problèmes si la soumission échoue avant le rechargement
        // setTimeout(() => { promptInput.value = ''; }, 50);
    });
    */

</script>

</body>
</html>