QuentinL52 commited on
Commit
f05c40c
·
verified ·
1 Parent(s): c5b054b

Update src/services/interview_service.py

Browse files
Files changed (1) hide show
  1. src/services/interview_service.py +46 -114
src/services/interview_service.py CHANGED
@@ -1,21 +1,31 @@
1
- # Mise à jour pour src/services/interview_service.py
2
-
3
  import os
4
- from typing import Dict, List, Any
 
 
5
  from typing_extensions import TypedDict
 
6
  from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
7
  from langgraph.graph import StateGraph, START, END
8
  from langgraph.graph.message import add_messages
9
  from langchain_openai import ChatOpenAI
 
10
  from src.config import read_system_prompt, format_cv
11
 
12
  class State(TypedDict):
13
- messages: List[add_messages]
14
 
15
- class InterviewService:
16
- def __init__(self, models: Dict[str, Any]):
17
- self.models = models
 
 
 
 
 
 
 
18
  self.llm = self._get_llm()
 
19
  self.system_prompt_template = self._load_prompt_template()
20
  self.graph = self._build_graph()
21
 
@@ -28,103 +38,44 @@ class InterviewService:
28
  )
29
 
30
  def _load_prompt_template(self) -> str:
31
- return read_system_prompt('prompts/rag_prompt_old.txt')
32
-
33
- def _analyze_candidate_profile(self, cv_data: Dict[str, Any]) -> Dict[str, str]:
34
- """Analyse le profil candidat pour générer des insights pour l'entretien"""
35
-
36
- # Analyse des compétences avec niveaux
37
- skills_analysis = self._generate_skills_analysis(cv_data)
38
-
39
- # Analyse de reconversion
40
- reconversion_analysis = self._generate_reconversion_analysis(cv_data)
41
-
42
- return {
43
- "skills_analysis": skills_analysis,
44
- "reconversion_analysis": reconversion_analysis
45
- }
46
 
47
- def _generate_skills_analysis(self, cv_data: Dict[str, Any]) -> str:
48
- """Génère une analyse textuelle des compétences pour le prompt"""
49
-
50
- competences = cv_data.get("analyse_competences", [])
51
-
52
  if not competences:
53
  return "Aucune analyse de compétences disponible."
54
 
55
- # Grouper par niveau
56
- levels_groups = {
57
- "expert": [],
58
- "avance": [],
59
- "intermediaire": [],
60
- "debutant": []
61
- }
62
-
63
  for comp in competences:
64
- level = comp.get("level", "debutant")
65
- skill = comp.get("skill", "")
66
- if skill and level in levels_groups:
67
- levels_groups[level].append(skill)
68
-
69
- # Construire l'analyse textuelle
70
- analysis_parts = []
71
-
72
- if levels_groups["expert"]:
73
- analysis_parts.append(f"COMPÉTENCES EXPERTES : {', '.join(levels_groups['expert'])}")
74
- analysis_parts.append("→ Pose des questions techniques approfondies, demande des exemples d'innovation et de leadership technique")
75
 
76
- if levels_groups["avance"]:
77
- analysis_parts.append(f"COMPÉTENCES AVANCÉES : {', '.join(levels_groups['avance'])}")
78
- analysis_parts.append("→ Explore les défis complexes, l'autonomie et la résolution de problèmes")
79
-
80
- if levels_groups["intermediaire"]:
81
- analysis_parts.append(f"COMPÉTENCES INTERMÉDIAIRES : {', '.join(levels_groups['intermediaire'])}")
82
- analysis_parts.append("→ Vérifie la compréhension pratique avec des exemples concrets")
83
-
84
- if levels_groups["debutant"]:
85
- analysis_parts.append(f"COMPÉTENCES DÉBUTANTES : {', '.join(levels_groups['debutant'])}")
86
- analysis_parts.append("→ Teste les connaissances de base et évalue la motivation à apprendre")
87
-
88
- return "\n".join(analysis_parts) if analysis_parts else "Aucune compétence analysée."
89
 
90
- def _generate_reconversion_analysis(self, cv_data: Dict[str, Any]) -> str:
91
- """Génère une analyse de reconversion pour le prompt"""
92
-
93
- reconversion_data = cv_data.get("reconversion", {})
94
-
95
- if not reconversion_data:
96
- return "Aucune analyse de reconversion disponible."
97
-
98
- is_reconversion = reconversion_data.get("is_reconversion", False)
99
- analysis = reconversion_data.get("analysis", "")
100
 
 
101
  if not is_reconversion:
102
- return "PROFIL CLASSIQUE : Parcours cohérent dans le domaine. Focus sur l'évolution et les projets marquants."
103
-
104
- reconversion_guidance = [
105
- "CANDIDAT EN RECONVERSION DÉTECTÉE :",
106
- f"Analyse : {analysis}",
107
- "",
108
- "POINTS À EXPLORER OBLIGATOIREMENT :",
109
- "1. Motivations du changement de carrière",
110
- "2. Compétences transférables de l'expérience passée",
111
- "3. Démarches d'apprentissage et de formation",
112
- "4. Engagement et projets dans la nouvelle voie",
113
- "5. Vision à long terme dans ce nouveau domaine",
114
- "",
115
- "APPROCHE : Valorise l'expérience passée, rassure sur la pertinence de la reconversion"
116
- ]
117
 
118
- return "\n".join(reconversion_guidance)
 
119
 
120
- def _chatbot_node(self, state: State) -> Dict[str, Any]:
121
  messages = state["messages"]
122
  formatted_cv_str = format_cv(self.cv_data)
123
 
