Update main.py
Browse files
main.py
CHANGED
@@ -1,14 +1,11 @@
|
|
1 |
import json
|
2 |
import os
|
3 |
import time
|
4 |
-
import datetime
|
5 |
-
import pandas as pd
|
6 |
from pathlib import Path
|
7 |
import chainlit as cl
|
8 |
-
from
|
9 |
-
from
|
10 |
-
from
|
11 |
-
from offres_emploi.utils import dt_to_str_iso
|
12 |
|
13 |
os.environ["GITHUB_TOKEN"] = os.environ["GITHUB_TOKEN"]
|
14 |
|
@@ -53,92 +50,40 @@ def Chargement_des_datas_web(profile):
|
|
53 |
fileOpen.close()
|
54 |
return txt
|
55 |
|
56 |
-
def connexion_France_Travail():
|
57 |
-
client = Api(client_id=os.getenv('POLE_EMPLOI_CLIENT_ID'),
|
58 |
-
client_secret=os.getenv('POLE_EMPLOI_CLIENT_SECRET'))
|
59 |
-
return client
|
60 |
-
|
61 |
-
def API_France_Travail_ROME(romeListArray):
|
62 |
-
client = connexion_France_Travail()
|
63 |
-
todayDate = datetime.datetime.today()
|
64 |
-
month, year = (todayDate.month-1, todayDate.year) if todayDate.month != 1 else (12, todayDate.year-1)
|
65 |
-
start_dt = todayDate.replace(day=1, month=month, year=year)
|
66 |
-
end_dt = datetime.datetime.today()
|
67 |
-
results = []
|
68 |
-
romeList = []
|
69 |
-
if romeListArray.find('-') != -1:
|
70 |
-
romeList = romeListArray.split('-')
|
71 |
-
else:
|
72 |
-
romeList.append(romeListArray)
|
73 |
-
for k in romeList:
|
74 |
-
k = k.lstrip()
|
75 |
-
k = k.rstrip()
|
76 |
-
params = {"motsCles": k.replace('/', '').replace('-', '').replace(',', '').replace(' ', ','),'minCreationDate': dt_to_str_iso(start_dt),'maxCreationDate': dt_to_str_iso(end_dt),'range':'0-149'}
|
77 |
-
try:
|
78 |
-
search_on_big_data = client.search(params=params)
|
79 |
-
results += search_on_big_data["resultats"]
|
80 |
-
except:
|
81 |
-
print("Il n'y a pas d'offres d'emploi.")
|
82 |
-
|
83 |
-
results_df = pd.DataFrame(results)
|
84 |
-
return results_df
|
85 |
-
|
86 |
-
def API_France_Travail_Metier(metier):
|
87 |
-
client = connexion_France_Travail()
|
88 |
-
todayDate = datetime.datetime.today()
|
89 |
-
month, year = (todayDate.month-1, todayDate.year) if todayDate.month != 1 else (12, todayDate.year-1)
|
90 |
-
start_dt = todayDate.replace(day=1, month=month, year=year)
|
91 |
-
end_dt = datetime.datetime.today()
|
92 |
-
results = []
|
93 |
-
params = {"motsCles": metier,'minCreationDate': dt_to_str_iso(start_dt),'maxCreationDate': dt_to_str_iso(end_dt),'range':'0-149'}
|
94 |
-
try:
|
95 |
-
search_on_big_data = client.search(params=params)
|
96 |
-
results += search_on_big_data["resultats"]
|
97 |
-
except:
|
98 |
-
print("Il n'y a pas d'offres d'emploi.")
|
99 |
-
|
100 |
-
results_df = pd.DataFrame(results)
|
101 |
-
return results_df
|
102 |
-
|
103 |
@cl.step(type="llm", show_input=True)
|
104 |
def Connexion_Mistral():
|
105 |
-
|
106 |
-
|
|
|
|
|
107 |
|
108 |
@cl.step(type="tool", show_input=True)
|
109 |
def Generation_reponse(client, data, question):
|
110 |
-
return client.
|
111 |
-
|
112 |
messages=[
|
113 |
SystemMessage(content="Tu es un spécialiste de l'enseignement supérieur, des formations et de la pédagogie. Tu es en capacité d'analyser en profondeur les séances pédagogiques et de les mettre en adéquation avec les théories de la recherche en éducation. Répondez à la question seulement et exclusivement à partir du contexte et des définitions ci-contre, de la manière la plus pertinente, seulement en fonction des informations fournies. Contexte : " + str(data) + ". Définition : les formations MIPI (Management de l'Innovation et du Patrimoine Immobilier) concernent le secteur de l'immobilier : facility management, property management, asset management. Les formations MITIC (Management de l'Innovation des Technologies de l'Information et de la Communication) concernent le secteur du numérique : management de projet, innovation et conseil, support numérique aux métiers"),
|
114 |
UserMessage(content=question + "Donne le résultat au format texte markdown, jusqu'à 3000 caractères convertis en UTF-8. Continue la réponse en citant, dans un paragraphe supplémentaire de 3 lignes, introduit un saut de ligne et par \"\n📚 Sources : \", les 3 verbatim, jusqu'à 100 caractères pour chaque verbatim, avec leur numéro de ligne respectif, qui ont permis de générer la réponse, à partir du contexte. Termine la réponse en créant, dans un dernier paragraphe d'une seule et unique ligne, introduite par un saut de ligne et par \"\n📣 Question en relation avec le sujet : \", 1 seule et unique question en relation avec la question posée, en commençant la ligne par \"Question relative au contexte :\"."),
|
115 |
],
|
116 |
-
|
|
|
|
|
117 |
max_tokens=1024,
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
UserMessage(content=question + "Donne le résultat au format texte markdown, jusqu'à 3000 caractères convertis en UTF-8. Continue la réponse en citant, dans un paragraphe supplémentaire de 3 lignes, introduit un saut de ligne et par \"\n📚 Sources : \", les 3 verbatim, jusqu'à 100 caractères pour chaque verbatim, avec leur numéro de ligne respectif, qui ont permis de générer la réponse, à partir du contexte. Termine la réponse en créant, dans un dernier paragraphe d'une seule et unique ligne, introduite par un saut de ligne et par \"\n📣 Question en relation avec le sujet : \", 1 seule et unique question en relation avec la question posée, en commençant la ligne par \"Question relative au contexte :\"."),
|
126 |
-
],
|
127 |
-
temperature=0.1,
|
128 |
-
max_tokens=1024,
|
129 |
-
top_p=0.1
|
130 |
-
)
|
131 |
-
msg = response.choices[0].message.content
|
132 |
-
return msg
|
133 |
-
|
134 |
@cl.step(type="tool", show_input=True)
|
135 |
async def Affichage_reponse(response):
|
136 |
msg = cl.Message(author="COPILOT",content="")
|
137 |
|
138 |
for update in response:
|
139 |
-
if update.
|
140 |
time.sleep(0.125)
|
141 |
-
await msg.stream_token(update.
|
142 |
|
143 |
await msg.send()
|
144 |
return msg
|
@@ -188,33 +133,16 @@ async def on_action(action):
|
|
188 |
async def on_action(action):
|
189 |
client = cl.user_session.get("client")
|
190 |
data = Chargement_des_datas_web(cl.user_session.get("chat_profile"))
|
191 |
-
|
192 |
-
diviseur = str(len(data) // 23500)
|
193 |
-
reste = str(len(data) % 23500)
|
194 |
-
|
195 |
question = action.value
|
196 |
|
197 |
-
|
198 |
-
if diviseur != 0:
|
199 |
-
for i in range(0, 3):
|
200 |
-
operator = i + 1
|
201 |
-
deb = i * 23500
|
202 |
-
end = operator * 23500
|
203 |
-
webData = data[deb:end]
|
204 |
-
answer += Generation_completion(client, webData, question)
|
205 |
-
else:
|
206 |
-
answer += Generation_reponse(client, data, question)
|
207 |
-
|
208 |
-
if diviseur != 0 and reste !=0 and len(reste) <= 23500:
|
209 |
-
answer += Generation_completion(client, reste, question)
|
210 |
-
|
211 |
-
response = Generation_reponse(client, answer, question)
|
212 |
|
213 |
msg = await Affichage_reponse(response)
|
214 |
|
215 |
-
|
216 |
|
217 |
-
await Affichage_question_contexte(
|
218 |
|
219 |
|
220 |
@cl.set_chat_profiles
|
@@ -374,60 +302,6 @@ async def chat_profile():
|
|
374 |
)
|
375 |
]
|
376 |
),
|
377 |
-
cl.ChatProfile(
|
378 |
-
name="Offres d'emploi par code ROME",
|
379 |
-
markdown_description="Posez vos questions sur les offres d'emploi en direct avec France Travail grâce aux codes ROME rattachés aux formations.",
|
380 |
-
icon="/public/public_request-theme.svg",
|
381 |
-
starters = [
|
382 |
-
cl.Starter(
|
383 |
-
label="Offres d'emploi de la licence MIPI",
|
384 |
-
message="M1403-M1604-M1204-M1605-M1203",
|
385 |
-
icon="/public/public_learn.svg",
|
386 |
-
),
|
387 |
-
cl.Starter(
|
388 |
-
label="Offres d'emploi de la licence MITIC",
|
389 |
-
message="M1403-M1604-M1204-M1605-M1203",
|
390 |
-
icon="/public/public_learn.svg",
|
391 |
-
),
|
392 |
-
cl.Starter(
|
393 |
-
label="Offres d'emploi du master MIPI",
|
394 |
-
message="M1702-M1402-M1403-H1206-M1703",
|
395 |
-
icon="/public/public_learn.svg",
|
396 |
-
),
|
397 |
-
cl.Starter(
|
398 |
-
label="Offres d'emploi du master MITIC",
|
399 |
-
message="M1702-M1402-M1403-H1206-M1703",
|
400 |
-
icon="/public/public_learn.svg",
|
401 |
-
)
|
402 |
-
]
|
403 |
-
),
|
404 |
-
cl.ChatProfile(
|
405 |
-
name="Offres d'emploi par métier type",
|
406 |
-
markdown_description="Posez vos questions sur les offres d'emploi en direct avec France Travail par métier type.",
|
407 |
-
icon="/public/public_request-theme.svg",
|
408 |
-
starters = [
|
409 |
-
cl.Starter(
|
410 |
-
label="Responsable de site industriel ou tertiaire",
|
411 |
-
message="Responsable de site industriel ou tertiaire",
|
412 |
-
icon="/public/public_learn.svg",
|
413 |
-
),
|
414 |
-
cl.Starter(
|
415 |
-
label="Conseiller en investissement immobilier",
|
416 |
-
message="Conseiller en investissement immobilier",
|
417 |
-
icon="/public/public_learn.svg",
|
418 |
-
),
|
419 |
-
cl.Starter(
|
420 |
-
label="Chef de projet digital",
|
421 |
-
message="Chef de projet digital",
|
422 |
-
icon="/public/public_learn.svg",
|
423 |
-
),
|
424 |
-
cl.Starter(
|
425 |
-
label="Manager de l'innovation numérique",
|
426 |
-
message="Manager de l'innovation numérique",
|
427 |
-
icon="/public/public_learn.svg",
|
428 |
-
)
|
429 |
-
]
|
430 |
-
),
|
431 |
]
|
432 |
|
433 |
@cl.on_chat_start
|
@@ -437,48 +311,17 @@ async def on_chat_start():
|
|
437 |
|
438 |
@cl.on_message
|
439 |
async def main(message: cl.Message):
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
client = cl.user_session.get("client")
|
444 |
|
445 |
-
|
446 |
|
447 |
-
|
448 |
|
449 |
-
|
450 |
-
|
451 |
-
else:
|
452 |
-
codeRomeStr = message.content
|
453 |
-
if codeRomeStr.find('-') != -1 or isinstance(codeRomeStr[-4], int) or isinstance(codeRomeStr[1:5], int):
|
454 |
-
await cl.Message(author="COPILOT", content="📊 Connexion à l'API France Travail").send()
|
455 |
-
df_FT = API_France_Travail_ROME(codeRomeStr)
|
456 |
-
elif isinstance(codeRomeStr[-4], int):
|
457 |
-
await cl.Message(author="COPILOT", content="📊 Connexion à l'API France Travail").send()
|
458 |
-
df_FT = API_France_Travail_ROME(codeRomeStr)
|
459 |
-
else:
|
460 |
-
df_FT = API_France_Travail_Metier(codeRomeStr)
|
461 |
-
|
462 |
-
await cl.Message(author="COPILOT", content="📈 Tableau des emplois les plus représentatifs").send()
|
463 |
-
df_intitule = df_FT.groupby('intitule').size().reset_index(name='obs')
|
464 |
-
df_intitule = df_intitule.sort_values(by=['obs'], ascending=True)
|
465 |
-
df_intitule = df_intitule.iloc[-25:]
|
466 |
-
displayTable = df_intitule.sort_values(by=['obs'], ascending=True).to_markdown
|
467 |
-
await cl.Message(author="COPILOT", content=displayTable).send()
|
468 |
-
|
469 |
-
df_FT_Select = df_FT[['intitule','typeContratLibelle','experienceLibelle','competences','description','qualitesProfessionnelles','salaire','lieuTravail','formations']].copy()
|
470 |
-
list_FT = df_FT_Select.values.tolist()
|
471 |
-
context = ''
|
472 |
-
for i in range(0,len(list_FT)):
|
473 |
-
context += "\n✔️ Emploi : " + str(list_FT[i][0]) + ";\n◉ Contrat : " + str(list_FT[i][1]) + ";\n◉ Compétences professionnelles : " + str(list_FT[i][3]).replace("{","").replace("}","").replace("[","").replace("]","").replace("code","").replace("libelle","") + ";\n" + "◉ Salaire : " + str(list_FT[i][6]).replace("{","").replace("}","").replace("[","").replace("]","") + ";\n◉ Qualification : " + str(list_FT[i][5]).replace("'libelle'","\n• 'libelle").replace("{","").replace("}","").replace("[","").replace("]","").replace("code","") + ";\n◉ Localisation : " + str(list_FT[i][7]).replace("{","").replace("}","").replace("[","").replace("]","") + ";\n◉ Expérience : " + str(list_FT[i][2]) + ";\n◉ Niveau de qualification : " + str(list_FT[i][8]).replace("{","").replace("}","").replace("[","").replace("]","") + ";\n◉ Description de l'emploi : " + str(list_FT[i][4]) + "\n"
|
474 |
|
475 |
-
listEmplois_name = f"Liste des emplois"
|
476 |
-
text_elements = []
|
477 |
-
text_elements.append(
|
478 |
-
cl.Text(content="Question : " + codeRomeStr + "\n\nRéponse :\n" + context.replace('[','').replace(']','').replace('{','').replace('}','').replace("'code'","\n• 'code'"), name=listEmplois_name, display="side")
|
479 |
-
)
|
480 |
-
await cl.Message(author="COPILOT", content="👨💼 Source France Travail : " + listEmplois_name, elements=text_elements).send()
|
481 |
-
|
482 |
@cl.on_stop
|
483 |
def on_stop():
|
484 |
print("L'utilisateur veut arrêter la completion en cours!")
|
|
|
1 |
import json
|
2 |
import os
|
3 |
import time
|
|
|
|
|
4 |
from pathlib import Path
|
5 |
import chainlit as cl
|
6 |
+
from azure.ai.inference import ChatCompletionsClient
|
7 |
+
from azure.ai.inference.models import SystemMessage, UserMessage
|
8 |
+
from azure.core.credentials import AzureKeyCredential
|
|
|
9 |
|
10 |
os.environ["GITHUB_TOKEN"] = os.environ["GITHUB_TOKEN"]
|
11 |
|
|
|
50 |
fileOpen.close()
|
51 |
return txt
|
52 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
@cl.step(type="llm", show_input=True)
|
54 |
def Connexion_Mistral():
|
55 |
+
return ChatCompletionsClient(
|
56 |
+
endpoint="https://models.inference.ai.azure.com",
|
57 |
+
credential=AzureKeyCredential(os.environ["GITHUB_TOKEN"]),
|
58 |
+
)
|
59 |
|
60 |
@cl.step(type="tool", show_input=True)
|
61 |
def Generation_reponse(client, data, question):
|
62 |
+
return client.complete(
|
63 |
+
stream=True,
|
64 |
messages=[
|
65 |
SystemMessage(content="Tu es un spécialiste de l'enseignement supérieur, des formations et de la pédagogie. Tu es en capacité d'analyser en profondeur les séances pédagogiques et de les mettre en adéquation avec les théories de la recherche en éducation. Répondez à la question seulement et exclusivement à partir du contexte et des définitions ci-contre, de la manière la plus pertinente, seulement en fonction des informations fournies. Contexte : " + str(data) + ". Définition : les formations MIPI (Management de l'Innovation et du Patrimoine Immobilier) concernent le secteur de l'immobilier : facility management, property management, asset management. Les formations MITIC (Management de l'Innovation des Technologies de l'Information et de la Communication) concernent le secteur du numérique : management de projet, innovation et conseil, support numérique aux métiers"),
|
66 |
UserMessage(content=question + "Donne le résultat au format texte markdown, jusqu'à 3000 caractères convertis en UTF-8. Continue la réponse en citant, dans un paragraphe supplémentaire de 3 lignes, introduit un saut de ligne et par \"\n📚 Sources : \", les 3 verbatim, jusqu'à 100 caractères pour chaque verbatim, avec leur numéro de ligne respectif, qui ont permis de générer la réponse, à partir du contexte. Termine la réponse en créant, dans un dernier paragraphe d'une seule et unique ligne, introduite par un saut de ligne et par \"\n📣 Question en relation avec le sujet : \", 1 seule et unique question en relation avec la question posée, en commençant la ligne par \"Question relative au contexte :\"."),
|
67 |
],
|
68 |
+
model="Phi-3.5-MoE-instruct",
|
69 |
+
presence_penalty=0.1,
|
70 |
+
frequency_penalty=0.8,
|
71 |
max_tokens=1024,
|
72 |
+
stop=["<|endoftext|>"],
|
73 |
+
temperature=0,
|
74 |
+
top_p=1,
|
75 |
+
model_extras={
|
76 |
+
"logprobs": True
|
77 |
+
}
|
78 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
@cl.step(type="tool", show_input=True)
|
80 |
async def Affichage_reponse(response):
|
81 |
msg = cl.Message(author="COPILOT",content="")
|
82 |
|
83 |
for update in response:
|
84 |
+
if update.choices:
|
85 |
time.sleep(0.125)
|
86 |
+
await msg.stream_token(update.choices[0].delta.content.replace('Ã','é').replace('©','').replace('Ã','è').replace('¨','').replace('â','\'').replace('€','').replace('™','').replace('Å','oe').replace('“','').replace('®','î').replace('´','ô').replace('<','').replace('>','').replace('/',''))
|
87 |
|
88 |
await msg.send()
|
89 |
return msg
|
|
|
133 |
async def on_action(action):
|
134 |
client = cl.user_session.get("client")
|
135 |
data = Chargement_des_datas_web(cl.user_session.get("chat_profile"))
|
136 |
+
data = data[0:6975]
|
|
|
|
|
|
|
137 |
question = action.value
|
138 |
|
139 |
+
response = Generation_reponse(client, data, question)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
|
141 |
msg = await Affichage_reponse(response)
|
142 |
|
143 |
+
answer = msg.content
|
144 |
|
145 |
+
await Affichage_question_contexte(answer, question)
|
146 |
|
147 |
|
148 |
@cl.set_chat_profiles
|
|
|
302 |
)
|
303 |
]
|
304 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
]
|
306 |
|
307 |
@cl.on_chat_start
|
|
|
311 |
|
312 |
@cl.on_message
|
313 |
async def main(message: cl.Message):
|
314 |
+
data = Chargement_des_datas(cl.user_session.get("chat_profile"))
|
315 |
+
cl.user_session.set("data", data)
|
316 |
+
client = cl.user_session.get("client")
|
|
|
317 |
|
318 |
+
response = Generation_reponse(client, data, message.content)
|
319 |
|
320 |
+
msg = await Affichage_reponse(response)
|
321 |
|
322 |
+
answer = msg.content
|
323 |
+
await Affichage_question_contexte(answer, message.content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
324 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
@cl.on_stop
|
326 |
def on_stop():
|
327 |
print("L'utilisateur veut arrêter la completion en cours!")
|