clementBE commited on
Commit
b71c521
·
verified ·
1 Parent(s): 7153300

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -34
app.py CHANGED
@@ -3,14 +3,15 @@ import pandas as pd
3
  import os
4
  import time
5
  from typing import List, Union, Dict, Any, Tuple
 
6
 
7
  # =================================================================
8
  # CONFIGURATION AND LANGUAGE DEFINITIONS
9
  # =================================================================
10
 
11
- # Setting EXPECTED_DATA_COUNT based on the final verified structure: 89
12
- EXPECTED_DATA_COUNT = 89
13
- EXPECTED_COUNT = 89
14
 
15
  # --- Shared Choices (French Only) ---
16
  FREQ_FR = ["Jamais", "Rarement", "Parfois", "Souvent"]
@@ -52,6 +53,33 @@ INFO5_CHOICES = [
52
  "autre réaction"
53
  ]
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  # --- Language Definitions (French Only) ---
57
  LANG_FR = {
@@ -68,14 +96,10 @@ LANG_FR = {
68
  "SPACE1_LABEL": "SPACE1 - Fréquentes-tu des lieux culturels (au sens large, y compris alternatifs, non institutionnels) ?",
69
  "SPACE2A_TITLE": "Derniers lieux culturels fréquentés (3 max. - si Rarement/Parfois/Souvent)",
70
  "SPACE2B_LABEL": "SPACE2b (si “jamais”) - Pourquoi ne fréquentes-tu jamais de lieux culturels ? (plusieurs réponses possibles)",
71
-
72
- # FIX: Mise à jour du titre SPACE3 selon la nouvelle qualification demandée (titre SPACE4)
73
  "SPACE3_TITLE": "SPACE4 - Pourrais-tu qualifier ces lieux ?",
74
  "SPACE3_QUAL_1": "Lieu 1 : Alternatif/Underground (1) à Institutionnel/Mainstream (10)",
75
  "SPACE3_QUAL_2": "Lieu 2 : Alternatif (1) à Institutionnel (10)",
76
  "SPACE3_QUAL_3": "Lieu 3 : Alternatif (1) à Institutionnel (10)",
77
-
78
- # Les labels suivants conservent leur numérotation pour la cohérence des variables
79
  "SPACE4_LABEL": "SPACE4_bis - Est-ce que tu suis régulièrement une communauté alternative en ligne (médias sociaux, newsletter, groupe dédié...)",
80
  "SPACE5_LABEL": "SPACE5 - Peux-tu indiquer son nom ou son url ? (si SPACE4_bis=oui)",
81
  "SPACE6_LABEL": "SPACE6 - As-tu connaissance de pratiques d’engagement citoyen dans ces lieux ?",
@@ -83,8 +107,9 @@ LANG_FR = {
83
  "SPACE_DOMAIN_LABEL": "Peux-tu caractériser le domaine dans lequel s’inscrit principalement cette pratique ?",
84
  "SPACE11_LABEL": "SPACE11 - Sais-tu si elle s’appuie sur une communauté en ligne et l’usage d’un média social en ligne ?",
85
  "SPACE2B_OPTIONS": ["Pas le temps", "Trop cher", "Je ne sais pas où aller", "Pas intéressé", "Autre"],
86
- "INFO1_LABEL": "INFO1 - Toi-même, participes-tu à des pratiques d’engagement citoyen ?",
87
  "ENGAGEMENT_ORGANISATION_LABEL": "ENGAGE2 - Dans quelle(s) organisation(s) es-tu engagé·e ?",
 
88
  "ENGAGEMENT_DOMAINE_LABEL": "ENGAGE3 - Dans quel domaine ? (Si engagé·e)",
89
  "INFO_ACTIVITES_LABEL": "ENGAGE4 - Participes-tu ou as-tu participé à une ou plusieurs des activités suivantes ?",
90
  "INFO_RESEAUX_SOCIAUX_LABEL": "ENGAGE5 - Utilises-tu les réseaux sociaux pour t’engager dans des causes ?",
@@ -103,7 +128,8 @@ LANG_FR = {
103
  "PLATFORM_TITLE": "DIGITAL1 - Quelles plateformes utilises-tu le plus ? (Heures/jour approx.)",
104
  "PURPOSE_TITLE": "DIGITAL2 - Pour quel(s) usage(s) emploies-tu ces plateformes ?",
105
  "DEMO_GENDER_LABEL": "DEMO_GENDER - Ton genre :",
106
- "DEMO_AGE_LABEL": "DEMO_AGE - Ta date de naissance (AAAA-MM-JJ)",
 
107
  "DEMO_LOCATION_COMMUNE_LABEL": "DEMO_LOCATION - Commune de résidence habituelle :",
108
  "DEMO_LOCATION_ARROND_LABEL": "Arrondissement (si Paris) :",
109
  "DEMO_PARENTS_LOCATION_LABEL": "DEMO_PARENTS - Est-ce le lieu d’habitation de tes parents ?",
@@ -149,12 +175,10 @@ space2a_2 = gr.Textbox(label="Lieu 2", visible=False)
149
  space2a_3 = gr.Textbox(label="Lieu 3", visible=False)
150
  space2b = gr.CheckboxGroup(label=LANG["SPACE2B_LABEL"], choices=LANG["SPACE2B_OPTIONS"], visible=False)
151
 
152
- # FIX: Mise à jour des sliders SPACE3 (nouveau label et description)
153
  space3_1 = gr.Slider(label=LANG["SPACE3_QUAL_1"], minimum=1, maximum=10, step=1, visible=False)
154
  space3_2 = gr.Slider(label=LANG["SPACE3_QUAL_2"], minimum=1, maximum=10, step=1, visible=False)
155
  space3_3 = gr.Slider(label=LANG["SPACE3_QUAL_3"], minimum=1, maximum=10, step=1, visible=False)
156
 
157
- # Les composants suivants conservent leur nom de variable (space4, space5, space6...) pour la cohérence des données
158
  space4 = gr.Radio(label=LANG["SPACE4_LABEL"], choices=["Oui", "Non"])
159
  space5 = gr.Textbox(label=LANG["SPACE5_LABEL"], visible=False)
160
  space6 = gr.Radio(label=LANG["SPACE6_LABEL"], choices=["Oui", "Non", "Ne sait pas"])
@@ -170,8 +194,9 @@ space_domain_3 = gr.Radio(label=f"Pratique 3 - {LANG['SPACE_DOMAIN_LABEL']}", ch
170
  space11 = gr.CheckboxGroup(label=LANG["SPACE11_LABEL"], choices=SOCIAL_MEDIA_CHOICES)
171
 
172
  # === TAB 2 Components ===
173
- info1 = gr.Radio(label=LANG["INFO1_LABEL"], choices=["Oui", "Non", "De temps en temps"])
174
- engagement_organisation = gr.Textbox(label=LANG["ENGAGEMENT_ORGANISATION_LABEL"], placeholder="Nom de l'association, collectif...")
 
175
  engagement_domaine = gr.Textbox(label=LANG["ENGAGEMENT_DOMAINE_LABEL"], placeholder="Domaine de l'engagement...")
176
  info_activites = gr.CheckboxGroup(label=LANG["INFO_ACTIVITES_LABEL"], choices=["Participer à une manifestation/grève", "Contacter un élu", "Signer une pétition en ligne", "Boycotter un produit/marque", "Faire un don à une association", "Autre"], interactive=True)
177
  info_reseaux_sociaux = gr.Radio(label=LANG["INFO_RESEAUX_SOCIAUX_LABEL"], choices=["Oui", "Non", "Parfois"])
@@ -224,14 +249,17 @@ purpose_components.append(gr.Radio(label=f"Fréquence pour: {PURPOSE_CHOICES[-1]
224
  purpose_social, purpose_professionnel, purpose_autre_freq) = purpose_components
225
 
226
 
227
- # === TAB 5 Components ===
228
  demo_gender = gr.Radio(label=LANG["DEMO_GENDER_LABEL"], choices=["Homme", "Femme", "Non-binaire", "Préfère ne pas dire"])
229
- demo_age = gr.Textbox(label=LANG["DEMO_AGE_LABEL"], placeholder="ex: 1995-05-20")
 
230
  demo_location_commune = gr.Textbox(label=LANG["DEMO_LOCATION_COMMUNE_LABEL"], placeholder="Nom de la commune")
231
  demo_location_arrond = gr.Textbox(label=LANG["DEMO_LOCATION_ARROND_LABEL"], placeholder="ex: 75005")
232
  demo_parents_location = gr.Radio(label=LANG["DEMO_PARENTS_LOCATION_LABEL"], choices=["Oui", "Non"])
233
- demo_inscription = gr.Radio(label=LANG["DEMO_INSCRIPTION_LABEL"], choices=["L1", "L2", "L3", "M1", "M2", "D (Doctorat)", "DU/Autre"])
234
- demo_discipline = gr.Textbox(label=LANG["DEMO_DISCIPLINE_LABEL"], placeholder="Cinéma, Lettres, Communication, etc.")
 
 
235
  demo_job = gr.Radio(label=LANG["DEMO_JOB_LABEL"], choices=["Oui", "Non"])
236
  demo_income = gr.Radio(label=LANG["DEMO_INCOME_LABEL"], choices=INCOME_CHOICES)
237
  demo_socialcapital1_parent1 = gr.Radio(label=LANG["DEMO_SOCIALCAPITAL1_PARENT1_LABEL"], choices=INSEE_CHOICES)
@@ -268,6 +296,8 @@ def get_column_names(data_components: list) -> list:
268
  clean_name = "SPACE4_QUAL_2"
269
  elif "Lieu 3 : Alternatif" in name:
270
  clean_name = "SPACE4_QUAL_3"
 
 
271
 
272
  names.append(clean_name)
273
  else:
@@ -329,6 +359,9 @@ def update_domain_visibility(practice_text):
329
  is_cited = bool(practice_text.strip())
330
  return gr.update(visible=is_cited)
331
 
 
 
 
332
  def process_survey(*data_values: Any) -> Tuple[str, gr.File]:
333
  """
334
  Processes survey data, creates a temporary CSV file, and returns the path
@@ -341,23 +374,30 @@ def process_survey(*data_values: Any) -> Tuple[str, gr.File]:
341
  error_msg = f"Erreur critique: Le nombre d'entrées reçues est incorrect ({len(all_inputs_list)} au lieu de {EXPECTED_COUNT}). Veuillez contacter le développeur."
342
  return error_msg, gr.update(visible=False, value=None)
343
 
344
- # Language is hardcoded as "FR"
345
  language = "FR"
346
 
347
  try:
348
  column_names = get_column_names(DATA_INPUT_COMPONENTS)
349
- column_names.insert(0, "DEMO_LANGUAGE") # Insert language as the first column name
350
 
351
  data_row = [language] + all_inputs_list
352
 
353
  df = pd.DataFrame([data_row], columns=column_names)
354
 
355
- # Create a temporary file name
356
- temp_filename = f"/tmp/survey_response_{int(time.time())}.csv"
 
 
 
 
 
 
 
 
357
  os.makedirs(os.path.dirname(temp_filename), exist_ok=True)
358
  df.to_csv(temp_filename, index=False, encoding='utf-8')
359
 
360
- success_msg = f"✨ Succès ! Le questionnaire a été soumis. Cliquez sur le lien ci-dessous pour **Télécharger le Fichier CSV**."
361
 
362
  return success_msg, gr.update(value=temp_filename, visible=True)
363
 
@@ -375,15 +415,15 @@ DATA_INPUT_COMPONENTS = [
375
  # TAB 1 - Contact & Lieux (22)
376
  approach_answer, refusal_reason, refusal_reason_other, contact_later,
377
  space1, space2a_1, space2a_2, space2a_3, space2b,
378
- space3_1, space3_2, space3_3, # Ces 3 composants sont les nouveaux sliders de qualification
379
  space4, space5,
380
  space6,
381
  space7_1, space_domain_1,
382
  space7_2, space_domain_2,
383
  space7_3, space_domain_3,
384
  space11,
385
- # TAB 2 - Engagement (5)
386
- info1, engagement_organisation, engagement_domaine, info_activites, info_reseaux_sociaux,
387
  # TAB 3 - Actualité (16)
388
  info_frequence_actu, info2, info3, info_opposite_feeling, info_contradict_opinion,
389
  info4, info5,
@@ -453,7 +493,6 @@ with gr.Blocks(title=LANG["TITLE"], css=".gradio-container { max-width: 1200px;
453
  space2a_2.render()
454
  space2a_3.render()
455
 
456
- # FIX: Nouveau titre pour la qualification des lieux (SPACE4 dans le texte)
457
  gr.Markdown(f"#### {LANG['SPACE3_TITLE']}")
458
  with gr.Row() as space3_row:
459
  space3_1.render()
@@ -464,7 +503,7 @@ with gr.Blocks(title=LANG["TITLE"], css=".gradio-container { max-width: 1200px;
464
  space1.change(update_visibility_space1, inputs=[space1], outputs=[space2a_1, space2a_2, space2a_3, space3_1, space3_2, space3_3, space2b])
465
 
466
  gr.Markdown("### Usages alternatifs et Engagement")
467
- space4.render() # Reste SPACE4_bis dans le label textuel pour la cohérence
468
  space5.render()
469
  space4.change(update_visibility_space4, inputs=[space4], outputs=[space5])
470
 
@@ -498,11 +537,19 @@ with gr.Blocks(title=LANG["TITLE"], css=".gradio-container { max-width: 1200px;
498
  # TAB 2: Engagement Citoyen
499
  # =================================================================
500
  with gr.Tab(LANG["TAB_2_TITLE"]):
501
- info1.render()
502
- engagement_organisation.render()
 
503
  engagement_domaine.render()
504
  info_activites.render()
505
  info_reseaux_sociaux.render()
 
 
 
 
 
 
 
506
 
507
  # =================================================================
508
  # TAB 3: Consommation d’actualités
@@ -578,18 +625,18 @@ with gr.Blocks(title=LANG["TITLE"], css=".gradio-container { max-width: 1200px;
578
 
579
 
580
  # =================================================================
581
- # TAB 5: Profil Démographique
582
  # =================================================================
583
  with gr.Tab(LANG["TAB_5_TITLE"]):
584
  demo_gender.render()
585
- demo_age.render()
586
  with gr.Row():
587
  demo_location_commune.render()
588
  demo_location_arrond.render()
589
  demo_parents_location.render()
590
  with gr.Row():
591
- demo_inscription.render()
592
- demo_discipline.render()
593
  with gr.Row():
594
  demo_job.render()
595
  demo_income.render()
@@ -612,7 +659,7 @@ with gr.Blocks(title=LANG["TITLE"], css=".gradio-container { max-width: 1200px;
612
  # =================================================================
613
  with gr.Tab(LANG["TAB_7_TITLE"]):
614
  gr.Markdown("### Finalisation du Questionnaire")
615
- gr.Markdown("Vérifiez que toutes vos réponses sont complètes avant de soumettre. Une fois soumis, le fichier CSV contenant les données apparaîtra ci-dessous pour téléchargement.")
616
 
617
  with gr.Row():
618
  submit_btn.render()
 
3
  import os
4
  import time
5
  from typing import List, Union, Dict, Any, Tuple
6
+ from datetime import datetime
7
 
8
  # =================================================================
9
  # CONFIGURATION AND LANGUAGE DEFINITIONS
10
  # =================================================================
11
 
12
+ # Setting EXPECTED_DATA_COUNT based on the final verified structure: 90
13
+ EXPECTED_DATA_COUNT = 90
14
+ EXPECTED_COUNT = 90
15
 
16
  # --- Shared Choices (French Only) ---
17
  FREQ_FR = ["Jamais", "Rarement", "Parfois", "Souvent"]
 
53
  "autre réaction"
54
  ]
55
 
56
+ ENGAGE1_CHOICES = [
57
+ "non",
58
+ "en tant que sympathisant",
59
+ "comme donateur-rice",
60
+ "en tant que bénévole",
61
+ "comme participant·e/spectateur-rice",
62
+ "comme organisateur-rice/responsable"
63
+ ]
64
+
65
+ ENGAGE2_CHOICES = [
66
+ "une association",
67
+ "un collectif",
68
+ "une ONG",
69
+ "un parti politique",
70
+ "un syndicat étudiant",
71
+ "une assemblée ou une instance représentative (collectivité, communes…)",
72
+ "autre (préciser)",
73
+ "aucune de ces formes"
74
+ ]
75
+
76
+ # FIX: Nouvelles listes pour DEMO_INSCRIPTION et DEMO_DISCIPLINE
77
+ DEMO_INSCRIPTION_CHOICES = ["L1", "L2", "L3", "M1", "M2", "D", "DU", "autre niveau d’étude/diplôme"]
78
+ DEMO_DISCIPLINE_CHOICES = [
79
+ "Cinéma", "Communication", "Langues", "LEA", "Lettres", "Médiation", "Musique",
80
+ "Sciences du langage", "Théâtre", "Traduction", "Autres"
81
+ ]
82
+
83
 
84
  # --- Language Definitions (French Only) ---
85
  LANG_FR = {
 
96
  "SPACE1_LABEL": "SPACE1 - Fréquentes-tu des lieux culturels (au sens large, y compris alternatifs, non institutionnels) ?",
97
  "SPACE2A_TITLE": "Derniers lieux culturels fréquentés (3 max. - si Rarement/Parfois/Souvent)",
98
  "SPACE2B_LABEL": "SPACE2b (si “jamais”) - Pourquoi ne fréquentes-tu jamais de lieux culturels ? (plusieurs réponses possibles)",
 
 
99
  "SPACE3_TITLE": "SPACE4 - Pourrais-tu qualifier ces lieux ?",
100
  "SPACE3_QUAL_1": "Lieu 1 : Alternatif/Underground (1) à Institutionnel/Mainstream (10)",
101
  "SPACE3_QUAL_2": "Lieu 2 : Alternatif (1) à Institutionnel (10)",
102
  "SPACE3_QUAL_3": "Lieu 3 : Alternatif (1) à Institutionnel (10)",
 
 
103
  "SPACE4_LABEL": "SPACE4_bis - Est-ce que tu suis régulièrement une communauté alternative en ligne (médias sociaux, newsletter, groupe dédié...)",
104
  "SPACE5_LABEL": "SPACE5 - Peux-tu indiquer son nom ou son url ? (si SPACE4_bis=oui)",
105
  "SPACE6_LABEL": "SPACE6 - As-tu connaissance de pratiques d’engagement citoyen dans ces lieux ?",
 
107
  "SPACE_DOMAIN_LABEL": "Peux-tu caractériser le domaine dans lequel s’inscrit principalement cette pratique ?",
108
  "SPACE11_LABEL": "SPACE11 - Sais-tu si elle s’appuie sur une communauté en ligne et l’usage d’un média social en ligne ?",
109
  "SPACE2B_OPTIONS": ["Pas le temps", "Trop cher", "Je ne sais pas où aller", "Pas intéressé", "Autre"],
110
+ "ENGAGE1_LABEL": "ENGAGE1 - Toi-même, participes-tu à des pratiques d’engagement citoyen ?",
111
  "ENGAGEMENT_ORGANISATION_LABEL": "ENGAGE2 - Dans quelle(s) organisation(s) es-tu engagé·e ?",
112
+ "ENGAGE2_AUTRE_DETAIL_LABEL": "ENGAGE2 - Précisez 'autre'",
113
  "ENGAGEMENT_DOMAINE_LABEL": "ENGAGE3 - Dans quel domaine ? (Si engagé·e)",
114
  "INFO_ACTIVITES_LABEL": "ENGAGE4 - Participes-tu ou as-tu participé à une ou plusieurs des activités suivantes ?",
115
  "INFO_RESEAUX_SOCIAUX_LABEL": "ENGAGE5 - Utilises-tu les réseaux sociaux pour t’engager dans des causes ?",
 
128
  "PLATFORM_TITLE": "DIGITAL1 - Quelles plateformes utilises-tu le plus ? (Heures/jour approx.)",
129
  "PURPOSE_TITLE": "DIGITAL2 - Pour quel(s) usage(s) emploies-tu ces plateformes ?",
130
  "DEMO_GENDER_LABEL": "DEMO_GENDER - Ton genre :",
131
+ # FIX: Nouveau label pour l'âge
132
+ "DEMO_AGE_LABEL": "DEMO_AGE - Ton âge (années) :",
133
  "DEMO_LOCATION_COMMUNE_LABEL": "DEMO_LOCATION - Commune de résidence habituelle :",
134
  "DEMO_LOCATION_ARROND_LABEL": "Arrondissement (si Paris) :",
135
  "DEMO_PARENTS_LOCATION_LABEL": "DEMO_PARENTS - Est-ce le lieu d’habitation de tes parents ?",
 
175
  space2a_3 = gr.Textbox(label="Lieu 3", visible=False)
176
  space2b = gr.CheckboxGroup(label=LANG["SPACE2B_LABEL"], choices=LANG["SPACE2B_OPTIONS"], visible=False)
177
 
 
178
  space3_1 = gr.Slider(label=LANG["SPACE3_QUAL_1"], minimum=1, maximum=10, step=1, visible=False)
179
  space3_2 = gr.Slider(label=LANG["SPACE3_QUAL_2"], minimum=1, maximum=10, step=1, visible=False)
180
  space3_3 = gr.Slider(label=LANG["SPACE3_QUAL_3"], minimum=1, maximum=10, step=1, visible=False)
181
 
 
182
  space4 = gr.Radio(label=LANG["SPACE4_LABEL"], choices=["Oui", "Non"])
183
  space5 = gr.Textbox(label=LANG["SPACE5_LABEL"], visible=False)
184
  space6 = gr.Radio(label=LANG["SPACE6_LABEL"], choices=["Oui", "Non", "Ne sait pas"])
 
194
  space11 = gr.CheckboxGroup(label=LANG["SPACE11_LABEL"], choices=SOCIAL_MEDIA_CHOICES)
195
 
196
  # === TAB 2 Components ===
197
+ engage1_role = gr.CheckboxGroup(label=LANG["ENGAGE1_LABEL"], choices=ENGAGE1_CHOICES)
198
+ engage2_type = gr.CheckboxGroup(label=LANG["ENGAGEMENT_ORGANISATION_LABEL"], choices=ENGAGE2_CHOICES)
199
+ engage2_autre_detail = gr.Textbox(label=LANG["ENGAGE2_AUTRE_DETAIL_LABEL"], visible=False)
200
  engagement_domaine = gr.Textbox(label=LANG["ENGAGEMENT_DOMAINE_LABEL"], placeholder="Domaine de l'engagement...")
201
  info_activites = gr.CheckboxGroup(label=LANG["INFO_ACTIVITES_LABEL"], choices=["Participer à une manifestation/grève", "Contacter un élu", "Signer une pétition en ligne", "Boycotter un produit/marque", "Faire un don à une association", "Autre"], interactive=True)
202
  info_reseaux_sociaux = gr.Radio(label=LANG["INFO_RESEAUX_SOCIAUX_LABEL"], choices=["Oui", "Non", "Parfois"])
 
249
  purpose_social, purpose_professionnel, purpose_autre_freq) = purpose_components
250
 
251
 
252
+ # === TAB 5 Components (Mises à jour) ===
253
  demo_gender = gr.Radio(label=LANG["DEMO_GENDER_LABEL"], choices=["Homme", "Femme", "Non-binaire", "Préfère ne pas dire"])
254
+ # FIX: Changement en Number
255
+ demo_age = gr.Number(label=LANG["DEMO_AGE_LABEL"], minimum=18, maximum=100, step=1, placeholder="ex: 25")
256
  demo_location_commune = gr.Textbox(label=LANG["DEMO_LOCATION_COMMUNE_LABEL"], placeholder="Nom de la commune")
257
  demo_location_arrond = gr.Textbox(label=LANG["DEMO_LOCATION_ARROND_LABEL"], placeholder="ex: 75005")
258
  demo_parents_location = gr.Radio(label=LANG["DEMO_PARENTS_LOCATION_LABEL"], choices=["Oui", "Non"])
259
+ # FIX: Changement en CheckboxGroup
260
+ demo_inscription = gr.CheckboxGroup(label=LANG["DEMO_INSCRIPTION_LABEL"], choices=DEMO_INSCRIPTION_CHOICES)
261
+ # FIX: Changement en CheckboxGroup
262
+ demo_discipline = gr.CheckboxGroup(label=LANG["DEMO_DISCIPLINE_LABEL"], choices=DEMO_DISCIPLINE_CHOICES)
263
  demo_job = gr.Radio(label=LANG["DEMO_JOB_LABEL"], choices=["Oui", "Non"])
264
  demo_income = gr.Radio(label=LANG["DEMO_INCOME_LABEL"], choices=INCOME_CHOICES)
265
  demo_socialcapital1_parent1 = gr.Radio(label=LANG["DEMO_SOCIALCAPITAL1_PARENT1_LABEL"], choices=INSEE_CHOICES)
 
296
  clean_name = "SPACE4_QUAL_2"
297
  elif "Lieu 3 : Alternatif" in name:
298
  clean_name = "SPACE4_QUAL_3"
299
+ elif clean_name == "ENGAGE2_Précisez_'autre'":
300
+ clean_name = "ENGAGE2_Autre_Precision"
301
 
302
  names.append(clean_name)
303
  else:
 
359
  is_cited = bool(practice_text.strip())
360
  return gr.update(visible=is_cited)
361
 
362
+ def update_visibility_engage2_autre(engage2_choices: List[str]):
363
+ return gr.update(visible="autre (préciser)" in engage2_choices)
364
+
365
  def process_survey(*data_values: Any) -> Tuple[str, gr.File]:
366
  """
367
  Processes survey data, creates a temporary CSV file, and returns the path
 
374
  error_msg = f"Erreur critique: Le nombre d'entrées reçues est incorrect ({len(all_inputs_list)} au lieu de {EXPECTED_COUNT}). Veuillez contacter le développeur."
375
  return error_msg, gr.update(visible=False, value=None)
376
 
 
377
  language = "FR"
378
 
379
  try:
380
  column_names = get_column_names(DATA_INPUT_COMPONENTS)
381
+ column_names.insert(0, "DEMO_LANGUAGE")
382
 
383
  data_row = [language] + all_inputs_list
384
 
385
  df = pd.DataFrame([data_row], columns=column_names)
386
 
387
+ # Nommage du fichier: Enquêteur ID + Date
388
+ enqueteur_id_val = all_inputs_list[0]
389
+ current_date_str = datetime.now().strftime("%Y-%m-%d")
390
+
391
+ safe_enqueteur_id = str(enqueteur_id_val).strip()
392
+ safe_enqueteur_id = "".join(c if c.isalnum() else '_' for c in safe_enqueteur_id)
393
+ if not safe_enqueteur_id:
394
+ safe_enqueteur_id = "NO_ID"
395
+
396
+ temp_filename = f"/tmp/{safe_enqueteur_id}_{current_date_str}.csv"
397
  os.makedirs(os.path.dirname(temp_filename), exist_ok=True)
398
  df.to_csv(temp_filename, index=False, encoding='utf-8')
399
 
400
+ success_msg = f"✨ Succès ! Le questionnaire a été soumis. Cliquez sur le lien ci-dessous pour **Télécharger le Fichier CSV** nommé `{safe_enqueteur_id}_{current_date_str}.csv`."
401
 
402
  return success_msg, gr.update(value=temp_filename, visible=True)
403
 
 
415
  # TAB 1 - Contact & Lieux (22)
416
  approach_answer, refusal_reason, refusal_reason_other, contact_later,
417
  space1, space2a_1, space2a_2, space2a_3, space2b,
418
+ space3_1, space3_2, space3_3,
419
  space4, space5,
420
  space6,
421
  space7_1, space_domain_1,
422
  space7_2, space_domain_2,
423
  space7_3, space_domain_3,
424
  space11,
425
+ # TAB 2 - Engagement (6)
426
+ engage1_role, engage2_type, engage2_autre_detail, engagement_domaine, info_activites, info_reseaux_sociaux,
427
  # TAB 3 - Actualité (16)
428
  info_frequence_actu, info2, info3, info_opposite_feeling, info_contradict_opinion,
429
  info4, info5,
 
493
  space2a_2.render()
494
  space2a_3.render()
495
 
 
496
  gr.Markdown(f"#### {LANG['SPACE3_TITLE']}")
497
  with gr.Row() as space3_row:
498
  space3_1.render()
 
503
  space1.change(update_visibility_space1, inputs=[space1], outputs=[space2a_1, space2a_2, space2a_3, space3_1, space3_2, space3_3, space2b])
504
 
505
  gr.Markdown("### Usages alternatifs et Engagement")
506
+ space4.render()
507
  space5.render()
508
  space4.change(update_visibility_space4, inputs=[space4], outputs=[space5])
509
 
 
537
  # TAB 2: Engagement Citoyen
538
  # =================================================================
539
  with gr.Tab(LANG["TAB_2_TITLE"]):
540
+ engage1_role.render()
541
+ engage2_type.render()
542
+ engage2_autre_detail.render()
543
  engagement_domaine.render()
544
  info_activites.render()
545
  info_reseaux_sociaux.render()
546
+
547
+ engage2_type.change(
548
+ fn=update_visibility_engage2_autre,
549
+ inputs=[engage2_type],
550
+ outputs=[engage2_autre_detail]
551
+ )
552
+
553
 
554
  # =================================================================
555
  # TAB 3: Consommation d’actualités
 
625
 
626
 
627
  # =================================================================
628
+ # TAB 5: Profil Démographique (Mise à jour Age, Inscription, Discipline)
629
  # =================================================================
630
  with gr.Tab(LANG["TAB_5_TITLE"]):
631
  demo_gender.render()
632
+ demo_age.render() # FIX: Rendu du Number
633
  with gr.Row():
634
  demo_location_commune.render()
635
  demo_location_arrond.render()
636
  demo_parents_location.render()
637
  with gr.Row():
638
+ demo_inscription.render() # FIX: Rendu du CheckboxGroup
639
+ demo_discipline.render() # FIX: Rendu du CheckboxGroup
640
  with gr.Row():
641
  demo_job.render()
642
  demo_income.render()
 
659
  # =================================================================
660
  with gr.Tab(LANG["TAB_7_TITLE"]):
661
  gr.Markdown("### Finalisation du Questionnaire")
662
+ gr.Markdown("Vérifiez que toutes vos réponses sont complètes avant de soumettre. Une fois soumis, le fichier CSV (nommé avec l'identifiant de l'enquêteur et la date) apparaîtra ci-dessous pour téléchargement.")
663
 
664
  with gr.Row():
665
  submit_btn.render()