import os import time from operator import itemgetter from collections import Counter from langchain_community.document_loaders import PyPDFLoader, TextLoader from chainlit.types import AskFileResponse from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.schema.runnable import Runnable, RunnablePassthrough, RunnableLambda from langchain.schema.runnable.config import RunnableConfig from langchain_community.embeddings import HuggingFaceEmbeddings from langchain.chains import ConversationalRetrievalChain, create_extraction_chain from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler from langchain.chains import LLMChain from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.schema import StrOutputParser from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT from langchain.chains.question_answering import load_qa_chain from langchain.chains.qa_with_sources import load_qa_with_sources_chain from langchain_pinecone import PineconeVectorStore from pinecone import Pinecone from langchain.memory import ChatMessageHistory, ConversationBufferMemory import pandas as pd import numpy as np from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT from langchain_anthropic import ChatAnthropic import chainlit as cl from chainlit.input_widget import Select, TextInput from chainlit import user_session from offres_emploi import Api from offres_emploi.utils import dt_to_str_iso import datetime import plotly.express as px import bcrypt import json import requests import http.client from literalai import LiteralClient literal_client = LiteralClient(api_key=os.getenv("LITERAL_API_KEY")) literal_client.instrument_openai() @cl.password_auth_callback def auth_callback(username: str, password: str): auth = json.loads(os.environ['CHAINLIT_AUTH_LOGIN']) ident = next(d['ident'] for d in auth if d['ident'] == username) pwd = next(d['pwd'] for d in auth if d['ident'] == username) resultLogAdmin = bcrypt.checkpw(username.encode('utf-8'), bcrypt.hashpw(ident.encode('utf-8'), bcrypt.gensalt())) resultPwdAdmin = bcrypt.checkpw(password.encode('utf-8'), bcrypt.hashpw(pwd.encode('utf-8'), bcrypt.gensalt())) resultRole = next(d['role'] for d in auth if d['ident'] == username) if resultLogAdmin and resultPwdAdmin and resultRole == "admindatapcc": return cl.User( identifier=ident + " : đŸ§‘â€đŸ’Œ Admin Datapcc", metadata={"role": "admin", "provider": "credentials"} ) elif resultLogAdmin and resultPwdAdmin and resultRole == "userdatapcc": return cl.User( identifier=ident + " : 🧑‍🎓 User Datapcc", metadata={"role": "user", "provider": "credentials"} ) def process_file(file: AskFileResponse): if file.type == "text/plain": Loader = TextLoader elif file.type == "application/pdf": Loader = PyPDFLoader text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100) loader = Loader(file.path) documents = loader.load() docs = text_splitter.split_documents(documents) return docs def modele(document): match document: case "Note de composante sectorielle": note = """ 2. Analyse du systĂšme travail 2.1 Secteurs en lien avec la discipline 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. 2.2 Analyses des offres d’emploi 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. 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. 2.2.3 Indiquer si les emplois sont en tension """ case "Fiche Potentiel Profil de Sortie": note = """ 1. Nom de la fiche 2. Niveau du diplĂŽme et son IntitulĂ© (nom long plus sigle). Le niveau de qualification 3. Le rĂ©sumĂ© du profil et du potentiel de sortie. Il est composĂ© de plusieurs parties : 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. 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 4. La rĂ©glementation le cas Ă©chĂ©ant 5. Secteurs d'activitĂ© ou types d'emplois accessibles par le dĂ©tenteur de ce diplĂŽme 6. Le type de structure et d’organisations professionnelles 7. Listes des suites de parcours acadĂ©miques ou passerelles de formation 8. Codes Rome 9. RĂ©fĂ©rence de la fiche RNCP """ return note def definition(document): if document == "activite": meanings = """ 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. """ elif document == "competence": meanings = """ 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. """ elif document == "promptLibraryNCS": meanings = """ 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. """ elif document == "promptLibraryFCS": meanings = """ 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? """ return meanings def listToString(list): return str(list) def arrayToString(array): arrayList = [] for i in range(0,len(array)): if listToString(array[i]).find("libelle")!=-1: arrayList.append(array[i]['libelle']) else: arrayList.append("; ") string = ', '.join(arrayList) return string + '; ' def searchByRome(rome,index): libelle = '' if rome.find(',') != -1: romeArray = rome.split(',') for i in range(0,len(romeArray)): codeRome = romeArray[i].strip() if i <= 5 and len(codeRome) == 5: all_docs = index.query( top_k=1, vector= [0] * 768, # embedding dimension namespace='', filter={"categorie": {"$eq": "rome"}, "rome":{"$eq": codeRome}}, include_metadata=True ) libelle = libelle + " " + all_docs['matches'][0]['metadata']['libelle_rome'] else: all_docs = index.query( top_k=1, vector= [0] * 768, # embedding dimension namespace='', filter={"categorie": {"$eq": "rome"}, "rome":{"$eq": rome}}, include_metadata=True ) libelle = libelle + " " + all_docs['matches'][0]['metadata']['libelle_rome'] return libelle @cl.author_rename def rename(orig_author: str): rename_dict = {"ConversationalRetrievalChain": "💬 Assistant conversationnel", "Retriever": "Agent conversationnel", "StuffDocumentsChain": "ChaĂźne de documents", "LLMChain": "Agent", "ChatAnthropic": "IA đŸ€–"} return rename_dict.get(orig_author, orig_author) @cl.action_callback("download") async def on_action(action): content = [] content.append(action.value) arrayContent = np.array(content) df = pd.DataFrame(arrayContent) with open('./' + action.description + '.txt', 'wb') as csv_file: df.to_csv(path_or_buf=csv_file, index=False,header=False, encoding='utf-8') elements = [ cl.File( name= action.description + ".txt", path="./" + action.description + ".txt", display="inline", ), ] await cl.Message( author="Datapcc : 🌐🌐🌐", content="[Lien] 🔗", elements=elements ).send() await action.remove() @cl.action_callback("saveToMemory") async def on_action(action): buffer = cl.user_session.get("saveMemory") cl.user_session.set("saveMemory", buffer + action.value) await cl.Message( author="Datapcc : 🌐🌐🌐", content="đŸ—ƒïž Document sauvegardĂ© dans le buffer Memory!" ).send() await action.remove() @cl.cache def to_cache(file): #time.sleep(5) # Simulate a time-consuming process return "https://cipen.univ-gustave-eiffel.fr/fileadmin/CIPEN/datas/assets/docs/" + file + ".csv" @cl.set_chat_profiles async def chat_profile(): return [ cl.ChatProfile(name="Note composante sectorielle - NCS",markdown_description="Note composante sectorielle",icon="./public/favicon.png",), ] @cl.on_chat_start async def start(): await cl.Avatar( name="You", path="./public/logo-ofipe.jpg", ).send() chat_profile = cl.user_session.get("chat_profile") chatProfile = chat_profile.split(' - ') if chatProfile[1] == 'NCS': app_user = cl.user_session.get("user") welcomeUser = app_user.identifier welcomeUserArray = welcomeUser.split('@') welcomeUserStr = welcomeUserArray[0].replace('.',' ') await cl.Message(f"> Bonjour {welcomeUserStr}").send() valuesRome = [] valuesRome = ["", "M1302 - DU entrepreneuriat", "F1102,B1301 - LP ChargĂ©.e d'Affaires en Agencement (CAA)", "M1502,M1503 - LP Gestion OpĂ©rationnelles des Ressources Humaines", "K1902 - LP Management et Droits des Affaires ImmobiliĂšres"] cl.user_session.set("arraySettingsRome", valuesRome) settings = await cl.ChatSettings( [ Select( id="rome", label="Codes Rome", values=valuesRome, initial_index=0, ), TextInput(id="romeInput", label="ou saisir une liste de codes ROME jusqu'Ă  5 codes", placeholder="ou saisir une liste de codes ROME jusqu'Ă  5 codes", tooltip="saisir une liste de codes Rome sĂ©parĂ©s par des virgules, jusqu'Ă  5 codes ROME"), Select( id="type", label="Type de fiche", values=["", "Note de composante sectorielle - NCS", "Fiche synoptique - FCS", "Fiche Potentiel Profil de Sortie - FPPS", "Fiche activitĂ© - FCA", "Fiche compĂ©tence - FCC", "Module de formation - cours - MDF", "Matrice de cohĂ©rences - MDC", "RĂ©fĂ©rentiel d'Ă©valuation - REV"], initial_index=0, ), ] ).send() value = settings["rome"] if len(value) < 2: warning = [ cl.Image(name="Warning", size="small", display="inline", path="./public/warning.png") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="1ïžâƒŁ Cliquez sur le bouton dont l'image suit, dans le prompt, pour commencer Ă  Ă©laborer un premier texte de la chaĂźne documentaire APCC!").send() await cl.Message(author="Datapcc : 🌐🌐🌐",content="", elements=warning).send() await cl.Message(author="Datapcc : 🌐🌐🌐",content="2ïžâƒŁ Puis sĂ©lectionnez ou saisissez un ou plusieurs codes ROME et un type de fiche dans les menus dĂ©roulants proposĂ©s. Et vous ĂȘtes prĂȘt!\n\n🔗 Plateforme de feedback et de fil d'activitĂ© : https://cloud.getliteral.ai/").send() os.environ['ANTHROPIC_API_KEY'] = os.environ['ANTHROPIC_API_KEY'] contextChat = cl.user_session.get("contextChatBot") if not contextChat: contextChat = "Il n'y a pas de contexte." model = ChatAnthropic( temperature=1, model_name="claude-3-opus-20240229" ) cl.user_session.set("memory", ConversationBufferMemory(return_messages=True)) memory = cl.user_session.get("memory") prompt = ChatPromptTemplate.from_messages( [ ( "system", f"Contexte : 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. En fonction des informations suivantes et du contexte suivant seulement et strictement. Contexte : {contextChat}. RĂ©ponds Ă  la question suivante de la maniĂšre la plus pertinente, la plus exhaustive et la plus dĂ©taillĂ©e possible, avec au minimum 3000 tokens jusqu'Ă  4000 tokens, seulement et strictement dans le contexte et les informations fournies. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies.", ), MessagesPlaceholder(variable_name="history"), ("human", "{question}, dans le contexte fourni."), ] ) runnable = ( RunnablePassthrough.assign( history=RunnableLambda(memory.load_memory_variables) | itemgetter("history") ) | prompt | model | StrOutputParser() ) cl.user_session.set("runnable", runnable) @literal_client.step(type="run") async def construction_REV(romeListArray,settings): if cl.user_session.get("FCS" + romeListArray[0]) and cl.user_session.get("allskills"): getChain = await recuperation_contexte("FCS" + romeListArray[0]) getChainSkills = await recuperation_contexte("allskills") client_anthropic = await IA() allcompetences = getChainSkills question = f"En fonction du contexte qui suit. Contexte : fiche synoptique : {cl.user_session.get('FCS' + romeListArray[0])}. Liste des compĂ©tences professionnelles : {allcompetences}. CrĂ©e un rĂ©fĂ©rentiel d'Ă©valuation en fonction des compĂ©tences prĂ©cĂ©dentes, sous la forme d'un tableau recensant les modalitĂ©s d'Ă©valuation, les compĂ©tences professionnelles et les critĂšres d'Ă©valuation, tu en dĂ©duiras un autre tableau en fonction des compĂ©tences professionnelles prĂ©cĂ©dentes et des compĂ©tences transversales correspondantes, exploitable dans le logiciel Excel, en respectant tous les intitulĂ©s, en langue française seulement et exclusivement, en 4000 mots. RĂ©ponds et restitue le rĂ©fĂ©rentiel d'Ă©valuation au format tableau." completion_REV = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"RĂ©ponds Ă  la question suivante en utilisant seulement le contexte ci-contre. RĂ©ponds Ă  la maniĂšre d'un ingĂ©nieur pĂ©dagogique pour crĂ©er un rĂ©fĂ©rentiel. 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 fournies dans le contexte ne sont pas suffisantes, fais une projection sur les modalitĂ©s d'Ă©valuation, les critĂšres d'Ă©valuation, pour construire le rĂ©fĂ©rentiel d'Ă©valuation. Questions : {question}" }] ) await cl.sleep(3) await cl.Message( author="Datapcc : 🌐🌐🌐",content="RĂ©fĂ©rentiel d'Ă©valuation :\n\n" + completion_REV.content[0].text ).send() cl.user_session.set("REV" + romeListArray[0], completion_REV.content[0].text) cl.user_session.set("contextChatBot", completion_REV.content[0].text) await cl.sleep(2) actions = [ cl.Action(name="download", value=completion_REV.content[0].text, description="download_referentiel_evaluation") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger le rĂ©fĂ©rentiel", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value=completion_REV.content[0].text, description="Mettre en mĂ©moire le rĂ©fĂ©rentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire le rĂ©fĂ©rentiel", actions=saves).send() await cl.sleep(2) if not cl.user_session.get("saveMemory"): cl.user_session.set("saveMemory", "") memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() else: await cl.Message( author="Datapcc : 🌐🌐🌐",content="⛔ Vous n'avez pas encore crĂ©Ă© de Fiche synoptique!" ).send() return "Construction du RĂ©fĂ©rentiel d'Evaluation" @literal_client.step(type="run") async def construction_MDC(romeListArray,settings): if cl.user_session.get("FCS" + romeListArray[0]) and cl.user_session.get("allskills") and cl.user_session.get("MDF" + romeListArray[0]): await recuperation_contexte("FCS" + romeListArray[0]) getChainSkills = await recuperation_contexte("allskills") getChainMDF = await recuperation_contexte("MDF" + romeListArray[0]) client_anthropic = await IA() allcompetences = getChainSkills allmodules = getChainMDF question = f"En fonction du contexte qui suit. Contexte : liste des compĂ©tences professionnelles : {allcompetences}. Liste des modules de formation et des cours : {allmodules}. DĂ©duis une matrice de cohĂ©rences en corrĂ©lation des modules de formation, des cours prĂ©cĂ©dents et des compĂ©tences professionnelles prĂ©cĂ©dentes ci-avant, sous la forme d'un tableau Ă  double entrĂ©e, exploitable dans le logiciel Excel, en respectant tous les intitulĂ©s, et rempli par des coches entre les modules, les cours et les compĂ©tences professionnelles correspondantes, en langue française seulement et exclusivement, en 4000 mots. RĂ©ponds et restitue la matrice de cohĂ©rences au format tableau avec des lignes correspondant aux modules de formation et aux cours et des colonnes avec des titres de colonne correspondant aux compĂ©tences professionnelles, et pour finir des cellules avec les coches X montrant la corrĂ©lation entre les modules, les cours et les compĂ©tences professionnelles." completion_MDC = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"RĂ©ponds Ă  la question suivante en utilisant seulement le contexte ci-contre. RĂ©ponds Ă  la maniĂšre d'un ingĂ©nieur pĂ©dagogique pour crĂ©er un rĂ©fĂ©rentiel. 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 quand mĂȘme Ă  une estimation et donc Ă  une projection sur les liens entre les modules de formation et les compĂ©tences, pour construire la matrice de cohĂ©rences. Questions : {question}" }] ) await cl.sleep(3) await cl.Message( author="Datapcc : 🌐🌐🌐",content="Matrice de cohĂ©rences :\n\n" + completion_MDC.content[0].text ).send() cl.user_session.set("MDC" + romeListArray[0], completion_MDC.content[0].text) cl.user_session.set("contextChatBot", completion_MDC.content[0].text) await cl.sleep(2) actions = [ cl.Action(name="download", value=completion_MDC.content[0].text, description="download_matrice_coherence") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la matrice", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value=completion_MDC.content[0].text, description="Mettre en mĂ©moire la matrice") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire la matrice", actions=saves).send() await cl.sleep(2) if not cl.user_session.get("saveMemory"): cl.user_session.set("saveMemory", "") memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() else: await cl.Message( author="Datapcc : 🌐🌐🌐",content="⛔ Vous n'avez pas encore crĂ©Ă© de Fiche synoptique!" ).send() return "Construction de la Matrice de CohĂ©rences" @literal_client.step(type="run") async def construction_MDF(romeListArray,settings): if cl.user_session.get("FCS" + romeListArray[0]) and cl.user_session.get("allskills"): getChainNCS = await recuperation_contexte("NCS" + romeListArray[0]) getChain = await recuperation_contexte("FCS" + romeListArray[0]) getChainSkills = await recuperation_contexte("allskills") getChainActivities = await recuperation_contexte("allactivities") client_anthropic = await IA() allactivites = getChainActivities allcompetences = getChainSkills question = f"En fonction du contexte qui suit. Contexte : note de composante sectorielle : {getChainNCS} Ă  partir de laquelle tu fais une dĂ©duction des niveaux d'Ă©tudes, de l'expĂ©rience professionnelle, des besoins de formation caractĂ©risĂ©s ainsi que des objectifs Ă  atteindre pendant ces formations. Liste des activitĂ©s professionnelles : {allactivites}. Liste des compĂ©tences professionnelles : {allcompetences}. Public cible : de la note de composante sectorielle, donne les niveaux d'Ă©tudes requis en fonction des niveaux de qualification donnĂ©s dans la note de composante sectorielle. DĂ©duis un ensemble de 10 modules de formations, en corrĂ©lation avec les compĂ©tences professionnelles prĂ©cĂ©dentes, dont les intitulĂ©s seront trĂšs dĂ©taillĂ©s et trĂšs complĂšts, entrecoupĂ©s eux-mĂȘmes de 5 cours, en langue française seulement et exclusivement, en 4000 mots. RĂ©ponds et restitue la rĂ©ponse au format tableau de 10 lignes correspondant aux 10 compĂ©tences professionnelles et de 3 colonnes dont les intitulĂ©s du header sont les compĂ©tences professionnelles, les modules de formation et les cours associĂ©s." completion_MDF = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"RĂ©ponds Ă  la question suivante en utilisant seulement le contexte dĂ©taillĂ© ci-aprĂšs. RĂ©ponds Ă  la maniĂšre d'un ingĂ©nieur pĂ©dagogique pour crĂ©er un rĂ©fĂ©rentiel. Si les informations du contexte sont insuffisantes, crĂ©e approximativement les modules de formation et les cours tout en rĂ©alisant une estimation sur les intitulĂ©s, et tout en faisant une prĂ©diction et donc une projection sur les objectifs pĂ©dagogiques, les besoins en compĂ©tences et en formation, les niveaux requis, les lacunes Ă  combler, les mĂ©thodes pĂ©dagogiques et les objectifs d'apprentissage, pour construire les modules de formation. Questions : {question}" }] ) await cl.sleep(3) await cl.Message( author="Datapcc : 🌐🌐🌐",content="Modules de formations :\n\n" + completion_MDF.content[0].text ).send() cl.user_session.set("MDF" + romeListArray[0], completion_MDF.content[0].text) cl.user_session.set("contextChatBot", getChainSkills + "\n" + completion_MDF.content[0].text) await cl.sleep(2) actions = [ cl.Action(name="download", value=completion_MDF.content[0].text, description="download_module_formation") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger les modules", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value=completion_MDF.content[0].text, description="Mettre en mĂ©moire les modules") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire les modules", actions=saves).send() await cl.sleep(2) if not cl.user_session.get("saveMemory"): cl.user_session.set("saveMemory", "") memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() else: await cl.Message( author="Datapcc : 🌐🌐🌐",content="⛔ Vous n'avez pas encore crĂ©Ă© de Fiche synoptique!" ).send() return "Construction des Modules de formation - Cours" @literal_client.step(type="run") async def construction_FCC(romeListArray,settings): if cl.user_session.get("FCS" + romeListArray[0]) and (settings['competence'].find('--- Choisir une compĂ©tence ---')==-1 or settings['competenceInput']): getChain = await recuperation_contexte("FCS" + romeListArray[0]) client_anthropic = await IA() ficheSynoptique = getChain if settings['competenceInput']: competenceSingle = settings['competenceInput'] else: competenceSingle = settings['competence'] question = f"En fonction de la compĂ©tence : {competenceSingle}, issue du document prĂ©cĂ©dent correspondant Ă  la fiche synoptique, crĂ©e une fiche compĂ©tence trĂšs dĂ©taillĂ©e et trĂšs complĂšte de la compĂ©tence professionnelle prĂ©cĂ©dente, en se fixant sur les mots de l'intitulĂ© de cette mĂȘme compĂ©tence professionnelle, en 3000 mots et 5 paragraphes comportant les paragraphes suivants : 1. description de la compĂ©tence et le processus de la mise en oeuvre dans laquelle seront identifiĂ©es les situations susceptibles de dĂ©clencher la mise en oeuvre des tĂąches et la mobilisation des savoirs, 2. contexte exposant les conditions et les contraintes d'exĂ©cution ainsi que les environnements techniques, 3. critĂšres exposant les critĂšres de rĂ©ussite de l'action et correspondant Ă  une pertinence une efficience une efficacitĂ© une cohĂ©rence, 4. liste des savoirs et savoir-faire et savoirs comportementaux." completion_FCC = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"Contexte : RĂ©ponds Ă  la question suivante en utilisant seulement le contexte ci-contre. RĂ©ponds Ă  la maniĂšre d'un ingĂ©nieur pĂ©dagogique pour crĂ©er un rĂ©fĂ©rentiel. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies. Contexte: 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. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies. Fiche synoptique : {ficheSynoptique}. Questions : {question}" }] ) await cl.sleep(3) await cl.Message( author="Datapcc : 🌐🌐🌐",content="Fiche compĂ©tence : " + competenceSingle + "\n\n" + completion_FCC.content[0].text ).send() cl.user_session.set("FCC" + romeListArray[0], completion_FCC.content[0].text) cl.user_session.set("contextChatBot", ficheSynoptique + "\n" + completion_FCC.content[0].text) await cl.sleep(2) actions = [ cl.Action(name="download", value=completion_FCC.content[0].text, description="download_fiche_competence") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la fiche", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value=completion_FCC.content[0].text, description="Mettre en mĂ©moire la fiche") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire la fiche", actions=saves).send() await cl.sleep(2) if not cl.user_session.get("saveMemory"): cl.user_session.set("saveMemory", "") memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() else: await cl.Message( author="Datapcc : 🌐🌐🌐",content="⛔ Vous n'avez pas encore crĂ©Ă© de Fiche synoptique!" ).send() return "Construction de la Fiche CompĂ©tence : " + competenceSingle @literal_client.step(type="run") async def construction_FCA(romeListArray,settings): if cl.user_session.get("FCS" + romeListArray[0]) and (settings['activite'].find('--- Choisir une activitĂ© ---')==-1 or settings['activiteInput']): getChain = await recuperation_contexte("FCS" + romeListArray[0]) client_anthropic = await IA() ficheSynoptique = getChain if settings['activiteInput']: activiteSingle = settings['activiteInput'] else: activiteSingle = settings['activite'] question = f"En fonction de l'activitĂ© : {activiteSingle}, issue du document prĂ©cĂ©dent correspondant Ă  la fiche synoptique, crĂ©e une fiche activitĂ© trĂšs dĂ©taillĂ©e et trĂšs complĂšte de l'activitĂ© professionnelle prĂ©cĂ©dente, en se fixant sur les mots de l'intitulĂ© de cette mĂȘme activitĂ© professionnelle, en 3000 mots et 5 paragraphes comportant les paragraphes suivants : 1. description de l'activitĂ© pour indiquer la finalitĂ© de l'activitĂ© en terme de service ou de produit, 2. description pour indiquer les Ă©tapes du processus mĂ©tier en dĂ©crivant la combinatoire entre les principales compĂ©tences de l'activitĂ© et en indiquant les actions et les opĂ©rations avec les ressources et les moyens nĂ©cessaires pour finalement dĂ©crire les relations hiĂ©rarchiques et fonctionnelles des interlocuteurs, 3. contextualisation pour indiquer les conditions d'exercice de l'activitĂ© : lieu mobilitĂ© risques astreintes, 4. liste des compĂ©tences professionnelles de l'activitĂ©, 5. compĂ©tences transversales de l'activitĂ©." completion_FCA = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"Contexte : RĂ©ponds Ă  la question suivante en utilisant seulement le contexte ci-contre. RĂ©ponds Ă  la maniĂšre d'un ingĂ©nieur pĂ©dagogique pour crĂ©er un rĂ©fĂ©rentiel. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies. Contexte: 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. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies. Fiche synoptique : {ficheSynoptique}. Questions : {question}" }] ) await cl.sleep(3) await cl.Message( author="Datapcc : 🌐🌐🌐",content="Fiche activitĂ© : " + activiteSingle + "\n\n" + completion_FCA.content[0].text ).send() cl.user_session.set("FCA" + romeListArray[0], completion_FCA.content[0].text) cl.user_session.set("contextChatBot", ficheSynoptique + "\n" + completion_FCA.content[0].text) await cl.sleep(2) actions = [ cl.Action(name="download", value=completion_FCA.content[0].text, description="download_fiche_activite") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la fiche", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value=completion_FCA.content[0].text, description="Mettre en mĂ©moire la fiche") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire la fiche", actions=saves).send() await cl.sleep(2) if not cl.user_session.get("saveMemory"): cl.user_session.set("saveMemory", "") memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() else: await cl.Message( author="Datapcc : 🌐🌐🌐",content="⛔ Vous n'avez pas encore crĂ©Ă© de Fiche synoptique!" ).send() return "Construction de la Fiche ActivitĂ©" + activiteSingle @literal_client.step(type="run") async def construction_FPPS(romeListArray,settings): if cl.user_session.get("NCS" + romeListArray[0]) and cl.user_session.get("FCS" + romeListArray[0]): goFPPS1 = await cl.AskUserMessage(content="A partir de quelle formation, voulez-vous construire la Fiche Potentiel et Profil de Sortie?", timeout=120).send() if goFPPS1: goFPPS2 = await cl.AskUserMessage(content="A partir de quel(s) code(s) ROME, voulez-vous construire la Fiche Potentiel et Profil de Sortie?", timeout=120).send() if goFPPS2: docsearch = await vectorOFDatabase_connexion() retrieve = docsearch.similarity_search(goFPPS1['output'], k=5, filter={'categorie': {'$eq': 'OF'}}) infoFormation = '' for i in range(0,len(retrieve)): infoFormation += '\n' + retrieve[i].page_content noteSectorielle = await recuperation_contexte("NCS" + romeListArray[0]) ficheSynoptique = await recuperation_contexte("FCS" + romeListArray[0]) intituleFormation = goFPPS1['output'] codesRome = goFPPS2['output'] client_anthropic = await IA() question =f"En fonction du contexte intĂ©grant les descriptifs de formation, la note de composante sectorielle et la fiche synoptique, crĂ©e une fiche Potentiel Profil de Sortie sous forme d'une fiche descriptive trĂšs dĂ©taillĂ©e et trĂšs complĂšte, construite d'aprĂšs le modĂšle et la structure de document suivante. Structure de document : {str(modele('Fiche Potentiel Profil de Sortie'))}" completion_FPPS = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"Contexte : RĂ©ponds Ă  la question suivante en utilisant le contexte ci-contre. RĂ©ponds Ă  la maniĂšre d'un ingĂ©nieur pĂ©dagogique pour crĂ©er un rĂ©fĂ©rentiel. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez en vous basant sur les informations fournies. Contexte: Descriptifs de formation : {infoFormation}. Note de composante sectorielle : {noteSectorielle}. Fiche Synoptique : {ficheSynoptique}. IntitulĂ© de la formation : {intituleFormation}. Codes ROME : {codesRome}. Questions : {question}" }] ) completionFPPS = completion_FPPS.content[0].text await cl.sleep(0.5) await cl.Message( author="Datapcc : 🌐🌐🌐",content="Fiche Potentiel Profil de sortie : " + romeListArray[1] + "\n\n" + completion_FPPS.content[0].text ).send() cl.user_session.set("FPPS" + romeListArray[0], completion_FPPS.content[0].text) cl.user_session.set("contextChatBot", "Note sectorielle" + noteSectorielle + "\nFiche syoptique" + ficheSynoptique + "\nFiche Potentiel Profil de sortie" + completion_FPPS.content[0].text) await cl.sleep(1) actions = [ cl.Action(name="download", value=completion_FPPS.content[0].text, description="download_fiche_synoptique") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la fiche", actions=actions).send() await cl.sleep(1) saves = [ cl.Action(name="saveToMemory", value=completion_FPPS.content[0].text, description="Mettre en mĂ©moire la fiche") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire la fiche", actions=saves).send() await cl.sleep(1) memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() else: await cl.Message( author="Datapcc : 🌐🌐🌐",content="⛔ Vous n'avez pas encore crĂ©Ă© de Note sectorielle ou de Fiche Synoptique!" ).send() return "Construction de la Fiche Potentiel Profil de Sortie" @literal_client.step(type="run") async def construction_FCS(romeListArray,settings): if cl.user_session.get("NCS" + romeListArray[0]): goFCS = await cl.AskActionMessage( content="Voulez-vous tĂ©lĂ©verser votre propre document de Note sectorielle?", actions=[ cl.Action(name="continue", value="continue", label="✅ Oui, je veux charger ma note sectorielle pour modifier le contexte"), cl.Action(name="cancel", value="cancel", label="❌ Non, je veux continuer avec la version du contexte en cours"), ], ).send() if goFCS and goFCS.get("value") == "continue": files = None while files == None: files = await cl.AskFileMessage( content="TĂ©lĂ©charger votre document de note sectorielle (⚠ Attention, le contexte initial sera modifiĂ©!)", accept=["text/plain", "application/pdf"],max_size_mb=2 ).send() text_file = files[0] text_file_string = process_file(text_file) text_file_string = text_file_string[0].page_content cl.user_session.set("NCS" + romeListArray[0], str(text_file_string)) getChain = "NCS" + romeListArray[0] + " : " + str(text_file_string) else: getChain = await recuperation_contexte("NCS" + romeListArray[0]) client_anthropic = await IA() question =""" 1) Extrais de la note de composante sectorielle du contexte, seulement et strictement la liste des 5 appellations mĂ©tiers principales et Ă©cris-la au format liste formĂ©e de 5 lignes de ces mĂȘmes mĂ©tiers, sans phrase d'introduction de type \"Voici...\" et sans y apporter plus de prĂ©cision quant Ă  la gĂ©nĂ©ration de la note de composante sectorielle; la liste devant se termniner par la derniĂšre appellation mĂ©tier. 2) En fonction des 5 appellations mĂ©tiers du secteur listĂ©es dans le document prĂ©cĂ©dent correspondant Ă  la note de composante sectorielle, crĂ©e une fiche synoptique sous forme d'une fiche descriptive trĂšs dĂ©taillĂ©e et trĂšs complĂšte, en 5000 mots, comprenant une liste numĂ©rotĂ©es de 5 activitĂ©s professionnelles diffĂ©rentes bien dĂ©crites, entrecoupĂ©es elles-mĂȘmes par une sous-liste numĂ©rotĂ©es, imbriquĂ©e dans chaque liste activitĂ© professionnelle, de 5 compĂ©tences professionnelles distinctes et bien dĂ©crites commençant par un verbe d'action conformĂ©ment Ă  la taxonomie de Bloom, marquant une progression dans l'acquisition des compĂ©tences. 3) Extrais de la fiche synoptique crĂ©Ă©e, seulement et strictement la liste des 25 premiĂšres activitĂ©s professionnelles principales et Ă©cris-la sur une seule ligne construite de ces mĂȘmes 10 activitĂ©s sĂ©parĂ©es par des points virgules, sans phrase d'introduction de type \"Voici...\" et sans y apporter plus de prĂ©cision quant Ă  la gĂ©nĂ©ration de la fiche synoptique; la ligne devant commencer par \"activitĂ©s : --- Choisir une activitĂ© --- ; \" et devant se termniner par la derniĂšre activitĂ© professionnelle. 4) Extrais de la fiche synoptique crĂ©Ă©e, seulement et strictement la liste des 25 premiĂšres compĂ©tences professionnelles principales et Ă©cris-la sur une seule ligne construite de ces mĂȘmes 10 compĂ©tences sĂ©parĂ©es par des points virgules, sans phrase d'introduction de type \"Voici...\" et sans y apporter plus de prĂ©cision quant Ă  la gĂ©nĂ©ration de la fiche synoptique; la ligne devant commencer par \"compĂ©tences : --- Choisir une compĂ©tence --- ; \" et devant se termniner par la derniĂšre compĂ©tence professionnelle. """ completion_FCS = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"Contexte : RĂ©ponds aux questions suivantes en utilisant seulement le contexte ci-contre. RĂ©ponds Ă  la maniĂšre d'un ingĂ©nieur pĂ©dagogique pour crĂ©er un rĂ©fĂ©rentiel. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies. Contexte: 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. 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. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies. Note de composante sectorielle : {getChain}. Questions : {question}" }] ) completionFCS = completion_FCS.content[0].text await cl.sleep(2) arrayActivites = completionFCS.split('activitĂ©s : ') arrayOfActivites = arrayActivites[1].split('compĂ©tences : ') arrayOfCompetences = completionFCS.split('compĂ©tences : ') arrayOfRome = np.array(cl.user_session.get("arraySettingsRome")) if settings['rome']: indexOfRome = np.where(arrayOfRome==settings['rome'])[0][0] else: indexOfRome = 0 settings = await cl.ChatSettings( [ Select( id="rome", label="Codes Rome", values=["", "M1302 - DU entrepreneuriat", "F1102,B1301 - LP ChargĂ©.e d'Affaires en Agencement (CAA)", "M1502,M1503 - LP Gestion OpĂ©rationnelles des Ressources Humaines", "K1902 - LP Management et Droits des Affaires ImmobiliĂšres"], initial_index=indexOfRome, ), TextInput(id="romeInput", label="ou saisir une liste de codes ROME jusqu'Ă  5 codes", initial=settings['romeInput'], placeholder="ou saisir une liste de codes ROME jusqu'Ă  5 codes", tooltip="saisir une liste de codes Rome sĂ©parĂ©s par des virgules, jusqu'Ă  5 codes ROME"), Select( id="type", label="Type de fiche", values=["", "Note de composante sectorielle - NCS", "Fiche synoptique - FCS", "Fiche Potentiel Profil de Sortie - FPPS", "Fiche activitĂ© - FCA", "Fiche compĂ©tence - FCC", "Module de formation - cours - MDF", "Matrice de cohĂ©rences - MDC", "RĂ©fĂ©rentiel d'Ă©valuation - REV"], initial_index=2, ), Select( id="activite", label="Activites", values=arrayOfActivites[0].split(';'), initial_index=0, ), TextInput(id="activiteInput", label="ou saisir une activitĂ©", placeholder="ou saisir une activitĂ©", tooltip="saisir votre propre activitĂ© professionnelle pour en avoir un descriptif dĂ©taillĂ©"), Select( id="competence", label="Competences", values=arrayOfCompetences[1].split(';'), initial_index=0, ), TextInput(id="competenceInput", label="ou saisir une compĂ©tence", placeholder="ou saisir une compĂ©tence", tooltip="saisir votre propre compĂ©tence professionnelle pour en avoir un descriptif dĂ©taillĂ©"), ] ).send() await cl.sleep(3) await cl.Message( author="Datapcc : 🌐🌐🌐",content="Fiche synoptique : " + romeListArray[1] + "\n\n" + completion_FCS.content[0].text ).send() cl.user_session.set("FCS" + romeListArray[0], completion_FCS.content[0].text) cl.user_session.set("contextChatBot", getChain + "\n" + completion_FCS.content[0].text) await cl.sleep(2) listPrompts_name = f"Liste des requĂȘtes sur la fiche synoptique" prompt_elements = [] prompt_elements.append( cl.Text(content=definition('promptLibraryFCS'), name=listPrompts_name) ) await cl.Message(author="Datapcc : 🌐🌐🌐",content="📚 BibliothĂšque de prompts : " + listPrompts_name, elements=prompt_elements).send() await cl.sleep(2) actions = [ cl.Action(name="download", value=completion_FCS.content[0].text, description="download_fiche_synoptique") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la fiche", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value=completion_FCS.content[0].text, description="Mettre en mĂ©moire la fiche") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire la fiche", actions=saves).send() await cl.sleep(2) memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() await cl.sleep(2) cl.user_session.set("allactivities", arrayOfActivites[0]) cl.user_session.set("allskills", arrayOfCompetences[1]) else: await cl.Message( author="Datapcc : 🌐🌐🌐",content="⛔ Vous n'avez pas encore crĂ©Ă© de Note sectorielle!" ).send() return "Construction de la Fiche Synoptique" @literal_client.step(type="run") async def construction_NCS(romeListArray): context = await contexte(romeListArray) emploisST = cl.user_session.get("EmploiST") ### Anthropic Completion ### client_anthropic = await IA() structure = str(modele('Note de composante sectorielle')) definitions = definition('activite') + ' ' + definition('competence') question =""" 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. """ completion_NCS = client_anthropic.messages.create( model="claude-3-opus-20240229", max_tokens=4000, temperature=1, messages=[{ "role": 'user', "content": f"Contexte : 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. En fonction des informations suivantes et du contexte suivant seulement et strictement. 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. Question : {question}" }] ) await cl.sleep(2) await cl.Message( author="Datapcc : 🌐🌐🌐",content="Note de composante sectorielle de(s) code(s) ROME : " + romeListArray[0] + "\n\n" + completion_NCS.content[0].text ).send() cl.user_session.set("NCS" + romeListArray[0], completion_NCS.content[0].text) cl.user_session.set("contextChatBot", context + "\n" + completion_NCS.content[0].text) await cl.sleep(2) listEmplois_name = f"Liste des emplois" text_elements = [] text_elements.append( 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) ) await cl.Message(author="Datapcc : 🌐🌐🌐",content="đŸ‘šâ€đŸ’Œ Source PĂŽle Emploi : " + listEmplois_name, elements=text_elements).send() await cl.sleep(2) if romeListArray[0].find(',') != -1: codeArray = romeListArray[0].split(',') ficheMetiers = [] for i in range(0,len(codeArray)): ficheMetiers = [ cl.File(name= "Fiche mĂ©tier " + codeArray[i],url="https://candidat.francetravail.fr/marche-du-travail/fichemetierrome.blocficherome.telechargerpdf?codeRome=" + codeArray[i],display="inline",) ] await cl.Message( author="Datapcc : 🌐🌐🌐", content="[Fiches mĂ©tiers] 🔗", elements=ficheMetiers ).send() else: ficheMetiers = [ cl.File(name= "Fiche mĂ©tier " + romeListArray[0],url="https://candidat.francetravail.fr/marche-du-travail/fichemetierrome.blocficherome.telechargerpdf?codeRome=" + romeListArray[0],display="inline",) ] await cl.Message( author="Datapcc : 🌐🌐🌐", content="[Fiches mĂ©tiers] 🔗", elements=ficheMetiers ).send() await cl.sleep(2) listPrompts_name = f"Liste des requĂȘtes sur la note sectorielle" prompt_elements = [] prompt_elements.append( cl.Text(content=definition('promptLibraryNCS'), name=listPrompts_name) ) await cl.Message(author="Datapcc : 🌐🌐🌐",content="📚 BibliothĂšque de prompts : " + listPrompts_name, elements=prompt_elements).send() await cl.sleep(2) actions = [ cl.Action(name="download", value=completion_NCS.content[0].text, description="download_note_sectorielle") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la note", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value=completion_NCS.content[0].text, description="Mettre en mĂ©moire la note") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire la note", actions=saves).send() await cl.sleep(2) return "Construction de la Note Sectorielle" @cl.step(type="run") async def recuperation_contexte(getNote): getContext = cl.user_session.get(getNote) return getNote + " :\n" + getContext @cl.step(type="retrieval") async def contexte(romeListArray): results = await API_connexion(romeListArray) index = await vectorDatabase_connexion() emplois = [] for i in range(0,len(results)): if i == 0: emplois.append("Secteur : " + searchByRome(romeListArray[0],index) + " " + romeListArray[1]) else: emplois.append("\nEmploi : " + results[i]['intitule'] + "; Contrat : " + results[i]['typeContrat'] + "; CompĂ©tences professionnelles : " + arrayToString(results[i]['competences']) if listToString(results[i]).find("'competences':")!=-1 else "; " + "Salaire : " + listToString(results[i]['salaire']) + "; Qualification : " + results[i]['qualificationLibelle'] if listToString(results[i]).find("'qualificationLibelle':")!=-1 else "; " + "; Localisation : " + listToString(results[i]['lieuTravail']) + "; Entreprise : " + listToString(results[i]['entreprise']['nom']) if listToString(results[i]['entreprise']).find("'nom':")!=-1 else "; ") emplois_list = ''.join(emplois) context = emplois_list.replace('[','').replace(']','').replace('{','').replace('}','') ficheMetier = await Fiche_metier("https://candidat.francetravail.fr/marche-du-travail/fichemetierrome.blocficherome.telechargerpdf?codeRome=", romeListArray[0]) ficheMetiersCompetencesSavoirs = await Fiche_metier_competences_savoirs(romeListArray[0]) metierSecteurContexteTravail = await Metier_secteur_contexte_travail(romeListArray[0]) cl.user_session.set("EmploiST", context) 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 #return "Liste des emplois issus de France Travail :\n" + context #return "\nMetier secteur contexte au travail :\n" + metierSecteurContexteTravail + "\nListe des emplois issus de France Travail :\n" + context @cl.step(type="tool") async def Metier_secteur_contexte_travail(codes): payload = { 'grant_type': 'client_credentials', 'client_id': 'PAR_datalabapc_54c735e1b592af9d016cf0e45f8973082303609fc997f0821a9b308c07995251', 'client_secret': 'b968556f8b4bf2c42af42498304bab0d76edcef23ed4723bbd621ae317a6657e', 'scope': 'api_rome-metiersv1' } r = requests.post("https://entreprise.pole-emploi.fr/connexion/oauth2/access_token?realm=/partenaire", headers={"Content-Type":"application/x-www-form-urlencoded"}, data=payload) data = "[" + r.content.decode("utf-8") + "]" load_json = json.loads(data) token = next(d['access_token'] for d in load_json if d['scope'] == 'api_rome-metiersv1') conn = http.client.HTTPSConnection("api.pole-emploi.io") headers = { 'Authorization': "Bearer " + token, 'Accept': "application/json, */*" } dataset = '' if codes.find(',') != -1: codeArray = codes.split(',') for i in range(0,len(codeArray)): conn.request("GET", "/partenaire/rome-metiers/v1/metiers/metier/" + codeArray[i], headers=headers) res = conn.getresponse() data = res.read() datas = data.decode("utf-8") dataset += str(datas.replace('"','').replace('{','').replace('}','').replace('[','').replace(']','').replace('code','').replace('libelle','').replace(',:',', ').replace('::',':')) else: conn.request("GET", "/partenaire/rome-metiers/v1/metiers/metier/" + codes, headers=headers) res = conn.getresponse() data = res.read() datas = data.decode("utf-8") dataset += str(datas.replace('"','').replace('{','').replace('}','').replace('[','').replace(']','').replace('code','').replace('libelle','').replace(',:',', ').replace('::',':')) return dataset @cl.step(type="tool") async def Fiche_metier_competences_savoirs(codes): payload = { 'grant_type': 'client_credentials', 'client_id': 'PAR_datalabapc_54c735e1b592af9d016cf0e45f8973082303609fc997f0821a9b308c07995251', 'client_secret': 'b968556f8b4bf2c42af42498304bab0d76edcef23ed4723bbd621ae317a6657e', 'scope': 'api_rome-fiches-metiersv1' } r = requests.post("https://entreprise.pole-emploi.fr/connexion/oauth2/access_token?realm=/partenaire", headers={"Content-Type":"application/x-www-form-urlencoded"}, data=payload) data = "[" + r.content.decode("utf-8") + "]" load_json = json.loads(data) token = next(d['access_token'] for d in load_json if d['scope'] == 'api_rome-fiches-metiersv1') conn = http.client.HTTPSConnection("api.pole-emploi.io") headers = { 'Authorization': "Bearer " + token, 'Accept': "application/json, */*" } dataset = '' if codes.find(',') != -1: codeArray = codes.split(',') for i in range(0,len(codeArray)): conn.request("GET", "/partenaire/rome-fiches-metiers/v1/fiches-rome/fiche-metier/" + codeArray[i], headers=headers) res = conn.getresponse() data = res.read() datas = data.decode("utf-8") dataset += str(datas.replace('"','').replace('{','').replace('}','').replace('[','').replace(']','').replace('code','').replace('libelle','').replace(',:',', ').replace('::',':')) else: conn.request("GET", "/partenaire/rome-fiches-metiers/v1/fiches-rome/fiche-metier/" + codes, headers=headers) res = conn.getresponse() data = res.read() datas = data.decode("utf-8") dataset += str(datas.replace('"','').replace('{','').replace('}','').replace('[','').replace(']','').replace('code','').replace('libelle','').replace(',:',', ').replace('::',':')) return dataset @cl.step(type="tool") async def Fiche_metier(url, codes): docs = [] docs_string = '' text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100) if codes.find(',') != -1: codeArray = codes.split(',') for i in range(0,len(codeArray)): response = requests.get(url + codeArray[i]) if response: loader = PyPDFLoader(url + codeArray[i]) documents = loader.load() docs.append(text_splitter.split_documents(documents)) for j in range(0,len(docs)): docs_string += docs[j][0].page_content else: response = requests.get(url + codes) if response: loader = PyPDFLoader(url + codes) documents = loader.load() docs = text_splitter.split_documents(documents) docs_string = docs[0].page_content return docs_string @cl.step(type="tool") async def vectorOFDatabase_connexion(): os.environ['PINECONE_API_KEY'] = os.environ['PINECONE_API_KEY'] os.environ['PINECONE_INDEX_NAME'] = os.environ['PINECONE_INDEX_NAME'] os.environ['PINECONE_ENVIRONMENT'] = os.environ['PINECONE_ENVIRONMENT'] embeddings = HuggingFaceEmbeddings() docsearch = PineconeVectorStore(index_name=os.environ['PINECONE_INDEX_NAME'], embedding=embeddings) return docsearch @cl.step(type="tool") async def vectorDatabase_connexion(): pc = Pinecone(api_key='1e6bca4f-7ae3-4798-b85f-13139e82a7b8') index_name = "all-skills" index = pc.Index(index_name) return index @cl.step(type="tool") async def API_connexion(romeListArray): client = Api(client_id=os.environ['POLE_EMPLOI_CLIENT_ID'], client_secret=os.environ['POLE_EMPLOI_CLIENT_SECRET']) todayDate = datetime.datetime.today() month, year = (todayDate.month-1, todayDate.year) if todayDate.month != 1 else (12, todayDate.year-1) start_dt = todayDate.replace(day=1, month=month, year=year) end_dt = datetime.datetime.today() params = {"motsCles": romeListArray[0],'lieux':'75D','minCreationDate': dt_to_str_iso(start_dt),'maxCreationDate': dt_to_str_iso(end_dt),'range':'0-149'} search_on_big_data = client.search(params=params) results = search_on_big_data["resultats"] return results @cl.step(type="llm") async def IA(): anthropic = Anthropic( api_key=os.environ['ANTHROPIC_API_KEY'], ) return anthropic @cl.on_settings_update async def setup_agent(settings): if not settings['rome'] and not settings['type'] and not settings['romeInput']: await cl.Message( author="Datapcc : 🌐🌐🌐",content=f"⚠ Pas de contexte : {settings['rome']}\n⚠ Pas de type de fiche : {settings['type']}\n⛔ Vous ne pouvez pas Ă©laborer de fiche!" ).send() elif settings['rome'] and not settings['type'] and not settings['romeInput']: await cl.Message( author="Datapcc : 🌐🌐🌐",content=f"👍 Changement de contexte : {settings['rome']}\n⚠ Pas de type de fiche : {settings['type']}\n⛔ Vous ne pouvez pas Ă©laborer de fiche!" ).send() elif not settings['rome'] and settings['type'] and not settings['romeInput']: await cl.Message( author="Datapcc : 🌐🌐🌐",content=f"⚠ Pas de contexte : {settings['rome']}\n👍 Type de fiche : {settings['type']}\n⛔ Vous ne pouvez pas Ă©laborer de fiche!" ).send() else: if settings['romeInput']: await cl.Message( author="Datapcc : 🌐🌐🌐",content=f"👍 Changement de contexte : {settings['romeInput']}\n👍 Type de fiche : {settings['type']}" ).send() romeList = settings['romeInput'] + " - " + settings['romeInput'] cl.user_session.set("romeFree", romeList) else: await cl.Message( author="Datapcc : 🌐🌐🌐",content=f"👍 Changement de contexte : {settings['rome']}\n👍 Type de fiche : {settings['type']}" ).send() romeList = settings['rome'] romeListArray = romeList.split(' - ') cl.user_session.set("typeDoc", settings['type']) if not cl.user_session.get("saveMemory"): cl.user_session.set("saveMemory", "") if settings['type'] == 'Note de composante sectorielle - NCS': await construction_NCS(romeListArray) elif settings['type'] == 'Fiche synoptique - FCS': await construction_FCS(romeListArray,settings) elif settings['type'] == 'Fiche Potentiel Profil de Sortie - FPPS': await construction_FPPS(romeListArray,settings) elif settings['type'] == 'Fiche activitĂ© - FCA': await construction_FCA(romeListArray,settings) elif settings['type'] == 'Fiche compĂ©tence - FCC': await construction_FCC(romeListArray,settings) elif settings['type'] == 'Module de formation - cours - MDF': await construction_MDF(romeListArray,settings) elif settings['type'] == 'Matrice de cohĂ©rences - MDC': await construction_MDC(romeListArray,settings) elif settings['type'] == "RĂ©fĂ©rentiel d'Ă©valuation - REV": await construction_REV(romeListArray,settings) os.environ['ANTHROPIC_API_KEY'] = os.environ['ANTHROPIC_API_KEY'] contextChat = cl.user_session.get("contextChatBot") if not contextChat: contextChat = "Il n'y a pas de contexte." model = ChatAnthropic( temperature=1, model_name="claude-3-opus-20240229" ) memory = cl.user_session.get("memory") prompt = ChatPromptTemplate.from_messages( [ ( "system", f"Contexte : 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. En fonction des informations suivantes et du contexte suivant seulement et strictement. Contexte : {contextChat}. RĂ©ponds Ă  la question suivante de la maniĂšre la plus pertinente, la plus exhaustive et la plus dĂ©taillĂ©e possible, avec au minimum 3000 tokens jusqu'Ă  4000 tokens, seulement et strictement dans le contexte et les informations fournies. Essayez donc de comprendre en profondeur le contexte et rĂ©pondez uniquement en vous basant sur les informations fournies.", ), MessagesPlaceholder(variable_name="history"), ("human", "{question}, dans le contexte fourni."), ] ) runnable = ( RunnablePassthrough.assign( history=RunnableLambda(memory.load_memory_variables) | itemgetter("history") ) | prompt | model | StrOutputParser() ) cl.user_session.set("runnable", runnable) @cl.on_message async def main(message: cl.Message): async with cl.Step(root=True, name="RĂ©ponse de Claude Anthropic", type="llm") as parent_step: parent_step.input = message.content chat_profile = cl.user_session.get("chat_profile") chatProfile = chat_profile.split(' - ') memory = cl.user_session.get("memory") runnable = cl.user_session.get("runnable") # type: Runnable msg = cl.Message(author="Datapcc : 🌐🌐🌐",content="") text_elements = [] answer = [] async for chunk in runnable.astream( {"question": message.content}, config=RunnableConfig(callbacks=[cl.AsyncLangchainCallbackHandler(stream_final_answer=True)]), #config=RunnableConfig(callbacks=[cl.LangchainCallbackHandler()]), ): await parent_step.stream_token(chunk) await msg.stream_token(chunk) QA_context_name = f"Question-rĂ©ponse sur le contexte" text_elements.append( cl.Text(content="Question : " + message.content + "\n\nRĂ©ponse :\n" + msg.content, name=QA_context_name) ) actions = [ cl.Action(name="download", value="Question : " + message.content + "\n\nRĂ©ponse : " + msg.content, description="download_QA_emplois") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Download", actions=actions).send() await cl.sleep(2) saves = [ cl.Action(name="saveToMemory", value="Question : " + message.content + "\n\nRĂ©ponse : " + msg.content, description="Mettre en mĂ©moire la rĂ©ponse Ă  votre requĂȘte") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="Mettre en mĂ©moire la rĂ©ponse Ă  votre requĂȘte", actions=saves).send() await cl.sleep(2) memories = [ cl.Action(name="download", value=cl.user_session.get('saveMemory'), description="download_referentiel") ] await cl.Message(author="Datapcc : 🌐🌐🌐",content="TĂ©lĂ©charger la mise en mĂ©moire de vos fiches", actions=memories).send() await cl.sleep(2) await cl.Message(author="Datapcc : 🌐🌐🌐",content="Contexte : " + QA_context_name, elements=text_elements).send() memory.chat_memory.add_user_message(message.content) memory.chat_memory.add_ai_message(msg.content)