import gradio as gr import os import tempfile from datetime import datetime import logging import json import PyPDF2 from docx import Document # Configuration logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Initialisation des services from ai_enhance import AIEnhance from presentation_generator import PresentationGenerator ai_service = AIEnhance() presentation_generator = PresentationGenerator() # Code secret CODE_SECRET = "32015" # code à cinq chiffres def verifier_code(code): """Vérifie si le code entré est correct""" if code == CODE_SECRET: return True, "🔓 Accès autorisé !" else: return False, "❌ Code incorrect. Veuillez réessayer." # FONCTIONS D'EXTRACTION DE TEXTE CORRIGÉES def extract_text_from_pdf(file_path): """Extrait le texte d'un fichier PDF""" try: with open(file_path, 'rb') as file: pdf_reader = PyPDF2.PdfReader(file) text = "" for page in pdf_reader.pages: text += page.extract_text() + "\n" return text.strip() except Exception as e: logger.error(f"Erreur extraction PDF: {e}") raise Exception(f"Erreur lors de l'extraction du PDF: {str(e)}") def extract_text_from_docx(file_path): """Extrait le texte d'un fichier Word""" try: doc = Document(file_path) text = "" for paragraph in doc.paragraphs: text += paragraph.text + "\n" return text.strip() except Exception as e: logger.error(f"Erreur extraction DOCX: {e}") raise Exception(f"Erreur lors de l'extraction du document Word: {str(e)}") def extract_text_from_txt(file_path): """Extrait le texte d'un fichier texte""" try: with open(file_path, 'r', encoding='utf-8') as file: return file.read().strip() except Exception as e: logger.error(f"Erreur extraction TXT: {e}") raise Exception(f"Erreur lors de l'extraction du fichier texte: {str(e)}") def extract_text_from_file(file_obj): """Extrait le texte selon le format du fichier - VERSION CORRIGÉE""" try: # GESTION CORRIGÉE DU TYPE DE FICHIER if hasattr(file_obj, 'name'): file_path = file_obj.name else: file_path = file_obj # C'est déjà un chemin file_extension = os.path.splitext(file_path)[1].lower() logger.info(f"📁 Extraction du fichier: {file_path}") if file_extension == '.pdf': return extract_text_from_pdf(file_path) elif file_extension in ['.doc', '.docx']: return extract_text_from_docx(file_path) elif file_extension == '.txt': return extract_text_from_txt(file_path) else: raise Exception(f"Format non supporté: {file_extension}") except Exception as e: logger.error(f"❌ Erreur extraction: {e}") raise def create_presentation_structure(texte): """Crée la structure de présentation avec analyse IA""" try: # ESSAYER DIFFÉRENTES MÉTHODES POUR TROUVER CELLE QUI FONCTIONNE if hasattr(ai_service, '_basic_analysis'): analysis = ai_service._basic_analysis(texte) elif hasattr(ai_service, 'analyze_text_advanced'): analysis = ai_service.analyze_text_advanced(texte) else: # Créer une analyse de base manuellement analysis = { "statistics": { "word_count": len(texte.split()), "sentence_count": texte.count('.'), "paragraph_count": len([p for p in texte.split('\n\n') if p.strip()]) }, "keywords": ["texte", "analyse", "présentation"], "recommended_structure": { "slides": [ {"title": "Introduction", "content": "Présentation du sujet"}, {"title": "Développement", "content": "Points principaux"}, {"title": "Conclusion", "content": "Synthèse"} ], "recommended_style": "professionnel" }, "content_analysis": "général" } summary = ai_service.smart_summarize(texte) structure = { "title": f"Présentation: {analysis['content_analysis'].capitalize()}", "slides": analysis["recommended_structure"]["slides"], "key_points": analysis["keywords"][:8], "style_recommendation": analysis["recommended_structure"]["recommended_style"], "analysis_metadata": analysis } return structure, summary except Exception as e: logger.error(f"Erreur dans create_presentation_structure: {e}") # Retourner une structure par défaut en cas d'erreur default_structure = { "title": "Présentation Générée par IA", "slides": [ {"title": "Introduction", "content": "Votre texte a été analysé avec succès"}, {"title": "Points Principaux", "content": "Les insights clés ont été extraits"}, {"title": "Conclusion", "content": "Synthèse des éléments importants"} ], "key_points": ["analyse", "texte", "présentation"], "analysis_metadata": {"statistics": {"word_count": len(texte.split())}} } return default_structure, texte[:200] + "..." def generate_presentation_gradio(texte, style="professionnel"): """Version Gradio améliorée avec prévisualisation""" try: if not texte or len(texte.strip()) < 50: return None, None, "❌ Veuillez entrer au moins 50 caractères." logger.info(f"🚀 Génération IA pour {len(texte)} caractères") # Générer la structure structure, summary = create_presentation_structure(texte) filename = presentation_generator.generate_presentation(structure, style) # Créer une belle prévisualisation preview_html = create_preview_html(structure, summary) logger.info("✅ Présentation générée avec succès!") return filename, preview_html, f"🎉 Présentation générée! ({len(structure['slides'])} slides)" except Exception as e: logger.error(f"❌ Erreur lors de la génération: {e}") return None, None, f"❌ Erreur: {str(e)}" def create_preview_html(structure, summary): """Crée une belle prévisualisation HTML des slides""" html_content = f"""

