From 8398676af7d5729b11f7241cf93056317772123a Mon Sep 17 00:00:00 2001 From: heronalps Date: Sat, 16 Nov 2024 15:38:08 -0800 Subject: [PATCH] adding arize phoenix --- apps/web/pages/brainbite_original.tsx | 488 ++++++++++++++++++++++++++ apps/web/server/arize-trace.ts | 31 ++ prompts.tsx | 167 +++++++++ 3 files changed, 686 insertions(+) create mode 100644 apps/web/pages/brainbite_original.tsx create mode 100644 apps/web/server/arize-trace.ts create mode 100644 prompts.tsx diff --git a/apps/web/pages/brainbite_original.tsx b/apps/web/pages/brainbite_original.tsx new file mode 100644 index 0000000..fea45ce --- /dev/null +++ b/apps/web/pages/brainbite_original.tsx @@ -0,0 +1,488 @@ + +"use client" + +import { Loading } from "@/components/ui/loading"; +import { z } from "zod"; +import React, { useState, useEffect, useRef, useCallback, use } from "react"; +import { + Carousel, + CarouselContent, + CarouselItem, + type CarouselApi, + CarouselPrevious, + CarouselNext, +} from "@/components/ui/carousel"; +import { event } from '@/lib/telemetry-client'; +import { LearnCarouselItem } from "@/types/LearnCarouselItem"; +import { Card, CardContent, CardHeader } from "@/components/ui/card"; +import MarkdownRender from "@/components/markdown-render" +import Image from "next/image"; +import { WebSearchImage } from "@/types/WebSearchImage"; +import { toast } from "@/components/ui/use-toast"; +import { useMakeCopilotReadable } from "@copilotkit/react-core"; +import { LuSearch } from "react-icons/lu"; +import { Button } from "@/components/ui/button"; +import { modals } from "@/components/modal-manager"; + +type BoookRecommendation = { + userLearningGuide: string; + bookRecommendations?: string[]; + keyPointsOfBooks?: string[]; + bookImages?: { + [key: string]: WebSearchImage; + }; +}; + +export default function LearnPage() { + const [carouselItems, setCarouselItems] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + const [recommendedBooks, setRecommendedBooks] = useState({}); + + const getCopilotrecommendedBooksContext = () => { + return { + userLearningGuide: recommendedBooks?.userLearningGuide || "", + bookRecommendations: recommendedBooks?.bookRecommendations || [], + keyPointsOfBooks: recommendedBooks?.keyPointsOfBooks || [], + } || {}; + } + useMakeCopilotReadable("Recommended Books for user based on input: " + JSON.stringify(getCopilotrecommendedBooksContext())); + const getCopilotCarouselContext = () => { + return { + learningContentSlides: carouselItems.map((item: { + title: string; + content: string; + }) => item.content).join(", "), + } || {}; + } + useMakeCopilotReadable("Recommended learning lesson based on input: " + JSON.stringify(getCopilotCarouselContext())); + + const fetchRecommendedBooks = async (input: { + query: string; + answers: Record; + }) => { + setIsLoading(true); + toast({ + title: "Fetching recommended books", + duration: 3000, + }) + try { + const response = await fetch(`/api/get-recommended-books`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(input), + }); + if (!response.ok) { + throw new Error('Failed to fetch carousel items'); + } + const data = await response.json(); + setRecommendedBooks(data.response); + } catch (error) { + console.error('Failed to fetch carousel items:', error); + } finally { + setIsLoading(false); + } + }; + + const fetchCarouselItems = async (input: { + query: string; + answers: Record; + }) => { + setIsLoading(true); + try { + toast({ + title: "Loading book details content...", + duration: 3000, + }) + const response = await fetch(`/api/build-lesson`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(input), + }); + if (!response.ok) { + throw new Error('Failed to fetch carousel items'); + } + const data = await response.json(); + setCarouselItems(data.response); + } catch (error) { + console.error('Failed to fetch carousel items:', error); + } finally { + setIsLoading(false); + } + }; + + return <> +
+
+ { + console.log('submit', data); + if (!isLoading) { + event('fetchcarouselitems', { + label: 'learn', + value: JSON.stringify(data), + category: 'learn', + }); + void fetchCarouselItems(data); + } + }} + onBookSubmit={(data) => { + console.log('submit', data); + if (!isLoading) { + event('fetchRecommendedBooks', { + label: 'learn', + value: JSON.stringify(data), + category: 'learn', + }); + void fetchRecommendedBooks(data); + } + }} + /> + { + console.log('clicked book:', book); + if (!isLoading) { + event('fetchcarouselitems', { + label: 'learn', + value: book, + category: 'learn', + }); + void fetchCarouselItems({ + query: `${book} book`, + answers: {} + }); + } + }} + bookRecommendations={recommendedBooks} /> + +
+
+ +} + +export const BookRecommendationSection = ({ + bookRecommendations, + onBookClick, + isLoading, +}: { + bookRecommendations?: BoookRecommendation + onBookClick: (book: string) => void; + isLoading?: boolean; +}) => { + return ( +
+
+ {bookRecommendations?.bookRecommendations?.length && bookRecommendations.bookRecommendations.map((book) => ( +
{ + if (isLoading) return; + onBookClick(book) + }}> + {`Cover + {/*

{book}

*/} +
+ ))} +
+ {bookRecommendations?.userLearningGuide && + + Your Learning Guide + + + {bookRecommendations?.userLearningGuide} + + } + {bookRecommendations?.keyPointsOfBooks?.length && + + Personalized Key Learning Points + + + {bookRecommendations?.keyPointsOfBooks?.slice(0, 3)?.map((point, index) => ( +

{point}

+ ))} +
+
} +
+ ); +} + + +export const LearnCarousel = ({ + carouselItems, +}: { + carouselItems: LearnCarouselItem[]; +}) => { + const [api, setApi] = useState(); + const [current, setCurrent] = useState(0); + const [audioCache, setAudioCache] = useState>(new Map()); + const audioRef = useRef(null); + const [autoplay, setAutoplay] = useState(false); + + const handleAudioEnd = useCallback(() => { + if (autoplay && api) { + api.scrollNext(); + } + }, [autoplay, api]); + + useEffect(() => { + if (!api) { + return; + } + + setCurrent(api.selectedScrollSnap() + 1); + + api.on("select", () => { + if (audioRef.current && !audioRef.current.paused) { + audioRef.current.pause(); + audioRef.current.currentTime = 0; + } + setCurrent(api.selectedScrollSnap() + 1); + }); + }, [api]); + + useEffect(() => { + if (!autoplay) { + if (audioRef.current && !audioRef.current.paused) { + audioRef.current.pause(); + audioRef.current.currentTime = 0; + } + return; + } + + const speakCurrentItem = async () => { + const currentItemText = carouselItems[current - 1]?.full_slide_content || carouselItems[current - 1]?.content; + if (!currentItemText) return; + + if (audioCache.has(current - 1)) { + const cachedAudio = audioCache.get(current - 1); + audioRef.current = cachedAudio; + audioRef.current.onended = handleAudioEnd; + audioRef.current.play().catch(e => console.error("Error playing audio:", e)); + } else { + const endpoint = `/api/tts`; + const data = { input: currentItemText }; + const response = await fetch(endpoint, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) + }); + + const audioBlob = await response.blob(); + const audioUrl = URL.createObjectURL(audioBlob); + const audioEl = new Audio(audioUrl); + audioEl.onended = handleAudioEnd; + setAudioCache(new Map(audioCache.set(current - 1, audioEl))); + audioRef.current = audioEl; + audioRef.current.play().catch(e => console.error("Error playing audio:", e)); + } + }; + + if (autoplay) { + speakCurrentItem(); + } + }, [current, carouselItems, audioCache, autoplay, handleAudioEnd]); + + const toggleAutoplay = () => { + setAutoplay(!autoplay); + }; + + return carouselItems.length > 0 ? ( + <> +
+ {current === 1 && ( + + )} + {current > 1 && autoplay && ( +
+ + +
+ )} + + + {carouselItems.map((item, index) => ( + + + {index === current - 1 && audioRef.current && ( + + ))} + + + + +
+ Slide {current} of {carouselItems?.length || 0} +
+
+ + ) : null; +}; + +const LearnCarouselContent = ({ + item +}: { + item: LearnCarouselItem +}) => { + return + +

+ {item.title} +

+ {/*

+ {item.content} +

*/} + {/* @ts-ignore */} + + {item.content || ""} + + { + item.mainImage && ({item.mainImage?.name) + } +
+ + {item.full_slide_content || ""} + +
+} + +function SearchBar({ + onSubmit, + onBookSubmit, + isLoading, +}: { + onSubmit: (data: any) => void; + onBookSubmit: (data: any) => void; + isLoading: boolean; +}) { + const [query, setQuery] = useState(''); + const [extraQuestions, setExtraQuestions] = useState([]); + const [answers, setAnswers] = useState({}); + useMakeCopilotReadable("User input: " + JSON.stringify({ query, answers })); + + const handleQuerySubmit = async (e: any) => { + e.preventDefault(); + const response = await fetch(`/api/get-recommended-question?query=${encodeURIComponent(query)}`); + if (response.ok) { + const data = await response.json(); + setExtraQuestions(data.response || []); + } + }; + + const handleAnswerChange = (question, answer) => { + setAnswers(prev => ({ ...prev, [question]: answer })); + }; + + const handleSubmitAll = (e: any) => { + e.preventDefault(); + // onSubmit({ + // query, + // answers, + // }); + onBookSubmit({ + query, + answers, + }); + }; + + return ( +
+
+
+

Get Personalized Learning Content from Books

+
+ setQuery(e.target.value)} className="px-4 py-2 w-full" placeholder="What do you want to learn about?" /> + +
+