datacipen commited on
Commit
0fb8776
1 Parent(s): 65cb14d

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +293 -307
main.py CHANGED
@@ -177,53 +177,59 @@ def localisation():
177
  { "ID": "972", "Longitude": -61.024174, "Latitude": 14.641528 },
178
  { "ID": "971", "Longitude": -61.551, "Latitude": 16.265 }
179
  ]
180
- longLat = pd.DataFrame(ListCentroids)
181
- return longLat
182
 
183
- def modele(document):
184
- match document:
185
- case "Note de composante sectorielle":
186
- note = """2. Analyse du système travail
187
- 2.1 Secteurs en lien avec la discipline
188
- 2.1.1 Indiquer la nature des secteurs, la répartition des entreprises. Décrire les enjeux pour ce secteur (axes de développement, de transformations). Indiquer les OPérateurs de COmpétences de la branche professionnelle correspondante en France.
189
- 2.2 Analyses des offres d’emploi
190
- 2.2.1 Indiquer les statistiques de l’emploi sur une période. Identifier les 5 principales appellations métiers seulement en fonction du contexte, en créer une liste contextualisée, avec les pourcentages du nombre d'offres pour chaque emploi par rapport au nombre total d'offres.
191
- 2.2.2 missions, activités et compétences demandées (écrites avec un verbe d'action). Décrire le/les profils types des recrutés par les employeurs du système de travail. Lister, au format liste, les évolutions professionnelles ou les exemples de spécialisation, lister, au format liste, les débouchés, lister, au format liste, les avantages du métier, lister, au format liste, les inconvénients du métier, lister, au format liste, les conseils pour réussir dans ce métier.
192
- 2.2.3 Indiquer si les emplois sont en tension
193
- """
194
- case "Fiche Potentiel Profil de Sortie":
195
- note = """1. Nom de la fiche
196
- 2. Niveau du diplôme et son Intitulé (nom long plus sigle). Le niveau de qualification
197
- 3. Le résumé du profil et du potentiel de sortie. Il est composé de plusieurs parties :
198
- L'identité/ les spécificités de la composante. Cette introduction de 5 à 10 lignes est utile pour caractériser le diplôme. Il s'agit d’avoir une description sur les thématiques de recherche de la composante. Elles sont indiquées afin d’établir le lien entre la recherche et des enjeux possibles dans le système travail. Elle facilite la compréhension des domaines de compétences dans lequel s’inscrit le futur diplômé. La culture disciplinaire est à indiquer car elle contribue à caractériser le diplôme.
199
- L'identité professionnelle du diplômé. Les informations professionnelles sont organisées par mailles (du plus large au plus précis) secteur, famille de métiers, activités, compétences, compétences transversales. Il est nécessaire d’être attentif au niveau de qualification de sortie. Nous avons des emplois accessibles dès l’obtention du diplôme, d'autres ne le seront qu’avec un une qualification supérieure et/ou avec de l’expérience. Il souhaitable de faire une description globale du profil en apportant des informations sur le niveau d’autonomie et de responsabilité et les caractéristiques d’exercice des emplois (spécialisé ou généraliste, polyvalent ou expert etc).Cette seconde partie de texte de 10 à 15 lignes introduit les domaines et enjeux sectoriels et/ou terrain de mise en œuvre (3 lignes), les principales appellations d’emploi (1 à 2 lignes), les activités professionnelles (employabilité ) et le processus métier (3 à 4 lignes), les principaux interlocuteurs (1 à 2 lignes), les différents contextes de mise en œuvre (déplacements, langues étrangères). Cette description peut être suivi la liste d’emplois (avec une présentation courte 5 lignes) accessibles en indiquant le cas échéant les spécificités
200
- 4. La réglementation le cas échéant
201
- 5. Secteurs d'activité ou types d'emplois accessibles par le détenteur de ce diplôme
202
- 6. Le type de structure et d’organisations professionnelles
203
- 7. Listes des suites de parcours académiques ou passerelles de formation
204
- 8. Codes Rome
205
- 9. Référence de la fiche RNCP
206
- """
207
- return note
208
-
209
- def definition(document):
210
- if document == "activite":
211
- meanings = """
212
- Définition d'une activité : une activité est un ensemble cohérent d'actions combinées : pour la réaliser, plusieurs compétences et opérations sont nécessaires, soit successivement, soit conjointement. Elles s'inscrivent à des moments clés du processus de réalisation et ne peuvent en aucun cas être occultées, car elles conditionnent le résultat. Plusieurs activités en vue d'une finalité avec une valeur ajoutée à un produit ou un service sont nécessaires pour mettre en œuvre un processus métier. De ce fait, il est essentiel de déterminer pour chaque activité sa propre finalité et de s'assurer que l'ensemble des activités participent bien d'un même processus.
213
- """
214
- elif document == "competence":
215
- meanings = """
216
- Définition d'une compétence : la compétence est une combinaison de savoirs en action, mobilisés en vue de réaliser une activité professionnelle. Elle s'apprécie, en tant qu'acquis de l'apprentissage selon des modalités adaptées permettant d'en certifier la possession et au regard de l'atteinte d'un résultat pour un niveau d'exigence prédéterminé. Les compétences peuvent être regroupées par domaines selon la nature et leur liaison subordonnée aux activités. Elles s'écrivent à l'aide de verbe d'action à l'infinitif comme le stipule la taxonomie de Bloom pour marquer une progression dans l'exercice de la compétence.
217
- """
218
- elif document == "promptLibraryNCS":
219
- meanings = """
220
- Exemple de requêtes sur la note sectorielle : traitement statistique et génération des codes des objets de datavisualisation\nQuestion1 : donne le dataframe des appellations métiers et de leur pourcentage.\nQuestion2 : donne le plotly.js du dataframe avec les labels des appellations métiers et les labels des pourcentages.\nQuestion3 : convertis en plotly.js au format javascript\nQuestion4 : donne les salaires moyens.\nQuestion5 : donne le résultat des salaires moyens par appellations métiers dans un tableau.\nQuestion6 : donne le plotly du tableau des salaires moyens par appellation métier.\nQuestion7 : convertis en plotly.js au format javascript avec les labels des salaires moyens et les labels des appellations métiers\nQuestion8 : donne le pourcentage des contrats en CDI.\nQuestion9 : donne le résultat dans un tableau\nQuestion10 : donne le plotly du tableau\nQuestion11 : convertis le plotly en plotly.js au format javascript, avec affichage de tous les labels.\nQuestion12 : donne les 10 compétences professionnelles principales avec leur pourcentage.\nQuestion13 : donne le résultat dans un tableau.\nQuestion14 : donne le plotly du tableau\nQuestion15 : convertis le plotly en plotly.js au format javascript, avec affichage de tous les labels.\nQuestion16 : quelles sont les appellations métiers accessibles selon une expérience débutant, en donnant un pourcentage?\nQuestion17 : donne le résultat dans un tableau.\nQuestion18 : donne le plotly du tableau.\nQuestion19 : convertis le plotly en plotly.js au format javascript, avec affichage de tous les labels.\nQuestion20 : quelles sont les appellations métiers accessibles selon un niveau de qualification jusqu'à Bac+2 ou assimilés, en donnant un pourcentage?\nQuestion21 : donne le résultat dans un tableau.\nQuestion22 : donne le plotly du tableau\nQuestion23 : convertis le plotly en plotly.js au format javascript, avec affichage de tous les labels.\nQuestion24 : donne le pourcentage des appellations métiers en fonction des types d'entreprise.\nQuestion25 : construis le tableau en faisant une estimation.\nQuestion26 : donne le plotly du tableau estimé avec les pourcentage évalués par toi-même\nQuestion27 : convertis le plotly en plotly.js au format javascript, avec affichage de tous les labels, issus de votre estimation.
221
- """
222
- elif document == "promptLibraryFCS":
223
- meanings = """
224
- Exemple de requêtes sur la fiche synoptique : construction d'un programme de formation complet\nQuestion1 : crée un programme de formation, en 4000 mots, sur 3 ans découpés en 6 semestres, comportant 3 blocs de compétences pédagogiques, dont les intitulés commencent par un verbe d'action, par semestre correspondant à 3 unités d'enseignement par semestre et 3 cours par unité d'enseignement, en corrélation avec les activités professionnelles et les compétences professionnelles de la fiche synoptique, marquant une progression dans les apprentissages.\nQuestion2 : donne le synopsis du cours1 de l'UE1\nQuestion3 : plus?\nQuestion4 : et les supports pédagogiques?
225
- """
226
- return meanings
 
 
 
 
 
 
 
 
227
 
