/* eslint-disable @next/next/no-img-element */ import { PlayCircle } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; import Lightbox, { GenericSlide, VideoSlide } from 'yet-another-react-lightbox'; import 'yet-another-react-lightbox/styles.css'; import { Message } from './ChatWindow'; type Video = { url: string; img_src: string; title: string; iframe_src: string; }; declare module 'yet-another-react-lightbox' { export interface VideoSlide extends GenericSlide { type: 'video-slide'; src: string; iframe_src: string; } interface SlideTypes { 'video-slide': VideoSlide; } } const Searchvideos = ({ query, chatHistory, messageId, onVideosLoaded, }: { query: string; chatHistory: Message[]; messageId: string; onVideosLoaded?: (count: number) => void; }) => { const [videos, setVideos] = useState(null); const [loading, setLoading] = useState(true); const [open, setOpen] = useState(false); const [slides, setSlides] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [displayLimit, setDisplayLimit] = useState(10); // Initially show only 10 videos const videoRefs = useRef<(HTMLIFrameElement | null)[]>([]); const loadedMessageIdsRef = useRef>(new Set()); // Function to show more videos when the Show More button is clicked const handleShowMore = () => { // If we're already showing all videos, don't do anything if (videos && displayLimit >= videos.length) return; // Otherwise, increase the display limit by 10, or show all videos setDisplayLimit((prev) => videos ? Math.min(prev + 10, videos.length) : prev, ); }; useEffect(() => { // Skip fetching if videos are already loaded for this message if (loadedMessageIdsRef.current.has(messageId)) { return; } const fetchVideos = async () => { setLoading(true); const chatModelProvider = localStorage.getItem('chatModelProvider'); const chatModel = localStorage.getItem('chatModel'); const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL'); const customOpenAIKey = localStorage.getItem('openAIApiKey'); const ollamaContextWindow = localStorage.getItem('ollamaContextWindow') || '2048'; try { const res = await fetch(`/api/videos`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query: query, chatHistory: chatHistory, chatModel: { provider: chatModelProvider, model: chatModel, ...(chatModelProvider === 'custom_openai' && { customOpenAIBaseURL: customOpenAIBaseURL, customOpenAIKey: customOpenAIKey, }), ...(chatModelProvider === 'ollama' && { ollamaContextWindow: parseInt(ollamaContextWindow), }), }, }), }); const data = await res.json(); const videos = data.videos ?? []; setVideos(videos); setSlides( videos.map((video: Video) => { return { type: 'video-slide', iframe_src: video.iframe_src, src: video.img_src, }; }), ); if (onVideosLoaded && videos.length > 0) { onVideosLoaded(videos.length); } // Mark as loaded to prevent refetching loadedMessageIdsRef.current.add(messageId); } catch (error) { console.error('Error fetching videos:', error); } finally { setLoading(false); } }; fetchVideos(); }, [query, messageId, chatHistory, onVideosLoaded]); return ( <> {loading && (
{[...Array(4)].map((_, i) => (
))}
)} {videos !== null && videos.length > 0 && ( <>
{videos.slice(0, displayLimit).map((video, i) => (
{ setOpen(true); setSlides([ slides[i], ...slides.slice(0, i), ...slides.slice(i + 1), ]); }} className="relative transition duration-200 active:scale-95 hover:scale-[1.02] cursor-pointer" key={i} > {video.title}

Video

))}
{videos.length > displayLimit && (
)} setOpen(false)} slides={slides} index={currentIndex} on={{ view: ({ index }) => { const previousIframe = videoRefs.current[currentIndex]; if (previousIframe?.contentWindow) { previousIframe.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*', ); } setCurrentIndex(index); }, }} render={{ slide: ({ slide }) => { const index = slides.findIndex((s) => s === slide); return slide.type === 'video-slide' ? (