IKRAMELHADI commited on
Commit
58fae89
·
1 Parent(s): e137539

testtest2

Browse files
Files changed (1) hide show
  1. app.py +53 -60
app.py CHANGED
@@ -1,56 +1,40 @@
 
1
  import gradio as gr
2
  import pandas as pd
3
- import numpy as np
4
  import joblib
5
  import xgboost as xgb
6
  import freesound
7
 
8
 
9
  # =========================
10
- # Token FreeSound
11
  # =========================
12
- API_TOKEN = "A ECRIRE" # <- tu remplaces ici
13
 
14
-
15
- # =========================
16
- # Durées
17
- # =========================
18
  MIN_EFFECT, MAX_EFFECT = 0.5, 3.0
19
  MIN_MUSIC, MAX_MUSIC = 10.0, 60.0
20
 
 
 
21
 
22
  # =========================
23
  # UI (CSS)
24
  # =========================
25
  CSS = """
26
- .card {
27
- border: 1px solid #e5e7eb;
28
- background: #ffffff;
29
- padding: 16px;
30
- border-radius: 16px;
31
- }
32
- .card-error{
33
- border-color: #fca5a5;
34
- background: #fff1f2;
35
- }
36
- .card-title{ font-weight: 950; margin-bottom: 8px; }
37
  .badges{ display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px; }
38
- .badge{
39
- padding:6px 10px; border-radius:999px; font-weight:900; font-size:13px;
40
- border: 1px solid #e5e7eb;
41
- }
42
- .badge-type{ background:#eef2ff; color:#3730a3;}
43
- .badge-time{ background:#ecfeff; color:#155e75;}
44
-
45
  .grid{ display:grid; grid-template-columns:1fr; gap:10px; }
46
  .box{ border:1px solid #e5e7eb; border-radius:14px; padding:12px; background:#fafafa; }
47
  .box-title{ font-weight:900; margin-bottom:4px; }
48
  .box-value{ font-size:18px; font-weight:800; }
49
-
50
  .hint{ margin-top:10px; color:#6b7280; font-size:12px; }
51
-
52
- #header-title { font-size: 28px; font-weight: 950; margin-bottom: 6px; }
53
- #header-sub { color:#6b7280; margin-top:0px; line-height:1.45; }
54
  """
55
 
56
 