228
  def listToString(list):
229
  return str(list)
@@ -289,134 +295,6 @@ async def on_action(action):
289
  author="Datapcc : 🌐🌐🌐", content="[Lien] 🔗", elements=elements
290
  ).send()
291
  await action.remove()
292
-
293
- @cl.action_callback("datavizEmploi")
294
- async def on_action(action):
295
- client = Api(client_id=os.environ['POLE_EMPLOI_CLIENT_ID'],
296
- client_secret=os.environ['POLE_EMPLOI_CLIENT_SECRET'])
297
- todayDate = datetime.datetime.today()
298
- month, year = (todayDate.month-1, todayDate.year) if todayDate.month != 1 else (12, todayDate.year-1)
299
- start_dt = todayDate.replace(day=1, month=month, year=year)
300
- end_dt = datetime.datetime.today()
301
- arraydataframe = []
302
- arrayfirstdataframe = []
303
- arraylocalisationdataframe = []
304
- results = []
305
- count = 0
306
- listrome = action.value
307
- arrayrome = listrome.split(',')
308
- for k in arrayrome:
309
- params = {"motsCles": k,'minCreationDate': dt_to_str_iso(start_dt),'maxCreationDate': dt_to_str_iso(end_dt),'range':'0-149'}
310
- search_on_big_data = client.search(params=params)
311
- results += search_on_big_data["resultats"]
312
- results_df = pd.DataFrame(results)
313
- if results_df.empty == False:
314
- count = count + 1
315
- finals = results_df[['intitule','typeContratLibelle','experienceLibelle','competences','qualitesProfessionnelles','salaire','lieuTravail','formations']]
316
- finals["lieuTravail"] = finals["lieuTravail"].apply(lambda x: np.array(x)).apply(lambda x: x['libelle']).apply(lambda x: x[0:3]).apply(lambda x: x.strip())
317
- finals_df = finals
318
- finals_df.dropna(subset=['qualitesProfessionnelles','formations','competences'], inplace=True)
319
- finals_df["competences"] = finals_df["competences"].apply(lambda x:[str(e['libelle']) for e in x]).apply(lambda x:'; '.join(map(str, x)))
320
- finals_df["qualitesProfessionnelles"] = finals_df["qualitesProfessionnelles"].apply(lambda x:[str(e['libelle']) + ": " + str(e['description']) for e in x]).apply(lambda x:'; '.join(map(str, x)))
321
- finals_df["formations"] = finals_df["formations"].apply(lambda x:[str(e['niveauLibelle']) for e in x]).apply(lambda x:'; '.join(map(str, x)))
322
- finals_df = finals_df.sort_values(by=['lieuTravail'])
323
- finals_localisation = results_df[['lieuTravail']]
324
- finals_localisation["lieuTravail"] = finals_localisation["lieuTravail"].apply(lambda x: np.array(x)).apply(lambda x: x['libelle']).apply(lambda x: x[0:3]).apply(lambda x: x.strip())
325
- finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Fra'].index, inplace = True)
326
- finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'FRA'].index, inplace = True)
327
- finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Ile'].index, inplace = True)
328
- finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Mar'].index, inplace = True)
329
- finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Bou'].index, inplace = True)
330
- finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == '976'].index, inplace = True)
331
- arraylocalisationdataframe.append(finals_localisation)
332
- arrayfirstdataframe.append(results_df)
333
- if len(finals_df) != 0:
334
- arraydataframe.append(finals_df)
335
- first_df = pd.concat(arrayfirstdataframe)
336
- finals_df = pd.concat(arraydataframe)
337
- localisation_df = pd.concat(arraylocalisationdataframe)
338
-
339
- ######## Emplois ########
340
- df_intitule = first_df.groupby('intitule').size().reset_index(name='obs')
341
- df_intitule = df_intitule.sort_values(by=['obs'])
342
- df_intitule = df_intitule.iloc[-25:]
343
- fig_intitule = px.bar(df_intitule, x='obs', y='intitule', width=800, height=600, orientation='h', color='obs', title="Les principaux emplois", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df_intitule["intitule"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df_intitule["intitule"]], showlegend=False)
344
-
345
- ######## Types de contrat ########
346
- df_contrat = first_df.groupby('typeContratLibelle').size().reset_index(name='obs')
347
- fig_contrat = px.pie(df_contrat, names='typeContratLibelle', width=800, height=800, values='obs', color='obs', title="Les types de contrat", labels={'obs':'nombre'}, color_discrete_sequence=px.colors.qualitative.Safe).update_traces(textposition='inside', textinfo='percent+label').update_layout(font=dict(size=10,color="RebeccaPurple"))
348
-
349
- df_secteur = first_df.groupby('secteurActiviteLibelle').size().reset_index(name='obs')
350
- df_secteur = df_secteur.sort_values(by=['obs'])
351
- df_secteur = df_secteur.iloc[-25:]
352
- fig_secteur = px.bar(df_secteur, x='obs', y='secteurActiviteLibelle', width=800, height=600, orientation='h', color='obs', title="Les principaux secteurs d'activités", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df_secteur["secteurActiviteLibelle"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df_secteur["secteurActiviteLibelle"]], showlegend=False)
353
-
354
- ######## Compétences professionnelles ########
355
- df1 = finals_df
356
- df1['competences'] = finals_df['competences'].str.split(';')
357
- df2 = df1.explode('competences')
358
- df2 = df2.groupby('competences').size().reset_index(name='obs')
359
- df2 = df2.sort_values(by=['obs'])
360
- df2 = df2.iloc[-20:]
361
- fig_competences = px.bar(df2, x='obs', y='competences', width=800, height=550, orientation='h', color='obs', title="Les principales compétences professionnelles", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df2["competences"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df2['competences']], showlegend=False)
362
-
363
- ######## Compétences transversales ########
364
- df_transversales = finals_df
365
- df_transversales['qualitesProfessionnelles'] = finals_df['qualitesProfessionnelles'].str.split(';')
366
- df_comptransversales = df_transversales.explode('qualitesProfessionnelles')
367
- df_comptransversales = df_comptransversales.groupby('qualitesProfessionnelles').size().reset_index(name='obs')
368
- df_comptransversales = df_comptransversales.sort_values(by=['obs'])
369
- df_comptransversales = df_comptransversales.iloc[-20:]
370
- fig_transversales = px.bar(df_comptransversales, x='obs', y='qualitesProfessionnelles', width=800, height=550, orientation='h', color='obs', title="Les principales compétences transversales", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df_comptransversales["qualitesProfessionnelles"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df_comptransversales["qualitesProfessionnelles"]], showlegend=False)
371
-
372
- ######## Niveaux de qualification ########
373
- df_formations = finals_df.groupby('formations').size().reset_index(name='obs')
374
- fig_formations = px.pie(df_formations, names='formations', width=800, height=800, values='obs', color='obs', title="Les niveaux de qualification", labels={'obs':'nombre'}, color_discrete_sequence=px.colors.qualitative.Safe).update_traces(textposition='inside', textinfo='percent+label').update_layout(font=dict(size=10,color="RebeccaPurple"))
375
-
376
- ######## Expériences professionnelles ########
377
- df_experience = finals_df.groupby('experienceLibelle').size().reset_index(name='obs')
378
- fig_experience = px.pie(df_experience, names='experienceLibelle', width=800, height=800, values='obs', color='obs', title="Les expériences professionnelles", labels={'obs':'nombre'}, color_discrete_sequence=px.colors.qualitative.Safe).update_traces(textposition='inside', textinfo='percent+label').update_layout(font=dict(size=10,color="RebeccaPurple"))
379
-
380
- res = requests.get(
381
- "https://raw.githubusercontent.com/codeforgermany/click_that_hood/main/public/data/spain-provinces.geojson"
382
- )
383
- ######## localisation ########
384
- longLat = localisation()
385
- df_localisation = localisation_df.groupby('lieuTravail').size().reset_index(name='obs')
386
- df_localisation = df_localisation.sort_values(by=['lieuTravail'])
387
- df_localisation['longitude'] = df_localisation['lieuTravail']
388
- df_localisation['latitude'] = df_localisation['lieuTravail']
389
-
390
- df_localisation["longitude"] = df_localisation['longitude'].apply(lambda x:longLat.loc[longLat['ID'] == x, 'Longitude'].iloc[0])
391
- df_localisation["latitude"] = df_localisation['latitude'].apply(lambda x:longLat.loc[longLat['ID'] == x, 'Latitude'].iloc[0])
392
-
393
- fig_localisation = px.scatter_mapbox(df_localisation, lat="latitude", lon="longitude", height=600,hover_name="lieuTravail", size="obs").update_layout(
394
- mapbox={
395
- "style": "carto-positron",
396
- "center": {"lon": 2, "lat" : 47},
397
- "zoom": 4.5,
398
- "layers": [
399
- {
400
- "source": res.json(),
401
- "type": "line",
402
- "color": "green",
403
- "line": {"width": 0},
404
- }
405
- ],
406
- }
407
- )
408
-
409
- elements.append(cl.Plotly(name="chart_intitule", figure=fig_intitule, display="inline", size="large"))
410
- elements.append(cl.Plotly(name="chart_contrat", figure=fig_contrat, display="inline", size="large"))
411
- elements.append(cl.Plotly(name="chart_competences", figure=fig_competences, display="inline", size="large"))
412
- elements.append(cl.Plotly(name="chart_transversales", figure=fig_transversales, display="inline", size="large"))
413
- elements.append(cl.Plotly(name="chart_formations", figure=fig_formations, display="inline", size="large"))
414
- elements.append(cl.Plotly(name="chart_experience", figure=fig_experience, display="inline", size="large"))
415
- elements.append(cl.Plotly(name="chart_secteur", figure=fig_secteur, display="inline", size="large"))
416
- elements.append(cl.Plotly(name="chart_localisation", figure=fig_localisation, display="inline", size="large"))
417
-
418
- await cl.Message(content="Datavisualisation du marché de l'emploi", elements=elements).send()
419
- await action.remove()
420
 
