File size: 24,389 Bytes
3cec7bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f0e478f
3cec7bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f0e478f
3cec7bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
import streamlit as st
from PyPDF2 import PdfReader
import pandas as pd
from groq import Groq
from referentials import REFERENTIALS
import json
import re

# Configuration avancée de la page
st.set_page_config(
    layout="wide", 
    page_title="Analyse de CV - GFSI (Version 25.12)", 
    page_icon="📄",
    initial_sidebar_state="expanded"
)

# Fonction pour configurer le client Groq avec validation
def get_groq_client(api_key):
    """
    Initialise et valide un client Groq avec la clé API fournie.
    
    Args:
        api_key (str): Clé API Groq
        
    Returns:
        Groq: Instance de client Groq ou None en cas d'erreur
    """
    if not api_key or not api_key.startswith("gsk_"):
        st.error("La clé API semble invalide. Les clés Groq commencent généralement par 'gsk_'.")
        return None
    
    try:
        client = Groq(api_key=api_key)
        # Test de la connexion avec une requête minimale
        test_response = client.chat.completions.create(
            messages=[{"role": "user", "content": "Test de connexion"}],
            model="llama-3.1-8b-instant",
            max_tokens=10
        )
        if test_response:
            return client
    except Exception as e:
        st.error(f"Erreur de connexion à l'API Groq : {str(e)}")
        return None

# Extraction améliorée de texte depuis un PDF
def extract_text_from_pdf(file):
    """
    Extrait le texte d'un fichier PDF avec gestion optimisée des erreurs.
    
    Args:
        file (UploadedFile): Fichier PDF téléchargé
        
    Returns:
        str: Texte extrait du PDF ou None en cas d'erreur
    """
    try:
        with st.spinner("Extraction du texte en cours..."):
            reader = PdfReader(file)
            
            # Vérification des pages vides
            if len(reader.pages) == 0:
                st.warning("Le PDF ne contient aucune page.")
                return None
            
            # Extraction avec nettoyage des caractères spéciaux
            text_parts = []
            for page in reader.pages:
                page_text = page.extract_text()
                if page_text:
                    # Nettoyage des caractères problématiques
                    page_text = re.sub(r'\s+', ' ', page_text)
                    text_parts.append(page_text)
            
            if not text_parts:
                st.warning("Aucun texte n'a pu être extrait du PDF. Vérifiez qu'il ne s'agit pas d'un PDF scanné.")
                return None
                
            return " ".join(text_parts)
    except Exception as e:
        st.error(f"Erreur lors de l'extraction du texte : {str(e)}")
        st.info("Conseils: Vérifiez que le PDF n'est pas protégé ou qu'il ne s'agit pas d'un document scanné sans OCR.")
        return None

