1- from typing import Optional , Dict , Any
1+ from typing import Any , Dict
22from typing_extensions import Annotated
3- from zenml import log_artifact_metadata , pipeline , step
3+ from zenml import get_step_context , log_metadata , step
4+ from zenml .metadata .metadata_types import Uri
45from zenml .types import HTMLString
6+ from zenml .utils .dashboard_utils import get_model_version_url
57
68@step (enable_cache = False )
79def create_chat_interface (
810 deployment_info : Dict [str , Any ],
911 ) -> Annotated [HTMLString , "chat_bot" ]:
12+ step_context = get_step_context ()
1013 html = """
1114 <div id="zenml-chat-container" class="w-full max-w-4xl mx-auto">
1215 <style>
@@ -138,7 +141,6 @@ def create_chat_interface(
138141 margin-bottom: 0;
139142 }
140143
141- /* Ensure proper text wrapping */
142144 .zenml-message-content * {
143145 max-width: 100%;
144146 overflow-wrap: break-word;
@@ -147,17 +149,12 @@ def create_chat_interface(
147149 }
148150 </style>
149151
150- <div id="zenml-chat-window">
152+ <div id="zenml-chat-window">
151153 <div id="zenml-chat-header">
152154 <h1>ZenML Assistant</h1>
153155 </div>
154156
155157 <div id="zenml-chat-messages">
156- <div class="zenml-message">
157- <div class="zenml-message-content">
158- Hi! I'm your ZenML assistant. How can I help you today?
159- </div>
160- </div>
161158 <div id="zenml-typing-indicator">
162159 Assistant is typing...
163160 </div>
@@ -171,19 +168,66 @@ def create_chat_interface(
171168
172169 <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
173170 <script>
171+ // Initialize immediately instead of waiting for load event
174172 (function() {
173+ const STORAGE_KEY = 'zenmlChatHistory-' + window.location.pathname;
175174 const chatMessages = document.getElementById('zenml-chat-messages');
176175 const userInput = document.getElementById('zenml-user-input');
177176 const sendButton = document.getElementById('zenml-send-button');
178177 const typingIndicator = document.getElementById('zenml-typing-indicator');
179-
180- userInput.addEventListener('keypress', function(e) {
181- if (e.key === 'Enter') {
182- sendMessage();
178+ let messages = [];
179+
180+ // Initialize chat history immediately
181+ function initializeChatHistory() {
182+ try {
183+ const storedMessages = localStorage.getItem(STORAGE_KEY);
184+ if (storedMessages) {
185+ messages = JSON.parse(storedMessages);
186+ if (Array.isArray(messages) && messages.length > 0) {
187+ messages.forEach(message => appendMessage(message.text, message.isUser, true));
188+ } else {
189+ addInitialMessage();
190+ }
191+ } else {
192+ addInitialMessage();
193+ }
194+ } catch (error) {
195+ console.error('Error loading chat history:', error);
196+ addInitialMessage();
183197 }
184- });
185-
186- sendButton.addEventListener('click', sendMessage);
198+ }
199+
200+ function addInitialMessage() {
201+ const initialMessage = "Hi! I'm your ZenML assistant. How can I help you today?";
202+ appendMessage(initialMessage, false);
203+ }
204+
205+ function appendMessage(text, isUser, isLoading = false) {
206+ const messageDiv = document.createElement('div');
207+ messageDiv.className = `zenml-message ${isUser ? 'user' : ''}`;
208+
209+ const contentDiv = document.createElement('div');
210+ contentDiv.className = 'zenml-message-content';
211+
212+ if (!isUser) {
213+ contentDiv.innerHTML = marked.parse(text);
214+ } else {
215+ contentDiv.textContent = text;
216+ }
217+
218+ messageDiv.appendChild(contentDiv);
219+ chatMessages.insertBefore(messageDiv, typingIndicator);
220+ chatMessages.scrollTop = chatMessages.scrollHeight;
221+
222+ if (!isLoading) {
223+ messages.push({ text, isUser });
224+ try {
225+ localStorage.setItem(STORAGE_KEY, JSON.stringify(messages));
226+ } catch (error) {
227+ console.error('Error saving to localStorage:', error);
228+ }
229+ }
230+ }
187231
188232 async function sendMessage() {
189233 const message = userInput.value.trim();
@@ -239,25 +283,26 @@ def create_chat_interface(
239283 userInput.focus();
240284 }
241285
242- function appendMessage(text, isUser) {
243- const messageDiv = document.createElement('div');
244- messageDiv.className = `zenml-message ${isUser ? 'user' : ''}`;
245-
246- const contentDiv = document.createElement('div');
247- contentDiv.className = 'zenml-message-content';
248-
249- if (!isUser) {
250- contentDiv.innerHTML = marked.parse(text);
251- } else {
252- contentDiv.textContent = text;
286+ userInput.addEventListener('keypress', function(e) {
287+ if (e.key === 'Enter') {
288+ sendMessage();
253289 }
254-
255- messageDiv.appendChild(contentDiv);
256- chatMessages.appendChild(messageDiv);
257- chatMessages.scrollTop = chatMessages.scrollHeight;
258- }
290+ });
291+
292+ sendButton.addEventListener('click', sendMessage);
293+
294+ // Initialize immediately
295+ initializeChatHistory();
259296 })();
260297 </script>
261298 </div>
262299 """
300+ model_version_url = get_model_version_url (step_context .model .id )
301+ log_metadata (
302+ infer_artifact = True ,
303+ metadata = {
304+ "deployment_info" : deployment_info ,
305+ "deployment_url" : Uri (f"{ model_version_url } /?tab=deployments" ),
306+ },
307+ )
263308 return HTMLString (html )
0 commit comments