421
  @cl.action_callback("saveMemory")
422
  async def on_action(action):
@@ -517,54 +395,23 @@ async def start():
517
  @literal_client.step(type="run")
518
  async def construction_NCS(competenceList):
519
  context = await contexte(competenceList)
520
- emploisST = cl.user_session.get("EmploiST")
521
- memory = ConversationBufferMemory(return_messages=True)
522
- ### Mistral Completion ###
523
- client_llm = await IA()
524
- structure = str(modele('Note de composante sectorielle'))
525
- definitions = definition('activite') + ' ' + definition('competence')
526
- template = """<s>[INST] Vous êtes un spécialiste du marché de l'emploi en fonction du niveau de qualification, des compétences professionnelles, des compétences transversales, du salaire et de l'expérience. Vous êtes doué pour faire des analyses du système travail sur les métiers les plus demandés grâce à votre aptitude à synthétiser les informations en fonction des critères définis ci-avant.
527
-
528
- En fonction des informations suivantes et du contexte suivant seulement et strictement, répondez à la question ci-dessous à partir du contexte ci-dessous :
529
- {context}
530
- {question} [/INST] </s>
531
- """
532
- question_p ="""
533
- Peux-tu créer une note sectorielle d'après le modèle de note sectorielle précédent en respectant ses parties : 2., 2.1, 2.1.1, 2.2, 2.2.1, 2.2.2, 2.2.3 et d'après le contexte en vous réferrant strictement aux données du contexte fixé? Réponse sous forme d'un texte généré d'après le modèle et le contexte en 5000 mots et en langue française absolument.
534
- """
535
- context_p = f"Contexte : {context}. {definitions} Modèle de note sectorielle : {structure}. Réponds en langue française strictement à la question suivante en respectant strictement les données du contexte. Si vous ne pouvez pas répondre à la question sur la base des informations, dites que vous ne trouvez pas de réponse ou que vous ne parvenez pas à trouver de réponse. Essayez donc de comprendre en profondeur le contexte et répondez uniquement en vous basant sur les informations fournies. Ne générez pas de réponses non pertinentes. Si les informations du contexte sont insuffisantes, procédez à une projection sur le secteur, les entreprises et le marché de l'emploi, pour construire la note de composante sectorielle."
536
- prompt = PromptTemplate(template=template, input_variables=["question","context"])
537
- #llm_chain = LLMChain(prompt=prompt, llm=client_llm)
538
- #completion_NCS = llm_chain.run({"question":question_p,"context":context_p}, callbacks=[StreamingStdOutCallbackHandler()])
539
- chain = (
540
- RunnablePassthrough.assign(
541
- history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
542
- )
543
- | prompt | client_llm
544
- )
545
-
546
- msg = cl.Message(author="Datapcc : 🌐🌐🌐",content="")
547
- async for chunk in chain.astream({"question":question_p,"context":context_p},
548
- config=RunnableConfig(callbacks=[cl.AsyncLangchainCallbackHandler(stream_final_answer=True)])):
549
- await msg.stream_token(chunk)
550
-
551
- cl.user_session.set("NCS" + romeListArray[0], msg.content)
552
- cl.user_session.set("contextChatBot", context + "\n" + msg.content)
553
- await cl.sleep(2)
554
  listEmplois_name = f"Liste des emplois"
555
  text_elements = []
556
  text_elements.append(
557
- cl.Text(content="Question : " + romeListArray[0] + "\n\nRéponse :\n" + emploisST.replace('Emploi : ','\n✔️ Emploi : ').replace('Contrat : ','\nContrat : ').replace('Compétences professionnelles : ','\nCompétences professionnelles : ').replace('Salaire : ','\nSalaire : ').replace('Qualification : ','\nQualification : '), name=listEmplois_name)
558
  )
559
- await cl.Message(author="Datapcc : 🌐🌐🌐",content="👨‍💼 Source Pôle Emploi : " + listEmplois_name, elements=text_elements).send()
560
- await cl.sleep(2)
561
- datavizEmploi = [
562
- cl.Action(name="datavizEmploi", value=romeListArray[0], description="Afficher la datavisualisation du marché de l'emploi")
563
- ]
564
- await cl.Message(author="Datapcc : 🌐🌐🌐",content="📊 Afficher la datavisualisation du marché de l'emploi", actions=datavizEmploi).send()
565
- await cl.sleep(2)
566
- if romeListArray[0].find(',') != -1:
567
- codeArray = romeListArray[0].split(',')
568
  ficheMetiers = []
