Aidahaouas commited on
Commit
e4d59e7
·
1 Parent(s): 29b0b66

interface updates

Browse files
.env CHANGED
@@ -4,6 +4,9 @@ LANGSMITH_TRACING=true
4
  LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
5
  LANGSMITH_API_KEY="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"
6
  LANGSMITH_PROJECT="rag_architecture"
7
- #OPENAI_API_KEY="<your-openai-api-key>"
8
 
9
- PINECONE_API_KEY="pcsk_4cofG5_Uk93QCMSKiPvf7btHrPtuhvK71HmcSwfp5g3hHMZTWfapyjs8tvDCYcQteB51Z"
 
 
 
 
 
4
  LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
5
  LANGSMITH_API_KEY="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"
6
  LANGSMITH_PROJECT="rag_architecture"
 
7
 
8
+ PINECONE_API_KEY="pcsk_4cofG5_Uk93QCMSKiPvf7btHrPtuhvK71HmcSwfp5g3hHMZTWfapyjs8tvDCYcQteB51Z"
9
+
10
+ NEO4J_URI="neo4j+s://e50baf05.databases.neo4j.io"
11
+ NEO4J_USERNAME="neo4j"
12
+ NEO4J_PASSWORD="uu6scz4Hf9SwY6SlJgHxk58SHv1m3YNz_RwxAYQKaJc"
__pycache__/config.cpython-310.pyc CHANGED
Binary files a/__pycache__/config.cpython-310.pyc and b/__pycache__/config.cpython-310.pyc differ
 
__pycache__/pdf_processing.cpython-310.pyc CHANGED
Binary files a/__pycache__/pdf_processing.cpython-310.pyc and b/__pycache__/pdf_processing.cpython-310.pyc differ
 
__pycache__/pinecone_utilsB.cpython-310.pyc CHANGED
Binary files a/__pycache__/pinecone_utilsB.cpython-310.pyc and b/__pycache__/pinecone_utilsB.cpython-310.pyc differ
 
app.py CHANGED
@@ -1,10 +1,8 @@
1
  import streamlit as st
2
- from pdf_processing import get_existing_pdf, load_and_preprocess_pdf, split_text
3
  from graph_agentA import agent as agent_A
4
  from graph_agentB import agent as agent_B
5
  from config import *
6
  from dotenv import load_dotenv
7
- from initIndex import *
8
  from pinecone_utilsB import *
9
 
10
 
@@ -76,9 +74,13 @@ def process_query_B(query):
76
  def display_sidebar():
77
  """Affiche la barre latérale."""
78
  with st.sidebar:
79
- st.title("📄 La confession muette")
80
- st.write("Posez vos questions sur le document.")
81
- st.image(agent_B.get_graph().draw_mermaid_png(), caption="Workflow Graph (Architecture B)")
 
 
 
 
82
 
83
  def display_chat_history():
84
  """Affiche l'historique de chat."""
@@ -96,20 +98,31 @@ def main():
96
  if not check_indexes_ready():
97
  return
98
 
99
- st.title("Architecture A et B")
100
- use_architecture_B = st.checkbox("Utiliser l'architecture B (avancée)")
101
-
 
 
 
 
 
 
 
 
 
 
 
 
102
  display_sidebar()
103
  display_chat_history()
104
 
105
  query = st.chat_input("Posez votre question ici:")
106
  if query:
107
- if use_architecture_B:
108
  process_query_B(query)
109
  else:
110
  process_query_A(query)
111
  st.rerun()
112
 
113
  if __name__ == "__main__":
114
- main()
115
-
 
1
  import streamlit as st
 
2
  from graph_agentA import agent as agent_A
3
  from graph_agentB import agent as agent_B
4
  from config import *
5
  from dotenv import load_dotenv
 
6
  from pinecone_utilsB import *
7
 
8
 
 
74
  def display_sidebar():
75
  """Affiche la barre latérale."""
76
  with st.sidebar:
77
+ lien_ressource = "https://www.fnac.com/livre-numerique/a21290809/Gaspard-Boreal-La-Confession-muette"
78
+ #st.title("📄 La confession muette")
79
+ #st.write("Posez vos questions sur le document.")
80
+ st.image(agent_B.get_graph().draw_mermaid_png(), caption="Workflow Graph")
81
+ st.markdown("Document de référence 📄 : \nLa confession muette ()2025")
82
+ st.markdown("Avec l'aimable autorisation de Gaspard Boréal: \n[Récit d'origine]({})".format(lien_ressource))
83
+
84
 
85
  def display_chat_history():
86
  """Affiche l'historique de chat."""
 
98
  if not check_indexes_ready():
99
  return
100
 
101
+ st.title("RAG architectures")
102
+ st.markdown(
103
+ """
104
+ <style>
105
+ div[data-testid="stSelectbox"] {
106
+ width: 200px !important;
107
+ }
108
+ </style>
109
+ """,
110
+ unsafe_allow_html=True
111
+ )
112
+ architecture = st.selectbox(
113
+ "Sélectionnez une architecture :",
114
+ ["Basic", "Intermédiaire", "Avancée"]
115
+ )
116
  display_sidebar()
