Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| from audio_recorder_streamlit import audio_recorder | |
| import os | |
| import tempfile | |
| from typing import List | |
| from pydub import AudioSegment | |
| from groq import Groq | |
| from langchain.chains import LLMChain | |
| from langchain_groq import ChatGroq | |
| from langchain.prompts import PromptTemplate | |
| from datetime import datetime | |
| import smtplib | |
| from email.mime.text import MIMEText | |
| from email.mime.multipart import MIMEMultipart | |
| from email.mime.application import MIMEApplication | |
| from reportlab.lib import colors | |
| from reportlab.lib.pagesizes import letter | |
| from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| import re | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| SENDER_EMAIL = os.environ.get('SENDER_EMAIL') | |
| SENDER_PASSWORD = os.environ.get('SENDER_PASSWORD') | |
| class PDFGenerator: | |
| def create_pdf(content: str, filename: str) -> str: | |
| doc = SimpleDocTemplate(filename, pagesize=letter) | |
| styles = getSampleStyleSheet() | |
| custom_style = ParagraphStyle( | |
| 'CustomStyle', | |
| parent=styles['Normal'], | |
| spaceBefore=12, | |
| spaceAfter=12, | |
| fontSize=12, | |
| leading=14, | |
| ) | |
| story = [] | |
| # Ajouter le titre | |
| title_style = ParagraphStyle( | |
| 'CustomTitle', | |
| parent=styles['Heading1'], | |
| fontSize=16, | |
| spaceAfter=30, | |
| ) | |
| story.append(Paragraph("Résumé Audio", title_style)) | |
| # Ajouter la date | |
| date_str = datetime.now().strftime("%d/%m/%Y %H:%M") | |
| story.append(Paragraph(f"Date: {date_str}", custom_style)) | |
| story.append(Spacer(1, 20)) | |
| # Convertir le contenu en paragraphes | |
| for line in content.split('\n'): | |
| if line.strip(): | |
| if line.startswith('#'): | |
| # C'est un titre | |
| story.append(Paragraph(line.strip('# '), styles['Heading2'])) | |
| else: | |
| story.append(Paragraph(line, custom_style)) | |
| doc.build(story) | |
| return filename | |
| class EmailSender: | |
| def __init__(self, sender_email: str, sender_password: str): | |
| self.sender_email = sender_email | |
| self.sender_password = sender_password | |
| def send_email(self, recipient_email: str, subject: str, body: str, pdf_path: str) -> bool: | |
| try: | |
| msg = MIMEMultipart() | |
| msg['From'] = self.sender_email | |
| msg['To'] = recipient_email | |
| msg['Subject'] = subject | |
| msg.attach(MIMEText(body, 'plain')) | |
| with open(pdf_path, 'rb') as f: | |
| pdf_attachment = MIMEApplication(f.read(), _subtype='pdf') | |
| pdf_attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(pdf_path)) | |
| msg.attach(pdf_attachment) | |
| server = smtplib.SMTP('smtp.gmail.com', 587) | |
| server.starttls() | |
| server.login(self.sender_email, self.sender_password) | |
| server.send_message(msg) | |
| server.quit() | |
| return True | |
| except Exception as e: | |
| st.error(f"Erreur d'envoi d'email: {str(e)}") | |
| return False | |
| # ... [Garder la classe AudioProcessor inchangée] ... | |
| class AudioProcessor: | |
| def __init__(self, chunk_length_ms: int = 60000): | |
| self.chunk_length_ms = chunk_length_ms | |
| self.groq_client = Groq( | |
| #api_key="" | |
| ) | |
| self.llm = ChatGroq( | |
| model="mixtral-8x7b-32768", | |
| temperature=0.7, | |
| #api_key="" | |
| ) | |
| def chunk_audio(self, file_path: str) -> List[AudioSegment]: | |
| audio = AudioSegment.from_file(file_path) | |
| chunks = [ | |
| audio[i:i + self.chunk_length_ms] | |
| for i in range(0, len(audio), self.chunk_length_ms) | |
| ] | |
| return chunks | |
| def transcribe_chunk(self, audio_chunk: AudioSegment) -> str: | |
| with tempfile.NamedTemporaryFile(suffix='.mp3', delete=True) as temp_file: | |
| audio_chunk.export(temp_file.name, format="mp3") | |
| with open(temp_file.name, "rb") as audio_file: | |
| response = self.groq_client.audio.transcriptions.create( | |
| file=audio_file, | |
| model="whisper-large-v3-turbo", | |
| language="fr" | |
| ) | |
| return response.text | |
| def generate_summary(self, transcription: str) -> str: | |
| prompt_template = """ | |
| Vous êtes un assistant expert spécialisé dans le résumé et l'analyse d'enregistrements audio en langue française. | |
| Voici la transcription à analyser: | |
| {transcript} | |
| Veuillez fournir: | |
| 1. Un résumé concis (3-4 phrases) | |
| 2. Les points clés (maximum 5 points) | |
| 3. Les actions recommandées (si pertinent) | |
| 4. Une conclusion brève | |
| Format souhaité: | |
| # Résumé | |
| [votre résumé] | |
| # Points Clés | |
| • [point 1] | |
| • [point 2] | |
| ... | |
| # Actions Recommandées | |
| 1. [action 1] | |
| 2. [action 2] | |
| ... | |
| # Conclusion | |
| [votre conclusion] | |
| """ | |
| chain = LLMChain( | |
| llm=self.llm, | |
| prompt=PromptTemplate( | |
| template=prompt_template, | |
| input_variables=["transcript"] | |
| ) | |
| ) | |
| return chain.run(transcript=transcription) | |
| def save_uploaded_file(uploaded_file): | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(uploaded_file.name)[1]) as tmp_file: | |
| tmp_file.write(uploaded_file.getvalue()) | |
| return tmp_file.name | |
| def is_valid_email(email: str) -> bool: | |
| pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$' | |
| return re.match(pattern, email) is not None | |
| def main(): | |
| st.set_page_config(page_title="Audio Summarizer", page_icon="🎙️") | |
| # Configuration email dans les secrets de Streamlit | |
| #SENDER_EMAIL = "" | |
| #SENDER_PASSWORD = "" | |
| email_sender = EmailSender(SENDER_EMAIL, SENDER_PASSWORD) | |
| st.title("🎙️ Audio Summarizer") | |
| # Initialisation des sessions states | |
| if 'audio_processor' not in st.session_state: | |
| st.session_state.audio_processor = AudioProcessor() | |
| # Interface utilisateur | |
| st.markdown("### 📤 Chargez votre fichier audio") | |
| uploaded_file = st.file_uploader("", type=['mp3', 'wav', 'm4a', 'ogg']) | |
| # Zone d'enregistrement audio | |
| st.markdown("### 🎤 Ou enregistrez directement") | |
| audio_bytes = audio_recorder() | |
| if audio_bytes: | |
| st.audio(audio_bytes, format="audio/wav") | |
| if uploaded_file or audio_bytes: | |
| with st.spinner("Traitement en cours..."): | |
| try: | |
| if uploaded_file: | |
| file_path = save_uploaded_file(uploaded_file) | |
| else: | |
| # Sauvegarder l'enregistrement audio | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| file_path = f"recording_{timestamp}.wav" | |
| with open(file_path, 'wb') as f: | |
| f.write(audio_bytes) | |
| # Traitement de l'audio | |
| chunks = st.session_state.audio_processor.chunk_audio(file_path) | |
| # Transcription | |
| with st.expander("Transcription", expanded=False): | |
| transcriptions = [] | |
| progress_bar = st.progress(0) | |
| for i, chunk in enumerate(chunks): | |
| transcription = st.session_state.audio_processor.transcribe_chunk(chunk) | |
| transcriptions.append(transcription) | |
| progress_bar.progress((i + 1) / len(chunks)) | |
| full_transcription = " ".join(transcriptions) | |
| st.text_area("Texte transcrit:", value=full_transcription, height=200) | |
| # Génération du résumé | |
| summary = st.session_state.audio_processor.generate_summary(full_transcription) | |
| st.markdown("### 📝 Résumé et Analyse") | |
| st.markdown(summary) | |
| # Création du PDF | |
| pdf_filename = f"resume_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf" | |
| pdf_path = PDFGenerator.create_pdf(summary, pdf_filename) | |
| # Options d'exportation | |
| with open(pdf_path, "rb") as pdf_file: | |
| pdf_bytes = pdf_file.read() | |
| st.download_button( | |
| label="📥 Télécharger le résumé (PDF)", | |
| data=pdf_bytes, | |
| file_name=pdf_filename, | |
| mime="application/pdf" | |
| ) | |
| # Section d'envoi par email | |
| st.markdown("### 📧 Recevoir le résumé par email") | |
| recipient_email = st.text_input("Entrez votre adresse email:") | |
| if st.button("Envoyer par email"): | |
| if not is_valid_email(recipient_email): | |
| st.error("Veuillez entrer une adresse email valide.") | |
| else: | |
| with st.spinner("Envoi de l'email en cours..."): | |
| email_body = "Veuillez trouver ci-joint le résumé de votre audio." | |
| if email_sender.send_email( | |
| recipient_email, | |
| "Résumé de votre enregistrement audio", | |
| email_body, | |
| pdf_path | |
| ): | |
| st.success("Email envoyé avec succès!") | |
| else: | |
| st.error("Échec de l'envoi de l'email.") | |
| except Exception as e: | |
| st.error(f"Une erreur est survenue: {str(e)}") | |
| finally: | |
| # Nettoyage des fichiers temporaires | |
| if 'file_path' in locals(): | |
| os.unlink(file_path) | |
| if 'pdf_path' in locals(): | |
| os.unlink(pdf_path) | |
| if __name__ == "__main__": | |
| main() |