569
  for i in range(0,len(codeArray)):
570
  ficheMetiers = [
@@ -575,86 +422,48 @@ async def construction_NCS(competenceList):
575
  ).send()
576
  else:
577
  ficheMetiers = [
578
- cl.File(name= "Fiche métier " + romeListArray[0],url="https://www.soi-tc.fr/assets/fiches_pe/FEM_" + romeListArray[0] + ".pdf",display="inline",)
579
  ]
580
  await cl.Message(
581
  author="Datapcc : 🌐🌐🌐", content="[Fiches métiers] 🔗", elements=ficheMetiers
582
  ).send()
583
 
584
- await cl.sleep(2)
585
- listPrompts_name = f"Liste des requêtes sur la note sectorielle"
586
- prompt_elements = []
587
- prompt_elements.append(
588
- cl.Text(content=definition('promptLibraryNCS'), name=listPrompts_name)
 
589
  )
590
- await cl.Message(author="Datapcc : 🌐🌐🌐",content="📚 Bibliothèque de prompts : " + listPrompts_name, elements=prompt_elements).send()
591
- await cl.sleep(2)
592
- actions = [
593
- cl.Action(name="download", value=msg.content, description="download_note_sectorielle")
594
- ]
595
- await cl.Message(author="Datapcc : 🌐🌐🌐",content="Télécharger la note", actions=actions).send()
596
- await cl.sleep(2)
597
- saves = [
598
- cl.Action(name="saveToMemory", value=msg.content, description="Mettre en mémoire la note")
599
- ]
600
- await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mémoire la note", actions=saves).send()
601
- await cl.sleep(2)
602
-
603
- memory.chat_memory.add_user_message(question_p)
604
- memory.chat_memory.add_ai_message(msg.content)
605
- return "Construction de la Note Sectorielle"
606
 
607
  @cl.step(type="run")
608
  async def recuperation_contexte(getNote):
609
  getContext = cl.user_session.get(getNote)
610
  return getNote + " :\n" + getContext
611
  @cl.step(type="retrieval")
612
- async def contexte(romeListArray):
613
- #results = await API_FranceTravail(romeListArray)
614
- results = await creation_liste_code_Rome_et_emplois(romeListArray)
615
- results_df = results
616
- finals = results_df[['intitule','typeContratLibelle','experienceLibelle','competences','qualitesProfessionnelles','salaire','lieuTravail','formations','description']].copy()
617
- finals["lieuTravail"] = finals["lieuTravail"].apply(lambda x: x['libelle']).apply(lambda x: x[0:3]).apply(lambda x: x.strip())
618
- emplois = results_df.values.tolist()
619
-
620
- listEmplois = []
621
- for i in range(0,len(emplois)):
622
- listEmplois.append("\nEmploi : " + emplois[i][0] + "; Contrat : " + emplois[i][1] + "; Compétences professionnelles : " + arrayToString(emplois[i][3]) + "; " + "Salaire : " + listToString(emplois[i][5]) + "; Qualification : " + emplois[i][4] + "; Localisation : " + emplois[i][6] + "; Expérience : " + emplois[i][2] + "; Niveau de qualification : " + listToString(emplois[i][7]) + "; Description de l'emploi : " + listToString(emplois[i][8]))
623
- #emplois_list = results[0]
624
- #context = emplois_list.replace('[','').replace(']','').replace('{','').replace('}','')
625
- context = listEmplois
626
- ficheMetier = await FicheMetier("https://candidat.francetravail.fr/metierscope/fiche-metier/", romeListArray[0])
627
- ficheClesMetier = await ChiffresClesMetier("https://dataemploi.francetravail.fr/metier/chiffres-cles/NAT/FR/", romeListArray[0])
628
- #ficheMetiersCompetencesSavoirs = await Fiche_metier_competences_savoirs(romeListArray[0])
629
- #metierSecteurContexteTravail = await Metier_secteur_contexte_travail(romeListArray[0])
630
- cl.user_session.set("EmploiST", context)
631
- return "Fiches Métiers :\n" + ficheMetier + "\nChiifres clés métiers :\n" + ficheClesMetier + "\nListe des emplois issus de France Travail :\n" + context
632
- #return "Fiche métier Compétences Savoirs :\n" + ficheMetiersCompetencesSavoirs + "\nMetier secteur contexte au travail :\n" + metierSecteurContexteTravail + "\nListe des emplois issus de France Travail :\n" + context
633
- #return "Liste des emplois issus de France Travail :\n" + context
634
- #return "\nMetier secteur contexte au travail :\n" + metierSecteurContexteTravail + "\nListe des emplois issus de France Travail :\n" + context
635
- @cl.step(type="tool")
636
- async def FicheMetier(url, codes):
637
- if codes.find(',') != -1:
638
- all = ""
639
- codeArray = codes.split(',')
640
- for i in range(0,len(codeArray)):
641
- response = requests.get(url + codeArray[i])
642
- soup = BeautifulSoup(response.text, "html.parser")
643
- allmissions = soup.select('div.fm-presentation-text')
644
- allcompetences = soup.select('div#part2')
645
- allcontextes = soup.select('div#part3')
646
- all = all + "Fiche Métier " + codeArray[i] + ":\nLes missions principales : " + removeTags(allmissions[0]) + ". Les compétences recherchées : " + removeTags(allcompetences[0]) + ". Les contextes au travail : " + removeTags(allcontextes[0]) + "."
647
- else:
648
- response = requests.get(url + codes)
649
- soup = BeautifulSoup(response.text, "html.parser")
650
- allmissions = soup.select('div.fm-presentation-text')
651
- allcompetences = soup.select('div#part2')
652
- allcontextes = soup.select('div#part3')
653
- all = "Fiche Métier " + codes + ":\nLes missions principales : " + removeTags(allmissions[0]) + ". Les compétences recherchées : " + removeTags(allcompetences[0]) + ". Les contextes au travail : " + removeTags(allcontextes[0]) + "."
654
- return all
655
 
656
  @cl.step(type="tool")
657
- async def ChiffresClesMetier(url, codes):
658
  if codes.find(',') != -1:
659
  all = ""
660
  codeArray = codes.split(',')
@@ -749,7 +558,198 @@ async def ChiffresClesMetier(url, codes):
749
  return all
750
 
751
  @cl.step(type="tool")
752
- async def creation_liste_code_Rome_et_emplois(competence):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
753
  os.environ['PINECONE_API_KEYROME'] = os.environ['PINECONE_API_KEYROME']
754
  docsearch = await connexion_catalogue_Rome()
755
  retrieve_comp = docsearch.similarity_search(competence, k=30, filter={"categorie": {"$eq": os.environ['PINECONE_API_KEYROME']}})
@@ -773,7 +773,7 @@ async def creation_liste_code_Rome_et_emplois(competence):
773
 
774
  results_df = results_df.drop_duplicates(subset=["codeRome"])
775
  results_df = results_df.head(5)
776
- codeRomeString = results_df["codeRome"].to_string(index = False)
777
  codeRome_list = results_df["codeRome"].tolist()