# Analyse améliorée du CV avec l'API Groq et référentiel
def analyze_cv_with_groq(cv_text, referential, groq_client, model="openai/gpt-oss-120b"):
    """
    Analyse approfondie du CV en fonction des référentiels GFSI avec références systématiques.
    
    Args:
        cv_text (str): Texte du CV à analyser
        referential (str): Nom du référentiel GFSI sélectionné
        groq_client (Groq): Instance de client Groq
        model (str): Modèle LLM à utiliser
        
    Returns:
        dict: Résultats structurés de l'analyse ou None en cas d'erreur
    """
    referential_data = REFERENTIALS.get(referential, {})
    
    # Structuration des exigences pour analyse systématique
    requirements_categories = {
        "General_Requirements": referential_data.get("General_Requirements", {}),
        "Qualifications": referential_data.get("Qualifications", {}),
        "Audit_Experience": referential_data.get("Audit_Experience", {}),
        "Advanced_Requirements": referential_data.get("Advanced_Requirements", {})
    }
    
    # Construction d'un prompt structuré pour obtenir une réponse analysable
    prompt = f"""
    Vous êtes un expert en évaluation des compétences selon les référentiels GFSI.
    
    TÂCHE: Analysez ce CV pour vérifier sa conformité avec le référentiel {referential} de manière systématique.
    
    INSTRUCTIONS:
    1. Ne jamais mentionner le nom du candidat - utilisez toujours "le candidat"
    2. Pour chaque exigence, fournissez:
       - La référence exacte de l'exigence (code/numéro)
       - Votre évaluation avec STATUT: CONFORME, NON CONFORME, ou PARTIELLEMENT CONFORME
       - Les éléments du CV justifiant votre évaluation
       - Des recommandations spécifiques si nécessaire
    3. Structurez votre réponse exactement selon le format JSON demandé à la fin
    
    RÉFÉRENTIEL {referential} - EXIGENCES:
    
    SECTION 1: EXIGENCES GÉNÉRALES
    {json.dumps(requirements_categories["General_Requirements"], ensure_ascii=False, indent=2)}
    
    SECTION 2: QUALIFICATIONS
    {json.dumps(requirements_categories["Qualifications"], ensure_ascii=False, indent=2)}
    
    SECTION 3: EXPÉRIENCE EN AUDIT
    {json.dumps(requirements_categories["Audit_Experience"], ensure_ascii=False, indent=2)}
    
    SECTION 4: EXIGENCES AVANCÉES
    {json.dumps(requirements_categories["Advanced_Requirements"], ensure_ascii=False, indent=2)}
    
    CV DU CANDIDAT:
    {cv_text}
    
    INSTRUCTIONS SUPPLÉMENTAIRES:
    - Vérifiez chaque formation et expérience plusieurs fois, car les terminologies peuvent varier
    - Évaluez si l'équivalence des formations est acceptable selon le référentiel
    - Identifiez précisément chaque lacune avec référence à l'exigence spécifique
    
    FORMAT DE RÉPONSE: Fournissez votre analyse au format JSON avec la structure suivante:
    {{
      "analysis": {{
        "general_requirements": [
          {{
            "reference": "REF-CODE-1",
            "requirement": "Description de l'exigence",
            "status": "CONFORME/NON CONFORME/PARTIELLEMENT CONFORME",
            "evidence": "Éléments du CV justifiant l'évaluation",
            "recommendations": "Recommandations si nécessaire"
          }}
        ],
        "qualifications": [...],
        "audit_experience": [...],
        "advanced_requirements": [...]
      }},
      "summary": {{
        "conformant_count": 12,  
        "non_conformant_count": 3,
        "partially_conformant_count": 2,
        "overall_assessment": "CONFORME/NON CONFORME/PARTIELLEMENT CONFORME",
        "key_strengths": ["Force 1", "Force 2"],
        "key_gaps": ["Lacune 1", "Lacune 2"],
        "conclusion": "Conclusion générale sur l'adéquation du candidat"
      }}
    }}
    
    IMPORTANT: Assurez-vous que votre réponse soit un JSON valide et bien structuré.
    """
    
    try:
        with st.spinner("Analyse approfondie du CV en cours..."):
            messages = [
                {"role": "system", "content": "Vous êtes un expert en conformité GFSI qui fournit des analyses structurées avec références systématiques aux exigences."},
                {"role": "user", "content": prompt}
            ]
            
            response = groq_client.chat.completions.create(
                messages=messages,
                model=model,
                max_tokens=4000,
                temperature=0.1,
                response_format={"type": "json_object"}
            )
            
            # Parsing de la réponse en JSON
            try:
                result = json.loads(response.choices[0].message.content)
                return result
            except json.JSONDecodeError:
                # Si le parsing JSON échoue, tenter de récupérer le contenu brut
                content = response.choices[0].message.content
                st.warning("L'analyse n'a pas pu être structurée correctement. Affichage des résultats bruts.")
                return {"raw_content": content}
    except Exception as e:
        st.error(f"Erreur lors de l'analyse du CV : {str(e)}")
        return None

