'use client' import styles from "./referencePanel.module.css"; import { useEffect, useState } from "react"; import { ArrowRight, File } from "@phosphor-icons/react"; import markdownIt from "markdown-it"; const md = new markdownIt({ html: true, linkify: true, typographer: true }); import { SingleChatMessage, Context, WebPage, OnlineContextData } from "../chatMessage/chatMessage"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, } from "@/components/ui/sheet"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; interface ReferencePanelProps { referencePanelData: SingleChatMessage | null; setShowReferencePanel: (showReferencePanel: boolean) => void; } interface NotesContextReferenceData { title: string; content: string; } interface NotesContextReferenceCardProps extends NotesContextReferenceData { showFullContent: boolean; } function NotesContextReferenceCard(props: NotesContextReferenceCardProps) { const snippet = md.render(props.content); const [isHovering, setIsHovering] = useState(false); return ( <> setIsHovering(true)} onMouseLeave={() => setIsHovering(false)} className={`${props.showFullContent ? 'w-auto' : 'w-[200px]'} overflow-hidden break-words text-balance rounded-lg p-2 bg-muted border-none`} >

{props.title}

{props.title}

) } export interface ReferencePanelData { notesReferenceCardData: NotesContextReferenceData[]; onlineReferenceCardData: OnlineReferenceData[]; } interface OnlineReferenceData { title: string; description: string; link: string; } interface OnlineReferenceCardProps extends OnlineReferenceData { showFullContent: boolean; } function GenericOnlineReferenceCard(props: OnlineReferenceCardProps) { const [isHovering, setIsHovering] = useState(false); if (!props.link) { return null; } const domain = new URL(props.link).hostname; const favicon = `https://www.google.com/s2/favicons?domain=${domain}`; const handleMouseEnter = () => { console.log("mouse entered card"); setIsHovering(true); } const handleMouseLeave = () => { console.log("mouse left card"); setIsHovering(false); } return ( <>

{domain}

{props.title}

{props.description}

{domain}

{props.title}

{props.description}

) } export function constructAllReferences(contextData: Context[], onlineData: { [key: string]: OnlineContextData }) { const onlineReferences: OnlineReferenceData[] = []; const contextReferences: NotesContextReferenceData[] = []; if (onlineData) { let localOnlineReferences = []; for (const [key, value] of Object.entries(onlineData)) { if (value.answerBox) { localOnlineReferences.push({ title: value.answerBox.title, description: value.answerBox.answer, link: value.answerBox.source }); } if (value.knowledgeGraph) { localOnlineReferences.push({ title: value.knowledgeGraph.title, description: value.knowledgeGraph.description, link: value.knowledgeGraph.descriptionLink }); } if (value.webpages) { // If webpages is of type Array, iterate through it and add each webpage to the localOnlineReferences array if (value.webpages instanceof Array) { let webPageResults = value.webpages.map((webPage) => { return { title: webPage.query, description: webPage.snippet, link: webPage.link } }); localOnlineReferences.push(...webPageResults); } else { let singleWebpage = value.webpages as WebPage; // If webpages is an object, add the object to the localOnlineReferences array localOnlineReferences.push({ title: singleWebpage.query, description: singleWebpage.snippet, link: singleWebpage.link }); } } if (value.organic) { let organicResults = value.organic.map((organicContext) => { return { title: organicContext.title, description: organicContext.snippet, link: organicContext.link } }); localOnlineReferences.push(...organicResults); } } onlineReferences.push(...localOnlineReferences); } if (contextData) { let localContextReferences = contextData.map((context) => { if (!context.compiled) { const fileContent = context as unknown as string; const title = fileContent.split('\n')[0]; const content = fileContent.split('\n').slice(1).join('\n'); return { title: title, content: content }; } return { title: context.file, content: context.compiled } }); contextReferences.push(...localContextReferences); } return { notesReferenceCardData: contextReferences, onlineReferenceCardData: onlineReferences } } export interface TeaserReferenceSectionProps { notesReferenceCardData: NotesContextReferenceData[]; onlineReferenceCardData: OnlineReferenceData[]; isMobileWidth: boolean; } export function TeaserReferencesSection(props: TeaserReferenceSectionProps) { const [numTeaserSlots, setNumTeaserSlots] = useState(3); useEffect(() => { setNumTeaserSlots(props.isMobileWidth ? 1 : 3); }, [props.isMobileWidth]); const notesDataToShow = props.notesReferenceCardData.slice(0, numTeaserSlots); const onlineDataToShow = notesDataToShow.length < numTeaserSlots ? props.onlineReferenceCardData.slice(0, numTeaserSlots - notesDataToShow.length) : []; const shouldShowShowMoreButton = props.notesReferenceCardData.length > 0 || props.onlineReferenceCardData.length > 0; const numReferences = props.notesReferenceCardData.length + props.onlineReferenceCardData.length; if (numReferences === 0) { return null; } return (

References

{numReferences} sources

{ notesDataToShow.map((note, index) => { return }) } { onlineDataToShow.map((online, index) => { return }) } { shouldShowShowMoreButton && }
) } interface ReferencePanelDataProps { notesReferenceCardData: NotesContextReferenceData[]; onlineReferenceCardData: OnlineReferenceData[]; } export default function ReferencePanel(props: ReferencePanelDataProps) { if (!props.notesReferenceCardData && !props.onlineReferenceCardData) { return null; } return ( View references References View all references for this response
{ props.notesReferenceCardData.map((note, index) => { return }) } { props.onlineReferenceCardData.map((online, index) => { return }) }
); } function CompiledReference(props: { context: (Context | string) }) { let snippet = ""; let file = ""; if (typeof props.context === "string") { // Treat context as a string and get the first line for the file name const lines = props.context.split("\n"); file = lines[0]; snippet = lines.slice(1).join("\n"); } else { const context = props.context as Context; snippet = context.compiled; file = context.file; } const [showSnippet, setShowSnippet] = useState(false); return (
setShowSnippet(!showSnippet)}>
{file}
{snippet}
) } function WebPageReference(props: { webpages: WebPage, query: string | null }) { let snippet = md.render(props.webpages.snippet); const [showSnippet, setShowSnippet] = useState(false); return (
setShowSnippet(!showSnippet)}>
{ props.query ? ( {props.query} ) : {props.webpages.query} }
) } function OnlineReferences(props: { onlineContext: OnlineContextData, query: string }) { const webpages = props.onlineContext.webpages; const answerBox = props.onlineContext.answerBox; const peopleAlsoAsk = props.onlineContext.peopleAlsoAsk; const knowledgeGraph = props.onlineContext.knowledgeGraph; const organic = props.onlineContext.organic; return (
{ webpages && ( !Array.isArray(webpages) ? ( ) : ( webpages.map((webpage, index) => { return }) ) ) } { answerBox && (
{answerBox.title}
{answerBox.answer}
) } { organic && organic.map((organicData, index) => { return (
{organicData.title}
{organicData.snippet}
) }) } { peopleAlsoAsk && peopleAlsoAsk.map((people, index) => { return (
{people.question}
{people.snippet}
) }) } { knowledgeGraph && (
{knowledgeGraph.title}
{knowledgeGraph.description}
) }
) }