'use client' import './globals.css'; import styles from './page.module.css'; import React, { useEffect, useState } from 'react'; import SuggestionCard from './components/suggestions/suggestionCard'; import SidePanel from './components/sidePanel/chatHistorySidePanel'; import NavMenu from './components/navMenu/navMenu'; import Loading from './components/loading/loading'; import useSWR from 'swr'; import Image from 'next/image'; import 'katex/dist/katex.min.css'; import ChatInputArea, { ChatOptions } from './components/chatInputArea/chatInputArea'; import { useAuthenticatedData } from './common/auth'; import { Card, CardTitle } from '@/components/ui/card'; import { convertColorToBorderClass } from './common/colorUtils'; import { getIconFromIconName } from './common/iconUtils'; import { ClockCounterClockwise } from '@phosphor-icons/react'; import { AgentData } from './agents/page'; import { Suggestion, suggestionsData } from './components/suggestions/suggestionsData'; //get today's day const today = new Date(); const day = today.getDay(); const greetings = [ `Good ${today.getHours() < 12 ? 'morning' : today.getHours() < 15 ? 'afternoon' : 'evening'}! What would you like to do today?`, 'How can I help you today?', `Good ${today.getHours() < 12 ? 'morning' : today.getHours() < 15 ? 'afternoon' : 'evening'}! What's on your mind?`, `Ready to breeze through your ${['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][day]}?`, `Want to navigate your ${['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][day]} workload?` ]; const greeting = greetings[~~(Math.random() * greetings.length)]; interface ChatBodyDataProps { chatOptionsData: ChatOptions | null; onConversationIdChange?: (conversationId: string) => void; setUploadedFiles: (files: string[]) => void; isMobileWidth?: boolean; isLoggedIn: boolean; } async function createNewConvo(slug: string) { try { const response = await fetch(`/api/chat/sessions?client=web&agent_slug=${slug}`, { method: "POST" }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); const conversationID = data.conversation_id; if (!conversationID) { throw new Error("Conversation ID not found in response"); } return conversationID; } catch (error) { console.error("Error creating new conversation:", error); throw error; } } function ChatBodyData(props: ChatBodyDataProps) { const [message, setMessage] = useState(''); const [processingMessage, setProcessingMessage] = useState(false); const [shuffledOptions, setShuffledOptions] = useState([]); const [selectedAgent, setSelectedAgent] = useState("khoj"); const [agentIcons, setAgentIcons] = useState([]); const [agents, setAgents] = useState([]); const agentsFetcher = () => window.fetch('/api/agents').then(res => res.json()).catch(err => console.log(err)); const { data: agentsData, error } = useSWR('agents', agentsFetcher, { revalidateOnFocus: false }); function shuffleAndSetOptions() { const shuffled = [...suggestionsData].sort(() => 0.5 - Math.random()); setShuffledOptions(shuffled.slice(0, 3)); } useEffect(() => { if (props.chatOptionsData) { shuffleAndSetOptions(); } }, [props.chatOptionsData]); useEffect(() => { const nSlice = props.isMobileWidth ? 3 : 4; const shuffledAgents = agentsData ? [...agentsData].sort(() => 0.5 - Math.random()) : []; const agents = agentsData ? [agentsData[0]] : []; // Always add the first/default agent. shuffledAgents.slice(0, nSlice - 1).forEach(agent => { if (!agents.find(a => a.slug === agent.slug)) { agents.push(agent); } }); setAgents(agents); //generate colored icons for the selected agents const agentIcons = agents.map( agent => getIconFromIconName(agent.icon, agent.color) || {agent.name} ); setAgentIcons(agentIcons); }, [agentsData]); function shuffleSuggestionsCards() { shuffleAndSetOptions(); } useEffect(() => { const processMessage = async () => { if (message && !processingMessage) { setProcessingMessage(true); try { const newConversationId = await createNewConvo(selectedAgent || "khoj"); props.onConversationIdChange?.(newConversationId); window.location.href = `/chat?conversationId=${newConversationId}`; localStorage.setItem('message', message); } catch (error) { console.error("Error creating new conversation:", error); setProcessingMessage(false); } setMessage(''); } }; processMessage(); if (message) { setProcessingMessage(true); }; }, [selectedAgent, message]); function fillArea(link: string, type: string, prompt: string) { if (!link) { let message_str = ""; prompt = prompt.charAt(0).toLowerCase() + prompt.slice(1); if (type === "Online Search") { message_str = "/online " + prompt; } else if (type === "Paint") { message_str = "/paint " + prompt; } else { message_str = prompt; } // Get the textarea element const message_area = document.getElementById("message") as HTMLTextAreaElement; if (message_area) { // Update the value directly message_area.value = message_str; setMessage(message_str); } } } return (

{greeting}

{ !props.isMobileWidth &&
{agentIcons.map((icon, index) => ( setSelectedAgent(agents[index].slug)}> {icon} {agents[index].name} ))} window.location.href = "/agents"}> See All →
}
{ !props.isMobileWidth &&
setMessage(message)} sendDisabled={processingMessage} chatOptionsData={props.chatOptionsData} conversationId={null} isMobileWidth={props.isMobileWidth} setUploadedFiles={props.setUploadedFiles} />
}
{shuffledOptions.map((suggestion, index) => (
fillArea(suggestion.link, suggestion.type, suggestion.description)}>
))}
{ props.isMobileWidth &&
setMessage(message)} sendDisabled={processingMessage} chatOptionsData={props.chatOptionsData} conversationId={null} isMobileWidth={props.isMobileWidth} setUploadedFiles={props.setUploadedFiles} />
{agentIcons.map((icon, index) => ( setSelectedAgent(agents[index].slug)}> {icon} {agents[index].name} ))} window.location.href = "/agents"}> See All →
}
); } export default function Home() { const [chatOptionsData, setChatOptionsData] = useState(null); const [isLoading, setLoading] = useState(true); const [title, setTitle] = useState(''); const [conversationId, setConversationID] = useState(null); const [uploadedFiles, setUploadedFiles] = useState([]); const [isMobileWidth, setIsMobileWidth] = useState(false); const authenticatedData = useAuthenticatedData(); const handleConversationIdChange = (newConversationId: string) => { setConversationID(newConversationId); }; useEffect(() => { fetch('/api/chat/options') .then(response => response.json()) .then((data: ChatOptions) => { setLoading(false); if (data) { setChatOptionsData(data); } }) .catch(err => { console.error(err); return; }); setIsMobileWidth(window.innerWidth < 786); window.addEventListener('resize', () => { setIsMobileWidth(window.innerWidth < 786); }); }, []); if (isLoading) { return ; } return (
{title}
); }