diff --git a/components/AiButton.js b/components/AiButton.js index 0d8d1da..8d03d86 100644 --- a/components/AiButton.js +++ b/components/AiButton.js @@ -1,4 +1,3 @@ - import React, { useState } from "react"; import ChatComponent from "./chatbutton1"; // Adjust the path as needed @@ -13,29 +12,45 @@ function AiButton() { return (
- {/* Render the "Ask AI" button if the chat is not shown */} - {!showChat && ( - - )} - {/* Render the ChatComponent when showChat is true, passing the onClose prop */} - {showChat && } + + +
+ {showChat && } +
+ +
); } diff --git a/components/chatbutton1.js b/components/chatbutton1.js index c3f3b35..2628348 100644 --- a/components/chatbutton1.js +++ b/components/chatbutton1.js @@ -1,11 +1,81 @@ import React, { useState, useRef, useEffect } from "react"; +// Simple markdown renderer component +function MarkdownRenderer({ content }) { + const renderMarkdown = (text) => { + // Convert markdown to HTML + let html = text + // Headers + .replace(/^### (.*$)/gm, '

$1

') + .replace(/^## (.*$)/gm, '

$1

') + .replace(/^# (.*$)/gm, '

$1

') + // Bold + .replace(/\*\*(.*?)\*\*/g, '$1') + // Italic + .replace(/\*(.*?)\*/g, '$1') + // Code blocks + .replace(/```([\s\S]*?)```/g, '
$1
') + // Inline code + .replace(/`([^`]+)`/g, '$1') + // Unordered lists + .replace(/^\* (.*$)/gm, '
  • $1
  • ') + .replace(/(
  • .*<\/li>)/s, '') + // Ordered lists + .replace(/^\d+\. (.*$)/gm, '
  • $1
  • ') + .replace(/(
  • .*<\/li>)/s, '
      $1
    ') + // Line breaks + .replace(/\n\n/g, '

    ') + .replace(/\n/g, '
    ') + // Wrap in paragraph tags + .replace(/^(?!<[h1-6]|)(.+)$/gm, '

    $1

    '); + + return html; + }; + + return ( +
    + ); +}; + function ChatComponent({ onClose }) { // holds the current user input and the chat history. const [inputMessage, setInputMessage] = useState(""); const [chatHistory, setChatHistory] = useState([]); const [isLoading, setIsLoading] = useState(false); + // New state to track whether to show suggested questions + const [showSuggestions, setShowSuggestions] = useState(true); + // New state to store the randomly selected questions + const [randomQuestions, setRandomQuestions] = useState([]); + + // List Predefined questions + const suggestedQuestions = [ + "What is the Allora Network?", + "What role do worker nodes play in the network?", + "What are the different layers of the network?", + "What are the main defining characteristics of Allora?", + "What are the differences between Reputers and Validators?", + "How do consumers access inferences within Allora?", + "What role does context awareness play in Allora's design, and how is it achieved through forecasting tasks?", + "How does Allora ensure the reliability and security of the network?", + "How does the tokenomics design of the Allora token (ALLO) ensure long-term network sustainability?", + ]; + + // Function to select 3 random questions + const getRandomQuestions = () => { + const shuffled = [...suggestedQuestions].sort(() => 0.5 - Math.random()); + return shuffled.slice(0, 3); + }; + + // Initialize with 3 random questions on component mount + useEffect(() => { + setRandomQuestions(getRandomQuestions()); + }, []); + + // this references the chat history container. const chatContainerRef = useRef(null); @@ -16,93 +86,286 @@ function ChatComponent({ onClose }) { } }, [chatHistory]); - // this is handler for form submission. - const handleSubmit = async (e) => { - e.preventDefault(); - - // Store the message and immediately clear the input field - const message = inputMessage; - setInputMessage(""); // Clear input immediately - - // Add user's message to the chat history. - const newUserEntry = { sender: "user", text: message }; - setChatHistory((prev) => [...prev, newUserEntry]); - - // Show loading indicator - setIsLoading(true); - - try { - // Send user's message to the FastAPI backend. - const response = await fetch("https://b832b91b8183b88b9c22eda604f1e09.testnet.allora.run/chat", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ message: message }), - }); - console.log("API went through"); - - if (!response.ok) { - throw new Error(`Server error: ${response.statusText}`); + // Hide suggestions when conversation starts + useEffect(() => { + if (chatHistory.length > 0) { + setShowSuggestions(false); } - - // Parse the JSON response. - const data = await response.json(); - - // Add the assistant's response to the chat history. - const newBotEntry = { - sender: "bot", - text: data.response, - sources: data.sources, + }, [chatHistory]); + // New handler for when a suggested question is clicked + const handleSuggestionClick = (question) => { + // Process the suggested question like a regular submission + handleMessageSubmit(question); + }; + + // Extracted logic to handle message submission + const handleMessageSubmit = async (message) => { + // Add user's message to the chat history. + const newUserEntry = { + sender: "user", + text: message.trim() // Trim any extra whitespace }; - setChatHistory((prev) => [...prev, newBotEntry]); - } catch (error) { - console.error("Error fetching chat response:", error); - // display an error message in the UI. - const errorEntry = { - sender: "bot", text: "Sorry, something went wrong." - }; - setChatHistory((prev) => [...prev, errorEntry]); - } finally { - // Hide loading indicator - setIsLoading(false); - } - }; - + setChatHistory((prev) => [...prev, newUserEntry]); + + // Show loading indicator + setIsLoading(true); + + try { + // Send user's message to the FastAPI backend. + const response = await fetch("https://b832b91b8183b88b9c22eda604f1e09.testnet.allora.run/chat", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ message: message.trim() }), + }); + console.log("API went through"); + + if (!response.ok) { + throw new Error(`Server error: ${response.statusText}`); + } + + // Parse the JSON response. + const data = await response.json(); + + // Add the assistant's response to the chat history. + const newBotEntry = { + sender: "bot", + text: data.response, + sources: data.sources, + }; + setChatHistory((prev) => [...prev, newBotEntry]); + } catch (error) { + console.error("Error fetching chat response:", error); + // display an error message in the UI. + const errorEntry = { + sender: "bot", + text: "Sorry, something went wrong. Please try again." + }; + setChatHistory((prev) => [...prev, errorEntry]); + } finally { + // Hide loading indicator + setIsLoading(false); + } + }; + + // this is handler for form submission. + const handleSubmit = async (e) => { + e.preventDefault(); + + // Store the message and immediately clear the input field + const message = inputMessage; + setInputMessage(""); // Clear input immediately + + // Process the message + await handleMessageSubmit(message); + }; return (
    + + {/* Header with title and close button */}
    -

    Chat with our AI

    +
    +
    +
    +

    Allie

    +
    AI Assistant
    +
    +
    @@ -110,123 +373,258 @@ function ChatComponent({ onClose }) { className="chat-history" ref={chatContainerRef} style={{ - border: "1px solid #ccc", - padding: "10px", - height: "300px", - overflowY: "scroll", - backgroundColor: "#1e1e1e", + padding: "16px 24px", + height: "420px", + overflowY: "auto", + backgroundColor: "transparent", position: "relative", + scrollBehavior: "smooth", }} > + {/* Suggested Questions */} + {showSuggestions && ( +
    +
    + ✨ Try asking about: +
    + {randomQuestions.map((question, index) => ( + + ))} +
    + )} + {chatHistory.map((entry, index) => (
    -

    {entry.text}

    - {entry.sources && entry.sources.length > 0 } + {entry.sender === "bot" ? ( + + ) : ( + entry.text + )} + + {/* Sources display for bot messages */} + {entry.sources && entry.sources.length > 0 && ( +
    +
    Sources:
    + {entry.sources.map((source, idx) => ( +
    + 📄 {source} +
    + ))} +
    + )}
    ))} - {/* Loading indicator */} + {/* Enhanced Loading indicator */} {isLoading && ( -
    +
    -
    -
    +
    +
    +
    - Thinking... + animation: "pulse 1.4s ease-in-out infinite", + animationDelay: "0.2s" + }} /> +
    +
    + Thinking...
    -
    )}
    -
    - setInputMessage(e.target.value)} - placeholder="Type your message..." + onKeyDown={(e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + const syntheticEvent = { preventDefault: () => {} }; + handleSubmit(syntheticEvent); + } + }} + placeholder="Ask me anything..." required + rows={1} style={{ flex: "1", - padding: "10px", - backgroundColor: "#333", - color: "#fff", - border: "1px solid #555", - borderRadius: "5px", + minHeight: "44px", + maxHeight: "120px", + padding: "12px 16px", + backgroundColor: "rgba(30, 41, 59, 0.5)", + color: "#f1f5f9", + border: "1px solid rgba(71, 85, 105, 0.3)", + borderRadius: "12px", + fontSize: "0.95rem", + transition: "all 0.2s cubic-bezier(0.16, 1, 0.3, 1)", + outline: "none", + resize: "none", + fontFamily: 'inherit', + lineHeight: "1.5" }} /> -
    +
    ); } -export default ChatComponent; \ No newline at end of file +export default ChatComponent;