# Affichage amélioré des résultats d'analyse
def display_analysis_results(analysis_result, referential):
    """
    Affiche les résultats de l'analyse de manière structurée et visuelle.
    
    Args:
        analysis_result (dict): Résultats de l'analyse
        referential (str): Référentiel GFSI utilisé pour l'analyse
    """
    if not analysis_result:
        return
    
    # Cas où le résultat est brut (non JSON)
    if "raw_content" in analysis_result:
        st.markdown(
            f"""
            <div style='font-size:18px;line-height:1.6;margin-top:20px;'>
                {analysis_result["raw_content"]}
            </div>
            """,
            unsafe_allow_html=True
        )
        return
    
    # Affichage du résumé global
    st.markdown(f"## Résumé de l'analyse selon le référentiel {referential}")
    
    summary = analysis_result.get("summary", {})
    conformant = summary.get("conformant_count", 0)
    non_conformant = summary.get("non_conformant_count", 0)
    partially = summary.get("partially_conformant_count", 0)
    total = conformant + non_conformant + partially
    
    # Affichage des statistiques
    col1, col2, col3, col4 = st.columns(4)
    with col1:
        st.metric("Total des exigences", total)
    with col2:
        st.metric("Conformes", conformant, f"{int(conformant/total*100 if total else 0)}%")
    with col3:
        st.metric("Non conformes", non_conformant, f"{int(non_conformant/total*100 if total else 0)}%")
    with col4:
        st.metric("Partiellement conformes", partially, f"{int(partially/total*100 if total else 0)}%")
    
    # Conclusion globale
    conclusion_color = {
        "CONFORME": "#28a745",
        "NON CONFORME": "#dc3545",
        "PARTIELLEMENT CONFORME": "#ffc107"
    }.get(summary.get("overall_assessment", ""), "#6c757d")
    
    st.markdown(
        f"""
        <div style="background-color:{conclusion_color};color:white;padding:20px;border-radius:10px;margin-top:20px;font-size:22px;line-height:1.8;">
            <strong>Évaluation générale :</strong> {summary.get("overall_assessment", "Non déterminée")}
        </div>
        """,
        unsafe_allow_html=True
    )
    
    # Forces et lacunes
    col1, col2 = st.columns(2)
    with col1:
        st.markdown("### Forces principales")
        for strength in summary.get("key_strengths", []):
            st.markdown(f"✅ {strength}")
    
    with col2:
        st.markdown("### Points d'amélioration")
        for gap in summary.get("key_gaps", []):
            st.markdown(f"❌ {gap}")
    
    # Conclusion détaillée
    st.markdown("### Conclusion")
    st.markdown(summary.get("conclusion", "Aucune conclusion disponible."))
    
    # Affichage détaillé des sections d'analyse
    analysis = analysis_result.get("analysis", {})
    
    # Liste des sections pour affichage uniforme
    sections = [
        ("Exigences générales", analysis.get("general_requirements", [])),
        ("Qualifications", analysis.get("qualifications", [])),
        ("Expérience en audit", analysis.get("audit_experience", [])),
        ("Exigences avancées", analysis.get("advanced_requirements", []))
    ]
    
    # Création d'onglets pour chaque section
    tabs = st.tabs([section[0] for section in sections])
    
    # Affichage du contenu de chaque section dans son onglet
    for i, (section_name, section_data) in enumerate(sections):
        with tabs[i]:
            if not section_data:
                st.info(f"Aucune donnée disponible pour la section {section_name}")
                continue
                
            for item in section_data:
                # Couleur en fonction du statut
                status_color = {
                    "CONFORME": "#28a745",
                    "NON CONFORME": "#dc3545",
                    "PARTIELLEMENT CONFORME": "#ffc107"
                }.get(item.get("status", ""), "#6c757d")
                
                # Création d'un expander pour chaque exigence
                with st.expander(f"{item.get('reference', 'REF')} - {item.get('requirement', 'Exigence')} ({item.get('status', 'Non évalué')})"):
                    st.markdown(
                        f"""
                        <div style="border-left: 5px solid {status_color}; padding-left: 10px;">
                            <p><strong>Référence:</strong> {item.get('reference', 'Non spécifiée')}</p>
                            <p><strong>Exigence:</strong> {item.get('requirement', 'Non spécifiée')}</p>
                            <p><strong>Statut:</strong> <span style="background-color:{status_color};color:white;padding:3px 6px;border-radius:3px;">{item.get('status', 'Non évalué')}</span></p>
                            <p><strong>Éléments justificatifs:</strong> {item.get('evidence', 'Aucun')}</p>
                            <p><strong>Recommandations:</strong> {item.get('recommendations', 'Aucune')}</p>
                        </div>
                        """,
                        unsafe_allow_html=True
                    )