@@ -92,9 +76,13 @@ def html_result(badge_text, duration, rating_text, downloads_text, extra_html=""
92
 
93
 
94
  # =========================
95
- # Interprétation
96
  # =========================
97
  def interpret_results(avg_class: int, dl_class: int) -> str:
 
 
 
 
98
  if avg_class == 0:
99
  return (
100
  "ℹ️ <b>Interprétation</b> :<br>"
@@ -133,9 +121,13 @@ def interpret_results(avg_class: int, dl_class: int) -> str:
133
 
134
 
135
  def avg_label_to_class(avg_label: str) -> int:
 
 
 
136
  if avg_label is None:
137
  return 0
138
  s = str(avg_label).strip().lower()
 
139
  if "miss" in s or "missing" in s or "none" in s or "no" in s:
140
  return 0
141
  if "high" in s or "élev" in s or "eleve" in s:
@@ -148,28 +140,27 @@ def avg_label_to_class(avg_label: str) -> int:
148
 
149
 
150
  # =========================
151
- # Init FreeSound Client
152
  # =========================
153
  client = freesound.FreesoundClient()
154
  client.set_token(API_TOKEN, "token")
155
 
156
 
157
  # =========================
158
- # Charger modèles (metadata)
159
  # =========================
 
160
  # Music
161
- xgb_music_num = joblib.load("xgb_num_downloads_music_model.pkl")
162
- xgb_music_feat_num = joblib.load("xgb_num_downloads_music_features.pkl")
163
- xgb_music_avg = joblib.load("xgb_avg_rating_music_model.pkl")
164
- xgb_music_feat_avg = joblib.load("xgb_avg_rating_music_features.pkl")
165
- le_music_avg = joblib.load("xgb_avg_rating_music_label_encoder.pkl")
166
-
167
- # Effect Sound
168
- xgb_effect_num = joblib.load("xgb_num_downloads_effectsound_model.pkl")
169
- xgb_effect_feat_num = joblib.load("xgb_num_downloads_effectsound_features.pkl")
170
- xgb_effect_avg = joblib.load("xgb_avg_rating_effectsound_model.pkl")
171
- xgb_effect_feat_avg = joblib.load("xgb_avg_rating_effectsound_features.pkl")
172
- le_effect_avg = joblib.load("xgb_avg_rating_effectsound_label_encoder.pkl")
173
 
174
  NUM_DOWNLOADS_MAP = {0: "Faible", 1: "Moyen", 2: "Élevé"}
175
 
@@ -181,19 +172,22 @@ def safe_float(v):
181
  return 0.0
182
 
183
 
184
- def predict_with_model(model, features, feat_list, le=None):
185
  row = []
186
  for col in feat_list:
187
- val = features.get(col, 0)
188
  if val is None or isinstance(val, (list, dict)):
189
  val = 0
190
  row.append(safe_float(val))
191
 
192
  X = pd.DataFrame([row], columns=feat_list)
193
- dmatrix = xgb.DMatrix(X.values, feature_names=feat_list)
194
- pred_int = int(model.get_booster().predict(dmatrix)[0])
195
 
196
- if le:
 
 
 
 
 
197
  return le.inverse_transform([pred_int])[0]
198
  return pred_int
199
 
@@ -202,15 +196,14 @@ def extract_and_predict(url: str):
202
  if not url or not url.strip():
203
  return html_error("URL vide", "Collez une URL FreeSound du type <code>https://freesound.org/s/123456/</code>")
204
 
 
205
  try:
206
  sound_id = int(url.rstrip("/").split("/")[-1])
207
  except Exception:
208
  return html_error("URL invalide", "Impossible d'extraire l'ID depuis l'URL.")
209
 
210
- # Champs nécessaires
211
- all_features = list(set(
212
- xgb_music_feat_num + xgb_music_feat_avg + xgb_effect_feat_num + xgb_effect_feat_avg
213
- ))
214
  fields = "duration," + ",".join(all_features)
215
 
216
  try:
@@ -224,7 +217,7 @@ def extract_and_predict(url: str):
224
  sound = results.results[0]
225
  duration = safe_float(sound.get("duration", 0))
226
 
227
- # Vérif durées
228
  if duration < MIN_EFFECT:
229
  return html_error(
230
  "Audio trop court",
@@ -238,11 +231,11 @@ def extract_and_predict(url: str):
238
  f"Plages : Effet sonore <b>{MIN_EFFECT}-{MAX_EFFECT}s</b> | Musique <b>{MIN_MUSIC}-{MAX_MUSIC}s</b>"
239
  )
240
 
241
- # Effect
242
  if MIN_EFFECT <= duration <= MAX_EFFECT:
243
  badge = "🔊 Effet sonore (metadata FreeSound)"
244
- dl_class = int(predict_with_model(xgb_effect_num, sound, xgb_effect_feat_num))
245
- avg_text = str(predict_with_model(xgb_effect_avg, sound, xgb_effect_feat_avg, le_effect_avg))
246
  dl_text = NUM_DOWNLOADS_MAP.get(dl_class, str(dl_class))
247
 
248
  avg_class = avg_label_to_class(avg_text)
@@ -256,8 +249,8 @@ def extract_and_predict(url: str):
256
 
257
  # Music
258
  badge = "🎵 Musique (metadata FreeSound)"
259
- dl_class = int(predict_with_model(xgb_music_num, sound, xgb_music_feat_num))
260
- avg_text = str(predict_with_model(xgb_music_avg, sound, xgb_music_feat_avg, le_music_avg))
261
  dl_text = NUM_DOWNLOADS_MAP.get(dl_class, str(dl_class))
262
 
263
  avg_class = avg_label_to_class(avg_text)
@@ -271,7 +264,7 @@ def extract_and_predict(url: str):
271
 
272
 
273
  # =========================
274
- # UI Gradio (metadata only)
275
  # =========================
276
  theme = gr.themes.Soft()
277
 
 
1
+ import os
2
  import gradio as gr
3
  import pandas as pd
 
4
  import joblib
5
  import xgboost as xgb
6
  import freesound
7
 
8
 
9
  # =========================
10
+ # CONFIG
11
  # =========================
12
+ API_TOKEN = "zE9NjEOgUMzH9K7mjiGBaPJiNwJLjSM53LevarRK" # <-- remplace ici
13
 
 
 
 
 
14
  MIN_EFFECT, MAX_EFFECT = 0.5, 3.0
15
  MIN_MUSIC, MAX_MUSIC = 10.0, 60.0
16
 
17
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
18
+
19
 
20
  # =========================
21
  # UI (CSS)
22
  # =========================
23
  CSS = """
24
+ .card { border:1px solid #e5e7eb; background:#fff; padding:16px; border-radius:16px; }
25
+ .card-error{ border-color:#fca5a5; background:#fff1f2; }
26
+ .card-title{ font-weight:950; margin-bottom:8px; }
 
 
 
 
 
 
 
 
27
  .badges{ display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px; }
28
+ .badge{ padding:6px 10px; border-radius:999px; font-weight:900; font-size:13px; border:1px solid #e5e7eb; }
29
+ .badge-type{ background:#eef2ff; color:#3730a3; }
30
+ .badge-time{ background:#ecfeff; color:#155e75; }
 
 
 
 
31
  .grid{ display:grid; grid-template-columns:1fr; gap:10px; }
32
  .box{ border:1px solid #e5e7eb; border-radius:14px; padding:12px; background:#fafafa; }
33
  .box-title{ font-weight:900; margin-bottom:4px; }
34
  .box-value{ font-size:18px; font-weight:800; }
 
35
  .hint{ margin-top:10px; color:#6b7280; font-size:12px; }
36
+ #header-title{ font-size:28px; font-weight:950; margin-bottom:6px; }
37
+ #header-sub{ color:#6b7280; margin-top:0px; line-height:1.45; }
 
38
  """
39
 
40
 
 
76
 
77
 
78
  # =========================
79
+ # INTERPRETATION
80
  # =========================
81
  def interpret_results(avg_class: int, dl_class: int) -> str:
82
+ """
83
+ avg_class: 0=Missed info, 1=Low, 2=Medium, 3=High (déduit du label texte)
84
+ dl_class: 0=Low, 1=Medium, 2=High (sortie num_downloads)
85
+ """
86
  if avg_class == 0:
87
  return (
88
  "ℹ️ <b>Interprétation</b> :<br>"
 
121
 
122
 
123
  def avg_label_to_class(avg_label: str) -> int:
124
+ """
125
+ Convertit label texte du label encoder en 0..3
126
+ """
127
  if avg_label is None:
128
  return 0
129
  s = str(avg_label).strip().lower()
130
+
131
  if "miss" in s or "missing" in s or "none" in s or "no" in s:
132
  return 0
133
  if "high" in s or "élev" in s or "eleve" in s:
 
140
 
141
 
142
  # =========================
143
+ # FreeSound client
144
  # =========================
145
  client = freesound.FreesoundClient()
146
  client.set_token(API_TOKEN, "token")
147
 
148
 
149
  # =========================
150
+ # Charger les modèles (NOMS EXACTS DU REPO)
151
  # =========================
152
+
153
  # Music
154
+ music_num_model = joblib.load(os.path.join(BASE_DIR, "music_model_num_downloads.joblib"))
155
+ music_feat_list = joblib.load(os.path.join(BASE_DIR, "music_model_features_list.joblib"))
156
+ music_avg_model = joblib.load(os.path.join(BASE_DIR, "music_xgb_avg_rating.joblib"))
157
+ music_avg_le = joblib.load(os.path.join(BASE_DIR, "music_xgb_avg_rating_label_encoder.joblib"))
158
+
159
+ # Effect sound
160
+ effect_num_model = joblib.load(os.path.join(BASE_DIR, "effectSound_model_num_downloads.joblib"))
161
+ effect_feat_list = joblib.load(os.path.join(BASE_DIR, "effect_model_features_list.joblib"))
162
+ effect_avg_model = joblib.load(os.path.join(BASE_DIR, "effectSound_xgb_avg_rating.joblib"))
163
+ effect_avg_le = joblib.load(os.path.join(BASE_DIR, "effectSound_xgb_avg_rating_label_encoder.joblib"))
 
 
164
 
165
  NUM_DOWNLOADS_MAP = {0: "Faible", 1: "Moyen", 2: "Élevé"}
166
 
 
172
  return 0.0
173
 
174
 
175
+ def predict_with_model(model, features_dict, feat_list, le=None):
176
  row = []
177
  for col in feat_list:
178
+ val = features_dict.get(col, 0)
179
  if val is None or isinstance(val, (list, dict)):
180
  val = 0
181
  row.append(safe_float(val))
182
 
183
  X = pd.DataFrame([row], columns=feat_list)
 
 
184
 
185
+ # DMatrix (avec feature names)
186
+ dm = xgb.DMatrix(X.values, feature_names=feat_list)
187
+
188
+ pred_int = int(model.get_booster().predict(dm)[0])
189
+
190
+ if le is not None:
191
  return le.inverse_transform([pred_int])[0]
192
  return pred_int
193
 
 
196
  if not url or not url.strip():
197
  return html_error("URL vide", "Collez une URL FreeSound du type <code>https://freesound.org/s/123456/</code>")
198
 
199
+ # Parse ID
200
  try:
201
  sound_id = int(url.rstrip("/").split("/")[-1])
202
  except Exception:
203
  return html_error("URL invalide", "Impossible d'extraire l'ID depuis l'URL.")
204
 
205
+ # champs nécessaires (union music+effect)
206
+ all_features = list(set(music_feat_list + effect_feat_list))
 
 
207
  fields = "duration," + ",".join(all_features)
208
 
209
  try:
 
217
  sound = results.results[0]
218
  duration = safe_float(sound.get("duration", 0))
219
 
220
+ # Durées supportées
221
  if duration < MIN_EFFECT:
222
  return html_error(
223
  "Audio trop court",
 
231
  f"Plages : Effet sonore <b>{MIN_EFFECT}-{MAX_EFFECT}s</b> | Musique <b>{MIN_MUSIC}-{MAX_MUSIC}s</b>"
232
  )
233
 
234
+ # Décision type
235
  if MIN_EFFECT <= duration <= MAX_EFFECT:
236
  badge = "🔊 Effet sonore (metadata FreeSound)"
237
+ dl_class = int(predict_with_model(effect_num_model, sound, effect_feat_list))
238
+ avg_text = str(predict_with_model(effect_avg_model, sound, effect_feat_list, effect_avg_le))
239
  dl_text = NUM_DOWNLOADS_MAP.get(dl_class, str(dl_class))
240
 
241
  avg_class = avg_label_to_class(avg_text)
 
249
 
250
  # Music
251
  badge = "🎵 Musique (metadata FreeSound)"
252
+ dl_class = int(predict_with_model(music_num_model, sound, music_feat_list))
253
+ avg_text = str(predict_with_model(music_avg_model, sound, music_feat_list, music_avg_le))
254
  dl_text = NUM_DOWNLOADS_MAP.get(dl_class, str(dl_class))
255
 
256
  avg_class = avg_label_to_class(avg_text)
 
264
 
265
 
266
  # =========================
267
+ # UI
268
  # =========================
269
  theme = gr.themes.Soft()
270