LilRg commited on
Commit
22dc1a7
·
verified ·
1 Parent(s): e9b5fc5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +346 -60
app.py CHANGED
@@ -1,64 +1,350 @@
 
 
1
  import gradio as gr
2
- from huggingface_hub import InferenceClient
3
-
4
- """
5
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
6
- """
7
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
8
-
9
-
10
- def respond(
11
- message,
12
- history: list[tuple[str, str]],
13
- system_message,
14
- max_tokens,
15
- temperature,
16
- top_p,
17
- ):
18
- messages = [{"role": "system", "content": system_message}]
19
-
20
- for val in history:
21
- if val[0]:
22
- messages.append({"role": "user", "content": val[0]})
23
- if val[1]:
24
- messages.append({"role": "assistant", "content": val[1]})
25
-
26
- messages.append({"role": "user", "content": message})
27
-
28
- response = ""
29
-
30
- for message in client.chat_completion(
31
- messages,
32
- max_tokens=max_tokens,
33
- stream=True,
34
- temperature=temperature,
35
- top_p=top_p,
36
- ):
37
- token = message.choices[0].delta.content
38
-
39
- response += token
40
- yield response
41
-
42
-
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- demo = gr.ChatInterface(
47
- respond,
48
- additional_inputs=[
49
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
50
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
51
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
52
- gr.Slider(
53
- minimum=0.1,
54
- maximum=1.0,
55
- value=0.95,
56
- step=0.05,
57
- label="Top-p (nucleus sampling)",
58
- ),
59
- ],
60
- )
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  if __name__ == "__main__":
64
- demo.launch()
 
1
+ import requests
2
+ import json
3
  import gradio as gr