124
- # Générer les analyses du profil candidat
125
- profile_analysis = self._analyze_candidate_profile(self.cv_data)
126
-
127
- # Formatage du prompt système enrichi
 
128
  system_prompt = self.system_prompt_template.format(
129
  entreprise=self.job_offer.get('entreprise', 'notre entreprise'),
130
  poste=self.job_offer.get('poste', 'ce poste'),
@@ -133,8 +84,8 @@ class InterviewService:
133
  competences=self.job_offer.get('competences', 'Non spécifiées'),
134
  pole=self.job_offer.get('pole', 'Non spécifié'),
135
  cv=formatted_cv_str,
136
- skills_analysis=profile_analysis["skills_analysis"],
137
- reconversion_analysis=profile_analysis["reconversion_analysis"]
138
  )
139
 
140
  llm_messages = [SystemMessage(content=system_prompt)] + messages
@@ -150,25 +101,6 @@ class InterviewService:
150
 
151
  return graph_builder.compile()
152
 
153
- def process_conversation(
154
- self,
155
- cv_document: Dict[str, Any],
156
- job_offer: Dict[str, Any],
157
- conversation_history: List[Dict[str, Any]],
158
- messages: List[Dict[str, Any]]
159
- ) -> Dict[str, Any]:
160
-
161
- if not cv_document or 'candidat' not in cv_document:
162
- raise ValueError("Document CV invalide fourni.")
163
-
164
- if not job_offer:
165
- raise ValueError("Données de l'offre d'emploi non fournies.")
166
-
167
- self.job_offer = job_offer
168
- self.cv_data = cv_document['candidat']
169
- self.conversation_history = conversation_history
170
- initial_state = conversation_history + messages
171
- result = self.graph.invoke({"messages": initial_state})
172
-
173
- response_content = result["messages"][-1].content
174
- return {"response": response_content}
 
 
 
1
  import os
2
+ import sys
3
+ import json
4
+ from typing import Dict, List, Any, Annotated
5
  from typing_extensions import TypedDict
6
+
7
  from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
8
  from langgraph.graph import StateGraph, START, END
9
  from langgraph.graph.message import add_messages
10
  from langchain_openai import ChatOpenAI
11
+
12
  from src.config import read_system_prompt, format_cv
13
 
14
  class State(TypedDict):
15
+ messages: Annotated[list, add_messages]
16
 
17
+ class InterviewProcessor:
18
+ def __init__(self, cv_document: Dict[str, Any], job_offer: Dict[str, Any], conversation_history: List[Dict[str, Any]]):
19
+ if not cv_document or 'candidat' not in cv_document:
20
+ raise ValueError("Document CV invalide fourni.")
21
+ if not job_offer:
22
+ raise ValueError("Données de l'offre d'emploi non fournies.")
23
+
24
+ self.job_offer = job_offer
25
+ self.cv_data = cv_document['candidat']
26
+ self.conversation_history = conversation_history
27
  self.llm = self._get_llm()
28
+
29
  self.system_prompt_template = self._load_prompt_template()
30
  self.graph = self._build_graph()
31
 
 
38
  )
39
 
40
  def _load_prompt_template(self) -> str:
41
+ return read_system_prompt('prompts/rag_prompt_old.txt')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ def _extract_skills_summary(self) -> str:
44
+ """Extrait un résumé simple des compétences avec niveaux"""
45
+ competences = self.cv_data.get('analyse_competences', [])
 
 
46
  if not competences:
47
  return "Aucune analyse de compétences disponible."
48
 
49
+ summary = []
 
 
 
 
 
 
 
50
  for comp in competences:
51
+ skill = comp.get('skill', '')
52
+ level = comp.get('level', 'débutant')
53
+ summary.append(f"{skill}: {level}")
 
 
 
 
 
 
 
 
54
 
55
+ return "Niveaux de compétences du candidat: " + " | ".join(summary)
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ def _extract_reconversion_info(self) -> str:
58
+ """Extrait les infos de reconversion"""
59
+ reconversion = self.cv_data.get('reconversion', {})
60
+ if not reconversion:
61
+ return ""
 
 
 
 
 
62
 
63
+ is_reconversion = reconversion.get('is_reconversion', False)
64
  if not is_reconversion:
65
+ return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ analysis = reconversion.get('analysis', '')
68
+ return f"CANDIDAT EN RECONVERSION: {analysis}"
69
 
70
+ def _chatbot_node(self, state: State) -> dict:
71
  messages = state["messages"]
72
  formatted_cv_str = format_cv(self.cv_data)
73
 
74
+ # Extractions simples
75
+ skills_summary = self._extract_skills_summary()
76
+ reconversion_info = self._extract_reconversion_info()
77
+
78
+ # Formatage du prompt système avec les nouvelles données
79
  system_prompt = self.system_prompt_template.format(
80
  entreprise=self.job_offer.get('entreprise', 'notre entreprise'),
81
  poste=self.job_offer.get('poste', 'ce poste'),
 
84
  competences=self.job_offer.get('competences', 'Non spécifiées'),
85
  pole=self.job_offer.get('pole', 'Non spécifié'),
86
  cv=formatted_cv_str,
87
+ skills_levels=skills_summary,
88
+ reconversion_info=reconversion_info
89
  )
90
 
91
  llm_messages = [SystemMessage(content=system_prompt)] + messages
 
101
 
102
  return graph_builder.compile()
103
 
104
+ def run(self, messages: List[Dict[str, Any]]) -> Dict[str, Any]:
105
+ initial_state = self.conversation_history + messages
106
+ return self.graph.invoke({"messages": initial_state})