OpenData-Bordeaux-IA-RSE / RAG_PDF_WEB.py
Ilyas KHIAT
paste
81f75af
import streamlit as st
from dotenv import load_dotenv
from PyPDF2 import PdfReader
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_community.chat_models import ChatOpenAI
from langchain.llms import HuggingFaceHub
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_community.document_loaders import WebBaseLoader
import os
from session import set_rag
from partie_prenante_carte import complete_and_verify_url
def get_docs_from_website(urls):
loader = WebBaseLoader(urls, header_template={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
})
docs = loader.load()
return docs
def get_pdf_text(pdf_docs):
text = ""
for pdf in pdf_docs:
pdf_reader = PdfReader(pdf)
for page in pdf_reader.pages:
text += page.extract_text()
return text
def get_text_chunks(text):
text_splitter = CharacterTextSplitter(
separator="\n",
chunk_size=1000, # the character length of the chunck
chunk_overlap=200, # the character length of the overlap between chuncks
length_function=len # the length function - in this case, character length (aka the python len() fn.)
)
chunks = text_splitter.split_text(text)
return chunks
def get_doc_chunks(docs):
# Split the loaded data
text_splitter = CharacterTextSplitter(separator='\n',
chunk_size=500,
chunk_overlap=40)
docs = text_splitter.split_documents(docs)
return docs
def get_vectorstore_from_docs(doc_chunks):
embedding = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = FAISS.from_documents(documents=doc_chunks, embedding=embedding)
return vectorstore
def get_vectorstore(text_chunks):
embedding = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embedding)
return vectorstore
def get_conversation_chain(vectorstore):
llm = ChatOpenAI(model="gpt-3.5-turbo",temperature=0.5, max_tokens=2048)
retriever=vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
# Chain
rag_chain = (
{"context": retriever , "question": RunnablePassthrough()}
| prompt
| llm
)
return rag_chain
def verify_and_complete_urls(urls):
for i in range(len(urls)):
is_valid, urls[i] = complete_and_verify_url(urls[i])
return urls
def rag_pdf_web():
load_dotenv()
st.header("INDIQUEZ VOS PAGES WEB ET/OU DOCUMENTS D’ENTREPRISE POUR AUDITER LE CONTENU RSE")
option = st.radio("Source", ("A partir de votre site web", "A partir de vos documents entreprise"))
vectorstore = None
chain = None
if option == "A partir de votre site web":
url1 = st.text_input("URL 1")
url2 = st.text_input("URL 2")
url3 = st.text_input("URL 3")
# Process the URLs
sous_options = st.radio("Choisissez votre sous-section", ("Ambition, Vision, Missions, Valeurs", "3 piliers de la démarche RSE"))
try:
if st.button("Process"):
with st.spinner("Processing..."):
#get text from the website
urls = [url1, url2, url3]
filtered_urls = [url for url in urls if url]
#verify and complete urls
filtered_urls = verify_and_complete_urls(filtered_urls)
#get text from the website
docs = get_docs_from_website(filtered_urls)
#get text chunks
text_chunks = get_doc_chunks(docs)
#create vectorstore
vectorstore = get_vectorstore_from_docs(text_chunks)
chain = get_conversation_chain(vectorstore)
if sous_options == "Ambition, Vision, Missions, Valeurs":
# question = '''voici les 4 points à génerer absolument, pas de reponse comme je ne sais pas; et n'oublie aucun des points , chaque paragraphe doit être de minimum 150 caractères:
# \n
# ### Ambition : \n
# Quelle est l'ambition de l'entreprise ? (répondre avec maximum 250 caractères)
# \n
# ### Vision : \n
# Quelle est la vision de l'entreprise ? (répondre avec maximum 250 caractères)
# \n
# ### Missions : \n
# Quelles sont les missions de l'entreprise ? (répondre avec maximum 250 caractères)
# \n
# renvoie ta réponse en markdown et bien formatée'''
# response = chain.invoke(question)
# st.markdown(response.content)
#ambition
ambition = chain.invoke("Quelle est l'ambition de l'entreprise ? (répondre avec maximum 250 caractères)")
st.markdown("### Ambition :")
st.markdown(ambition.content)
#vision
ambition = chain.invoke(" Quelle est la vision de l'entreprise ? (répondre avec maximum 250 caractères)")
st.markdown("### Vision :")
st.markdown(ambition.content)
#Mission
ambition = chain.invoke(" Quelle est la vision de l'entreprise ? (répondre avec maximum 250 caractères)")
st.markdown("### Mission :")
st.markdown(ambition.content)
#values
values = chain.invoke("Quels sont les valeurs de l'entreprise ? (répondre avec 10 mots maximum en bullet points)")
st.markdown("### Valeurs :")
st.markdown(values.content)
elif sous_options == "3 piliers de la démarche RSE":
question = ''' suggère nous les 3 piliers principaux de la démarche RSE pour cette entreprise. N'oublie aucun pilier RSE , ca doit avoir ce format :
\n
### le titre du pilier numero 1 \n
-la description du pilier (répondre avec maximum 250 caractères)
\n
- 2 indicateurs cibles pertinents à atteindre avec suggestion de valeur cible min, max
\n
### le titre du pilier numero 2 \n
-la description du pilier (répondre avec maximum 250 caractères)
\n
- 2 indicateurs cibles pertinents à atteindre avec suggestion de valeur cible min, max
\n
### le titre du pilier numero 3 \n
-la description du pilier (répondre avec maximum 250 caractères)
\n
- 2 indicateurs cibles pertinents à atteindre avec suggestion de valeur cible min, max
\n
renvoie ta réponse en markdown et bien formatée
'''
response = chain.invoke(question)
st.markdown(response.content)
except Exception as e:
st.error(f"Une erreur s'est produite : Url non valide ou problème de connexion à internet. Veuillez réessayer.")
if option == "A partir de vos documents entreprise":
pdf_docs = st.file_uploader("Upload les documents concernant la marque (maximum 3 fichiers de taille max de 5 Mo)", type="pdf", accept_multiple_files=True)
# Process the PDF documents
sous_options = st.radio("Choisissez votre sous-section", ("Ambition, Vision, Missions, Valeurs", "3 piliers de la démarche RSE"))
try:
if st.button("Process"):
with st.spinner("Processing..."):
#get pdf text in raw format
raw_text = get_pdf_text(pdf_docs)
#get text chunks
text_chunks = get_text_chunks(raw_text)
#create vectorstore
vectorstore = get_vectorstore(text_chunks)
chain = get_conversation_chain(vectorstore)
if sous_options == "Ambition, Vision, Missions, Valeurs":
#ambition
ambition = chain.invoke("Quelle est l'ambition de l'entreprise ? (répondre avec maximum 250 caractères)")
st.markdown("### Ambition :")
st.markdown(ambition.content)
#vision
ambition = chain.invoke(" Quelle est la vision de l'entreprise ? (répondre avec maximum 250 caractères)")
st.markdown("### Vision :")
st.markdown(ambition.content)
#Mission
ambition = chain.invoke(" Quelle est la vision de l'entreprise ? (répondre avec maximum 250 caractères)")
st.markdown("### Mission :")
st.markdown(ambition.content)
#values
values = chain.invoke("Quels sont les valeurs de l'entreprise ? (répondre avec 10 mots maximum en bullet points)")
st.markdown("### Valeurs :")
st.markdown(values.content)
elif sous_options == "3 piliers de la démarche RSE":
question = ''' suggère nous les 3 piliers principaux de la démarche RSE pour cette entreprise. Pour chaque pilier RSE doit avoir ce format :
\n
### le titre du ieme pilier \n
-la description du pilier (répondre avec maximum 250 caractères)
\n
- 2 indicateurs cibles pertinents à atteindre avec suggestion de valeur cible min, max
\n
renvoie ta réponse en markdown et bien formatée
'''
response = chain.invoke(question)
st.markdown(response.content)
except Exception as e:
st.error(f"Une erreur s'est produite : Pdf non valide ou problème de connexion à internet. Veuillez réessayer.")
if vectorstore and chain:
set_rag(vectorstore, chain)