📊 Aperçu de votre Présentation

🎯 Titre Principal

{structure['title']}

📝 Résumé IA

{summary}

🔄 Structure des Slides

""" # Ajouter chaque slide for i, slide in enumerate(structure['slides']): html_content += f"""
{i+1}

{slide['title']}

{slide['content']}

""" # Ajouter les points clés html_content += f"""

🎯 Points Clés Identifiés

""" for point in structure['key_points']: html_content += f'{point}' html_content += """
""" return html_content ##### FONCTIONS UPLOAD CORRIGÉES ##### def handle_file_upload(files): """Gère l'upload de fichiers et extrait le texte - VERSION CORRIGÉE""" if not files: return None, None, "❌ Aucun fichier sélectionné." try: # CORRECTION : Gradio passe une liste, prendre le premier élément file_obj = files[0] if isinstance(files, list) else files extracted_text = extract_text_from_file(file_obj) if not extracted_text or len(extracted_text.strip()) < 10: return None, None, "❌ Le fichier semble vide ou ne contient pas de texte extractible." # Statistiques word_count = len(extracted_text.split()) char_count = len(extracted_text) message = f"✅ Fichier traité avec succès! 📊 {word_count} mots, {char_count} caractères" return extracted_text, extracted_text, message except Exception as e: logger.error(f"Erreur upload: {e}") return None, None, f"❌ Erreur: {str(e)}" def generate_from_uploaded_text(analyzed_text, style="professionnel"): """Génère la présentation à partir du texte uploadé""" return generate_presentation_gradio(analyzed_text, style) def analyze_text_gradio(texte): """Version Gradio de votre api_analyze()""" try: if not texte or len(texte.strip()) < 10: return "❌ Texte trop court. Minimum 10 caractères." structure, summary = create_presentation_structure(texte) # Formatage pour l'interface Gradio result = f""" ## 📊 Analyse IA du Texte **Statistiques:** - {structure['analysis_metadata']['statistics']['word_count']} mots - {structure['analysis_metadata']['statistics']['sentence_count']} phrases - {structure['analysis_metadata']['statistics']['paragraph_count']} paragraphes **🎯 Thèmes identifiés:** {', '.join(structure['key_points'][:8])} **📝 Résumé:** {summary} **🏗️ Structure proposée:** """ for i, slide in enumerate(structure['slides']): result += f"\n{i+1}. **{slide['title']}** - {slide['content'][:100]}..." return result except Exception as e: return f"❌ Erreur d'analyse: {str(e)}" # FONCTION CORRIGÉE POUR LES INFOS DE FICHIER def update_file_info(files): """Met à jour les informations du fichier uploadé - VERSION CORRIGÉE""" if not files: return "Aucun fichier sélectionné" try: # CORRECTION : Gradio passe une liste, prendre le premier élément file_obj = files[0] if isinstance(files, list) else files # Gestion des différents types d'objets fichier if hasattr(file_obj, 'name'): file_path = file_obj.name elif isinstance(file_obj, str): file_path = file_obj else: return "Type de fichier non supporté" file_name = os.path.basename(file_path) file_size = os.path.getsize(file_path) / 1024 # KB return f"📄 {file_name} ({file_size:.1f} KB)" except Exception as e: logger.error(f"Erreur dans update_file_info: {e}") return "Erreur lors de la lecture du fichier" # INTERFACE PRINCIPALE AVEC AUTHENTIFICATION with gr.Blocks(theme=gr.themes.Soft(), title="Générateur de Présentation IA") as demo: # Écran d'authentification with gr.Column(visible=True) as auth_screen: gr.Markdown("# 🔒 Accès Sécurisé") gr.Markdown("Veuillez entrer le code d'accès à 5 chiffres") with gr.Row(): code_input = gr.Textbox( label="Code d'accès", type="text", max_lines=1, placeholder="Entrez les 5 chiffres...", elem_id="code_input" ) verifier_btn = gr.Button("Vérifier", variant="primary") message_sortie = gr.Textbox(label="Statut", interactive=False) # Application principale (cachée au début) with gr.Column(visible=False) as app_screen: gr.Markdown(""" # 🧠 Générateur de Présentation IA Intelligente **Powered by Lab_Math_and Labhp & CIE Label_Bertoua** Transformez votre texte en présentation PowerPoint professionnelle en quelques secondes ! """) with gr.Tab("🚀 Générer à partir de Texte"): with gr.Row(): with gr.Column(): text_input = gr.Textbox( label="📝 Collez votre texte ici", placeholder="Collez ou tapez votre texte, article, rapport... (minimum 50 caractères)", lines=12, max_lines=20 ) style_dropdown = gr.Dropdown( choices=["professionnel", "moderne", "creatif"], label="🎨 Style de présentation", value="professionnel", info="Choisissez le style visuel de votre présentation" ) generate_btn = gr.Button("🚀 Générer la Présentation", variant="primary", size="lg") with gr.Column(): output_file = gr.File(label="📥 Télécharger la Présentation", file_types=[".pptx"]) preview_output = gr.HTML(label="👁️ Aperçu de la Structure") output_message = gr.Textbox(label="📋 Statut", interactive=False) generate_btn.click( fn=generate_presentation_gradio, inputs=[text_input, style_dropdown], outputs=[output_file, preview_output, output_message] ) with gr.Tab("📁 Générer à partir de Fichier"): gr.Markdown("### 📤 Uploader votre document") gr.Markdown(""" **Formats supportés:** - 📄 PDF (rapports, articles) - 📝 DOC/DOCX (documents Word) - 📋 TXT (fichiers texte) """) with gr.Row(): with gr.Column(): upload_button = gr.UploadButton( "📁 Choisir un fichier", file_types=[".pdf", ".doc", ".docx", ".txt"], file_count="single", size="lg" ) uploaded_file_info = gr.Textbox( label="📋 Fichier sélectionné", interactive=False, value="Aucun fichier sélectionné" ) extract_btn = gr.Button("🔍 Extraire et Analyser", variant="primary") with gr.Column(): extracted_text = gr.Textbox( label="📝 Texte extrait", interactive=False, lines=8, max_lines=12, placeholder="Le texte extrait apparaîtra ici..." ) upload_status = gr.Textbox( label="📊 Statut extraction", interactive=False, value="En attente de fichier..." ) with gr.Row(): file_style_dropdown = gr.Dropdown( choices=["professionnel", "moderne", "creatif"], label="🎨 Style de présentation", value="professionnel" ) generate_from_file_btn = gr.Button("🚀 Générer la Présentation", variant="primary") with gr.Row(): file_output = gr.File(label="📥 Présentation Générée", file_types=[".pptx"]) file_preview = gr.HTML(label="👁️ Aperçu") file_message = gr.Textbox( label="📋 Statut génération", interactive=False, value="En attente..." ) # GESTION DES INTERACTIONS UPLOAD - VERSION CORRIGÉE upload_button.upload( fn=update_file_info, inputs=[upload_button], outputs=[uploaded_file_info] ) extract_btn.click( fn=handle_file_upload, inputs=[upload_button], outputs=[extracted_text, extracted_text, upload_status] ) generate_from_file_btn.click( fn=generate_from_uploaded_text, inputs=[extracted_text, file_style_dropdown], outputs=[file_output, file_preview, file_message] ) def gerer_acces(code): """Gère l'authentification et affiche l'application si le code est correct""" est_valide, message = verifier_code(code) return ( message, gr.update(visible=not est_valide), # Cacher l'écran d'auth gr.update(visible=est_valide) # Afficher l'application ) # Lier le bouton de vérification verifier_btn.click( fn=gerer_acces, inputs=[code_input], outputs=[message_sortie, auth_screen, app_screen] ) if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, share=False )