cd@bziiit.com commited on
Commit
59ba192
·
1 Parent(s): e39ca6e

Refactor : pass variable & prompt template by UAML file

Browse files
Files changed (8) hide show
  1. README.md +65 -1
  2. app.py +16 -25
  3. config.yaml +24 -1
  4. pages/chatbot.py +1 -1
  5. pages/form.py +7 -3
  6. rag.py +12 -5
  7. requirements.txt +1 -4
  8. util.py +7 -0
README.md CHANGED
@@ -9,4 +9,68 @@ app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  pinned: false
10
  ---
11
 
12
+ <!-- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference -->
13
+
14
+ # Application Template - README
15
+
16
+ ## Introduction
17
+
18
+ Cette application sert de base/template pour en déployer d'autres sur le même modèle via Huggingface. Elle est facilement duplicable en dupliquant l'espace. Elle est décomposée en plusieurs sections pour offrir une gestion complète des documents et des dialogues avec une Intelligence Artificielle (IA).
19
+
20
+ ### Structure de l'application
21
+
22
+ L'application est structurée en trois parties principales :
23
+
24
+ - **Documents**
25
+ - *Communs*
26
+ - *Vos Documents*
27
+ - **Configurations**
28
+ - *Prompt système*
29
+ - *Paramètres*
30
+ - **Dialogue**
31
+ - *Chatbot*
32
+
33
+ ### Fonctionnement des sections
34
+
35
+ #### 1. Documents
36
+
37
+ - **Documents Communs** :
38
+ Cette section permet de déposer des documents accessibles à tous les utilisateurs de l'application. Ces documents sont vectorisés et stockés dans une base de données vectorielle (voir section dédiée). Ils seront explorés lors des interactions avec l'IA.
39
+
40
+ - **Vos Documents** :
41
+ Chaque utilisateur peut uploader ses propres documents, qui seront pris en compte pendant sa session. Ces documents sont temporaires et ne sont accessibles que durant la session active de l'utilisateur.
42
+
43
+ #### 2. Configurations
44
+
45
+ - **Prompt système** :
46
+ Cette section permet de configurer le *prompt système* utilisé lors des conversations avec l'IA. Ce prompt influence le comportement de l'IA pendant le dialogue.
47
+
48
+ - **Paramètres** :
49
+ Ici, vous pouvez ajuster les paramètres dynamiques de l'application, tels que les préférences utilisateurs ou les options spécifiques à votre usage.
50
+
51
+ #### 3. Dialogue
52
+
53
+ - **Chatbot** :
54
+ Une interface de discussion avec l'IA, où il est possible de choisir le modèle d'IA avec lequel interagir. Vous pouvez aussi commencer la conversation à partir d'un *prompt* pré-défini.
55
+
56
+ ## Base de Données Vectorielle
57
+
58
+ Les documents (communs et personnels) sont vectorisés et stockés dans une base de données vectorielle. Cela permet à l'IA de rechercher et d'explorer ces documents pour enrichir les conversations en fonction des informations disponibles.
59
+
60
+ ## Paramètres Dynamiques
61
+
62
+ Cette application permet la gestion de paramètres dynamiques configurables via l'interface utilisateur. Ces paramètres modifient le comportement de l'application et de l'IA en fonction des besoins de l'utilisateur.
63
+
64
+ ## Prompts par Défaut
65
+
66
+ Des *prompts* par défaut peuvent être définis pour démarrer les conversations avec l'IA. Ces *prompts* sont personnalisables dans la section "Prompt système" des **Configurations**.
67
+
68
+ ## Déploiement
69
+
70
+ Pour déployer cette application sur Huggingface :
71
+
72
+ 1. Dupliquez l'espace Huggingface existant.
73
+ 2. Configurez les fichiers de l'application (paramètres, prompts par défaut, etc.).
74
+ 3. Assurez-vous que la base de données vectorielle est correctement co
75
+
76
+
app.py CHANGED
@@ -6,18 +6,16 @@ from rag import Rag
6
  from vectore_store.PineconeConnector import PineconeConnector
7
  from vectore_store.VectoreStoreManager import VectoreStoreManager
8
 
 
9
 
10
  load_dotenv()
11
 
12
  GROUP_NAME = os.environ.get("APP_NAME")
13
- LOGO = "assets/agir_agri.png"
14
 
15
  def init_app():
