User: I want to add an AI renaming feature to my AI assistant interface website. When the user clicks on the existing rename button, instead of being prompted to enter a name, a request will be sent to the existing AI model to summarise the chat in 5 words. Then, this will become the new name of the chat, all in the background. It should use the predefined model in the backend, and not any user models, to make sure it doesn't cost money for the user.<div><br></div><code fileName="ChatInterface.js" notes="">// src/components/ChatInterface.js
import React, { useState, useContext, useRef, useEffect, useCallback } from &quot;react&quot;;
import { ChatContext } from &quot;../context/ChatContext&quot;;
import Message from &quot;./Message&quot;;
import CodeModal from &quot;./CodeModal&quot;;
import InlineCodeEditor from &quot;./InlineCodeEditor&quot;;
import { escapeHtml } from &quot;../utils/escapeHtml&quot;;

function ChatInterface() {
  const {
    chats,
    currentChatId,
    addMessage,
    updateChat,
    selectedModelId,
    models,
  } = useContext(ChatContext);
  const currentChat = chats.find((chat) =&gt; chat.id === currentChatId);
  const [message, setMessage] = useState(&quot;&quot;);
  const [isTyping, setIsTyping] = useState(false);
  const messagesEndRef = useRef(null);
  const [isCodeModalOpen, setIsCodeModalOpen] = useState(false);
  const [currentEditingCode, setCurrentEditingCode] = useState(null);
  const [isSystemPromptOpen, setIsSystemPromptOpen] = useState(false);

  const addCodeAttachment = ({ codeContent, fileName, notes }) =&gt; {
    const escapedCode = escapeHtml(codeContent);
    const escapedFileName = escapeHtml(fileName || &quot;untitled&quot;);
    const escapedNotes = escapeHtml(notes || &quot;&quot;);
    const codeTag = `&lt;code fileName=&quot;${escapedFileName}&quot; notes=&quot;${escapedNotes}&quot;&gt;${escapedCode}&lt;/code&gt;`;
    setMessage((prev) =&gt; prev + codeTag);
  };

  const handleAttachCode = useCallback((codeSegment = null) =&gt; {
    setCurrentEditingCode(codeSegment);
    setIsCodeModalOpen(true);
  }, []);

  const handleCodeSave = (updatedCode) =&gt; {
    if (currentEditingCode) {
      // Update existing code
      const escapedCode = escapeHtml(updatedCode.codeContent);
      const escapedFileName = escapeHtml(updatedCode.fileName || &quot;untitled&quot;);
      const escapedNotes = escapeHtml(updatedCode.notes || &quot;&quot;);

      // Improved regex to handle multi-line and special characters
      const regex = new RegExp(
        `&lt;code\\s+fileName=&quot;${currentEditingCode.fileName}&quot;\\s+notes=&quot;${currentEditingCode.notes}&quot;&gt;([\\s\\S]*?)&lt;\\/code&gt;`
      );

      const updatedMessage = message.replace(
        regex,
        `&lt;code fileName=&quot;${escapedFileName}&quot; notes=&quot;${escapedNotes}&quot;&gt;${escapedCode}&lt;/code&gt;`
      );
      setMessage(updatedMessage);
    } else {
      // Add new code
      addCodeAttachment(updatedCode);
    }
    setIsCodeModalOpen(false);
    setCurrentEditingCode(null);
  };

  const handleSend = useCallback(async () =&gt; {
    if (!message.trim() || !currentChatId || !selectedModelId) return;

    // Retrieve the system prompt from the current chat
    const systemPrompt = currentChat.systemPrompt || &quot;&quot;;

    // Combine the system prompt with the user message
    // Ensure there&#039;s a separator (like a newline) for clarity
    const fullMessage = systemPrompt ? `${systemPrompt}\n${message}` : message;

    const userMessage = { sender: &quot;user&quot;, text: message };
    addMessage(currentChatId, userMessage);
    setMessage(&quot;&quot;);
    scrollToBottom();

    // Set typing indicator
    setIsTyping(true);

    try {
      const response = await fetch(&quot;http://localhost:8000/api/chat&quot;, {
        method: &quot;POST&quot;,
        headers: { &quot;Content-Type&quot;: &quot;application/json&quot; },
        body: JSON.stringify({
          session_id: currentChatId,
          text: fullMessage,
          model_id: selectedModelId, // Ensure this is correctly set
        }),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(
          errorData.detail || &quot;Failed to get response from the server.&quot;
        );
      }

      const data = await response.json();
      const responseText = data.response;
      const responseModelId = data.model_id; // Extract model_id from response

      const botMessage = {
        sender: &quot;bot&quot;,
        text: responseText,
        model_id: responseModelId, // Include model_id
      };
      addMessage(currentChatId, botMessage);
      scrollToBottom();
    } catch (error) {
      console.error(&quot;Error:&quot;, error);
      const errorMessage = {
        sender: &quot;bot&quot;,
        text: &quot;Sorry, something went wrong. Please try again.&quot;,
      };
      addMessage(currentChatId, errorMessage);
      scrollToBottom();
    } finally {
      // Remove typing indicator
      setIsTyping(false);
    }
  });

  const handleKeyDown = useCallback(
    (e) =&gt; {
      if (e.key === &quot;Enter&quot; &amp;&amp; !e.shiftKey) {
        e.preventDefault();
        handleSend();
      }
    },
    [handleSend]
  );

  const handleEditorKeyDown = useCallback((e) =&gt; {
    if (e.key === &#039;Enter&#039; &amp;&amp; !e.shiftKey) {
      e.preventDefault();
      handleSend();
    }
  }, [handleSend]);


  const scrollToBottom = useCallback(() =&gt; {
    messagesEndRef.current?.scrollIntoView({ behavior: &quot;smooth&quot; });
  }, []);

  if (!currentChat) {
    return (
      &lt;div className=&quot;flex-1 p-4&quot;&gt;No active chat. Please start a new chat.&lt;/div&gt;
    );
  }

  const handleSystemPromptChange = (e) =&gt; {
    const newPrompt = e.target.value;
    updateChat(currentChatId, { systemPrompt: newPrompt });
  };

  const toggleSystemPrompt = () =&gt; {
    setIsSystemPromptOpen(!isSystemPromptOpen);
  };

  return (
    &lt;div className=&quot;flex flex-col h-screen&quot;&gt;
      &lt;div className=&quot;flex-1 p-32 pt-8 pb-8 overflow-y-auto bg-[#eeeeee] dark:bg-[#161618]&quot;&gt;
        {/* Removed Model Selector Dropdown */}

        {/* Chat Messages */}
        {currentChat.messages.map((msg, index) =&gt; (
          &lt;Message
            key={index}
            chatId={currentChatId}
            messageIndex={index}
            sender={msg.sender}
            text={msg.text}
            model_id={msg.model_id} // Pass model_id
          /&gt;
        ))}
        {isTyping &amp;&amp; (
          &lt;div className=&quot;mb-4 flex justify-start&quot;&gt;
            &lt;div className=&quot;max-w-xs md:max-w-md lg:max-w-lg p-3 rounded-lg bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 flex items-center&quot;&gt;
              &lt;div className=&quot;flex space-x-1 mr-2&quot;&gt;
                &lt;div className=&quot;w-2 h-2 bg-gray-600 rounded-full animate-bounce-custom animation-delay-0&quot;&gt;&lt;/div&gt;
                &lt;div className=&quot;w-2 h-2 bg-gray-600 rounded-full animate-bounce-custom animation-delay-200&quot;&gt;&lt;/div&gt;
                &lt;div className=&quot;w-2 h-2 bg-gray-600 rounded-full animate-bounce-custom animation-delay-400&quot;&gt;&lt;/div&gt;
              &lt;/div&gt;
              &lt;span className=&quot;text-sm&quot;&gt;Echo is typing...&lt;/span&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        )}
        &lt;div ref={messagesEndRef} /&gt;
      &lt;/div&gt;
      &lt;div
        id=&quot;message_area&quot;
        className=&quot;p-4 border-t dark:border-gray-700 bg-white dark:bg-[#161618]&quot;
      &gt;
        &lt;button
          onClick={toggleSystemPrompt}
          className=&quot;mb-2 text-sm text-blue-500 hover:underline focus:outline-none&quot;
        &gt;
          {isSystemPromptOpen ? &quot;Hide System Prompt&quot; : &quot;Show System Prompt&quot;}
        &lt;/button&gt;
        {isSystemPromptOpen &amp;&amp; (
          &lt;textarea
            className=&quot;w-full p-2 border rounded-lg resize-none dark:bg-gray-800 dark:text-gray-200 mb-2&quot;
            rows=&quot;3&quot;
            placeholder=&quot;Enter system prompt...&quot;
            value={currentChat.systemPrompt}
            onChange={handleSystemPromptChange}
          /&gt;
        )}
        &lt;div className=&quot;flex flex-row&quot;&gt;
          &lt;div className=&quot;flex-grow&quot;&gt;
            &lt;InlineCodeEditor
              value={message}
              onChange={setMessage}
              onAttachCode={handleAttachCode}
              onKeyDown={handleEditorKeyDown}
            /&gt;
          &lt;/div&gt;
          &lt;div className=&quot;flex flex-col flex-shrink-0 items-start pl-4 space-y-2&quot;&gt;
            &lt;button
              onClick={() =&gt; setIsCodeModalOpen(true)}
              className=&quot;bg-blue-500 text-white px-3 py-2 rounded-lg hover:bg-blue-600 flex-grow w-full&quot;
            &gt;
              Attach Code
            &lt;/button&gt;
            &lt;button
              className=&quot;bg-green-500 text-white px-4 py-2 rounded-lg hover:bg-green-600 flex-grow mt-2 w-full&quot;
              onClick={handleSend}
            &gt;
              Send
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      {isCodeModalOpen &amp;&amp; (
        &lt;CodeModal
          onClose={() =&gt; {
            setIsCodeModalOpen(false);
            setCurrentEditingCode(null);
          }}
          onSave={handleCodeSave}
          initialData={currentEditingCode}
        /&gt;
      )}
    &lt;/div&gt;
  );
}

export default ChatInterface;
</code><code fileName="ChatItem.js" notes="">// src/components/ChatItem.js
import React, { useContext, useState } from &#039;react&#039;;
import { TrashIcon, PencilIcon, CheckIcon, XIcon } from &#039;@heroicons/react/solid&#039;;
import { ChatContext } from &#039;../context/ChatContext&#039;;

function ChatItem({ chat }) {
  const { currentChatId, setCurrentChatId, deleteChat, updateChat } = useContext(ChatContext);
  const [isEditing, setIsEditing] = useState(false);
  const [newName, setNewName] = useState(chat.name);
  const [renameError, setRenameError] = useState(null);

  const handleSelectChat = () =&gt; {
    setCurrentChatId(chat.id);
    setIsEditing(false); // Exit edit mode if selecting the chat
  };

  const handleDeleteChat = (e) =&gt; {
    e.stopPropagation(); // Prevent triggering the chat selection
    deleteChat(chat.id);
  };

  const handleEditClick = (e) =&gt; {
    e.stopPropagation(); // Prevent triggering the chat selection
    setIsEditing(true);
  };

  const handleRename = (e) =&gt; {
    e.preventDefault();
    if (newName.trim() === &#039;&#039;) {
      setRenameError(&#039;Chat name cannot be empty.&#039;);
      return;
    }
    console.log(`Renaming chat ID: ${chat.id} to &quot;${newName.trim()}&quot;`); // Debug log
    updateChat(chat.id, { name: newName.trim() });
    setIsEditing(false);
    setRenameError(null);
  };

  const handleCancelRename = () =&gt; {
    setNewName(chat.name);
    setIsEditing(false);
    setRenameError(null);
  };

  return (
    &lt;div
      className={`mb-2 cursor-pointer p-2 rounded ${
        chat.id === currentChatId
          ? &#039;bg-blue-100 dark:bg-blue-900&#039;
          : &#039;hover:bg-gray-100 dark:hover:bg-gray-700&#039;
      }`}
      onClick={!isEditing ? handleSelectChat : undefined} // Conditional onClick
    &gt;
      {isEditing ? (
        &lt;form onSubmit={handleRename} className=&quot;flex items-center space-x-2&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            value={newName}
            onChange={(e) =&gt; setNewName(e.target.value)}
            className=&quot;flex-1 min-w-0 px-2 py-1 rounded border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring focus:border-blue-300 dark:bg-zinc-800 dark:text-white&quot;
            autoFocus
          /&gt;
          &lt;button type=&quot;submit&quot; className=&quot;text-green-500 hover:text-green-700&quot; title=&quot;Save&quot;&gt;
            &lt;CheckIcon className=&quot;h-5 w-5&quot; /&gt;
          &lt;/button&gt;
          &lt;button
            type=&quot;button&quot;
            onClick={handleCancelRename}
            className=&quot;text-gray-500 hover:text-gray-700&quot;
            title=&quot;Cancel&quot;
          &gt;
            &lt;XIcon className=&quot;h-5 w-5&quot; /&gt;
          &lt;/button&gt;
        &lt;/form&gt;
      ) : (
        &lt;div className=&quot;flex justify-between items-center&quot;&gt;
          &lt;span className=&quot;text-black dark:text-white&quot;&gt;{chat.name}&lt;/span&gt;
          &lt;div className=&quot;flex items-center space-x-2&quot;&gt;
            &lt;button
              onClick={handleEditClick}
              className=&quot;text-gray-500 hover:text-gray-700 dark:text-gray-200 dark:hover:text-gray-400&quot;
              title=&quot;Rename Chat&quot;
              aria-label=&quot;Rename Chat&quot;
            &gt;
              &lt;PencilIcon className=&quot;h-5 w-5&quot; /&gt;
            &lt;/button&gt;
            &lt;button
              onClick={handleDeleteChat}
              className=&quot;text-red-500 hover:text-red-700&quot;
              title=&quot;Delete Chat&quot;
              aria-label=&quot;Delete Chat&quot;
            &gt;
              &lt;TrashIcon className=&quot;h-5 w-5&quot; /&gt;
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      )}
      {renameError &amp;&amp; (
        &lt;div className=&quot;text-red-500 text-sm mt-1&quot;&gt;
          {renameError}
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  );
}

export default ChatItem;
</code><code fileName="Home.js" notes="">import React, { useContext } from &#039;react&#039;;
import { ChatContext } from &#039;../context/ChatContext&#039;;

function Home() {
  const { addChat } = useContext(ChatContext);

  const getGreeting = () =&gt; {
    const hour = new Date().getHours();
    if (hour &lt; 12) return &#039;Good Morning, Ziggy&#039;;
    if (hour &lt; 18) return &#039;Good Afternoon, Ziggy&#039;;
    return &#039;Good Evening, Ziggy&#039;;
  };

  const handleStart = () =&gt; {
    addChat(&#039;New Chat&#039;);
  };

  return (
    &lt;div className=&quot;flex flex-col items-center justify-center flex-1 p-4&quot;&gt;
      &lt;h1 className=&quot;text-4xl font-bold mb-8 text-gray-800 dark:text-gray-200&quot;&gt;{getGreeting()}&lt;/h1&gt;
      &lt;button
        className=&quot;bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600&quot;
        onClick={handleStart}
      &gt;
        Start a New Chat
      &lt;/button&gt;
    &lt;/div&gt;
  );
}

export default Home;</code><code fileName="Message.js" notes="">// src/components/Message.js
import React, { useState, useContext } from &#039;react&#039;;
import MarkdownRenderer from &#039;./MarkdownRenderer&#039;;
import { CopyToClipboard } from &#039;react-copy-to-clipboard&#039;;
import { ClipboardCopyIcon } from &#039;@heroicons/react/solid&#039;;
import { CodeContext } from &#039;../context/CodeContext&#039;;
import CodeAttachmentBubble from &#039;./CodeAttachmentBubble&#039;;
import CodeModal from &#039;./CodeModal&#039;;
import { ChatContext } from &#039;../context/ChatContext&#039;;

function Message({ chatId, messageIndex, sender, text, model_id }) {
  const [copied, setCopied] = useState(false);
  const { showCode } = useContext(CodeContext);
  const [isEditModalOpen, setIsEditModalOpen] = useState(false);
  const [currentAttachment, setCurrentAttachment] = useState(null);
  const { updateMessage } = useContext(ChatContext); // Ensure ChatContext is imported
  const { models } = useContext(ChatContext);  // Access models from context

  const modelName = model_id 
    ? models.find((model) =&gt; model.id === model_id)?.name || &quot;Unknown Model&quot; 
    : null;

  const handleCopy = () =&gt; {
    setCopied(true);
    setTimeout(() =&gt; setCopied(false), 2000);
  };

  const safeText = String(text);

  // Function to extract code attachments
  const extractCodeAttachments = (text) =&gt; {
    const codeRegex = /&lt;code(?:\s+fileName=&quot;([^&quot;]*)&quot;)?(?:\s+notes=&quot;([^&quot;]*)&quot;)?&gt;([\s\S]*?)&lt;\/code&gt;/g;
    let match;
    const attachments = [];
    while ((match = codeRegex.exec(text)) !== null) {
      attachments.push({
        fileName: match[1] || &#039;Untitled&#039;,
        notes: match[2] || &#039;&#039;,
        codeContent: match[3],
      });
    }
    return attachments;
  };

  const codeAttachments = extractCodeAttachments(safeText);
  const cleanedText = safeText.replace(/&lt;code(?:\s+fileName=&quot;[^&quot;]*&quot;)?(?:\s+notes=&quot;[^&quot;]*&quot;)?&gt;[\s\S]*?&lt;\/code&gt;/g, &#039;&#039;);

  // Handlers for editing and deleting attachments
  const handleEdit = (attachment) =&gt; {
    setCurrentAttachment(attachment);
    setIsEditModalOpen(true);
  };

  const handleDelete = (attachment) =&gt; {
    // Implement deletion logic
    // For example, remove the attachment&#039;s &lt;code&gt; block from the message text
    const updatedText = text.replace(
      `&lt;code fileName=&quot;${attachment.fileName}&quot; notes=&quot;${attachment.notes}&quot;&gt;${attachment.codeContent}&lt;/code&gt;`,
      &#039;&#039;
    );
    updateMessage(chatId, messageIndex, { text: updatedText });
  };

  const handleUpdateAttachment = (updatedAttachment) =&gt; {
    // Replace the old &lt;code&gt; block with the updated one
    const oldCodeBlockRegex = new RegExp(
      `&lt;code(?:\\s+fileName=&quot;${updatedAttachment.fileName || &#039;Untitled&#039;}&quot;)?(?:\\s+notes=&quot;${updatedAttachment.notes || &#039;&#039;}&quot;)?&gt;[\\s\\S]*?&lt;\\/code&gt;`,
      &#039;g&#039;
    );
    const newCodeBlock = `&lt;code fileName=&quot;${updatedAttachment.fileName}&quot; notes=&quot;${updatedAttachment.notes}&quot;&gt;${updatedAttachment.codeContent}&lt;/code&gt;`;
    const updatedText = text.replace(oldCodeBlockRegex, newCodeBlock);
    updateMessage(chatId, messageIndex, { text: updatedText });
  };

  return (
    &lt;&gt;
      &lt;div className={`mb-4 flex ${sender === &#039;user&#039; ? &#039;justify-end&#039; : &#039;justify-start&#039;}`}&gt;
        &lt;div
          className={`max-w-xs md:max-w-md lg:max-w-5xl p-5 rounded-xl ${
            sender === &#039;user&#039;
              ? &#039;bg-zinc-950 text-white&#039;
              : &#039;bg-gray-200 dark:bg-[#282828] text-gray-800 dark:text-gray-200&#039;
          }`}
        &gt;
          {sender === &#039;bot&#039; &amp;&amp; modelName &amp;&amp; (
            &lt;div className=&quot;mb-2 text-sm text-gray-500 dark:text-gray-400&quot;&gt;
              &lt;strong&gt;Model:&lt;/strong&gt; {modelName}
            &lt;/div&gt;
          )}

          &lt;MarkdownRenderer text={cleanedText} /&gt;
          &lt;div className=&quot;mt-2 flex flex-wrap&quot;&gt;
            {codeAttachments.map((attachment, index) =&gt; (
              &lt;CodeAttachmentBubble
                key={index}
                attachment={attachment}
                onEdit={() =&gt; handleEdit(attachment)}
                onDelete={() =&gt; handleDelete(attachment)}
              /&gt;
            ))}
          &lt;/div&gt;
          &lt;CopyToClipboard text={text} onCopy={handleCopy}&gt;
            &lt;button className=&quot;mt-2 text-sm text-gray-500 hover:text-gray-700 flex items-center&quot;&gt;
              &lt;ClipboardCopyIcon className=&quot;h-5 w-5 mr-1&quot; /&gt; {copied ? &#039;Copied!&#039; : &#039;Copy&#039;}
            &lt;/button&gt;
          &lt;/CopyToClipboard&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      {isEditModalOpen &amp;&amp; currentAttachment &amp;&amp; (
        &lt;CodeModal
          onClose={() =&gt; setIsEditModalOpen(false)}
          onSave={handleUpdateAttachment}
          initialData={currentAttachment}
        /&gt;
      )}
    &lt;/&gt;
  );
}

export default React.memo(Message);</code><code fileName="Sidebar.js" notes="">// src/components/Sidebar.js
import React, { useContext, useState } from &quot;react&quot;;
import { ChatContext } from &quot;../context/ChatContext&quot;;
import { PlusIcon, TrashIcon } from &quot;@heroicons/react/solid&quot;;
import { ThemeContext } from &quot;../context/ThemeContext&quot;;
import ChatItem from &quot;./ChatItem&quot;;
import DarkModeToggle from &quot;./DarkModeToggle&quot;;
import ConfirmModal from &quot;./ConfirmModal&quot;;
import ModelList from &quot;./ModelList&quot;; // Import the ModelList component
import Favicon from &quot;../assets/favicon.png&quot;

function Sidebar() {
  const {
    chats,
    currentChatId,
    setCurrentChatId,
    addChat,
    deleteChat,
    updateChat,
    clearChats,
    models,
  } = useContext(ChatContext);

  const { theme, toggleTheme } = useContext(ThemeContext);

  const [isResetting, setIsResetting] = useState(false);
  const [error, setError] = useState(null);
  const [isModalOpen, setIsModalOpen] = useState(false); // For deleting all chats

  const handleNewChat = async () =&gt; {
    setIsResetting(true);
    setError(null);

    try {
      const response = await fetch(&quot;http://localhost:8000/api/reset&quot;, {
        method: &quot;POST&quot;,
        headers: {
          &quot;Content-Type&quot;: &quot;application/json&quot;,
        },
      });

      if (!response.ok) {
        throw new Error(&quot;Failed to reset chat.&quot;);
      }

      const data = await response.json();
      console.log(data.status);

      addChat(&quot;New Chat&quot;);
      //setCurrentChatId(null);
    } catch (err) {
      console.error(&quot;Error resetting chat:&quot;, err);
      setError(&quot;Unable to reset the chat. Please try again.&quot;);
    } finally {
      setIsResetting(false);
    }
  };

  const handleGoHome = () =&gt; {
    setCurrentChatId(null);
  };

  const handleDeleteAllChats = () =&gt; {
    setIsModalOpen(true);
  };

  const confirmDeleteAllChats = () =&gt; {
    clearChats();
    setIsModalOpen(false);
  };

  const cancelDeleteAllChats = () =&gt; {
    setIsModalOpen(false);
  };

  return (
    &lt;div className=&quot;w-72 bg-gray-100 dark:bg-zinc-900 border-r dark:border-gray-700 p-4 flex flex-col&quot;&gt;
      {/* Chatbot Name &quot;Echo&quot; at the top */}
      &lt;div
        className=&quot;mb-6 text-2xl font-bold text-gray-800 dark:text-gray-200 cursor-pointer flex flex-row align-middle&quot;
        onClick={handleGoHome}
      &gt;
      &lt;img src={Favicon} alt=&quot;Logo of Echo&quot; width={&quot;32&quot;} className=&quot;mr-2 mt-[2px]&quot; /&gt;
        Echo
      &lt;/div&gt;

      &lt;div className=&quot;flex justify-between items-center mb-4&quot;&gt;
        &lt;h2 className=&quot;text-xl font-bold text-gray-800 dark:text-gray-200&quot;&gt;
          Past Chats
        &lt;/h2&gt;
        &lt;button
          onClick={handleNewChat}
          className={`p-2 bg-blue-500 text-white rounded hover:bg-blue-600 flex items-center justify-center ${
            isResetting ? &quot;opacity-50 cursor-not-allowed&quot; : &quot;&quot;
          }`}
          title=&quot;Start New Chat&quot;
          disabled={isResetting}
        &gt;
          {isResetting ? &quot;Resetting...&quot; : &lt;PlusIcon className=&quot;h-5 w-5&quot; /&gt;}
        &lt;/button&gt;
      &lt;/div&gt;

      {error &amp;&amp; &lt;div className=&quot;mb-4 text-red-500 text-sm&quot;&gt;{error}&lt;/div&gt;}

      &lt;ul className=&quot;flex-1 overflow-y-auto space-y-2&quot;&gt;
        {chats.length === 0 &amp;&amp; (
          &lt;li className=&quot;text-gray-500 dark:text-gray-400&quot;&gt;No past chats.&lt;/li&gt;
        )}
        {chats.map((chat) =&gt; (
          &lt;ChatItem key={chat.id} chat={chat} /&gt;
        ))}
      &lt;/ul&gt;

      {/* Delete All Chats Button */}
      {chats.length &gt; 0 &amp;&amp; (
        &lt;button
          onClick={handleDeleteAllChats}
          className=&quot;mt-4 p-2 bg-red-500 text-white rounded hover:bg-red-600 flex items-center justify-center&quot;
          title=&quot;Delete All Chats&quot;
        &gt;
          &lt;TrashIcon className=&quot;h-5 w-5&quot; /&gt;
          &lt;span className=&quot;ml-2&quot;&gt;Delete All&lt;/span&gt;
        &lt;/button&gt;
      )}

      {/* Confirm Modal */}
      {isModalOpen &amp;&amp; (
        &lt;ConfirmModal
          title=&quot;Delete All Chats&quot;
          message=&quot;Are you sure you want to delete all chats? This action cannot be undone.&quot;
          onConfirm={confirmDeleteAllChats}
          onCancel={cancelDeleteAllChats}
        /&gt;
      )}

      {/* Model List */}
      &lt;ModelList /&gt;

      {/* Dark Mode Toggle at the bottom */}
      &lt;div className=&quot;mt-4&quot;&gt;
        &lt;DarkModeToggle theme={theme} toggleTheme={toggleTheme} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default Sidebar;</code><code fileName="ChatContext.js" notes="">// src/context/ChatContext.js
import React, { createContext, useState, useEffect } from &#039;react&#039;;
import { v4 as uuidv4 } from &#039;uuid&#039;;

export const ChatContext = createContext();

export const ChatProvider = ({ children }) =&gt; {
  const [chats, setChats] = useState(() =&gt; {
    const saved = localStorage.getItem(&#039;chats&#039;);
    return saved ? JSON.parse(saved) : [];
  });

  useEffect(() =&gt; {
    const saved = localStorage.getItem(&#039;chats&#039;);
    if (saved) {
      const parsedChats = JSON.parse(saved).map(chat =&gt; ({
        ...chat,
        messages: chat.messages.map(msg =&gt; ({
          ...msg,
          text: String(msg.text) // Ensure text is string
        }))
      }));
      setChats(parsedChats);
    } else {
      setChats([]);
    }
  }, []);

  const [currentChatId, setCurrentChatId] = useState(() =&gt; {
    const saved = localStorage.getItem(&#039;currentChatId&#039;);
    return saved ? JSON.parse(saved) : null;
  });

  const [models, setModels] = useState([]); // List of available models
  const [selectedModelId, setSelectedModelId] = useState(() =&gt; {
    const saved = localStorage.getItem(&#039;selectedModelId&#039;);
    return saved ? JSON.parse(saved) : null;
  });

  // Fetch models from the backend on component mount
  useEffect(() =&gt; {
    fetch(&#039;http://localhost:8000/api/models&#039;)
      .then((res) =&gt; {
        if (!res.ok) {
          throw new Error(`HTTP error! Status: ${res.status}`);
        }
        return res.json();
      })
      .then((data) =&gt; {
        console.log(&#039;Fetched models:&#039;, data); // Debugging line
        if (Array.isArray(data) &amp;&amp; data.length &gt; 0 &amp;&amp; !selectedModelId) {
          setSelectedModelId(data[0].id); // Select the first model by default
        }
        setModels(data);
      })
      .catch((error) =&gt; {
        console.error(&#039;Error fetching models:&#039;, error);
        setModels([]); // Prevent `.map` errors
      });
  }, []);

  // Persist chats to localStorage
  useEffect(() =&gt; {
    localStorage.setItem(&#039;chats&#039;, JSON.stringify(chats));
  }, [chats]);

  // Persist currentChatId to localStorage
  useEffect(() =&gt; {
    localStorage.setItem(&#039;currentChatId&#039;, JSON.stringify(currentChatId));
  }, [currentChatId]);

  // Persist selectedModelId to localStorage
  useEffect(() =&gt; {
    if (selectedModelId) {
      localStorage.setItem(&#039;selectedModelId&#039;, JSON.stringify(selectedModelId));
    }
  }, [selectedModelId]);

  const addChat = (name = `Chat ${chats.length + 1}`) =&gt; {
    const newChat = {
      id: uuidv4(),
      name: name,
      messages: [],
      systemPrompt: &#039;&#039;,
      model_id: selectedModelId, // Associate with selected model
    };
    setChats((prev) =&gt; [newChat, ...prev]);
    setCurrentChatId(newChat.id);
  };  

  const updateChat = (id, updatedChat) =&gt; {
    console.log(`Updating chat with ID: ${id}`, updatedChat); // Add this line
    setChats((prevChats) =&gt;
      prevChats.map((chat) =&gt; (chat.id === id ? { ...chat, ...updatedChat } : chat))
    );
  };

  const addMessage = (id, message) =&gt; {
    setChats((prevChats) =&gt;
      prevChats.map((chat) =&gt;
        chat.id === id
          ? { ...chat, messages: [...chat.messages, { ...message, text: String(message.text) }] }
          : chat
      )
    );
  };

  const deleteChat = (id) =&gt; {
    setChats((prevChats) =&gt; prevChats.filter((chat) =&gt; chat.id !== id));
    // If the deleted chat was the current one, reset currentChatId
    if (id === currentChatId) {
      setCurrentChatId(null);
    }
  };

  const clearChats = () =&gt; {
    setChats([]);
    setCurrentChatId(null);
  };

  const updateMessage = (chatId, messageIndex, updatedMessage) =&gt; {
    setChats((prevChats) =&gt;
      prevChats.map((chat) =&gt;
        chat.id === chatId
          ? {
              ...chat,
              messages: chat.messages.map((msg, idx) =&gt;
                idx === messageIndex
                  ? { ...msg, text: String(updatedMessage.text) }
                  : msg
              ),
            }
          : chat
      )
    );
  };

  const addModel = (model) =&gt; {
    setModels((prev) =&gt; [...prev, model]);
  };

  const removeModel = (modelId) =&gt; {
    setModels((prev) =&gt; prev.filter((model) =&gt; model.id !== modelId));
    // Optionally, handle chat associations if the removed model was in use
    if (selectedModelId === modelId) {
      setSelectedModelId(models.length &gt; 0 ? models[0].id : null);
    }
  };

  return (
    &lt;ChatContext.Provider
      value={{
        chats,
        currentChatId,
        setCurrentChatId,
        addChat,
        updateChat,
        addMessage,
        updateMessage,
        deleteChat,
        clearChats,
        models,
        addModel,
        removeModel,
        selectedModelId,
        setSelectedModelId,
      }}
    &gt;
      {children}
    &lt;/ChatContext.Provider&gt;
  );
};
</code>