778
  actionRome = await cl.AskActionMessage(
779
  content="Etes-vous d'accord avec la sélection des 5 codes Rome automatiques issus de la recherche sémantique ? :" + codeRomeString,
@@ -786,7 +786,6 @@ async def creation_liste_code_Rome_et_emplois(competence):
786
  await cl.Message(
787
  content="Connexion à France Travail, et récupération des offres d'emploi",
788
  ).send()
789
- df_emplois = await API_France_Travail(codeRome_list)
790
  cl.user_session.set("codeRomeArray", codeRome_list)
791
  else:
792
  actionsaisierome = await cl.AskUserMessage(content="Saisissez vos codes Rome dans le prompt? ⚠️ Attention, indiquez seulement des codes Rome séparés par des virgules", timeout=3600).send()
@@ -799,14 +798,17 @@ async def creation_liste_code_Rome_et_emplois(competence):
799
  teststringCodeRome = [ele for ele in stopWords if(ele in stringCodeRome)]
800
  teststringCodeRome = bool(teststringCodeRome)
801
  if teststringCodeRome == False:
802
- arrayCodeRome = stringCodeRome.spit(',')
803
  else:
804
  arrayCodeRome = codeRome_list
805
  await cl.Message(author="Datapcc : 🌐🌐🌐",content="Votre ssaisie est erronée. Nous continuons l'action avec les codes Rome sélectionnés automatiquement pour vous : " + codeRome_list).send()
806
- df_emplois = await API_France_Travail(arrayCodeRome)
807
  cl.user_session.set("codeRomeArray", arrayCodeRome)
808
-
809
- return df_emplois
 
 
 
 
810
 
811
  @cl.step(type="tool")
812
  async def connexion_catalogue_Rome():
@@ -816,22 +818,6 @@ async def connexion_catalogue_Rome():
816
  docsearch = PineconeVectorStore.from_existing_index(os.environ['PINECONE_INDEX_NAME'], embeddings)
817
  return docsearch
818
 
819
- @cl.step(type="tool")
820
- async def API_France_Travail(romeListArray):
821
- client = Api(client_id=os.environ['POLE_EMPLOI_CLIENT_ID'],
822
- client_secret=os.environ['POLE_EMPLOI_CLIENT_SECRET'])
823
- todayDate = datetime.datetime.today()
824
- month, year = (todayDate.month-1, todayDate.year) if todayDate.month != 1 else (12, todayDate.year-1)
825
- start_dt = todayDate.replace(day=1, month=month, year=year)
826
- end_dt = datetime.datetime.today()
827
- results = []
828
- for k in romeListArray:
829
- params = {"motsCles": k,'minCreationDate': dt_to_str_iso(start_dt),'maxCreationDate': dt_to_str_iso(end_dt),'range':'0-149'}
830
- search_on_big_data = client.search(params=params)
831
- results += search_on_big_data["resultats"]
832
- results_df = pd.DataFrame(results)
833
- return results_df
834
-
835
  @cl.step(type="llm")
836
  async def IA():
837
  os.environ['HUGGINGFACEHUB_API_TOKEN'] = os.environ['HUGGINGFACEHUB_API_TOKEN']
 
177
  { "ID": "972", "Longitude": -61.024174, "Latitude": 14.641528 },
178
  { "ID": "971", "Longitude": -61.551, "Latitude": 16.265 }
179
  ]
 
 
180
 
181
+ return ListCentroids
182
+
183
+ def plotDemandeur(dataframe, coderome):
184
+ df = dataframe.sort_values(by=['Indicateur'])
185
+ fig_demandeur = px.histogram(df, x='Indicateur', y='Valeur', height=1000, title="Demandeurs d'emploi et offres d'emploi du code ROME : " + coderome, color='Indicateur', labels={'Valeur':'Nombre'}, text_auto=True).update_layout(font=dict(size=9,color="RebeccaPurple"),autosize=True)
186
+ fig_demandeur.show()
187
+
188
+ def plotSalaire(dataframe):
189
+ df = dataframe.sort_values(by=['salaire'])
190
+ fig_demandeur = px.histogram(df, x='emploi', y='salaire', barmode='group', title="Salaires médians", color='categorie', text_auto=True).update_layout(font=dict(size=9,color="RebeccaPurple"),autosize=True)
191
+ fig_demandeur.show()
192
+
193
+ def plotDifficulte(dataframe):
194
+ if len(dataframe) == 0:
195
+ title = "Aucune donnée difficulté de recrutement renseignée!"
196
+ else:
197
+ title = "Difficulté de recrutement"
198
+ df = dataframe.sort_values(by=['Valeur'])
199
+ fig_demandeur = px.histogram(df, x='Indicateur', y='Valeur', title=title, color='Indicateur', labels={'Valeur':'Pourcentage'}, text_auto=True).update_layout(font=dict(size=9,color="RebeccaPurple"),autosize=True)
200
+ fig_demandeur.show()
201
+
202
+ def plotRepartition(dataframe,title):
203
+ df = dataframe.sort_values(by=['Valeur'])
204
+ fig_repartition = px.pie(df, names='Indicateur', values='Valeur', color='Indicateur', title=title, labels={'Valeur':'pourcentage'}, color_discrete_sequence=px.colors.qualitative.Safe).update_traces(textposition='inside', textinfo='percent+label').update_layout(font=dict(size=10,color="RebeccaPurple"))
205
+ fig_repartition.show()
206
+
207
+ def removeTags(all):
208
+ for data in all(['style', 'script']):
209
+ data.decompose()
210
+ return ''.join(all.stripped_strings)
211
+
212
+ def htmlToDataframe(htmlTable):
213
+ data = []
214
+ list_header = []
215
+ soup = BeautifulSoup(htmlTable,'html.parser')
216
+ header = soup.find_all("table")[0].find("tr")
217
+ for items in header:
218
+ try:
219
+ list_header.append(items.get_text())
220
+ except:
221
+ continue
222
+ HTML_data = soup.find_all("table")[0].find_all("tr")[1:]
223
+ for element in HTML_data:
224
+ sub_data = []
225
+ for sub_element in element:
226
+ try:
227
+ sub_data.append(sub_element.get_text())
228
+ except:
229
+ continue
230
+ data.append(sub_data)
231
+ dataFrame = pd.DataFrame(data = data, columns = list_header)
232
+ return dataFrame
233
 
234
  def listToString(list):
235
  return str(list)
 
295
  author="Datapcc : 🌐🌐🌐", content="[Lien] 🔗", elements=elements
296
  ).send()
297
  await action.remove()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
299
  @cl.action_callback("saveMemory")
300
  async def on_action(action):
 
395
  @literal_client.step(type="run")
396
  async def construction_NCS(competenceList):
397
  context = await contexte(competenceList)
