beryamosta commited on
Commit
ef6936b
·
verified ·
1 Parent(s): 0d0df3b

Create backend.py

Browse files
Files changed (1) hide show
  1. backend.py +260 -0
backend.py ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from llama_index.core.retrievers import VectorIndexRetriever
2
+ from llama_index.core import QueryBundle
3
+ import gradio as gr
4
+ import pandas as pd
5
+ from llama_index.core.postprocessor import LLMRerank
6
+ from IPython.display import display, HTML
7
+ from llama_index.core.vector_stores import (
8
+ MetadataFilter,
9
+ MetadataFilters,
10
+ FilterOperator,
11
+ FilterOperator
12
+ )
13
+ from llama_index.core.tools import RetrieverTool
14
+ from llama_index.core.retrievers import RouterRetriever
15
+ from llama_index.core.selectors import PydanticSingleSelector
16
+ from llama_index.core import (
17
+ VectorStoreIndex,
18
+ SimpleKeywordTableIndex,
19
+ SimpleDirectoryReader,
20
+ )
21
+ from llama_index.core import SummaryIndex, Settings
22
+ from llama_index.core.schema import IndexNode
23
+ from llama_index.core.tools import QueryEngineTool, ToolMetadata
24
+ from llama_index.llms.openai import OpenAI
25
+ from llama_index.core.callbacks import CallbackManager
26
+ from llama_index.core import Document
27
+ import os
28
+ from llama_index.embeddings.openai import OpenAIEmbedding
29
+ import nest_asyncio
30
+ import pandas as pd
31
+ import hashlib
32
+ import tiktoken
33
+ from dotenv import load_dotenv
34
+
35
+ load_dotenv()
36
+
37
+
38
+ nest_asyncio.apply()
39
+ openai_key = os.getenv('openai_key_secret')
40
+ os.environ["OPENAI_API_KEY"] = openai_key
41
+
42
+
43
+ llm=OpenAI(temperature=0, model="gpt-4o")
44
+ Settings.llm = llm
45
+ Settings.embed_model = OpenAIEmbedding(model="text-embedding-ada-002")
46
+ ds=pd.read_excel("data_metropole 2.xlsx")
47
+
48
+ # df est la DATAFRAME qui contient le fichier source
49
+ df=ds.drop(columns=['Theme ID', 'SousTheme ID', 'Signataire Matricule',
50
+ 'Suppleant Matricule', 'Date Nomination', 'Date Commite Technique', 'Numero',
51
+ 'Libelle', 'Date Creation', 'Date Debut'])
52
+ #la DATAFRAME (filter_signataire) est celle qui contient les colonne relative au signataire
53
+ #la DATAFRAME (filter) est celle qui contient les colonne relative au département
54
+
55
+ filter_signataire = df[['Signataire', 'Fonction']]
56
+ filter_signataire = filter_signataire.drop_duplicates()
57
+ filter = df[['Collectivite', 'Direction DGA', 'Liste Service Text']]
58
+ filter = filter.drop_duplicates()
59
+
60
+ # pre traitement est cleaning des dataframe
61
+ df = df.dropna(subset=['Item Text'])
62
+ df_sorted = df.sort_values(by=['Collectivite', 'Direction DGA', 'Liste Service Text', 'Item Text','Theme Title','SousTheme Title','Item Text'])
63
+
64
+ #traietement des dataframe
65
+ df.loc[:, 'content'] = df.apply(lambda x: f'''
66
+ / Theme : {x['Theme Title'] or ''}
67
+ / Sous-Theme : {x['SousTheme Title'] or ''}
68
+ / Item : {x['Item Text'] or ''}
69
+ / Signataire : {x['Signataire'] or ''}
70
+ / Suppleant : {x['Suppleant'] or ''}
71
+ / Les services : {x['Liste Service Text'] or ''}
72
+ ''', axis=1)
73
+
74
+ #############
75
+
76
+ df = df.fillna(value='')
77
+ filter = filter.fillna(value='')
78
+ filter_signataire = filter_signataire.fillna(value='')
79
+
80
+ #############
81
+
82
+ df.loc[:, 'description'] = df.apply(lambda x: f'''Collectivite : {x['Collectivite'] or ''}
83
+ Direction : {x['Direction DGA'] or ''}
84
+ Liste des Service : {x['Liste Service Text'] or ''}
85
+ ''', axis=1)
86
+
87
+ filter.loc[:, 'description'] = filter.apply(lambda x: f'''Collectivite : {x['Collectivite'] or ''}
88
+ Direction : {x['Direction DGA'] or ''}
89
+ Liste des Service : {x['Liste Service Text'] or ''}
90
+ ''', axis=1)
91
+
92
+ filter_signataire.loc[:, 'description'] = filter_signataire.apply(lambda x: f'''Signataire : {x['Signataire'] or ''}
93
+ Fonction : {x['Fonction'] or ''}
94
+ ''', axis=1)
95
+
96
+ def hachage(row):
97
+ return hashlib.sha1(row.encode("utf-8")).hexdigest()
98
+
99
+ # le hashage
100
+ df['hash'] = df.apply(lambda x: hachage(f'''Collectivite : {x['Collectivite'] or ''}
101
+ Direction : {x['Direction DGA'] or ''}
102
+ Liste des Service : {x['Liste Service Text'] or ''}
103
+ '''), axis=1)
104
+ filter['hash'] = filter.apply(lambda x: hachage(f'''Collectivite : {x['Collectivite'] or ''}
105
+ Direction : {x['Direction DGA'] or ''}
106
+ Liste des Service : {x['Liste Service Text'] or ''}
107
+ '''), axis=1)
108
+ #################################################"
109
+ filter_signataire['hash'] = filter_signataire.apply(lambda x: hachage(f'''Signataire : {x['Signataire'] or ''}
110
+ '''), axis=1)
111
+
112
+ #construction des DOCUMENTS pour la vectorisation
113
+ description_docs = [Document(text=row['description'],metadata={"id_documents": row['hash']}) for index, row in filter.iterrows()]
114
+ content_docs = [Document(text=row['content'],metadata={"id_documents": row['hash']}) for index, row in df.iterrows()]
115
+ signataire_docs = [Document(text=row['Signataire'],metadata={"id_signataire": row['hash']}) for index, row in filter_signataire.iterrows()]
116
+ content_signataire = [Document(text=row['content'],metadata={"id_signataire": row['hash']}) for index, row in df.iterrows()]
117
+
118
+ index = VectorStoreIndex.from_documents(
119
+ description_docs,
120
+ show_progress = True
121
+ )
122
+ index_all = VectorStoreIndex.from_documents(
123
+ content_docs,
124
+ show_progress = True
125
+ )
126
+ index_signataire = VectorStoreIndex.from_documents(
127
+ signataire_docs,
128
+ show_progress = True
129
+ )
130
+ index_all_signataire = VectorStoreIndex.from_documents(
131
+ content_signataire,
132
+ show_progress = True
133
+ )
134
+
135
+ def get_retrieved_nodes(
136
+ query_str, vector_top_k=10, reranker_top_n=3, with_reranker=False,index=index):
137
+ query_bundle = QueryBundle(query_str)
138
+ # configure retriever
139
+ retriever = VectorIndexRetriever(
140
+ index=index,
141
+ similarity_top_k=vector_top_k,
142
+
143
+ )
144
+ retrieved_nodes = retriever.retrieve(query_bundle)
145
+
146
+ if with_reranker:
147
+ # configure reranker
148
+ reranker = LLMRerank(
149
+ choice_batch_size=5,
150
+ top_n=reranker_top_n,
151
+ )
152
+ retrieved_nodes = reranker.postprocess_nodes(
153
+ retrieved_nodes, query_bundle
154
+ )
155
+
156
+ return retrieved_nodes
157
+ def get_all_text(new_nodes):
158
+ texts = []
159
+ for i, node in enumerate(new_nodes, 1):
160
+ texts.append(f"\nDocument {i} : {node.get_text()}")
161
+ return ' '.join(texts)
162
+
163
+ def further_retrieve(query):
164
+ # Retrieve new nodes based on the query
165
+ new_nodes = get_retrieved_nodes(
166
+ query,
167
+ index=index,
168
+ vector_top_k=10,
169
+ reranker_top_n=5,
170
+ with_reranker=False,
171
+ )
172
+ new_nodes_signataire = get_retrieved_nodes(
173
+ query,
174
+ index=index_all_signataire,
175
+ vector_top_k=10,
176
+ reranker_top_n=5,
177
+ with_reranker=False,
178
+ )
179
+ filters = MetadataFilters(
180
+ filters=[
181
+ MetadataFilter(key="id_documents", value=[node.metadata['id_documents'] for node in new_nodes], operator=FilterOperator.IN)
182
+ ],
183
+ )
184
+ filters_s = MetadataFilters(
185
+ filters=[
186
+ MetadataFilter(key="id_signataire", value=[node.metadata['id_signataire'] for node in new_nodes_signataire], operator=FilterOperator.IN)
187
+ ],
188
+ )
189
+
190
+ # Create a retriever with the specified filters
191
+ retriever_description = index_all.as_retriever(filters=filters, similarity_top_k=15)
192
+ retriever_signataire= index_all_signataire.as_retriever(filters=filters_s,similarity_top_k=4)
193
+ # initialize tools
194
+ description_tool = RetrieverTool.from_defaults(
195
+ retriever=retriever_description,
196
+ description="Useful for retrieving specific context from direction, liste service and collectivite",
197
+ )
198
+ signataire_tool = RetrieverTool.from_defaults(
199
+ retriever=retriever_signataire,
200
+ description="Useful for retrieving specific context from signataire and fonction",
201
+ )
202
+ # define retriever
203
+ retriever = RouterRetriever(
204
+ selector=PydanticSingleSelector.from_defaults(llm=llm),
205
+ retriever_tools=[
206
+ description_tool,
207
+ signataire_tool,
208
+ ],
209
+ )
210
+ try :
211
+ query_bundle = QueryBundle(query)
212
+ # Retrieve nodes based on the original query and filters
213
+ retrieved_nodes = retriever.retrieve(query_bundle)
214
+ reranker = LLMRerank(
215
+ choice_batch_size=5, # Process 5 nodes at a time
216
+ top_n=7 # Return the top 7 reranked nodes
217
+ )
218
+
219
+ # Post-process the retrieved nodes by reranking them
220
+ reranked_nodes = reranker.postprocess_nodes(retrieved_nodes, query_bundle)
221
+ return get_all_text(reranked_nodes)
222
+ except :
223
+ print("No rerank")
224
+ return get_all_text(retriever.retrieve(query))
225
+
226
+ def estimate_tokens(text):
227
+ # Encoder le texte pour obtenir les tokens
228
+ encoding = tiktoken.get_encoding("cl100k_base")
229
+ tokens = encoding.encode(text)
230
+ return len(tokens)
231
+
232
+
233
+ def prompt_objectif(user_input):
234
+ from openai import OpenAI
235
+ client = OpenAI(api_key=openai_key)
236
+ documents = further_retrieve(user_input)
237
+ try:
238
+ # Tokenize the text using tiktoken
239
+ encoder = tiktoken.get_encoding("cl100k_base")
240
+ tokens = encoder.encode(user_input)
241
+ encoded_text = encoder.decode(tokens)
242
+
243
+ # Make the API call to the language model
244
+ response = client.chat.completions.create(
245
+ model="gpt-4o",
246
+ messages=[
247
+ {"role": "system", "content": f"""Tu es un assistant utile. L'utilisateur posera une question et tu devras trouver la réponse dans les documents suivants.Focalise sur les service et la direction du signataire que l'utilisateur cherche. Tu ne dois pas poser de question en retour.Tu ne sois mentionner le numéro des documents. Tu t'exprimes dans la même langue que l'utilisateur.,
248
+ DOCUMENTS :
249
+ {documents}"""},
250
+ {"role": "user", "content": user_input},
251
+ ]
252
+ )
253
+
254
+ # Extract and return the generated response
255
+ resultat = response.choices[0].message.content
256
+ return resultat
257
+
258
+ except Exception as e:
259
+ print(f"Failed to generate questions: {e}")
260
+ return None