/* * ============================================================================= * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform * ----------------------------------------------------------------------------- * File: client/src/pages/slides-generator.tsx * * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * Website: https://www.spboucher.ai * Demo: https://www.vquant.ai * License: MIT (see LICENSE) * * Copyright © 2026 Simon-Pierre Boucher. All rights reserved. * ============================================================================= */ import { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { ArrowLeft, Presentation, Loader2, FileCheck, Sparkles } from "lucide-react"; import { useLocation } from "wouter"; import { useToast } from "@/hooks/use-toast"; export default function SlidesGenerator() { const [, setLocation] = useLocation(); const { toast } = useToast(); const [authorName, setAuthorName] = useState(""); const [companyName, setCompanyName] = useState("VQuant"); const [question, setQuestion] = useState(""); const [answer, setAnswer] = useState(""); const [figureUrls, setFigureUrls] = useState([]); const [isGenerating, setIsGenerating] = useState(false); const [isGenerated, setIsGenerated] = useState(false); useEffect(() => { // Récupérer le contenu depuis sessionStorage const storedContent = sessionStorage.getItem('slidesContent'); if (storedContent) { try { const { question: q, answer: a, figureUrls: f } = JSON.parse(storedContent); setQuestion(q); setAnswer(a); if (f) setFigureUrls(f); } catch (error) { console.error('Error parsing slides content:', error); toast({ title: "Erreur", description: "Impossible de charger le contenu. Retournez à la page principale.", variant: "destructive", }); } } else { toast({ title: "Aucun contenu", description: "Aucun contenu à convertir. Retournez à la page principale.", variant: "destructive", }); } }, []); const handleGenerateSlides = async () => { if (!authorName.trim()) { toast({ title: "Nom requis", description: "Veuillez entrer votre nom en tant qu'auteur", variant: "destructive", }); return; } setIsGenerating(true); try { console.log('[SlidesGenerator] Sending request to generate Beamer PDF...'); const response = await fetch('/api/convert-to-slides', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ question, answer, author: authorName, company: companyName, figureUrls, }), }); console.log('[SlidesGenerator] Response status:', response.status); console.log('[SlidesGenerator] Response content-type:', response.headers.get('content-type')); // Check if response is an error (JSON) const contentType = response.headers.get('content-type'); if (contentType?.includes('application/json')) { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to generate slides'); } // Check if response is OK if (!response.ok) { throw new Error(`Server error: ${response.status} ${response.statusText}`); } // Response should be PDF blob console.log('[SlidesGenerator] Downloading PDF blob...'); const blob = await response.blob(); console.log('[SlidesGenerator] PDF blob size:', blob.size, 'bytes'); if (blob.size === 0) { throw new Error('PDF is empty'); } // Download the PDF const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `VQuant-Presentation-${Date.now()}.pdf`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); console.log('[SlidesGenerator] ✓ PDF downloaded successfully'); toast({ title: "Présentation générée!", description: "Votre présentation Beamer PDF a été téléchargée avec succès!", }); // Mark as generated for UI update setIsGenerated(true); } catch (error) { console.error('[SlidesGenerator] Error generating slides:', error); toast({ title: "Erreur de génération", description: error instanceof Error ? error.message : "Une erreur s'est produite lors de la génération des slides. Veuillez réessayer.", variant: "destructive", }); } finally { setIsGenerating(false); } }; const handleGenerateAnother = () => { setIsGenerated(false); setAuthorName(""); sessionStorage.removeItem('slidesContent'); }; return (
{!isGenerated ? ( Générateur de Présentation Convertissez votre analyse en présentation reveal.js professionnelle avec Claude AI {/* Preview of content */}

Question :

{question}

Réponse :

{answer}

{/* Author name input */}
setAuthorName(e.target.value)} className="max-w-md" />
{/* Company name input */}
setCompanyName(e.target.value)} className="max-w-md" />
{/* Generate button */} {/* Info box */}

🎯 Comment ça marche :
1. Claude Opus 4.8 analyse votre contenu et extrait les points clés
2. Il structure l'analyse en slides professionnelles
3. LaTeX Beamer compile le tout en PDF de haute qualité
4. Le PDF est téléchargé automatiquement (30-90 secondes)

✨ Résultat : Présentation PDF de qualité académique/institutionnelle!

) : ( Présentation PDF Générée avec Succès! Votre présentation Beamer PDF professionnelle a été téléchargée

Le PDF est dans vos téléchargements!

Ouvrez-le avec n'importe quel lecteur PDF (Adobe, Preview, etc.)

✨ Votre présentation contient :

  • • Slide de titre avec vos informations
  • • Sommaire automatique
  • • Slides de contenu structurées
  • • Métriques clés mises en évidence
  • • Slide de conclusion
  • • Design professionnel LaTeX Beamer

🎯 Technologie utilisée :

  • Claude Opus 4.8 - Structure intelligente du contenu
  • LaTeX Beamer - Rendu professionnel de qualité académique
  • Theme Madrid - Design moderne et épuré
)}
); }