398
+ emploisST = context.to_string(index = False)
399
+ cl.user_session.set("contextChatBot", emploisST)
400
+ romeListArray = cl.user_session.get("codeRomeArray")
401
+ listEmplois = context.values.tolist()
402
+ stringEmplois = ''
403
+ for i in range(0,len(listEmplois)):
404
+ stringEmplois += "\n✔️ Emploi : " + listEmplois[i][0] + "; Contrat : " + listEmplois[i][1] + "; Compétences professionnelles : " + arrayToString(listEmplois[i][3]) + "; " + "Salaire : " + listToString(listEmplois[i][5]) + "; Qualification : " + listEmplois[i][4] + "; Localisation : " + listEmplois[i][6] + "; Expérience : " + listEmplois[i][2] + "; Niveau de qualification : " + listToString(listEmplois[i][7]) + "; Description de l'emploi : " + listToString(listEmplois[i][8])) + "\n"
405
+ await cl.sleep(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  listEmplois_name = f"Liste des emplois"
407
  text_elements = []
408
  text_elements.append(
409
+ cl.Text(content="Question : " + competenceList + "\n\nRéponse :\n" + stringEmplois, name=listEmplois_name)
410
  )
411
+ await cl.Message(author="Datapcc : 🌐🌐🌐",content="👨‍💼 Source France Travail : " + listEmplois_name, elements=text_elements).send()
412
+ await cl.sleep(1)
413
+ if romeListArray.find(',') != -1:
414
+ codeArray = romeListArray
 
 
 
 
 
415
  ficheMetiers = []
416
  for i in range(0,len(codeArray)):
417
  ficheMetiers = [
 
422
  ).send()
423
  else:
424
  ficheMetiers = [
425
+ cl.File(name= "Fiche métier " + romeListArray,url="https://www.soi-tc.fr/assets/fiches_pe/FEM_" + romeListArray + ".pdf",display="inline",)
426
  ]
427
  await cl.Message(
428
  author="Datapcc : 🌐🌐🌐", content="[Fiches métiers] 🔗", elements=ficheMetiers
429
  ).send()
430
 
431
+ await cl.sleep(1)
432
+ ficheClesMetier = await document_chiffres_cles_emplois("https://dataemploi.francetravail.fr/metier/chiffres-cles/NAT/FR/", romeListArray)
433
+ listClesMetier_name = f"Chiffres clés des emplois"
434
+ text_ClesMetier = []
435
+ text_ClesMetier.append(
436
+ cl.Text(content="Question : " + competenceList + "\n\nRéponse :\n" + ficheClesMetier, name=listClesMetier_name)
437
  )
438
+ await cl.Message(author="Datapcc : 🌐🌐🌐",content="📊 Source France Travail : " + listClesMetier_name, elements=text_ClesMetier).send()
439
+
440
+ return "datavisualisation des statistiques de l'emploi"
 
 
 
 
 
 
 
 
 
 
 
 
 
441
 
442
  @cl.step(type="run")
443
  async def recuperation_contexte(getNote):
444
  getContext = cl.user_session.get(getNote)
445
  return getNote + " :\n" + getContext
446
  @cl.step(type="retrieval")
447
+ async def contexte(competence):
448
+ results = await creation_liste_code_Rome(competence)
449
+ await cl.sleep(1)
450
+ romeListArray = cl.user_session.get("codeRomeArray")
451
+ df_emplois = await API_France_Travail(romeListArray)
452
+ await cl.sleep(1)
453
+ await datavisualisation_statistiques_emplois(df_emplois)
454
+ await cl.sleep(1)
455
+ for j in range(0, len(romeListArray)):
456
+ table = await datavisualisation_chiffres_cles_emplois("https://dataemploi.pole-emploi.fr/metier/chiffres-cles/NAT/FR/" + romeListArray[j])
457
+ plot_demandeur = plotDemandeur(htmlToDataframe(table[0]), codeRome_list[j])
458
+ plot_salaire = plotSalaire(htmlToDataframe(table[1]))
459
+ plot_difficulte = plotDifficulte(htmlToDataframe(table[2]))
460
+ plot_repartitionContrat = plotRepartition(htmlToDataframe(table[3]), "Répartition des embauches du métier : type de contrat")
461
+ plot_repartitionEntreprise = plotRepartition(htmlToDataframe(table[4]), "Répartition des embauches du métier : type entreprise")
462
+
463
+ return df_emplois
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
 
465
  @cl.step(type="tool")
466
+ async def document_chiffres_cles_emplois(url, codes):
467
  if codes.find(',') != -1:
468
  all = ""
469
  codeArray = codes.split(',')
 
558
  return all
559
 
560
  @cl.step(type="tool")
561
+ async def datavisualisation_chiffres_cles_emplois(url):
562
+ response = requests.get(url)
563
+ soup = BeautifulSoup(response.text, "lxml")
564
+
565
+ allembauches = soup.select('p.population_category')
566
+ allnumembauchesfirst = soup.select('p.population_main-num.data')
567
+ allnumembauches = removeTags(allnumembauchesfirst[0]).split('\xa0')
568
+ allnumembauches = ''.join(allnumembauches)
569
+ allnumoffres = removeTags(allnumembauchesfirst[1]).split('\xa0')
570
+ allnumoffres = ''.join(allnumoffres)
571
+ alldetailembauches = soup.select('p.hiring_text.ng-star-inserted')
572
+ allnumevolutionembauches = soup.select('p.main.ng-star-inserted')
573
+ alldetailevolutionembauches = soup.select('p.population_bubble-title')
574
+ alldemandeurs = "<table><tr><td>Indicateur</td><td>Valeur</td></tr><tr><td>" + removeTags(allembauches[0]) + " (" + removeTags(alldetailembauches[0]) + ");\nÉvolution demandeurs d'emploi (" + removeTags(alldetailevolutionembauches[0]) + ": " + removeTags(allnumevolutionembauches[0]) + ")</td><td>" + allnumembauches + "</td></tr>"
575
+ alldemandeurs += "<tr><td>" + removeTags(allembauches[1]) + " (" + removeTags(alldetailembauches[1]) + "); Évolution offres d'emploi (" + removeTags(alldetailevolutionembauches[1]) + ": " + removeTags(allnumevolutionembauches[1]) + ")</td><td>" + allnumoffres + "</td></tr>"
576
+ alldemandeurs += "</table>"
577
+
578
+ allFAP = soup.select('tr.sectorTable__line.ng-star-inserted')
579
+ allcategorie = soup.select('td.sectorTable__cell')
580
+ alltypesalaires = soup.select('th.sectorTable__cell')
581
+ allFAPsalaires = soup.select('p.sectorTable__cellValue')
582
+ allsalaires = "<table><tr><td>categorie</td><td>emploi</td><td>salaire</td></tr>"
583
+ allsalaires += "<tr><td>" + removeTags(alltypesalaires[1]) + "</td><td>" + removeTags(allcategorie[0]) + "</td><td>" + removeTags(allFAPsalaires[0]).replace('\xa0','').replace(' ','').replace('€','') + "</td></tr>"
584
+ allsalaires += "<tr><td>" + removeTags(alltypesalaires[2]) + "</td><td>" + removeTags(allcategorie[0]) + "</td><td>" + removeTags(allFAPsalaires[1]).replace('\xa0','').replace(' ','').replace('€','') + "</td></tr>"
585
+ allsalaires += "<tr><td>" + removeTags(alltypesalaires[3]) + "</td><td>" + removeTags(allcategorie[0]) + "</td><td>" + removeTags(allFAPsalaires[2]).replace('\xa0','').replace(' ','').replace('€','') + "</td></tr>"
586
+ if len(allFAP) >= 2:
587
+ allsalaires += "<tr><td>" + removeTags(alltypesalaires[1]) + "</td><td>" + removeTags(allcategorie[4]) + "</td><td>" + removeTags(allFAPsalaires[3]).replace('\xa0','').replace(' ','').replace('€','') + "</td></tr>"
588
+ allsalaires += "<tr><td>" + removeTags(alltypesalaires[2]) + "</td><td>" + removeTags(allcategorie[4]) + "</td><td>" + removeTags(allFAPsalaires[4]).replace('\xa0','').replace(' ','').replace('€','') + "</td></tr>"
589
+ allsalaires += "<tr><td>" + removeTags(alltypesalaires[3]) + "</td><td>" + removeTags(allcategorie[4]) + "</td><td>" + removeTags(allFAPsalaires[5]).replace('\xa0','').replace(' ','').replace('€','') + "</td></tr>"
590
+ allsalaires += "</table>"
591
+
592
+ alltypedifficultes = soup.select('.tabs-main-content_persp-col2-bar.ng-star-inserted')
593
+ alldifficulte = soup.select('p.horizontal-graph_title')
594
+ allpcdifficulte = soup.select('div.horizontal-graph_data')
595
+ alldifficultes = "<table><tr><td>Indicateur</td><td>Valeur</td></tr>"
596
+ for i in range(0,len(alltypedifficultes)):
597
+ alldifficultes += "<tr><td>" + removeTags(alldifficulte[i]) + "</td><td>" + removeTags(allpcdifficulte[i]).replace('Pour le territoire principal FRANCE pour les ' + removeTags(alldifficulte[i]),'').replace('%','') + "</td></tr>"
598
+ alldifficultes += "</table>"
599
+
600
+ alltyperepartitions = soup.select('div.hiring-contract_legende_item.ng-star-inserted')
601
+ allrepartition = soup.select('p.hiring-contract_legende_item_label')
602
+ allpcrepartition = soup.select('span.hiring-contract_legende_item-first')
603
+ allrepartitions = "<table><tr><td>Indicateur</td><td>Valeur</td></tr>"
604
+ for i in range(0,len(alltyperepartitions)):
605
+ allrepartitions += "<tr><td>" + removeTags(allrepartition[i]).replace('(' + removeTags(allpcrepartition[i]) + ')','') + "</td><td>" + removeTags(allpcrepartition[i]).replace('%','').replace(',','.') + "</td></tr>"
606
+ allrepartitions += "</table>"
607
+
608
+ allentrepriserepartitions = soup.select('div.horizontal-graph_pattern.sm-bubble_wrapper > span')
609
+ allentreprise = soup.select('span.sr-only')
610
+ allpcentreprise = soup.select('span.data.ng-star-inserted')
611
+ allentreprises = "<table><tr><td>Indicateur</td><td>Valeur</td></tr>"
612
+ for i in range(0,len(allentrepriserepartitions)):
613
+ allentreprises += "<tr><td>" + removeTags(allentrepriserepartitions[i])[0:-4] + "</td><td>" + removeTags(allentrepriserepartitions[i])[-4:].replace('%','').replace(',','.') + "</td></tr>"
614
+ allentreprises += "</table>"
615
+
616
+ return [alldemandeurs, allsalaires, alldifficultes, allrepartitions, allentreprises]
617
+
618
+ @cl.step(type="tool")
619
+ async def datavisualisation_statistiques_emplois(results_df):
620
+ arraydataframe = []
621
+ arrayfirstdataframe = []
622
+ arraylocalisationdataframe = []
623
+ results = []
624
+ count = 0
625
+ if results_df.empty == False:
626
+ count = count + 1
627
+ finals = results_df[['intitule','typeContratLibelle','experienceLibelle','competences','qualitesProfessionnelles','salaire','lieuTravail','formations']].copy()
628
+ finals["lieuTravail"] = finals["lieuTravail"].apply(lambda x: x['libelle']).apply(lambda x: x[0:3]).apply(lambda x: x.strip())
629
+ finals_df = finals
630
+ finals_df.dropna(subset=['qualitesProfessionnelles','formations','competences'], inplace=True)
631
+ finals_df["competences"] = finals_df["competences"].apply(lambda x:[str(e['libelle']) for e in x]).apply(lambda x:'; '.join(map(str, x)))
632
+ finals_df["qualitesProfessionnelles"] = finals_df["qualitesProfessionnelles"].apply(lambda x:[str(e['libelle']) + ": " + str(e['description']) for e in x]).apply(lambda x:'; '.join(map(str, x)))
633
+ finals_df["formations"] = finals_df["formations"].apply(lambda x:[str(e['niveauLibelle']) for e in x]).apply(lambda x:'; '.join(map(str, x)))
634
+ finals_df = finals_df.sort_values(by=['lieuTravail'])
635
+ finals_localisation = results_df[['lieuTravail']].copy()
636
+ finals_localisation["lieuTravail"] = finals_localisation["lieuTravail"].apply(lambda x: np.array(x)).apply(lambda x: x['libelle']).apply(lambda x: x[0:3]).apply(lambda x: x.strip())
637
+ finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Fra'].index, inplace = True)
638
+ finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'FRA'].index, inplace = True)
639
+ finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Ile'].index, inplace = True)
640
+ finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Mar'].index, inplace = True)
641
+ finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == 'Bou'].index, inplace = True)
642
+ finals_localisation.drop(finals_localisation[finals_localisation['lieuTravail'] == '976'].index, inplace = True)
643
+ arraylocalisationdataframe.append(finals_localisation)
644
+ arrayfirstdataframe.append(results_df)
645
+ if len(finals_df) != 0:
646
+ arraydataframe.append(finals_df)
647
+ first_df = pd.concat(arrayfirstdataframe)
648
+ finals_df = pd.concat(arraydataframe)
649
+ localisation_df = pd.concat(arraylocalisationdataframe)
650
+
651
+ ######## Emplois ########
652
+ df_intitule = first_df.groupby('intitule').size().reset_index(name='obs')
653
+ df_intitule = df_intitule.sort_values(by=['obs'])
654
+ df_intitule = df_intitule.iloc[-25:]
655
+ fig_intitule = px.bar(df_intitule, x='obs', y='intitule', orientation='h', color='obs', title="Les principaux emplois", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df_intitule["intitule"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df_intitule["intitule"]], showlegend=False)
656
+
657
+ ######## Types de contrat ########
658
+ df_contrat = first_df.groupby('typeContratLibelle').size().reset_index(name='obs')
659
+ fig_contrat = px.pie(df_contrat, names='typeContratLibelle', values='obs', color='obs', title="Les types de contrat", labels={'obs':'nombre'}, color_discrete_sequence=px.colors.qualitative.Safe).update_traces(textposition='inside', textinfo='percent+label').update_layout(font=dict(size=10,color="RebeccaPurple"))
660
+
661
+ df_secteur = first_df.groupby('secteurActiviteLibelle').size().reset_index(name='obs')
662
+ df_secteur = df_secteur.sort_values(by=['obs'])
663
+ df_secteur = df_secteur.iloc[-25:]
664
+ fig_secteur = px.bar(df_secteur, x='obs', y='secteurActiviteLibelle', orientation='h', color='obs', title="Les principaux secteurs d'activités", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df_secteur["secteurActiviteLibelle"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df_secteur["secteurActiviteLibelle"]], showlegend=False)
665
+
666
+ ######## Compétences professionnelles ########
667
+ df1 = finals_df
668
+ df1['competences'] = finals_df['competences'].str.split(';')
669
+ df2 = df1.explode('competences')
670
+ df2 = df2.groupby('competences').size().reset_index(name='obs')
671
+ df2 = df2.sort_values(by=['obs'])
672
+ df2 = df2.iloc[-20:]
673
+ fig_competences = px.bar(df2, x='obs', y='competences', orientation='h', color='obs', title="Les principales compétences professionnelles", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df2["competences"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df2['competences']], showlegend=False)
674
+
675
+ ######## Compétences transversales ########
676
+ df_transversales = finals_df
677
+ df_transversales['qualitesProfessionnelles'] = finals_df['qualitesProfessionnelles'].str.split(';')
678
+ df_comptransversales = df_transversales.explode('qualitesProfessionnelles')
679
+ df_comptransversales = df_comptransversales.groupby('qualitesProfessionnelles').size().reset_index(name='obs')
680
+ df_comptransversales = df_comptransversales.sort_values(by=['obs'])
681
+ df_comptransversales = df_comptransversales.iloc[-20:]
682
+ fig_transversales = px.bar(df_comptransversales, x='obs', y='qualitesProfessionnelles', orientation='h', color='obs', title="Les principales compétences transversales", labels={'obs':'nombre'}, color_continuous_scale="Teal", text_auto=True).update_layout(font=dict(size=10,color="RebeccaPurple"),autosize=True).update_traces(hovertemplate=df_comptransversales["qualitesProfessionnelles"] + ' <br>Nombre : %{x}', y=[y[:100] + "..." for y in df_comptransversales["qualitesProfessionnelles"]], showlegend=False)
683
+
684
+ ######## Niveaux de qualification ########
685
+ df_formations = finals_df.groupby('formations').size().reset_index(name='obs')
686
+ fig_formations = px.pie(df_formations, names='formations', values='obs', color='obs', title="Les niveaux de qualification", labels={'obs':'nombre'}, color_discrete_sequence=px.colors.qualitative.Safe).update_traces(textposition='inside', textinfo='percent+label').update_layout(font=dict(size=10,color="RebeccaPurple"))
687
+
688
+ ######## Expériences professionnelles ########
689
+ df_experience = finals_df.groupby('experienceLibelle').size().reset_index(name='obs')
690
+ fig_experience = px.pie(df_experience, names='experienceLibelle', values='obs', color='obs', title="Les expériences professionnelles", labels={'obs':'nombre'}, color_discrete_sequence=px.colors.qualitative.Safe).update_traces(textposition='inside', textinfo='percent+label').update_layout(font=dict(size=10,color="RebeccaPurple"))
691
+
692
+ res = requests.get(
693
+ "https://raw.githubusercontent.com/codeforgermany/click_that_hood/main/public/data/spain-provinces.geojson"
694
+ )
695
+ ######## localisation ########
696
+ ListCentroids = localisation()
697
+ df_localisation = localisation_df.groupby('lieuTravail').size().reset_index(name='obs')
698
+ df_localisation = df_localisation.sort_values(by=['lieuTravail'])
699
+ df_localisation['longitude'] = df_localisation['lieuTravail']
700
+ df_localisation['latitude'] = df_localisation['lieuTravail']
701
+
702
+
703
+ df_localisation["longitude"] = df_localisation['longitude'].apply(lambda x:[loc['Longitude'] for loc in ListCentroids if loc['ID'] == x]).apply(lambda x:''.join(map(str, x)))
704
+ df_localisation["longitude"] = pd.to_numeric(df_localisation["longitude"], downcast="float")
705
+ df_localisation["latitude"] = df_localisation['latitude'].apply(lambda x:[loc['Latitude'] for loc in ListCentroids if loc['ID'] == x]).apply(lambda x:''.join(map(str, x)))
706
+ df_localisation["latitude"] = pd.to_numeric(df_localisation["latitude"], downcast="float")
707
+
708
+ fig_localisation = px.scatter_mapbox(df_localisation, lat="latitude", lon="longitude", hover_name="lieuTravail", size="obs").update_layout(
709
+ mapbox={
710
+ "style": "carto-positron",
711
+ "center": {"lon": 2, "lat" : 47},
712
+ "zoom": 4.5,
713
+ "layers": [
714
+ {
715
+ "source": res.json(),
716
+ "type": "line",
717
+ "color": "green",
718
+ "line": {"width": 0},
719
+ }
720
+ ],
721
+ }
722
+ )
723
+
724
+ elements = []
725
+ elements.append(cl.Plotly(name="chart_intitule", figure=fig_intitule, display="inline", size="large"))
726
+ elements.append(cl.Plotly(name="chart_contrat", figure=fig_contrat, display="inline", size="large"))
727
+ elements.append(cl.Plotly(name="chart_competences", figure=fig_competences, display="inline", size="large"))
728
+ elements.append(cl.Plotly(name="chart_transversales", figure=fig_transversales, display="inline", size="large"))
729
+ elements.append(cl.Plotly(name="chart_formations", figure=fig_formations, display="inline", size="large"))
730
+ elements.append(cl.Plotly(name="chart_experience", figure=fig_experience, display="inline", size="large"))
731
+ elements.append(cl.Plotly(name="chart_secteur", figure=fig_secteur, display="inline", size="large"))
732
+ elements.append(cl.Plotly(name="chart_localisation", figure=fig_localisation, display="inline", size="large"))
733
+
734
+ await cl.Message(content="Datavisualisation du marché de l'emploi", elements=elements).send()
735
+
736
+ @cl.step(type="tool")
737
+ async def API_France_Travail(romeListArray):
738
+ client = await connexion_France_Travail()
739
+ todayDate = datetime.datetime.today()
740
+ month, year = (todayDate.month-1, todayDate.year) if todayDate.month != 1 else (12, todayDate.year-1)
741
+ start_dt = todayDate.replace(day=1, month=month, year=year)
742
+ end_dt = datetime.datetime.today()
743
+ results = []
744
+ for k in romeListArray:
745
+ params = {"motsCles": k,'minCreationDate': dt_to_str_iso(start_dt),'maxCreationDate': dt_to_str_iso(end_dt),'range':'0-149'}
746
+ search_on_big_data = client.search(params=params)
747
+ results += search_on_big_data["resultats"]
748
+ results_df = pd.DataFrame(results)
749
+ return results_df
750
+
751
+ @cl.step(type="tool")
752
+ async def creation_liste_code_Rome(competence):
753
  os.environ['PINECONE_API_KEYROME'] = os.environ['PINECONE_API_KEYROME']
