"use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { toast } from "@/hooks/use-toast"; import { Info, ExternalLink, PlayCircle, Loader2 } from "lucide-react"; import Link from "next/link"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; import { useSelector } from "react-redux"; import { RootState } from "@/store/store"; import { handleSaveLLMConfig } from "@/utils/storeHelpers"; import { Select, SelectContent, SelectItem, SelectTrigger } from "./ui/select"; interface ModelOption { value: string; label: string; description?: string; icon?: string; size: string; } interface ProviderConfig { textModels: ModelOption[]; imageModels: ModelOption[]; apiGuide: { title: string; steps: string[]; videoUrl?: string; docsUrl: string; }; } const PROVIDER_CONFIGS: Record = { openai: { textModels: [ { value: "gpt-4", label: "GPT-4", description: "Most capable model, best for complex tasks", icon: "/icons/openai.png", size: "8GB", }, ], imageModels: [ { value: "dall-e-3", label: "DALL-E 3", description: "Latest version with highest quality", icon: "/icons/dall-e.png", size: "8GB", }, ], apiGuide: { title: "How to get your OpenAI API Key", steps: [ "Go to platform.openai.com and sign in or create an account", 'Click on your profile icon and select "View API keys"', 'Click "Create new secret key" and give it a name', "Copy your API key immediately (you won't be able to see it again)", "Make sure you have sufficient credits in your account", ], videoUrl: "https://www.youtube.com/watch?v=OB99E7Y1cMA", docsUrl: "https://platform.openai.com/docs/api-reference/authentication", }, }, google: { textModels: [ { value: "gemini-pro", label: "Gemini Pro", description: "Balanced model for most tasks", icon: "/icons/google.png", size: "8GB", }, ], imageModels: [ { value: "imagen", label: "Imagen", description: "Google's primary image generation model", icon: "/icons/google.png", size: "8GB", }, ], apiGuide: { title: "How to get your Google AI Studio API Key", steps: [ "Visit aistudio.google.com", 'Click on "Get API key" in the top navigation', 'Click "Create API key" on the next page', 'Choose either "Create API Key in new Project" or select an existing project', "Copy your API key - you're ready to go!", ], videoUrl: "https://www.youtube.com/watch?v=o8iyrtQyrZM&t=66s", docsUrl: "https://aistudio.google.com/app/apikey", }, }, ollama: { textModels: [ { value: "llama3.1:8b", label: "Llama3.1:8b", description: "Balanced model for most tasks", icon: "/icons/ollama.png", size: "8GB", }, { value: "llama3.1:70b", label: "Llama3.1:70b", description: "Large model for complex tasks", icon: "/icons/ollama.png", size: "70GB", }, { value: "llama3.1:14b", label: "Llama3.1:14b", description: "Large model for complex tasks", icon: "/icons/ollama.png", size: "14GB", }, { value: "llama3.1:11b", label: "Llama3.1:11b", description: "Large model for complex tasks", icon: "/icons/ollama.png", size: "11GB", }, ], imageModels: [ { value: "pexels", label: "Pexels", description: "Pexels is a free stock photo and video platform that allows you to download high-quality images and videos for free.", icon: "/icons/pexels.png", size: "8GB", }, ], apiGuide: { title: "How to get your Pexels API Key", steps: [ "Visit pexels.com", 'Click on "Get API key" in the top navigation', "Copy your API key - you're ready to go!", ], videoUrl: "https://www.youtube.com/watch?v=o8iyrtQyrZM&t=66s", docsUrl: "https://www.pexels.com/api/documentation/", }, }, }; export default function Home() { const router = useRouter(); const config = useSelector((state: RootState) => state.userConfig); const [llmConfig, setLlmConfig] = useState(config.llm_config); const [ollamaModels, setOllamaModels] = useState<{ label: string; value: string; description: string; size: string; icon: string; }[]>([]); const [downloadingModel, setDownloadingModel] = useState({ name: '', size: null, downloaded: null, status: '', done: false, }); const [isLoading, setIsLoading] = useState(false); const canChangeKeys = config.can_change_keys; const api_key_changed = (newApiKey: string) => { if (llmConfig.LLM === 'openai') { setLlmConfig({ ...llmConfig, OPENAI_API_KEY: newApiKey }); } else if (llmConfig.LLM === 'google') { setLlmConfig({ ...llmConfig, GOOGLE_API_KEY: newApiKey }); } else if (llmConfig.LLM === 'ollama') { setLlmConfig({ ...llmConfig, PEXELS_API_KEY: newApiKey }); } } const handleSaveConfig = async () => { if (llmConfig.LLM === 'ollama') { try { setIsLoading(true); await pullOllamaModels(); toast({ title: 'Success', description: 'Model downloaded successfully', }); } catch (error) { console.error('Error pulling model:', error); toast({ title: 'Error', description: 'Failed to download model. Please try again.', variant: 'destructive', }); setIsLoading(false); return; } } try { await handleSaveLLMConfig(llmConfig); toast({ title: 'Success', description: 'Configuration saved successfully', }); setIsLoading(false); router.push("/upload"); } catch (error) { console.error('Error:', error); toast({ title: 'Error', description: 'Failed to save configuration', variant: 'destructive', }); setIsLoading(false); } }; const changeProvider = (provider: string) => { setLlmConfig({ ...llmConfig, LLM: provider }); if (provider === 'ollama') { fetchOllamaModels(); } } const pullOllamaModels = async (): Promise => { return new Promise((resolve, reject) => { const interval = setInterval(async () => { try { const response = await fetch(`/api/v1/ppt/ollama/pull-model?name=${llmConfig.OLLAMA_MODEL}`); if (response.status === 200) { const data = await response.json(); if (data.done) { clearInterval(interval); setDownloadingModel(data); resolve(); } else { setDownloadingModel(data); } } else { clearInterval(interval); reject(new Error('Model pulling failed')); } } catch (error) { console.log('Error fetching ollama models:', error); clearInterval(interval); reject(error); } }, 1000); }); } const fetchOllamaModels = async () => { try { const response = await fetch('/api/v1/ppt/ollama/list-supported-models'); const data = await response.json(); setOllamaModels(data.models); } catch (error) { console.error('Error fetching ollama models:', error); } } useEffect(() => { if (!canChangeKeys) { router.push("/upload"); } if (llmConfig.LLM === 'ollama') { fetchOllamaModels(); } }, []); if (!canChangeKeys) { return null; } return (
{/* Branding Header */}
Presenton Logo

Open-source AI presentation generator

{/* Main Configuration Card */}
{/* Provider Selection */}
{Object.keys(PROVIDER_CONFIGS).map((provider) => ( ))}
{/* API Key Input */} {llmConfig.LLM !== 'ollama' &&
api_key_changed(e.target.value)} className="w-full px-4 py-2.5 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors" placeholder="Enter your API key" />

Your API key will be stored locally and never shared

} { llmConfig.LLM === 'ollama' && (
{ollamaModels.length > 0 ? ( ) : (
)}
{ollamaModels.length === 0 && (

Loading available models...

)}
api_key_changed(e.target.value)} />

Required for generating presentation images

) } {/* Model Information */}

Selected Models

Using {llmConfig.LLM === 'ollama' ? llmConfig.OLLAMA_MODEL ?? '_____' : PROVIDER_CONFIGS[llmConfig.LLM!].textModels[0].label} for text generation and {PROVIDER_CONFIGS[llmConfig.LLM!].imageModels[0].label} for images

We've pre-selected the best models for optimal presentation generation

{/* API Guide Section */}

{PROVIDER_CONFIGS[llmConfig.LLM!].apiGuide.title}

    {PROVIDER_CONFIGS[llmConfig.LLM!].apiGuide.steps.map((step, index) => (
  1. {step}
  2. ))}
{PROVIDER_CONFIGS[llmConfig.LLM!].apiGuide.videoUrl && ( Watch Video Tutorial )} Official Documentation
{/* Save Button */} { llmConfig.LLM === 'ollama' && downloadingModel.status && downloadingModel.status !== 'pulled' && (
{downloadingModel.status}
) }
); }