QuentinL52 commited on
Commit
7139180
·
verified ·
1 Parent(s): 7ff33d3

Create cv_agents.py

Browse files
Files changed (1) hide show
  1. src/agents/cv_agents.py +192 -0
src/agents/cv_agents.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import logging
3
+ from typing import Dict, Any, List
4
+ from crewai import Agent, Task, Crew, Process
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ class CVAgentOrchestrator:
9
+ def __init__(self, llm):
10
+ self.llm = llm
11
+ self._create_agents()
12
+
13
+ def _create_agents(self):
14
+ self.section_splitter = Agent(
15
+ role="Analyseur de Structure de CV",
16
+ goal="Découper intelligemment un CV en sections thématiques",
17
+ backstory="Expert en analyse documentaire spécialisé dans la reconnaissance de structures de CV.",
18
+ verbose=False,
19
+ llm=self.llm
20
+ )
21
+
22
+ self.contact_extractor = Agent(
23
+ role="Extracteur d'informations de contact",
24
+ goal="Extraire les coordonnées du candidat",
25
+ backstory="Expert en extraction d'informations de contact avec précision.",
26
+ verbose=False,
27
+ llm=self.llm
28
+ )
29
+
30
+ self.skills_extractor = Agent(
31
+ role="Extracteur de compétences",
32
+ goal="Identifier hard skills et soft skills",
33
+ backstory="Spécialiste en identification de compétences techniques et comportementales.",
34
+ verbose=False,
35
+ llm=self.llm
36
+ )
37
+
38
+ self.experience_extractor = Agent(
39
+ role="Extracteur d'expériences",
40
+ goal="Extraire les expériences professionnelles",
41
+ backstory="Expert en analyse de parcours professionnels.",
42
+ verbose=False,
43
+ llm=self.llm
44
+ )
45
+
46
+ self.project_extractor = Agent(
47
+ role="Extracteur de projets",
48
+ goal="Identifier projets professionnels et personnels",
49
+ backstory="Spécialiste en identification de projets significatifs.",
50
+ verbose=False,
51
+ llm=self.llm
52
+ )
53
+
54
+ self.education_extractor = Agent(
55
+ role="Extracteur de formations",
56
+ goal="Extraire formations et diplômes",
57
+ backstory="Expert en analyse de parcours académiques.",
58
+ verbose=False,
59
+ llm=self.llm
60
+ )
61
+
62
+ self.reconversion_detector = Agent(
63
+ role="Détecteur de reconversion",
64
+ goal="Analyser les changements de carrière",
65
+ backstory="Conseiller d'orientation expert en transitions de carrière.",
66
+ verbose=False,
67
+ llm=self.llm
68
+ )
69
+
70
+ self.profile_builder = Agent(
71
+ role="Constructeur de profil",
72
+ goal="Assembler le profil candidat final",
73
+ backstory="Expert en structuration de données JSON.",
74
+ verbose=False,
75
+ llm=self.llm
76
+ )
77
+
78
+ def split_cv_sections(self, cv_content: str) -> Dict[str, str]:
79
+ task = Task(
80
+ description=f"Analyser ce CV et l'organiser en sections: {cv_content}",
81
+ expected_output="""JSON avec sections: contact, experiences, projects, education, skills, other""",
82
+ agent=self.section_splitter
83
+ )
84
+
85
+ crew = Crew(
86
+ agents=[self.section_splitter],
87
+ tasks=[task],
88
+ process=Process.sequential,
89
+ verbose=False,
90
+ telemetry=False
91
+ )
92
+
93
+ result = crew.kickoff()
94
+ return self._parse_sections_result(result)
95
+
96
+ def extract_all_sections(self, sections: Dict[str, str]) -> Dict[str, Any]:
97
+ tasks = self._create_extraction_tasks(sections)
98
+
99
+ crew = Crew(
100
+ agents=[
101
+ self.contact_extractor,
102
+ self.skills_extractor,
103
+ self.experience_extractor,
104
+ self.project_extractor,
105
+ self.education_extractor,
106
+ self.reconversion_detector,
107
+ self.profile_builder
108
+ ],
109
+ tasks=tasks,
110
+ process=Process.sequential,
111
+ verbose=False,
112
+ telemetry=False
113
+ )
114
+
115
+ result = crew.kickoff(inputs=sections)
116
+ return self._parse_final_result(result)
117
+
118
+ def _create_extraction_tasks(self, sections: Dict[str, str]) -> List[Task]:
119
+ contact_task = Task(
120
+ description="Extraire nom, email, téléphone, localisation de: {contact}",
121
+ expected_output='{"nom": "...", "email": "...", "numero_de_telephone": "...", "localisation": "..."}',
122
+ agent=self.contact_extractor
123
+ )
124
+
125
+ skills_task = Task(
126
+ description="Extraire compétences de: {experiences} {projects} {skills}",
127
+ expected_output='{"hard_skills": [...], "soft_skills": [...]}',
128
+ agent=self.skills_extractor,
129
+ context=[contact_task]
130
+ )
131
+
132
+ experience_task = Task(
133
+ description="Extraire expériences de: {experiences}",
134
+ expected_output='[{"Poste": "...", "Entreprise": "...", "start_date": "...", "end_date": "...", "responsabilités": [...]}]',
135
+ agent=self.experience_extractor,
136
+ context=[skills_task]
137
+ )
138
+
139
+ project_task = Task(
140
+ description="Extraire projets de: {projects} {experiences}",
141
+ expected_output='{"professional": [...], "personal": [...]}',
142
+ agent=self.project_extractor,
143
+ context=[experience_task]
144
+ )
145
+
146
+ education_task = Task(
147
+ description="Extraire formations de: {education}",
148
+ expected_output='[{"degree": "...", "institution": "...", "start_date": "...", "end_date": "..."}]',
149
+ agent=self.education_extractor,
150
+ context=[project_task]
151
+ )
152
+
153
+ reconversion_task = Task(
154
+ description="Analyser reconversion basée sur les expériences extraites",
155
+ expected_output='{"reconversion_analysis": {"is_reconversion": true/false, "analysis": "..."}}',
156
+ agent=self.reconversion_detector,
157
+ context=[education_task]
158
+ )
159
+
160
+ profile_task = Task(
161
+ description="Assembler profil final JSON avec clé 'candidat'",
162
+ expected_output='{"candidat": {...}}',
163
+ agent=self.profile_builder,
164
+ context=[reconversion_task]
165
+ )
166
+
167
+ return [contact_task, skills_task, experience_task, project_task, education_task, reconversion_task, profile_task]
168
+
169
+ def _parse_sections_result(self, result) -> Dict[str, str]:
170
+ result_str = result.raw if hasattr(result, 'raw') else str(result)
171
+
172
+ if '```json' in result_str:
173
+ result_str = result_str.split('```json')[1].split('```')[0].strip()
174
+ elif '```' in result_str:
175
+ parts = result_str.split('```')
176
+ if len(parts) >= 3:
177
+ result_str = parts[1].strip()
178
+
179
+ parsed = json.loads(result_str)
180
+ return parsed
181
+
182
+ def _parse_final_result(self, result) -> Dict[str, Any]:
183
+ result_str = result.raw if hasattr(result, 'raw') else str(result)
184
+
185
+ if '```json' in result_str:
186
+ result_str = result_str.split('```json')[1].split('```')[0].strip()
187
+ elif '```' in result_str:
188
+ parts = result_str.split('```')
189
+ if len(parts) >= 3:
190
+ result_str = parts[1].strip()
191
+
192
+ return json.loads(result_str)