754
  docsearch = await connexion_catalogue_Rome()
755
  retrieve_comp = docsearch.similarity_search(competence, k=30, filter={"categorie": {"$eq": os.environ['PINECONE_API_KEYROME']}})
 
773
 
774
  results_df = results_df.drop_duplicates(subset=["codeRome"])
775
  results_df = results_df.head(5)
776
+ codeRomeString = ' | ' + results_df["codeRome"].to_string(index = False) + ' |\n| -------- |'
777
  codeRome_list = results_df["codeRome"].tolist()
778
  actionRome = await cl.AskActionMessage(
779
  content="Etes-vous d'accord avec la sélection des 5 codes Rome automatiques issus de la recherche sémantique ? :" + codeRomeString,
 
786
  await cl.Message(
787
  content="Connexion à France Travail, et récupération des offres d'emploi",
788
  ).send()
 
789
  cl.user_session.set("codeRomeArray", codeRome_list)
790
  else:
791
  actionsaisierome = await cl.AskUserMessage(content="Saisissez vos codes Rome dans le prompt? ⚠️ Attention, indiquez seulement des codes Rome séparés par des virgules", timeout=3600).send()
 
798
  teststringCodeRome = [ele for ele in stopWords if(ele in stringCodeRome)]
799
  teststringCodeRome = bool(teststringCodeRome)
800
  if teststringCodeRome == False:
801
+ arrayCodeRome = stringCodeRome.split(',')
802
  else:
803
  arrayCodeRome = codeRome_list
804
  await cl.Message(author="Datapcc : 🌐🌐🌐",content="Votre ssaisie est erronée. Nous continuons l'action avec les codes Rome sélectionnés automatiquement pour vous : " + codeRome_list).send()
 
805
  cl.user_session.set("codeRomeArray", arrayCodeRome)
806
+
807
+ @cl.step(type="tool")
808
+ async def connexion_France_Travail():
809
+ client = Api(client_id=os.environ['POLE_EMPLOI_CLIENT_ID'],
810
+ client_secret=os.environ['POLE_EMPLOI_CLIENT_SECRET'])
811
+ return client
812
 
813
  @cl.step(type="tool")
814
  async def connexion_catalogue_Rome():
 
818
  docsearch = PineconeVectorStore.from_existing_index(os.environ['PINECONE_INDEX_NAME'], embeddings)
819
  return docsearch
820
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  @cl.step(type="llm")
822
  async def IA():
823
  os.environ['HUGGINGFACEHUB_API_TOKEN'] = os.environ['HUGGINGFACEHUB_API_TOKEN']