4
+ import logging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ logging.basicConfig(level=logging.ERROR)
7
+ logger = logging.getLogger(__name__)
8
+
9
+ # Clés API et informations
10
+ OPENROUTER_API_KEY = "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"
11
+ AIRTABLE_API_KEY = "patUUQ6NE9zUOqooM.ec8d096169d754852305c88c7966ad1f8a151f3bf015d39f80bb895bdad0e2f5"
12
+ AIRTABLE_BASE_ID = "appht9RdYAQVd32Py"
13
+ AIRTABLE_TABLE_NAME = "DescriptionsEtudiants"
14
+ YOUR_SITE_URL = "votre-site.com"
15
+ YOUR_APP_NAME = "MonChatbot"
16
+
17
+ # ID de l'étudiant
18
+ #student_id = 34
19
+ current_request = None
20
+
21
+ def getParams(x):
22
+ global current_request
23
+ params = current_request.query_params
24
+
25
+ if 'id' in params:
26
+ return params['id']
27
+ else:
28
+ return None
29
+
30
+ student_id = getParams(None)
31
+
32
+ def get_user_info_by_id(student_id):
33
+ url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/Inscription_Etudiants"
34
+ headers = {
35
+ "Authorization": f"Bearer {AIRTABLE_API_KEY}",
36
+ "Content-Type": "application/json"
37
+ }
38
+
39
+ # Filtrer les enregistrements par ID_Etu
40
+ params = {
41
+ "filterByFormula": f"{{ID_Etu}} = '{student_id}'"
42
+ }
43
+
44
+ try:
45
+ response = requests.get(url, headers=headers, params=params)
46
+
47
+ if response.status_code == 200:
48
+ data = response.json()
49
+
50
+ if len(data['records']) > 0:
51
+ record = data['records'][0] # On prend le premier enregistrement correspondant
52
+ user_name = record['fields'].get('Nom', 'Aucun nom trouvé')
53
+ user_email = record['fields'].get('Email', 'Aucun email trouvé')
54
+ return user_name, user_email
55
+ else:
56
+ return None, None
57
+ else:
58
+ logger.error(f"Erreur lors de la récupération des informations : {response.status_code} - {response.text}")
59
+ return None, None
60
+
61
+ except Exception as e:
62
+ logger.error(f"Erreur lors de la récupération des informations : {str(e)}")
63
+ return None, None
64
+
65
+
66
+ def get_student_description(student_id):
67
+ url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE_NAME}"
68
+ headers = {
69
+ "Authorization": f"Bearer {AIRTABLE_API_KEY}",
70
+ "Content-Type": "application/json"
71
+ }
72
+
73
+ try:
74
+ response = requests.get(url, headers=headers)
75
+ if response.status_code == 200:
76
+ data = response.json()
77
+ if 'records' in data:
78
+ for record in data['records']:
79
+ if record['fields'].get('ID_Etudiant') == student_id:
80
+ return record['fields'].get('Description Compétences Etudiants', 'Pas de description trouvée.')
81
+ return "Aucun enregistrement trouvé pour cet étudiant."
82
+ else:
83
+ logger.error(f"Erreur lors de la récupération de la description : {response.status_code} - {response.text}")
84
+ return f"Erreur lors de la récupération : {response.status_code} - {response.text}"
85
+ except Exception as e:
86
+ logger.error(f"Erreur lors de la récupération : {str(e)}")
87
+ return "Erreur lors de la récupération."
88
+
89
+ def update_student_description(student_id, new_description):
90
+ # Étape 1 : Récupérer tous les enregistrements
91
+ url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE_NAME}"
92
+ headers = {
93
+ "Authorization": f"Bearer {AIRTABLE_API_KEY}",
94
+ "Content-Type": "application/json"
95
+ }
96
+
97
+ try:
98
+ response = requests.get(url, headers=headers)
99
+ if response.status_code == 200:
100
+ data = response.json()
101
+ # Étape 2 : Trouver l'enregistrement correspondant à student_id
102
+ record_to_update = None
103
+ for record in data.get('records', []):
104
+ if 'fields' in record and record['fields'].get('ID_Etudiant') == student_id:
105
+ record_to_update = record
106
+ break
107
+
108
+ if record_to_update:
109
+ # Étape 3 : Mettre à jour la description
110
+ record_id = record_to_update['id']
111
+ update_url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/{AIRTABLE_TABLE_NAME}/{record_id}"
112
+ update_data = {
113
+ "fields": {
114
+ "Description Compétences Etudiants": new_description
115
+ }
116
+ }
117
+ update_response = requests.patch(update_url, headers=headers, json=update_data)
118
+
119
+ if update_response.status_code == 200:
120
+ return "Description mise à jour avec succès."
121
+ else:
122
+ logger.error(f"Erreur lors de la mise à jour : {update_response.status_code} - {update_response.text}")
123
+ return "Erreur lors de la mise à jour."
124
+ else:
125
+ return "Aucun étudiant trouvé avec cet ID."
126
+ else:
127
+ logger.error(f"Erreur lors de la récupération des enregistrements : {response.status_code} - {response.text}")
128
+ return "Erreur lors de la récupération des enregistrements."
129
+ except Exception as e:
130
+ logger.error(f"Erreur lors de la mise à jour : {str(e)}")
131
+ return "Erreur lors de la mise à jour."
132
+
133
+
134
+ def call_api_for_response_analysis(current_skills, user_response):
135
+ messages = [
136
+ {
137
+ "role": "system",
138
+ "content": "Tu es un expert en analyse de compétences. En fonction de la réponse de l'utilisateur, "
139
+ "tu dois reformuler et mettre à jour les compétences actuelles. "
140
+ "Retourne uniquement la nouvelle description des compétences mise à jour."
141
+ },
142
+ {
143
+ "role": "user",
144
+ "content": f"Compétences actuelles :\n{current_skills}\n\n"
145
+ f"Réponse de l'utilisateur :\n{user_response}\n\n"
146
+ "Reformule les compétences en prenant en compte la réponse de l'utilisateur."
147
+ }
148
+ ]
149
+
150
+ try:
151
+ api_response = requests.post(
152
+ url="https://openrouter.ai/api/v1/chat/completions",
153
+ headers={
154
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
155
+ "Content-Type": "application/json"
156
+ },
157
+ data=json.dumps({
158
+ "model": "mistralai/pixtral-12b:free",
159
+ "messages": messages
160
+ })
161
+ )
162
+
163
+ if api_response.status_code == 200:
164
+ data = api_response.json()
165
+ return data['choices'][0]['message']['content']
166
+ else:
167
+ logger.error(f"Erreur lors de l'analyse de la réponse : {api_response.status_code} - {api_response.text}")
168
+ return "Erreur lors de l'analyse de la réponse."
169
+
170
+ except Exception as e:
171
+ logger.error(f"Erreur lors de l'appel API: {str(e)}")
172
+ return "Erreur lors de l'appel API."
173
+
174
+ def get_enterprise_descriptions():
175
+ url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/Formulaire firm"
176
+ headers = {
177
+ "Authorization": f"Bearer {AIRTABLE_API_KEY}",
178
+ "Content-Type": "application/json"
179
+ }
180
+
181
+ response = requests.get(url, headers=headers)
182
+
183
+ if response.status_code == 200:
184
+ data = response.json()
185
+ firm_data = [
186
+ (
187
+ record['fields'].get('Recruteur / Entreprise'),
188
+ record['fields'].get('Compétences requises'),
189
+ record['fields'].get('ID_Offre')
190
+ )
191
+ for record in data['records']
192
+ ]
193
+ return firm_data
194
+ else:
195
+ logger.error(f"Erreur lors de la récupération des descriptions d'entreprises : {response.status_code} - {response.text}")
196
+ return []
197
+
198
+
199
+ def compare_skills_ai(student_skills, enterprise_skills):
200
+ messages = [
201
+ {"role": "system", "content": "Vous êtes un expert en recrutement chargé d'évaluer la correspondance entre les compétences d'un étudiant et celles requises par une entreprise. Votre tâche est d'analyser ces compétences et de fournir une valeur de correspondance entre l'étudiant et les différentes entreprise, je veux simplement la note global pour chaque entreprise. Tenez compte des compétences similaires ou complémentaires, pas seulement des correspondances exactes."},
202
+ {"role": "user", "content": f"Compétences de l'étudiant :\n{student_skills}\n\nCompétences requises par l'entreprise :\n{enterprise_skills}\n\nVeuillez analyser ces compétences et fournir un chiffre entre 0 et 100 pour la correspondance entre l'etudiant et l'entreprise afin de voir le taux de compatibilité entre l'etudiants et les différentes entreprises. ne détaille rien, juste la note global sans le détail. Ecrit que et uniquement le score, par exemple : 100 et pas : Score : 100, juste 100. Sans tiret nin rien juste le nombre"}
203
+ ]
204
+
205
+ try:
206
+ response = requests.post(
207
+ url="https://openrouter.ai/api/v1/chat/completions",
208
+ headers={
209
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
210
+ "HTTP-Referer": f"{YOUR_SITE_URL}",
211
+ "X-Title": f"{YOUR_APP_NAME}",
212
+ "Content-Type": "application/json"
213
+ },
214
+ data=json.dumps({
215
+ "model": "mistralai/pixtral-12b:free",
216
+ "messages": messages
217
+ })
218
+ )
219
+
220
+ if response.status_code == 200:
221
+ data = response.json()
222
+ ai_analysis = data['choices'][0]['message']['content']
223
+ try:
224
+ score = int(ai_analysis.strip())
225
+ return score
226
+ except ValueError:
227
+ logger.error(f"Erreur lors de la conversion du score : la réponse était '{ai_analysis}'")
228
+ return "Erreur lors de l'analyse des compétences : score non valide."
229
+ else:
230
+ logger.error(f"Erreur lors de l'appel à l'API : {response.status_code} - {response.text}")
231
+ return "Erreur lors de l'analyse des compétences."
232
+ except Exception as e:
233
+ logger.error(f"Erreur lors de l'appel API: {str(e)}")
234
+ return f"Erreur lors de l'analyse des compétences : {str(e)}"
235
+
236
+ def update_compatibility_table(student_id, skill_assessment, enterprise_skills, offer_id, compatibility_rate, student_name, student_mail):
237
+ url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/TauxCompatibilité"
238
+ headers = {
239
+ "Authorization": f"Bearer {AIRTABLE_API_KEY}",
240
+ "Content-Type": "application/json"
241
+ }
242
+
243
+ data = {
244
+ "fields": {
245
+ "ID_Etu": student_id,
246
+ "DescriptionEtu": skill_assessment,
247
+ "ID_Offre": offer_id,
248
+ "DescriptionOffre": enterprise_skills,
249
+ "Taux de compatibilité" : compatibility_rate,
250
+ "Nom": student_name,
251
+ "EmailEtudiant": student_mail
252
+ }
253
+ }
254
+
255
+ try:
256
+ response = requests.post(url, headers=headers, json=data)
257
+
258
+ if response.status_code == 200:
259
+ return "Données ajoutées avec succès !"
260
+ else:
261
+ logger.error(f"Erreur lors de l'ajout à la table de compatibilité : {response.status_code} - {response.text}")
262
+ return f"Erreur lors de l'ajout à la table de compatibilité : {response.status_code}"
263
+ except Exception as e:
264
+ logger.error(f"Erreur lors de l'ajout à Airtable : {str(e)}")
265
+ return f"Erreur lors de l'ajout à Airtable : {str(e)}"
266
+
267
+ def delete_compatibility_records(student_id):
268
+ """
269
+ Supprime tous les enregistrements de la table TauxCompatibilité associés à un étudiant donné (ID_Etu).
270
+ """
271
+ url = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}/TauxCompatibilité"
272
+ headers = {
273
+ "Authorization": f"Bearer {AIRTABLE_API_KEY}",
274
+ "Content-Type": "application/json"
275
+ }
276
+
277
+ try:
278
+ # Récupérer les enregistrements existants pour l'ID_Etu donné
279
+ response = requests.get(url, headers=headers)
280
+ response.raise_for_status()
281
+ records = response.json().get('records', [])
282
+
283
+ # Supprimer les enregistrements existants avec l'ID_Etu correspondant
284
+ for record in records:
285
+ if record['fields'].get('ID_Etu') == student_id:
286
+ delete_url = f"{url}/{record['id']}"
287
+ delete_response = requests.delete(delete_url, headers=headers)
288
+ delete_response.raise_for_status() # Vérifier si la suppression a réussi
289
+
290
+ return "Suppression des enregistrements existants réussie."
291
+
292
+ except Exception as e:
293
+ logger.error(f"Erreur lors de la suppression des enregistrements : {str(e)}")
294
+ return f"Erreur lors de la suppression des enregistrements : {str(e)}"
295
+
296
+
297
+ def start_conversation():
298
+ description = get_student_description(student_id)
299
+ initial_message = f"Bienvenue ! Voici vos compétences :\n{description}\n\nQue souhaitez-vous modifier ou améliorer dans vos compétences ?"
300
+ return [[None, initial_message]], description
301
+
302
+ def chatbot_conversation(message, history):
303
+ student_name, student_mail = get_user_info_by_id(student_id)
304
+ current_skills = get_student_description(student_id)
305
+
306
+ # Analyse la réponse et obtient les compétences mises à jour
307
+ updated_skills = call_api_for_response_analysis(current_skills, message)
308
+
309
+ enterprise_descriptions = get_enterprise_descriptions()
310
+ results = []
311
+ delete_compatibility_records(student_id)
312
+ for enterprise_name, enterprise_desc, offer_id in enterprise_descriptions:
313
+ analysis = compare_skills_ai(updated_skills, enterprise_desc)
314
+
315
+ add_response = update_compatibility_table(student_id, updated_skills, enterprise_desc, offer_id, analysis, student_name, student_mail)
316
+
317
+ results.append(f"Entreprise : {enterprise_name}\n{add_response}")
318
+
319
+ # Prépare la réponse pour le chatbot
320
+ response = "Voici la version mise à jour de vos compétences :\n\n" + updated_skills
321
+ history.append((message, response))
322
+
323
+ return history, updated_skills
324
+
325
+ def validate_update(updated_skills):
326
+ response = update_student_description(student_id, updated_skills)
327
+ return response
328
+
329
+ # Création de l'interface
330
+ with gr.Blocks() as demo:
331
+ chatbot = gr.Chatbot()
332
+ msg = gr.Textbox(label="Message")
333
+ skill_assessment_output = gr.Textbox(label="Compétences actuelles", interactive=False)
334
+ validate_button = gr.Button("Valider la mise à jour") # Nouveau bouton pour valider
335
+ validation_output = gr.Textbox(label="Résultat de la mise à jour", interactive=False) # Nouveau bloc pour afficher le résultat
336
+
337
+ msg.submit(fn=chatbot_conversation,
338
+ inputs=[msg, chatbot],
339
+ outputs=[chatbot, skill_assessment_output])
340
+
341
+ # Action du bouton pour mettre à jour la description
342
+ validate_button.click(fn=validate_update, inputs=skill_assessment_output, outputs=validation_output) # Utilisation du bloc validation_output
343
+
344
+ # Chargement initial du message de bienvenue
345
+ demo.load(start_conversation,
346
+ inputs=None,
347
+ outputs=[chatbot, skill_assessment_output])
348
 
349
  if __name__ == "__main__":
350
+ demo.launch()