# Génération d'un rapport exportable
def generate_exportable_report(analysis_result, referential, cv_text):
    """
    Génère un rapport exportable basé sur l'analyse du CV.
    
    Args:
        analysis_result (dict): Résultats de l'analyse
        referential (str): Référentiel utilisé
        cv_text (str): Texte du CV analysé
        
    Returns:
        str: HTML du rapport
    """
    if not analysis_result or "raw_content" in analysis_result:
        return None
        
    summary = analysis_result.get("summary", {})
    analysis = analysis_result.get("analysis", {})
    
    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Rapport d'analyse CV - {referential}</title>
        <style>
            body {{ font-family: Arial, sans-serif; margin: 20px; }}
            .header {{ background-color: #f8f9fa; padding: 20px; border-radius: 5px; margin-bottom: 20px; }}
            .section {{ margin-bottom: 30px; }}
            .item {{ border-left: 5px solid #ccc; padding-left: 15px; margin-bottom: 15px; }}
            .conforme {{ border-color: #28a745; }}
            .non-conforme {{ border-color: #dc3545; }}
            .partiel {{ border-color: #ffc107; }}
            .status-badge {{ padding: 3px 6px; border-radius: 3px; color: white; font-size: 12px; }}
            .summary {{ background-color: #f8f9fa; padding: 15px; border-radius: 5px; }}
            table {{ width: 100%; border-collapse: collapse; margin-bottom: 20px; }}
            th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
            th {{ background-color: #f2f2f2; }}
        </style>
    </head>
    <body>
        <div class="header">
            <h1>Rapport d'analyse de CV</h1>
            <p>Référentiel: <strong>{referential}</strong></p>
            <p>Date: <strong>{pd.Timestamp.now().strftime('%d/%m/%Y')}</strong></p>
        </div>
        
        <div class="section summary">
            <h2>Résumé de l'analyse</h2>
            <table>
                <tr>
                    <th>Exigences conformes</th>
                    <th>Exigences non conformes</th>
                    <th>Exigences partiellement conformes</th>
                    <th>Évaluation générale</th>
                </tr>
                <tr>
                    <td>{summary.get('conformant_count', 0)}</td>
                    <td>{summary.get('non_conformant_count', 0)}</td>
                    <td>{summary.get('partially_conformant_count', 0)}</td>
                    <td><strong>{summary.get('overall_assessment', 'Non déterminée')}</strong></td>
                </tr>
            </table>
            
            <h3>Forces principales</h3>
            <ul>
                {' '.join(f'<li>{strength}</li>' for strength in summary.get('key_strengths', []))}
            </ul>
            
            <h3>Points d'amélioration</h3>
            <ul>
                {' '.join(f'<li>{gap}</li>' for gap in summary.get('key_gaps', []))}
            </ul>
            
            <h3>Conclusion</h3>
            <p>{summary.get('conclusion', 'Aucune conclusion disponible.')}</p>
        </div>
    """
    
    # Ajout des sections détaillées
    sections = [
        ("Exigences générales", analysis.get("general_requirements", [])),
        ("Qualifications", analysis.get("qualifications", [])),
        ("Expérience en audit", analysis.get("audit_experience", [])),
        ("Exigences avancées", analysis.get("advanced_requirements", []))
    ]
    
    for section_name, section_data in sections:
        html += f"""
        <div class="section">
            <h2>{section_name}</h2>
        """
        
        if not section_data:
            html += "<p>Aucune donnée disponible pour cette section</p>"
        else:
            for item in section_data:
                status = item.get('status', '')
                status_class = ""
                if "CONFORME" in status and "NON" not in status:
                    status_class = "conforme"
                elif "NON CONFORME" in status:
                    status_class = "non-conforme"
                elif "PARTIELLEMENT" in status:
                    status_class = "partiel"
                
                html += f"""
                <div class="item {status_class}">
                    <h3>{item.get('reference', 'REF')} - {item.get('requirement', 'Exigence')}</h3>
                    <p><strong>Statut:</strong> <span class="status-badge" style="background-color: {'#28a745' if status_class == 'conforme' else '#dc3545' if status_class == 'non-conforme' else '#ffc107'};">{status}</span></p>
                    <p><strong>Éléments justificatifs:</strong> {item.get('evidence', 'Aucun')}</p>
                    <p><strong>Recommandations:</strong> {item.get('recommendations', 'Aucune')}</p>
                </div>
                """
        
        html += "</div>"
    
    html += """
    </body>
    </html>
    """
    
    return html

# Fonction principale améliorée
def main():
    """
    Interface principale améliorée avec fonctionnalités d'exportation et statistiques.
    """
    # Barre latérale pour configuration
    with st.sidebar:
        st.image("https://via.placeholder.com/150x60?text=GFSI+Analyzer", width=150)
        st.title("Configuration")
        
        # Gestion de la clé API avec sauvegarde dans session_state
        if "api_key" not in st.session_state:
            st.session_state.api_key = ""
        
        api_key = st.text_input(
            "Clé API Groq :", 
            value=st.session_state.api_key,
            type="password",
            help="La clé API commence par 'gsk_'"
        )
        
        if api_key != st.session_state.api_key:
            st.session_state.api_key = api_key
            st.session_state.groq_client = None if not api_key else get_groq_client(api_key)
        
        if "groq_client" not in st.session_state:
            st.session_state.groq_client = None if not api_key else get_groq_client(api_key)
        
        # Sélection du modèle
        model_options = {
            "openai/gpt-oss-120b": "openai/gpt-oss-120b (Haute précision)",
            "llama-3.2-11b-versatile": "Llama 3.2 11B (Équilibré)",
            "llama-3.1-8b-instant": "Llama 3.1 8B (Rapide)"
        }
        selected_model = st.selectbox(
            "Modèle d'IA:",
            options=list(model_options.keys()),
            format_func=lambda x: model_options[x],
            help="Balance entre précision d'analyse et vitesse"
        )
        
        st.markdown("---")
        st.markdown("### Options d'analyse")
        
        # Options de debug pour développement
        show_debug = st.checkbox("Afficher les données brutes (Debug)", False)
        
        # Informations supplémentaires
        st.markdown("---")
        st.markdown("### À propos")
        st.info("""
        **Outil d'analyse CV - GFSI**
        Version 25.12
        
        Référentiels supportés : BRCGS, FSSC 22000, IFS
        """)

    # Contenu principal
    st.title("Analyse de CV selon les Référentiels GFSI")
    st.markdown("---")

    # Panneau d'information avec des instructions complètes
    with st.expander("ℹ️ Guide d'utilisation", expanded=True):
        st.markdown("""
        ### Comment utiliser cet outil?
        
        1. **Configuration**:
           - Saisissez votre clé API Groq dans le panneau latéral
           - Sélectionnez le modèle d'IA à utiliser
        
        2. **Analyse**:
           - Téléchargez un CV au format PDF
           - Sélectionnez le référentiel GFSI applicable
           - Lancez l'analyse
        
        3. **Résultats**:
           - Consultez le rapport détaillé avec références aux exigences
           - Explorez les détails par section (Général, Qualifications, etc.)
           - Exportez les résultats au format HTML
        
        **Astuce**: Plus le document est clairement formaté, meilleure sera l'analyse.
        """)
    
    # Contenu principal - Interface d'analyse
    st.markdown("## Analyse de CV")
    
    # Vérification de la présence du client Groq
    if not st.session_state.groq_client:
        st.warning("⚠️ Veuillez configurer votre clé API Groq dans le panneau latéral pour continuer.")
        return
    
    # Chargement du fichier PDF
    uploaded_file = st.file_uploader(
        "📄 Téléchargez un fichier PDF (CV)", 
        type="pdf",
        help="Formats supportés : PDF. Taille maximale: 10MB"
    )
    
    if not uploaded_file:
        st.info("Veuillez télécharger un fichier PDF pour commencer l'analyse.")
        # Affichage d'exemples des référentiels
        st.markdown("### Aperçu des référentiels supportés")
        for ref_name, ref_data in REFERENTIALS.items():
            with st.expander(f"Référentiel {ref_name}"):
                st.json(ref_data)
        return
    
    # Sélection du référentiel
    referential = st.selectbox(
        "📋 Sélectionnez un référentiel", 
        list(REFERENTIALS.keys()),
        help="Choisissez le standard GFSI applicable pour ce candidat"
    )
    
    # Vérification que tous les éléments nécessaires sont présents
    if uploaded_file and referential and st.session_state.groq_client:
        # Bouton pour lancer l'analyse
        if st.button("🔍 Analyser le CV", type="primary"):
            # Extraction du texte du CV
            cv_text = extract_text_from_pdf(uploaded_file)
            
            # Afficher un extrait du texte extrait en mode debug
            if show_debug and cv_text:
                with st.expander("Aperçu du texte extrait", expanded=False):
                    st.text(cv_text[:1000] + "..." if len(cv_text) > 1000 else cv_text)
            
            if cv_text:
                # Analyse du CV avec références systématiques
                analysis_result = analyze_cv_with_groq(
                    cv_text, 
                    referential, 
                    st.session_state.groq_client,
                    model=selected_model
                )
                
                # Affichage des données brutes en mode debug
                if show_debug and analysis_result:
                    with st.expander("Données brutes de l'analyse (Debug)", expanded=False):
                        st.json(analysis_result)
                
                # Affichage des résultats
                if analysis_result:
                    # Affichage structuré des résultats
                    display_analysis_results(analysis_result, referential)
                    
                    # Génération et téléchargement du rapport
                    report_html = generate_exportable_report(analysis_result, referential, cv_text)
                    if report_html:
                        st.download_button(
                            label="📥 Télécharger le rapport complet",
                            data=report_html,
                            file_name=f"analyse_cv_{referential}_{pd.Timestamp.now().strftime('%Y%m%d_%H%M')}.html",
                            mime="text/html",
                        )

if __name__ == "__main__":
    main()