117
  display_chat_history()
118
 
119
  query = st.chat_input("Posez votre question ici:")
120
  if query:
121
+ if architecture == "Intermédiaire":
122
  process_query_B(query)
123
  else:
124
  process_query_A(query)
125
  st.rerun()
126
 
127
  if __name__ == "__main__":
128
+ main()
 
config.py CHANGED
@@ -4,7 +4,7 @@ from dotenv import load_dotenv
4
  from pinecone import Pinecone, ServerlessSpec, Index
5
  from langsmith import Client
6
  from langchain_mistralai.chat_models import ChatMistralAI
7
- from pdf_processing import get_existing_pdf, load_and_preprocess_pdf, split_text
8
 
9
  # Charger les variables d'environnement
10
  load_dotenv()
@@ -30,6 +30,15 @@ client = Client(
30
  api_key=langsmith_api_key,
31
  )
32
 
 
 
 
 
 
 
 
 
 
33
  # Mistral AI configuration
34
  mistral_api_key = os.getenv("MISTRAL_API_KEY")
35
  llm = ChatMistralAI(
 
4
  from pinecone import Pinecone, ServerlessSpec, Index
5
  from langsmith import Client
6
  from langchain_mistralai.chat_models import ChatMistralAI
7
+ from neo4j import GraphDatabase
8
 
9
  # Charger les variables d'environnement
10
  load_dotenv()
 
30
  api_key=langsmith_api_key,
31
  )
32
 
33
+ # Initialize Neo4j connection
34
+ neo4j_uri = os.getenv("NEO4J_URI")
35
+ neo4j_username = os.getenv("NEO4J_USERNAME")
36
+ neo4j_password = os.getenv("NEO4J_PASSWORD")
37
+ neo4j_driver = GraphDatabase.driver(
38
+ neo4j_uri,
39
+ auth=(neo4j_username, neo4j_password)
40
+ )
41
+
42
  # Mistral AI configuration
43
  mistral_api_key = os.getenv("MISTRAL_API_KEY")
