Team Ai
Apppublic

KBaba7/llama.cpp

sourceHugging Faceapache-2.0updated 2y agoView on Hugging Face
0likes
ChatScreen.tsx124 linesDownload Raw Back to components
1import { useEffect, useRef, useState } from 'react';2import { useAppContext } from '../utils/app.context';3import StorageUtils from '../utils/storage';4import { useNavigate } from 'react-router';5import ChatMessage from './ChatMessage';6import { PendingMessage } from '../utils/types';7 8export default function ChatScreen() {9  const {10    viewingConversation,11    sendMessage,12    isGenerating,13    stopGenerating,14    pendingMessages,15  } = useAppContext();16  const [inputMsg, setInputMsg] = useState('');17  const containerRef = useRef<HTMLDivElement>(null);18  const navigate = useNavigate();19 20  const currConvId = viewingConversation?.id ?? '';21  const pendingMsg: PendingMessage | undefined = pendingMessages[currConvId];22 23  const scrollToBottom = (requiresNearBottom: boolean) => {24    if (!containerRef.current) return;25    const msgListElem = containerRef.current;26    const spaceToBottom =27      msgListElem.scrollHeight -28      msgListElem.scrollTop -29      msgListElem.clientHeight;30    if (!requiresNearBottom || spaceToBottom < 50) {31      setTimeout(32        () => msgListElem.scrollTo({ top: msgListElem.scrollHeight }),33        134      );35    }36  };37 38  // scroll to bottom when conversation changes39  useEffect(() => {40    scrollToBottom(false);41  }, [viewingConversation?.id]);42 43  const sendNewMessage = async () => {44    if (inputMsg.trim().length === 0 || isGenerating(currConvId)) return;45    const convId = viewingConversation?.id ?? StorageUtils.getNewConvId();46    const lastInpMsg = inputMsg;47    setInputMsg('');48    if (!viewingConversation) {49      // if user is creating a new conversation, redirect to the new conversation50      navigate(`/chat/${convId}`);51    }52    scrollToBottom(false);53    // auto scroll as message is being generated54    const onChunk = () => scrollToBottom(true);55    if (!(await sendMessage(convId, inputMsg, onChunk))) {56      // restore the input message if failed57      setInputMsg(lastInpMsg);58    }59  };60 61  return (62    <>63      {/* chat messages */}64      <div65        id="messages-list"66        className="flex flex-col grow overflow-y-auto"67        ref={containerRef}68      >69        <div className="mt-auto flex justify-center">70          {/* placeholder to shift the message to the bottom */}71          {viewingConversation ? '' : 'Send a message to start'}72        </div>73        {viewingConversation?.messages.map((msg) => (74          <ChatMessage key={msg.id} msg={msg} scrollToBottom={scrollToBottom} />75        ))}76 77        {pendingMsg && (78          <ChatMessage79            msg={pendingMsg}80            scrollToBottom={scrollToBottom}81            isPending82            id="pending-msg"83          />84        )}85      </div>86 87      {/* chat input */}88      <div className="flex flex-row items-center mt-8 mb-6">89        <textarea90          className="textarea textarea-bordered w-full"91          placeholder="Type a message (Shift+Enter to add a new line)"92          value={inputMsg}93          onChange={(e) => setInputMsg(e.target.value)}94          onKeyDown={(e) => {95            if (e.key === 'Enter' && e.shiftKey) return;96            if (e.key === 'Enter' && !e.shiftKey) {97              e.preventDefault();98              sendNewMessage();99            }100          }}101          id="msg-input"102          dir="auto"103        ></textarea>104        {isGenerating(currConvId) ? (105          <button106            className="btn btn-neutral ml-2"107            onClick={() => stopGenerating(currConvId)}108          >109            Stop110          </button>111        ) : (112          <button113            className="btn btn-primary ml-2"114            onClick={sendNewMessage}115            disabled={inputMsg.trim().length === 0}116          >117            Send118          </button>119        )}120      </div>121    </>122  );123}124