alec228 commited on
Commit
2a0b1db
·
1 Parent(s): c23173c

Initial commit

Browse files
Files changed (3) hide show
  1. README_HF.md +66 -0
  2. app.py +183 -0
  3. requirements_hf.txt +10 -0
README_HF.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🎤 Analyse de Sentiment Audio
2
+
3
+ Ce Space Hugging Face permet d'analyser le sentiment d'extraits audio en français en combinant transcription et analyse de sentiment.
4
+
5
+ ## 🚀 Fonctionnalités
6
+
7
+ - **🎙️ Transcription audio** : Utilise Wav2Vec2 pour transcrire l'audio en français
8
+ - **😊 Analyse de sentiment** : Analyse le sentiment du texte transcrit avec BERT multilingue
9
+ - **📊 Analyse détaillée** : Segmentation par phrase avec scores de confiance
10
+ - **💾 Export CSV** : Sauvegarde de l'historique des analyses
11
+ - **🎯 Interface intuitive** : Interface Gradio moderne et responsive
12
+
13
+ ## 🛠️ Technologies utilisées
14
+
15
+ - **Transcription** : `jonatasgrosman/wav2vec2-large-xlsr-53-french`
16
+ - **Sentiment** : `nlptown/bert-base-multilingual-uncased-sentiment`
17
+ - **Interface** : Gradio
18
+ - **Backend** : PyTorch, Transformers
19
+
20
+ ## 📖 Comment utiliser
21
+
22
+ 1. **Enregistrez** votre voix directement dans le navigateur
23
+ 2. **Ou téléversez** un fichier audio (WAV recommandé)
24
+ 3. **Cliquez** sur "Analyser" pour lancer le traitement
25
+ 4. **Visualisez** les résultats : transcription, sentiment, et analyse détaillée
26
+ 5. **Exportez** l'historique au format CSV si nécessaire
27
+
28
+ ## 🎯 Cas d'usage
29
+
30
+ - Analyse de sentiment sur des appels clients
31
+ - Évaluation de podcasts ou interviews
32
+ - Validation d'analyses qualitatives de contenu audio
33
+ - Proof of Concept pour architectures multimodales
34
+
35
+ ## 🔧 Architecture
36
+
37
+ Le pipeline combine :
38
+ 1. **Extraction audio** → Prétraitement et normalisation
39
+ 2. **Transcription** → Wav2Vec2 pour la reconnaissance vocale
40
+ 3. **Analyse sentiment** → BERT pour la classification
41
+ 4. **Post-traitement** → Segmentation et scoring
42
+
43
+ ## 📝 Exemple de sortie
44
+
45
+ ```json
46
+ {
47
+ "transcription": "je suis très content de ce produit",
48
+ "sentiment": {
49
+ "positif": 0.85,
50
+ "neutre": 0.10,
51
+ "négatif": 0.05
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## 🌟 Fonctionnalités avancées
57
+
58
+ - **Gestion d'erreurs** robuste
59
+ - **Interface responsive** adaptée mobile/desktop
60
+ - **Historique persistant** des analyses
61
+ - **Export de données** au format CSV
62
+ - **Analyse segmentée** par phrase
63
+
64
+ ---
65
+
66
+ *Développé avec ❤️ pour l'analyse de sentiment audio en français*
app.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ from datetime import datetime
4
+
5
+ import gradio as gr
6
+ import torch
7
+ import pandas as pd
8
+ import soundfile as sf
9
+ import torchaudio
10
+
11
+ from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC
12
+ from src.transcription import SpeechEncoder
13
+ from src.sentiment import TextEncoder
14
+
15
+ # Configuration pour Hugging Face Spaces
16
+ HF_SPACE = os.getenv("HF_SPACE", "false").lower() == "true"
17
+
18
+ # Préchargement des modèles
19
+ print("Chargement des modèles...")
20
+ processor_ctc = Wav2Vec2Processor.from_pretrained(
21
+ "jonatasgrosman/wav2vec2-large-xlsr-53-french",
22
+ cache_dir="./models" if not HF_SPACE else None
23
+ )
24
+ model_ctc = Wav2Vec2ForCTC.from_pretrained(
25
+ "jonatasgrosman/wav2vec2-large-xlsr-53-french",
26
+ cache_dir="./models" if not HF_SPACE else None
27
+ )
28
+
29
+ speech_enc = SpeechEncoder()
30
+ text_enc = TextEncoder()
31
+ print("Modèles chargés avec succès!")
32
+
33
+ # Pipeline d'analyse
34
+ def analyze_audio(audio_path):
35
+ if audio_path is None:
36
+ return "Aucun audio fourni", "", pd.DataFrame(), {}
37
+
38
+ try:
39
+ # Lecture et prétraitement
40
+ data, sr = sf.read(audio_path)
41
+ arr = data.T if data.ndim > 1 else data
42
+ wav = torch.from_numpy(arr).unsqueeze(0).float()
43
+ if sr != 16000:
44
+ wav = torchaudio.transforms.Resample(sr, 16000)(wav)
45
+ sr = 16000
46
+ if wav.size(0) > 1:
47
+ wav = wav.mean(dim=0, keepdim=True)
48
+
49
+ # Transcription
50
+ inputs = processor_ctc(wav.squeeze().numpy(), sampling_rate=sr, return_tensors="pt")
51
+ with torch.no_grad():
52
+ logits = model_ctc(**inputs).logits
53
+ pred_ids = torch.argmax(logits, dim=-1)
54
+ transcription = processor_ctc.batch_decode(pred_ids)[0].lower()
55
+
56
+ # Sentiment principal
57
+ sent_dict = TextEncoder.analyze_sentiment(transcription)
58
+ label, conf = max(sent_dict.items(), key=lambda x: x[1])
59
+ emojis = {"positif": "😊", "neutre": "😐", "négatif": "☹️"}
60
+ emoji = emojis.get(label, "")
61
+
62
+ # Segmentation par phrase
63
+ segments = [s.strip() for s in re.split(r'[.?!]', transcription) if s.strip()]
64
+ seg_results = []
65
+ for seg in segments:
66
+ sd = TextEncoder.analyze_sentiment(seg)
67
+ l, c = max(sd.items(), key=lambda x: x[1])
68
+ seg_results.append({"Segment": seg, "Sentiment": l.capitalize(), "Confiance (%)": round(c*100,1)})
69
+ seg_df = pd.DataFrame(seg_results)
70
+
71
+ # Historique entry
72
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
73
+ history_entry = {
74
+ "Horodatage": timestamp,
75
+ "Transcription": transcription,
76
+ "Sentiment": label.capitalize(),
77
+ "Confiance (%)": round(conf*100,1)
78
+ }
79
+
80
+ # Rendu
81
+ summary_html = (
82
+ f"<div style='display:flex;align-items:center;'>"
83
+ f"<span style='font-size:3rem;margin-right:10px;'>{emoji}</span>"
84
+ f"<h2 style='color:#6a0dad;'>{label.upper()}</h2>"
85
+ f"</div>"
86
+ f"<p><strong>Confiance :</strong> {conf*100:.1f}%</p>"
87
+ )
88
+ return transcription, summary_html, seg_df, history_entry
89
+
90
+ except Exception as e:
91
+ error_msg = f"Erreur lors de l'analyse: {str(e)}"
92
+ return error_msg, "", pd.DataFrame(), {}
93
+
94
+ # Export CSV
95
+ def export_history_csv(history):
96
+ if not history:
97
+ return None
98
+ df = pd.DataFrame(history)
99
+ path = "history.csv"
100
+ df.to_csv(path, index=False)
101
+ return path
102
+
103
+ # Interface Gradio
104
+ demo = gr.Blocks(
105
+ theme=gr.themes.Monochrome(primary_hue="purple"),
106
+ title="Analyse de Sentiment Audio - Hugging Face Space"
107
+ )
108
+
109
+ with demo:
110
+ gr.Markdown("""
111
+ # 🎤 Analyse de Sentiment Audio
112
+
113
+ Ce Space permet d'analyser le sentiment d'extraits audio en français en combinant :
114
+ - **Transcription audio** avec Wav2Vec2
115
+ - **Analyse de sentiment** avec BERT multilingue
116
+ """)
117
+
118
+ gr.HTML("""
119
+ <div style="display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px;">
120
+ <div style="background-color: #f3e8ff; padding: 12px 20px; border-radius: 12px; border-left: 5px solid #8e44ad;">
121
+ <strong>Étape 1 :</strong> Enregistrez votre voix ou téléversez un fichier audio (format WAV recommandé).
122
+ </div>
123
+ <div style="background-color: #e0f7fa; padding: 12px 20px; border-radius: 12px; border-left: 5px solid #0097a7;">
124
+ <strong>Étape 2 :</strong> Cliquez sur le bouton <em><b>Analyser</b></em> pour lancer la transcription et l'analyse.
125
+ </div>
126
+ <div style="background-color: #fff3e0; padding: 12px 20px; border-radius: 12px; border-left: 5px solid #fb8c00;">
127
+ <strong>Étape 3 :</strong> Visualisez les résultats : transcription, sentiment, et analyse détaillée.
128
+ </div>
129
+ <div style="background-color: #e8f5e9; padding: 12px 20px; border-radius: 12px; border-left: 5px solid #43a047;">
130
+ <strong>Étape 4 :</strong> Exportez l'historique des analyses au format CSV si besoin.
131
+ </div>
132
+ </div>
133
+ """)
134
+
135
+ with gr.Row():
136
+ with gr.Column(scale=2):
137
+ audio_in = gr.Audio(
138
+ sources=["microphone", "upload"],
139
+ type="filepath",
140
+ label="Audio Input",
141
+ info="Enregistrez ou téléversez un fichier audio"
142
+ )
143
+ btn = gr.Button("🔍 Analyser", variant="primary")
144
+ export_btn = gr.Button("📊 Exporter CSV")
145
+
146
+ with gr.Column(scale=3):
147
+ chat = gr.Chatbot(label="Historique des échanges")
148
+ transcription_out = gr.Textbox(label="Transcription", interactive=False)
149
+ summary_out = gr.HTML(label="Sentiment")
150
+ seg_out = gr.Dataframe(label="Détail par segment")
151
+ hist_out = gr.Dataframe(label="Historique")
152
+
153
+ state_chat = gr.State([]) # list of (user,bot)
154
+ state_hist = gr.State([]) # list of dict entries
155
+
156
+ def chat_callback(audio_path, chat_history, hist_state):
157
+ transcription, summary, seg_df, hist_entry = analyze_audio(audio_path)
158
+ user_msg = "[Audio reçu]"
159
+ bot_msg = f"**Transcription :** {transcription}\n**Sentiment :** {summary}"
160
+ chat_history = chat_history + [(user_msg, bot_msg)]
161
+ if hist_entry:
162
+ hist_state = hist_state + [hist_entry]
163
+ return chat_history, transcription, summary, seg_df, hist_state
164
+
165
+ btn.click(
166
+ fn=chat_callback,
167
+ inputs=[audio_in, state_chat, state_hist],
168
+ outputs=[chat, transcription_out, summary_out, seg_out, state_hist]
169
+ )
170
+
171
+ export_btn.click(
172
+ fn=export_history_csv,
173
+ inputs=[state_hist],
174
+ outputs=[gr.File(label="Télécharger CSV")]
175
+ )
176
+
177
+ # Configuration pour Hugging Face Spaces
178
+ if __name__ == "__main__":
179
+ demo.launch(
180
+ server_name="0.0.0.0" if HF_SPACE else "127.0.0.1",
181
+ server_port=7860,
182
+ share=False
183
+ )
requirements_hf.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ transformers==4.36.2
2
+ torch==2.1.2
3
+ torchaudio==2.1.2
4
+ gradio==4.15.0
5
+ fastapi==0.104.1
6
+ uvicorn[standard]==0.24.0
7
+ soundfile==0.12.1
8
+ pandas==2.1.4
9
+ numpy==1.24.3
10
+ scikit-learn==1.3.2