44
  llm = ChatMistralAI(
index_documents.py CHANGED
@@ -1,5 +1,4 @@
1
  # index_documents.py
2
- from config import sparse_index, dense_index
3
  from pinecone_utilsA import index_pdf as index_pdf_A
4
  from pinecone_utilsB import *
5
  from pdf_processing import get_existing_pdf, load_and_preprocess_pdf, split_text
 
1
  # index_documents.py
 
2
  from pinecone_utilsA import index_pdf as index_pdf_A
3
  from pinecone_utilsB import *
4
  from pdf_processing import get_existing_pdf, load_and_preprocess_pdf, split_text
initIndex.py DELETED
@@ -1,28 +0,0 @@
1
- from config import *
2
- import os
3
- from dotenv import load_dotenv
4
- from pinecone import Pinecone, ServerlessSpec
5
- from pdf_processing import get_existing_pdf, load_and_preprocess_pdf, split_text
6
- from pinecone_utilsA import index_pdf as index_pdf_A
7
- from pinecone_utilsB import *
8
-
9
-
10
- #pdf_path = get_existing_pdf()
11
-
12
- def index_pdf(pdf_path, use_architecture_B=False):
13
- """Indexe un PDF dans Pinecone."""
14
- if not pdf_path:
15
- print("Aucun fichier PDF trouvé.")
16
- return
17
-
18
- text = load_and_preprocess_pdf(pdf_path)
19
- texts = split_text(text)
20
-
21
- if use_architecture_B:
22
- print("Indexation pour l'architecture B en cours...")
23
- index_pdf_B(texts)
24
- print("Indexation pour l'architecture B terminée.")
25
- else:
26
- print("Indexation pour l'architecture A en cours...")
27
- index_pdf_A(texts)
28
- print("Indexation pour l'architecture A terminée.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
neo4j_initialize.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.graphs import Neo4jGraph
2
+ from config import *
3
+ from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import FixedSizeSplitter
4
+ from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline
5
+ from langchain.embeddings import HuggingFaceEmbeddings
6
+ from pdf_processing import get_existing_pdf, load_and_preprocess_pdf, split_text
7
+ from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline
8
+ from neo4j import GraphDatabase
9
+
10
+ try:
11
+ with neo4j_driver.session() as session:
12
+ result = session.run("RETURN 1 AS test")
13
+ print("Connexion à Neo4j réussie :", result.single()["test"])
14
+ except Exception as e:
15
+ print("Erreur de connexion à Neo4j :", e)
16
+
17
+ graph = Neo4jGraph()
18
+
19
+ def generate_graph():
20
+
21
+ basic_node_labels = ["Personnage", "Objet", "Lieu", "Événement", "PériodeTemporelle"]
22
+ story_node_labels = ["Protagoniste", "Antagoniste", "PersonnageSecondaire", "CréatureMythique",
23
+ "FigureHistorique", "Narrateur"]
24
+ literary_node_labels = ["Thème", "Motif", "Symbole"]
25
+
26
+ node_labels = basic_node_labels + story_node_labels + literary_node_labels
27
+
28
+ rel_types = ["CONNAÎT", "SITUE_DANS", "FAIT_PARTIE_DE", "SE_PRODUIT_PENDANT", "IMPLIQUE",
29
+ "S'OPPOSE_À", "CRÉÉ_PAR", "INSPIRÉ_PAR", "REPRÉSENTE", "TRANSFORME"]
30
+
31
+ embeddings = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large")
32
+
33
+ prompt_template = '''
34
+ Vous êtes un expert en analyse de texte chargé d'extraire des informations à partir d'un récit et de les structurer sous forme de graphe de propriétés pour faciliter la compréhension et l'analyse du texte.
35
+
36
+ Extrayez les entités (nœuds) et spécifiez leur type à partir du texte d'entrée suivant.
37
+ Extrayez également les relations entre ces nœuds. La direction de la relation va du nœud de départ au nœud d'arrivée.
38
+
39
+ Retournez le résultat au format JSON en utilisant le modèle suivant :
40
+ {{
41
+ "nodes": [
42
+ {{
43
+ "id": "0",
44
+ "label": "type d'entité",
45
+ "properties": {{
46
+ "name": "nom de l'entité"
47
+ }}
48
+ }}
49
+ ],
50
+ "relationships": [
51
+ {{
52
+ "type": "TYPE_DE_RELATION",
53
+ "start_node_id": "0",
54
+ "end_node_id": "1",
55
+ "properties": {{
56
+ "details": "Description de la relation"
57
+ }}
58
+ }}
59
+ ]
60
+ }}
61
+
62
+ - Utilisez uniquement les informations du texte d'entrée. N'ajoutez aucune information supplémentaire.
63
+ - Si le texte d'entrée est vide, retournez un JSON vide.
64
+ - Créez autant de nœuds et de relations que nécessaire pour offrir un contexte riche et détaillé.
65
+ - Un assistant de connaissance basé sur l'IA doit pouvoir lire ce graphe et comprendre immédiatement le contexte pour poser des questions détaillées.
66
+ Utilisez uniquement les nœuds et relations suivants (s'ils sont fournis) :
67
+
68
+
69
+ Attribuez un identifiant unique (chaîne de caractères) à chaque nœud et réutilisez-le pour définir les relations.
70
+ Respectez les types de nœuds source et cible pour les relations, ainsi que la direction des relations.
71
+
72
+ Ne retournez aucune information supplémentaire autre que le JSON.
73
+
74
+
75
+
76
+ Texte d'entrée :
77
+
78
+ '''
79
+
80
+ kg_builder_pdf = SimpleKGPipeline(
81
+ llm=llm,
82
+ driver=neo4j_driver,
83
+ text_splitter=FixedSizeSplitter(chunk_size=1024, chunk_overlap=200),
84
+ embedder=embeddings,
85
+ entities=node_labels,
86
+ relations=rel_types,
87
+ prompt_template=prompt_template,
88
+ from_pdf=True
89
+ )
90
+
91
+ # Charger et prétraiter les PDF
92
+ pdf_files = get_existing_pdf()
93
+ texts = []
94
+ for pdf_file in pdf_files:
95
+ text = load_and_preprocess_pdf(pdf_file)
96
+ texts.extend(split_text(text))
97
+
98
+ results = kg_builder_pdf.run_async(texts)
99
+ graph.add_graph_documents(results)
100
+
101
+ if __name__ == "__main__":
102
+ generate_graph()
pinecone_utilsB.py CHANGED
@@ -1,17 +1,12 @@
1
  from sentence_transformers import SentenceTransformer
2
  from pinecone_text.sparse import BM25Encoder
3
- from langchain.retrievers import PineconeHybridSearchRetriever
4
  from langchain.embeddings import HuggingFaceEmbeddings
5
- from langchain_pinecone import PineconeVectorStore
6
- from langchain.schema import Document
7
- import pinecone
8
  import streamlit as st
9
  from config import sparse_index as indexB
10
  import nltk
11
  import zlib
12
  import base64
13
  import json
14
- import os
15
  import hashlib
16
  import uuid
17
 
@@ -120,9 +115,6 @@ def index_pdf_B(texts):
120
 
121
  def hybrid_search(query):
122
  """Récupère les documents pertinents en combinant les résultats de Pinecone et BM25."""
123
- #if not is_initialized():
124
- #st.warning("L'index BM25 n'est pas encore prêt. Veuillez patienter pendant l'indexation...")
125
- #return []
126
 
127
  try:
128
  # Générer le vecteur dense pour la requête
 
1
  from sentence_transformers import SentenceTransformer
2
  from pinecone_text.sparse import BM25Encoder
 
3
  from langchain.embeddings import HuggingFaceEmbeddings
 
 
 
4
  import streamlit as st
5
  from config import sparse_index as indexB
6
  import nltk
7
  import zlib
8
  import base64
9
  import json
 
10
  import hashlib
11
  import uuid
12
 
 
115
 
116
  def hybrid_search(query):
117
  """Récupère les documents pertinents en combinant les résultats de Pinecone et BM25."""
 
 
 
118
 
119
  try:
120
  # Générer le vecteur dense pour la requête