File size: 2,161 Bytes
f88b8e8
 
 
6da2b52
 
 
 
f88b8e8
6da2b52
 
 
 
 
 
f88b8e8
 
 
 
 
 
1556508
 
 
 
 
 
 
 
 
 
 
f88b8e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6da2b52
 
 
 
 
 
f88b8e8
6da2b52
1556508
6da2b52
 
 
 
f88b8e8
6da2b52
f88b8e8
6da2b52
1556508
6da2b52
 
 
1556508
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
"""
Configuration des LLMs et utilitaires de chargement.
"""

import os
from dotenv import load_dotenv
load_dotenv()
import fitz
import pymupdf4llm
from langchain_groq import ChatGroq
from langchain_openai import ChatOpenAI
import litellm
litellm.set_verbose = False


def load_pdf(pdf_path: str) -> str:
    """Convertit un PDF en texte Markdown via pymupdf4llm (structure + formatage)."""
    return pymupdf4llm.to_markdown(pdf_path)


def get_pdf_page_count(pdf_path: str) -> int:
    """Retourne le nombre de pages du PDF."""
    try:
        doc = fitz.open(pdf_path)
        count = doc.page_count
        doc.close()
        return count
    except Exception:
        return 1


def load_pdf_first_page_text(pdf_path: str) -> str:
    """Extrait le texte brut de la première page en ordre de lecture (haut → bas, gauche → droite).

    Utilise fitz directement pour capturer les headers/sidebars que pymupdf4llm
    peut ignorer ou réordonner sur les CV à mise en page complexe (bannières colorées,
    colonnes, boîtes décoratives).
    """
    doc = fitz.open(pdf_path)
    if not doc:
        return ""

    page = doc[0]
    # Récupère les blocs texte avec leurs coordonnées
    blocks = page.get_text("blocks")  # (x0, y0, x1, y1, text, block_no, block_type)
    # Filtre les blocs texte (type 0) non vides
    text_blocks = [b for b in blocks if b[6] == 0 and b[4].strip()]
    # Trie par ligne (y arrondi à 10px pour gérer l'alignement imparfait), puis par colonne (x)
    text_blocks.sort(key=lambda b: (round(b[1] / 10) * 10, b[0]))

    doc.close()
    return "\n".join(b[4].strip() for b in text_blocks)


OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
GROQ_API_KEY = os.getenv("GROQ_API_KEY")


def get_big_llm():
    """GPT-4o pour les tâches complexes — max_tokens élevé pour éviter la troncature JSON."""
    return ChatOpenAI(
        model="gpt-5.2",
        temperature=0.0,
        api_key=OPENAI_API_KEY
    )


def get_small_llm():
    """GPT-4o-mini pour l'extraction rapide."""
    return ChatOpenAI(
        model="gpt-4o",
        temperature=0.0,
        max_tokens=1500,
        api_key=OPENAI_API_KEY
    )