From 49fd7204aaf369623f2327d872e7df272bf62632 Mon Sep 17 00:00:00 2001 From: Altay Date: Sat, 16 Dec 2023 21:41:23 +0300 Subject: [PATCH] feat: add episode-ai-summary-footer --- .../episode-ai-summary-footer.tsx | 64 +++++++++++++++++++ .../episode-ai-summary-generator.tsx | 6 +- .../episode-ai-summary-streamer.tsx | 32 +++++++--- .../episode-ai-summary/episode-ai-summary.tsx | 25 ++------ 4 files changed, 91 insertions(+), 36 deletions(-) create mode 100644 components/episode-ai-summary/episode-ai-summary-footer.tsx diff --git a/components/episode-ai-summary/episode-ai-summary-footer.tsx b/components/episode-ai-summary/episode-ai-summary-footer.tsx new file mode 100644 index 0000000..cc9c4ad --- /dev/null +++ b/components/episode-ai-summary/episode-ai-summary-footer.tsx @@ -0,0 +1,64 @@ +'use client'; + +import type { Tables } from '@/types/supabase/database'; + +import { createSupabaseBrowserClient } from '@/lib/services/supabase/browser'; +import { Avatar, Flex, Text } from '@radix-ui/themes'; +import { useEffect, useRef, useState } from 'react'; +import { CgProfile } from 'react-icons/cg'; + +type Props = { + id: Tables<'episode'>['id']; +}; + +const fetchData = async (id: Props['id']) => { + const supabase = createSupabaseBrowserClient(); + + const { data } = await supabase + .from('episode_content') + .select('id, user:account(id, display_name, avatar_url)') + .eq('episode', id) + .single(); + + return data?.user ? { user: data.user } : { user: null }; +}; + +export function EpisodeAISummaryFooter(props: Props) { + const startedRef = useRef(false); + const [data, setData] = useState + > | null>(null); + + useEffect(() => { + if (!startedRef.current) { + startedRef.current = true; + + void fetchData(props.id) + .then(setData) + .catch(() => null); + } + }, [props.id]); + + if (data === null) { + return null; + } + + return data.user ? ( + + } + radius="full" + size="1" + src={data.user.avatar_url ?? ''} + /> + + + Generated by {data.user.display_name} + + + ) : ( + + Generated by a generous beecast user. + + ); +} diff --git a/components/episode-ai-summary/episode-ai-summary-generator.tsx b/components/episode-ai-summary/episode-ai-summary-generator.tsx index 296dcaf..743ccac 100644 --- a/components/episode-ai-summary/episode-ai-summary-generator.tsx +++ b/components/episode-ai-summary/episode-ai-summary-generator.tsx @@ -68,11 +68,7 @@ export function EpisodeAISummaryGenerator({ ); case 'summarizing': - return ( - - - - ); + return ; case 'error': return ( diff --git a/components/episode-ai-summary/episode-ai-summary-streamer.tsx b/components/episode-ai-summary/episode-ai-summary-streamer.tsx index 2b6683a..a94c94e 100644 --- a/components/episode-ai-summary/episode-ai-summary-streamer.tsx +++ b/components/episode-ai-summary/episode-ai-summary-streamer.tsx @@ -2,8 +2,12 @@ import type { Tables } from '@/types/supabase/database'; +import { Flex } from '@radix-ui/themes'; import { useChat } from 'ai/react'; -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; + +import { EpisodeAISummaryFooter } from './episode-ai-summary-footer'; +import { EpisodeAISummaryPanel } from './episode-ai-summary-panel'; type Props = { id: Tables<'episode'>['id']; @@ -11,9 +15,13 @@ type Props = { export function EpisodeAISummaryStreamer({ id }: Props) { const startedRef = useRef(false); + const [finished, setFinished] = useState(false); const { messages, reload, setMessages } = useChat({ api: `/api/ai/summarize/${id}`, + onFinish: () => { + setFinished(true); + }, }); useEffect(() => { @@ -28,15 +36,19 @@ export function EpisodeAISummaryStreamer({ id }: Props) { const assistantMessages = messages.filter((m) => m.role === 'assistant'); - if (assistantMessages.length === 0) { - return 'Summarizing episode...'; - } - return ( - <> - {assistantMessages.map((message) => ( - {message.content} - ))} - + + + {assistantMessages.length === 0 + ? 'Summarizing episode...' + : assistantMessages.map((message) => ( + + {message.content} + + ))} + + + {finished ? : null} + ); } diff --git a/components/episode-ai-summary/episode-ai-summary.tsx b/components/episode-ai-summary/episode-ai-summary.tsx index a42cc5b..465c5c7 100644 --- a/components/episode-ai-summary/episode-ai-summary.tsx +++ b/components/episode-ai-summary/episode-ai-summary.tsx @@ -3,11 +3,12 @@ import type { Tables } from '@/types/supabase/database'; import { DatabaseError } from '@/lib/errors'; import { fetchAccountAICredits } from '@/lib/services/account'; import { createSupabaseServerClient } from '@/lib/services/supabase/server'; -import { Avatar, Button, Flex, Text } from '@radix-ui/themes'; +import { Button, Flex } from '@radix-ui/themes'; import { cookies } from 'next/headers'; import Link from 'next/link'; -import { CgDollar, CgProfile } from 'react-icons/cg'; +import { CgDollar } from 'react-icons/cg'; +import { EpisodeAISummaryFooter } from './episode-ai-summary-footer'; import { EpisodeAISummaryGenerator } from './episode-ai-summary-generator'; import { EpisodeAISummaryPanel } from './episode-ai-summary-panel'; import { EpisodeAISummaryPlaceholder } from './episode-ai-summary-placeholder'; @@ -52,25 +53,7 @@ export async function EpisodeAISummary(props: Props) { {episodeContent.text_summary} - {episodeContent.user ? ( - - } - radius="full" - size="1" - src={episodeContent.user.avatar_url ?? ''} - /> - - - Generated by{' '} - {episodeContent.user.display_name} - - - ) : ( - - Generated by a generous beecast user. - - )} + ); }