16
-
17
- # Read the environment variable and create a dictionary
18
- variables = os.environ.get('VARIABLES')
19
- keys = variables.split(',')
20
- data_dict = {key: '' for key in keys} # Initialize with empty values
21
 
22
  if len(st.session_state) == 0:
23
  # Define Vectore store strategy
@@ -46,25 +44,18 @@ def main():
46
 
47
  pg = st.navigation(
48
  {
49
- "Documents": [
50
- saved_documents,
51
- documents,
52
- ],
53
- "Configurations": [
54
- prompt_system,
55
- form,
56
- ],
57
- "Dialogue": [
58
- chatbot
59
- ],
60
- }
61
- # [
62
- # saved_documents,
63
- # prompt_system,
64
- # documents,
65
- # form,
66
- # chatbot
67
- # ]
68
  )
69
 
70
  pg.run()
 
6
  from vectore_store.PineconeConnector import PineconeConnector
7
  from vectore_store.VectoreStoreManager import VectoreStoreManager
8
 
9
+ from util import getYamlConfig
10
 
11
  load_dotenv()
12
 
13
  GROUP_NAME = os.environ.get("APP_NAME")
14
+ LOGO = "assets/logo.png"
15
 
16
  def init_app():
17
+
18
+ data_dict = getYamlConfig()['variables']
 
 
 
19
 
20
  if len(st.session_state) == 0:
21
  # Define Vectore store strategy
 
44
 
45
  pg = st.navigation(
46
  {
47
+ "Documents": [
48
+ saved_documents,
49
+ documents,
50
+ ],
51
+ "Configurations": [
52
+ prompt_system,
53
+ form,
54
+ ],
55
+ "Dialogue": [
56
+ chatbot
57
+ ],
58
+ }
 
 
 
 
 
 
 
59
  )
60
 
61
  pg.run()
config.yaml CHANGED
@@ -9,4 +9,27 @@ prompts:
9
  - "Comment fonctionne la rotation des cultures et pourquoi est-elle importante ?"
10
  - "Explique les avantages de l'irrigation goutte à goutte pour les cultures."
11
  - "Quels sont les types de fertilisants les plus utilisés en agriculture et leurs impacts ?"
12
- - "Quelles sont les techniques de lutte biologique contre les nuisibles ?"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  - "Comment fonctionne la rotation des cultures et pourquoi est-elle importante ?"
10
  - "Explique les avantages de l'irrigation goutte à goutte pour les cultures."
11
  - "Quels sont les types de fertilisants les plus utilisés en agriculture et leurs impacts ?"
12
+ - "Quelles sont les techniques de lutte biologique contre les nuisibles ?"
13
+
14
+ variables:
15
+ - label : Mon paramètre 1
16
+ key : param1
17
+ value :
18
+ - label : Mon paramètre 2
19
+ key : param2
20
+ value :
21
+ - label : Mon paramètre 3
22
+ key : param3
23
+ value :
24
+
25
+ prompt_template: "
26
+ Paramètre 1 : {param1}
27
+ Paramètre 2 : {param2}
28
+ Paramètre 3 : {param3}
29
+
30
+ Documents partagées : {commonContext}
31
+ Document de référence : {documentContext}
32
+
33
+ Voici l'historique des messages : {messages}
34
+ Les attentes de l'utilisateur sont : {query}
35
+ "
pages/chatbot.py CHANGED
@@ -12,7 +12,7 @@ def display_messages():
12
 
13
  # Charger les données YAML
14
  def load_yaml(file_path):
15
- with open(file_path, 'r') as file:
16
  data = yaml.safe_load(file)
17
  return data
18
 
 
12
 
13
  # Charger les données YAML
14
  def load_yaml(file_path):
15
+ with open(file_path, 'r', encoding='utf-8') as file:
16
  data = yaml.safe_load(file)
17
  return data
18
 
pages/form.py CHANGED
@@ -3,8 +3,12 @@ import streamlit as st
3
  def page():
4
  st.subheader("Définissez vos paramètres")
5
 
6
- for key in st.session_state.data_dict.keys():
7
- value = st.text_input(label=key, value=st.session_state.data_dict[key])
8
- st.session_state.data_dict[key] = value # Update the session state with user input
 
 
 
 
9
 
10
  page()
 
3
  def page():
4
  st.subheader("Définissez vos paramètres")
5
 
