|
import os |
|
import json |
|
import bcrypt |
|
import pandas as pd |
|
from typing import List |
|
from pathlib import Path |
|
from langchain_huggingface import HuggingFaceEmbeddings |
|
from langchain_huggingface import HuggingFaceEndpoint |
|
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder |
|
from langchain.schema import StrOutputParser |
|
|
|
from operator import itemgetter |
|
from pinecone import Pinecone |
|
from langchain_pinecone import PineconeVectorStore |
|
from langchain_community.chat_message_histories import ChatMessageHistory |
|
from langchain.memory import ConversationBufferMemory |
|
from langchain.schema.runnable import Runnable, RunnablePassthrough, RunnableConfig, RunnableLambda |
|
from langchain.callbacks.base import BaseCallbackHandler |
|
from langchain.chains import ( |
|
StuffDocumentsChain, ConversationalRetrievalChain, create_extraction_chain |
|
) |
|
|
|
import chainlit as cl |
|
from chainlit.input_widget import TextInput, Select, Switch, Slider |
|
|
|
from deep_translator import GoogleTranslator |
|
|
|
from datetime import timedelta |
|
|
|
@cl.step(type="tool") |
|
async def LLMistral(): |
|
os.environ['HUGGINGFACEHUB_API_TOKEN'] = os.environ['HUGGINGFACEHUB_API_TOKEN'] |
|
|
|
|
|
|
|
repo_id = "mistralai/Mistral-7B-Instruct-v0.2" |
|
|
|
|
|
llm = HuggingFaceEndpoint( |
|
repo_id=repo_id, max_new_tokens=5300, temperature=0.5, task="text2text-generation", streaming=True |
|
) |
|
return llm |
|
|
|
@cl.step(type="tool") |
|
async def VectorDatabase(categorie): |
|
if categorie == "year" or categorie == "videosTC": |
|
index_name = "all-jdlp" |
|
embeddings = HuggingFaceEmbeddings() |
|
vectorstore = PineconeVectorStore( |
|
index_name=index_name, embedding=embeddings, pinecone_api_key=os.getenv('PINECONE_API_KEYJDLP') |
|
) |
|
return vectorstore |
|
|
|
@cl.step(type="retrieval") |
|
async def Retriever(categorie): |
|
vectorstore = await VectorDatabase(categorie) |
|
if categorie == "videosTC": |
|
retriever = vectorstore.as_retriever(search_type="similarity_score_threshold", search_kwargs={"score_threshold": .7, "k": 250,"filter": {"title": {"$eq": "videos-table-rondeia"}, "time": {"$gte": 1320}}}) |
|
return retriever |
|
|
|
@cl.step(type="embedding") |
|
async def Search(input, categorie): |
|
vectorstore = await VectorDatabase(categorie) |
|
results = [] |
|
test = [] |
|
sources_text = "" |
|
sources_offres = "" |
|
verbatim_text = "" |
|
count = 0 |
|
countOffres = 0 |
|
if categorie == "videosTC": |
|
search = vectorstore.similarity_search(input,k=50, filter={"title": {"$eq": "videos-table-rondeia"}, "time": {"$gte": 1320}}) |
|
for i in range(0,len(search)): |
|
if count <= 23: |
|
count = count + 1 |
|
timeSeq = search[i].metadata["time"] |
|
timeSeqRound = round(timeSeq) |
|
time = timedelta(seconds=timeSeqRound) |
|
sources_text = sources_text + '<div class="gridvid"><a target="_blank" title="' + search[i].metadata['titre'] + ' : ...' + search[i].page_content + '" href="' + search[i].metadata['video'] + '#start=' + str(timeSeq) + '"><img src="' + search[i].metadata['image'] + '" width="100%" alt="' + search[i].metadata['titre'] + ' : ...' + search[i].page_content + '"/><p>🕓 ' + str(time) + ' : ...' + search[i].page_content + ' : ' + search[i].metadata['titre'] + '</p></a></div>' |
|
sources_audio = sources_text + '<div class="gridvid"><a target="_blank" title="' + search[i].metadata['titre'] + ' : ...' + search[i].page_content + '" href="' + search[i].metadata['Audio'] + '#start=' + str(timeSeq) + '"><img src="' + search[i].metadata['thumb'] + '" width="100%" alt="' + search[i].metadata['titre'] + ' : ...' + search[i].page_content + '"/><p>🕓 ' + str(time) + ' : ...' + search[i].page_content + ' : ' + search[i].metadata['titre'] + '</p></a></div>' |
|
verbatim_text = verbatim_text + "<p style='font-size:0.8rem'>" + str(count) + ". " + search[i].metadata['titre'] + "</p><p style='font-size:0.8rem'>🕓 "+ str(time) + " : " + search[i].page_content + "</p>" |
|
|
|
results = [sources_text, verbatim_text, sources_audio] |
|
return results |
|
|
|
@cl.set_chat_profiles |
|
async def chat_profile(): |
|
return [ |
|
cl.ChatProfile(name="Table ronde autour de l'IA : «IA et gestes professionnels de l’enseignant»",markdown_description="Vidéo exploratoire autour de l'événement",icon="/public/logo-ofipe.png",), |
|
] |
|
|
|
|
|
|
|
|
|
|
|
@cl.set_starters |
|
async def set_starters(): |
|
return [ |
|
cl.Starter( |
|
label="L'IA comme outil pour les enseignants et les étudiants", |
|
message="Comment les enseignants et les étudiants peuvent-ils utiliser l'IA comme un outil pour améliorer l'apprentissage et l'enseignement ?", |
|
icon="/public/videocam-theme1.svg", |
|
), |
|
|
|
cl.Starter( |
|
label="Les limites de l'IA et la nécessité de l'intervention humaine", |
|
message="Quelles sont les limites de l'IA et pourquoi est-il important que les enseignants interviennent dans le processus d'apprentissage avec l'IA ?", |
|
icon="/public/videocam-theme2.svg", |
|
), |
|
cl.Starter( |
|
label="L'importance de l'esprit critique face à l'IA", |
|
message="Comment encourager les étudiants à développer un esprit critique face à l'IA et à ses résultats ?", |
|
icon="/public/videocam-theme3.svg", |
|
), |
|
cl.Starter( |
|
label="L'éthique et l'IA dans les enseignements du supérieur", |
|
message="Quels sont les enjeux éthiques liés à l'utilisation de l'IA dans les enseignements du supérieur et comment y faire face ?", |
|
icon="/public/videocam-theme4.svg", |
|
), |
|
cl.Starter( |
|
label="Les impacts de l'IA sur les métiers et les formations", |
|
message="Comment l'IA va transformer les métiers et les formations du supérieur et quels sont les défis à relever ?", |
|
icon="/public/videocam-theme5.svg", |
|
), |
|
cl.Starter( |
|
label="Les limites de l'IA et les défis technologiques", |
|
message="Quelles sont les limites actuelles de l'IA et quels sont les défis technologiques à relever pour améliorer son utilisation dans les enseignements du supérieur ?", |
|
icon="/public/videocam-theme6.svg", |
|
) |
|
] |
|
|
|
@cl.on_message |
|
async def on_message(message: cl.Message): |
|
if cl.context.session.client_type == "copilot": |
|
await cl.Message(f"Type : {message.type}").send() |
|
if message.type == "system_message": |
|
|
|
await cl.Message(f"Lien : ").send() |
|
return |
|
|
|
model = await LLMistral() |
|
retriever = await Retriever("videosTC") |
|
|
|
message_history = ChatMessageHistory() |
|
memory = ConversationBufferMemory(memory_key="chat_history",output_key="answer",chat_memory=message_history,return_messages=True) |
|
|
|
qa = ConversationalRetrievalChain.from_llm( |
|
model, |
|
memory=memory, |
|
chain_type="stuff", |
|
return_source_documents=True, |
|
verbose=False, |
|
retriever=retriever |
|
) |
|
|
|
msg = cl.Message(content="") |
|
|
|
class PostMessageHandler(BaseCallbackHandler): |
|
""" |
|
Callback handler for handling the retriever and LLM processes. |
|
Used to post the sources of the retrieved documents as a Chainlit element. |
|
""" |
|
|
|
def __init__(self, msg: cl.Message): |
|
BaseCallbackHandler.__init__(self) |
|
self.msg = msg |
|
self.sources = set() |
|
|
|
def on_retriever_end(self, documents, *, run_id, parent_run_id, **kwargs): |
|
for d in documents: |
|
source_page_pair = (d.metadata['source'], d.metadata['page']) |
|
self.sources.add(source_page_pair) |
|
|
|
def on_llm_end(self, response, *, run_id, parent_run_id, **kwargs): |
|
sources_text = "\n".join([f"{source}#page={page}" for source, page in self.sources]) |
|
self.msg.elements.append( |
|
cl.Text(name="Sources", content=sources_text, display="inline") |
|
) |
|
|
|
cb = cl.AsyncLangchainCallbackHandler() |
|
results = await qa.acall("Contexte : Vous êtes un chercheur de l'enseignement supérieur et vous êtes doué pour faire des analyses d'articles de recherche sur les thématiques liées à la pédagogie, en fonction des critères définis ci-avant. En fonction des informations suivantes et du contexte suivant seulement et strictement, répondez en langue française strictement à la question ci-dessous, en 5000 mots au moins. En plus, tu créeras et tu afficheras, à la fin de ta réponse, 3 questions supplémentaires en relation avec le contexte initial, à chaque étape de la conversation. Tu écriras et tu afficheras les 3 questions supplémentaires en relation avec le contexte initial, à la fin de ta réponse, avec un titrage de niveau 1 qui a pour titre \"Questions en relation avec le contexte : \". Lorsque cela est possible, cite les sources 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. Question : " + message.content, callbacks=[cb]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
answer = results["answer"] |
|
|
|
await cl.Message(content=GoogleTranslator(source='auto', target='fr').translate(answer[0:5000])).send() |
|
|
|
search = await Search(message.content, "videosTC") |
|
|
|
sources = [ |
|
cl.Text(name="Sources vidéo", content=search[0], display="inline") |
|
] |
|
await cl.Message( |
|
content="Vidéos : ", |
|
elements=sources, |
|
).send() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
verbatim = [ |
|
cl.Text(name="Verbatim", content=search[1], display="side") |
|
] |
|
await cl.Message( |
|
content="📚 Liste des Verbatim ", |
|
elements=verbatim, |
|
).send() |