6
+ # Boucle pour créer des inputs basés sur data_dict (qui est une liste ici)
7
+ for param in st.session_state.data_dict:
8
+ # Utilisation de la clé 'label' et 'value' pour afficher et récupérer les valeurs
9
+ value = st.text_input(label=param['label'], value=param['value'] if param['value'] else "")
10
+
11
+ # Mettre à jour la valeur dans le dictionnaire après la saisie utilisateur
12
+ param['value'] = value
13
 
14
  page()
rag.py CHANGED
@@ -10,10 +10,9 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
10
  from langchain.schema.runnable import RunnablePassthrough
11
  from langchain.prompts import PromptTemplate
12
  from langchain_community.vectorstores.utils import filter_complex_metadata
13
- #add new import
14
  from langchain_community.document_loaders.csv_loader import CSVLoader
15
 
16
- from prompt_template import base_template
17
 
18
 
19
  # load .env in local dev
@@ -31,6 +30,8 @@ class Rag:
31
  self.embedding = MistralAIEmbeddings(model="mistral-embed", mistral_api_key=env_api_key)
32
 
33
  self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100, length_function=len)
 
 
34
  self.prompt = PromptTemplate.from_template(base_template)
35
 
36
  self.vector_store = vectore_store
@@ -71,7 +72,7 @@ class Rag:
71
  },
72
  )
73
 
74
- def ask(self, query: str, messages: list, variables: dict = {}):
75
  self.chain = self.prompt | self.model | StrOutputParser()
76
 
77
  # Retrieve the context document
@@ -94,9 +95,15 @@ class Rag:
94
  # Suppression des valeurs nulles (facultatif)
95
  chain_input = {k: v for k, v in chain_input.items() if v is not None}
96
 
97
- # Ajout dynamique d'autres variables dans **extra_vars
98
- chain_input.update(variables)
 
 
 
 
 
99
 
 
100
  return self.chain.invoke(chain_input)
101
 
102
  def clear(self):
 
10
  from langchain.schema.runnable import RunnablePassthrough
11
  from langchain.prompts import PromptTemplate
12
  from langchain_community.vectorstores.utils import filter_complex_metadata
 
13
  from langchain_community.document_loaders.csv_loader import CSVLoader
14
 
15
+ from util import getYamlConfig
16
 
17
 
18
  # load .env in local dev
 
30
  self.embedding = MistralAIEmbeddings(model="mistral-embed", mistral_api_key=env_api_key)
31
 
32
  self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100, length_function=len)
33
+
34
+ base_template = getYamlConfig()['prompt_template']
35
  self.prompt = PromptTemplate.from_template(base_template)
36
 
37
  self.vector_store = vectore_store
 
72
  },
73
  )
74
 
75
+ def ask(self, query: str, messages: list, variables: list = None):
76
  self.chain = self.prompt | self.model | StrOutputParser()
77
 
78
  # Retrieve the context document
 
95
  # Suppression des valeurs nulles (facultatif)
96
  chain_input = {k: v for k, v in chain_input.items() if v is not None}
97
 
98
+ # Si des variables sous forme de liste sont fournies
99
+ if variables:
100
+ # Convertir la liste en dictionnaire avec 'key' comme clé et 'value' comme valeur
101
+ extra_vars = {item['key']: item['value'] for item in variables if 'key' in item and 'value' in item}
102
+
103
+ # Fusionner avec chain_input
104
+ chain_input.update(extra_vars)
105
 
106
+
107
  return self.chain.invoke(chain_input)
108
 
109
  def clear(self):
requirements.txt CHANGED
@@ -1,16 +1,13 @@
1
  streamlit==1.37.0
2
  streamlit_chat
3
- # abc
4
  python-dotenv
5
  pymupdf
 
6
  python-multipart
7
  pydantic
8
- langchain-pinecone
9
  pinecone-notebooks
10
  pinecone-client[grpc]
11
  async-timeout
12
- pymupdf
13
- python-dotenv
14
  typing-extensions
15
  langchain
16
  langchain-openai
 
1
  streamlit==1.37.0
2
  streamlit_chat
 
3
  python-dotenv
4
  pymupdf
5
+ pypdf
6
  python-multipart
7
  pydantic
 
8
  pinecone-notebooks
9
  pinecone-client[grpc]
10
  async-timeout
 
 
11
  typing-extensions
12
  langchain
13
  langchain-openai
util.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import os
2
+ import yaml
3
+
4
+ def getYamlConfig():
5
+ file_path = os.path.join(os.path.dirname(__file__), 'config.yaml')
6
+ with open(file_path, 'r', encoding='utf-8') as file:
7
+ return yaml.safe_load(file)