Update
This commit is contained in:
parent
a9b223109c
commit
6679b3c86f
10
.gitignore
vendored
10
.gitignore
vendored
|
|
@ -1,4 +1,12 @@
|
||||||
|
# Virtual environment (python)
|
||||||
venv/
|
venv/
|
||||||
|
|
||||||
|
# Rasa generated files
|
||||||
rasa/.rasa
|
rasa/.rasa
|
||||||
|
rasa/models
|
||||||
|
|
||||||
|
# App logs
|
||||||
log.txt
|
log.txt
|
||||||
rasa/models
|
|
||||||
|
# Defaults files
|
||||||
|
.DS_Store
|
||||||
|
|
|
||||||
361
README.md
361
README.md
|
|
@ -1,9 +1,358 @@
|
||||||
# Create pyhton virtul envionnement
|
# Information générale
|
||||||
python3 -m venv ./venv
|
|
||||||
source ./venv/bin/activae
|
|
||||||
|
|
||||||
# Install dependancies
|
## Description du PoC
|
||||||
pip3 install -r requirements.txt
|
Ce projet se concentre sur la mise en place d'un PoC visant à déclencher des actions concrètes à partir d'un NLP/LLM, afin d'exécuter des tâches spécifiques en fonction de l'intention par déclenchement (scripts python).
|
||||||
|
|
||||||
# Init rasa project
|
## Objectif du projet
|
||||||
|
L'objectif est de communiquer avec un chatbot sous l'environnement Rasa, permettant :
|
||||||
|
- La communication avec le LLM Llama3 (installé en local au travers de Ollama) lors d'une communication générale.
|
||||||
|
- Le déclenchement d'actions Python (scripts) lorsque les intentions suivantes sont reconnues :
|
||||||
|
- **Intention de connaître les informations d'une ville suisse** depuis le NPA, déclenchant l'accès à une API afin de récupérer ces informations.
|
||||||
|
- **Intention de connaître la signification d'un prénom**, interrogeant les connaissances du LLM llama3 avec une demande de prompt personnalisé afin de donner la signification ainsi que trois personnes historiquement célèbre ayant porté ce nom.
|
||||||
|
- **Intention de générer un profil d'une personne aléatoirement**, en interrogeant une API.
|
||||||
|
|
||||||
|
En fonction des intentions détectées par le NLU, les différentes actions sont routées et jouées.
|
||||||
|
|
||||||
|
## Réalisation
|
||||||
|
- Installer et configurer Ollama
|
||||||
|
- Créer et configurer l'environnement Rasa
|
||||||
|
- Créer les intentions, les stories, les règles et leur liaison aux actions.
|
||||||
|
- Créer les actions déclenchées en Python.
|
||||||
|
- Entraîner le modèle sur les intentions dans Rasa.
|
||||||
|
- Monter l'infrastructure.
|
||||||
|
- Interagir avec le chatbot et tester la bonne exécution des actions.
|
||||||
|
|
||||||
|
# Réalisation du PoC
|
||||||
|
|
||||||
|
## Prérequis
|
||||||
|
Les technologies utilisées sont accessibles librement ou gratuitement (API, technologies).
|
||||||
|
|
||||||
|
Les programmes suivants doivent être installés :
|
||||||
|
- Python 3.10 doit être installé sur la machine.
|
||||||
|
|
||||||
|
## Installation d'Ollama
|
||||||
|
Ollama est une plateforme conçue pour faciliter l'utilisation et le déploiement de modèles de langage de type LLM (Large Language Models) localement sur des machines. Ollama propose une interface simple pour interagir avec différents modèles de langage.
|
||||||
|
|
||||||
|
L'installation d'Ollama va nous permettre d'utiliser localement un LLM. Ce concept étant fort intéressant pour la création d'un privacy LLM.
|
||||||
|
|
||||||
|
- Installer Ollama depuis cet [https://ollama.com/](https://ollama.com/).
|
||||||
|
|
||||||
|
- Téléchargez le modèle Llama 3.2 (par défaut, le modèle contenant 3,2 milliards de paramètres est téléchargé).
|
||||||
|
```sh
|
||||||
|
ollama pull llama3.2
|
||||||
|
```
|
||||||
|
|
||||||
|
- Essayer d'exécuter et de converser avec le modèle.
|
||||||
|
```sh
|
||||||
|
ollama run llama3.2
|
||||||
|
>>> Hello, comment ça va ?
|
||||||
|
'Bonjour ! Je vais bien, merci pour ta question. C est un plaisir de discuter avec toi en français ! Comment puis-je t aider
|
||||||
|
aujourd hui ?'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
> Ollama offre l'accès à sont API sur http://localhost:11434/api/generate
|
||||||
|
|
||||||
|
## Créer le projet rasa
|
||||||
|
Rasa est une plateforme open source de développement de chatbots et d'assistants virtuels qui utilise le traitement du langage naturel (NLP) pour comprendre les intentions des utilisateurs et gérer les dialogues. Elle permet de créer des modèles personnalisés et d'exécuter des actions en réponse aux demandes des utilisateurs, tout en offrant des fonctionnalités avancées comme la gestion des dialogues contextuels et l'intégration avec diverses API.
|
||||||
|
|
||||||
|
### Créer un environnement virtuel python
|
||||||
|
```sh
|
||||||
|
python3.10 -m venv ./venv
|
||||||
|
source ./venv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
> Dans cet exemple, j'utilise la version 3.10 de Python, car c'est celle qui est le mieux supportée.
|
||||||
|
|
||||||
|
### Installer les dépendances
|
||||||
|
```sh
|
||||||
|
pip insatll -r requirements.txt
|
||||||
|
```
|
||||||
|
### Création d'un nouveau projet rasa
|
||||||
|
```sh
|
||||||
|
mkdir rasa && cd rasa
|
||||||
|
rasa init
|
||||||
|
|
||||||
|
.
|
||||||
|
├── actions
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── __pycache__
|
||||||
|
│ │ ├── __init__.cpython-38.pyc
|
||||||
|
│ │ └── actions.cpython-38.pyc
|
||||||
|
│ └── actions.py
|
||||||
|
├── config.yml
|
||||||
|
├── credentials.yml
|
||||||
|
├── data
|
||||||
|
│ ├── nlu.yml
|
||||||
|
│ ├── rules.yml
|
||||||
|
│ └── stories.yml
|
||||||
|
├── domain.yml
|
||||||
|
├── endpoints.yml
|
||||||
|
├── models
|
||||||
|
│ └── 20241008-123922-metal-event.tar.gz
|
||||||
|
└── tests
|
||||||
|
└── test_stories.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Construire le projet
|
||||||
|
### nlu.yml
|
||||||
|
Le fichier `nlu.yml`permet de spécifier les intentions qui seront entraîner par le modèle NLU (Natural Language Processing) :
|
||||||
|
|
||||||
|
Nous avons donc 4 intentions :
|
||||||
|
- Générer un profil utilisateur par défaut (API)
|
||||||
|
- Discuter de manière générale avec le LLM
|
||||||
|
- Demander au LLM la signification d'un prénom
|
||||||
|
- Récupérer les informations d'une ville Suisse depuis un NPA (API)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.1"
|
||||||
|
|
||||||
|
nlu:
|
||||||
|
- intent: intent_randomuser
|
||||||
|
examples: |
|
||||||
|
- Génère moi un profil utilisateur
|
||||||
|
- Crée un profil d'utilisateur
|
||||||
|
- Peux-tu me donner un profil utilisateur aléatoire ?
|
||||||
|
- J'ai besoin d'un profil utilisateur
|
||||||
|
- Donne-moi un exemple de profil utilisateur
|
||||||
|
- Fais-moi un profil utilisateur
|
||||||
|
- Génère un profil utilisateur au hasard
|
||||||
|
- Crée un utilisateur aléatoire pour moi
|
||||||
|
- Est-ce que tu peux créer un profil utilisateur ?
|
||||||
|
|
||||||
|
- intent: intent_ask_llama
|
||||||
|
examples: |
|
||||||
|
- Qu'est-ce que tu sais sur les modèles de langage ?
|
||||||
|
- Comment fonctionne un ordinateur ?
|
||||||
|
- Quelle est la capitale de la France ?
|
||||||
|
|
||||||
|
- intent: intent_firstname_signification_by_llama
|
||||||
|
examples: |
|
||||||
|
- Que signifie mon prénom [Guillaume](firstname) ?
|
||||||
|
- Peux-tu me dire ce que signifie le prénom [Juliette](firstname) ?
|
||||||
|
- Quelle est la signification de [Emma](firstname) ?
|
||||||
|
- Explique-moi la signification du prénom [Lucas](firstname).
|
||||||
|
- Que veut dire le prénom [Sophie](firstname) ?
|
||||||
|
- Quelle est l'origine du prénom [Maxime](firstname) ?
|
||||||
|
- Dis-moi la signification de [Chloé](firstname).
|
||||||
|
- Que représente le prénom [Thomas](firstname) ?
|
||||||
|
- Je voudrais savoir ce que signifie le prénom [Camille](firstname).
|
||||||
|
- Que signifie le prénom [Alice](firstname) ?
|
||||||
|
|
||||||
|
- intent: intent_swiss_zipcode
|
||||||
|
examples: |
|
||||||
|
- Quel est le code postal en Suisse de ce numéro [1977](zipcode)
|
||||||
|
- Donne-moi le code postal de [1977](zipcode)
|
||||||
|
- Quel est le code postal pour [1977](zipcode) ?
|
||||||
|
```
|
||||||
|
|
||||||
|
> À noter que dans des expressions telle que ```[1977](zipcode)```, le modèle NLU sera capable de reconnaître que 1977 représente une valeur variable, ce qui lui permettra d'attribuer les valeurs de code postal fournies à la variable `zipcode`.
|
||||||
|
|
||||||
|
### stories.yml
|
||||||
|
Le fichier `stories.yml` permet de définir les scénarios d'interaction en spécifiant les séquences d'actions et d'intentions que le modèle doit apprendre pour simuler un dialogue.
|
||||||
|
|
||||||
|
Nous sommes face à des stories très simple, soit :
|
||||||
|
- Reconnaître l'intention
|
||||||
|
- Exécuter l'action associée
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.1"
|
||||||
|
stories:
|
||||||
|
- story: request_randomuser
|
||||||
|
steps:
|
||||||
|
- intent: intent_randomuser
|
||||||
|
- action: action_randomuser
|
||||||
|
|
||||||
|
- story: request_ask_llama
|
||||||
|
steps:
|
||||||
|
- intent: intent_ask_llama
|
||||||
|
- action: action_ask_llama
|
||||||
|
|
||||||
|
- story: request_firstname_signification_by_llama
|
||||||
|
steps:
|
||||||
|
- intent: intent_firstname_signification_by_llama
|
||||||
|
- action: action_firstname_signification_by_llama
|
||||||
|
|
||||||
|
- story: request_swiss_zipcode
|
||||||
|
steps:
|
||||||
|
- intent: intent_swiss_zipcode
|
||||||
|
- action: action_swiss_zipcode
|
||||||
|
```
|
||||||
|
> Il est tout à fait possible de complexifier les stories comme :
|
||||||
|
> - Rajouter des réponses dans le scénario de conversation
|
||||||
|
|
||||||
|
### rules.yml
|
||||||
|
Le fichier `rules.yml` permet de spécifier les règles qui guideront le comportement du modèle, en définissant des séquences d'actions et de conditions à suivre lors des interactions avec les utilisateurs.:
|
||||||
|
|
||||||
|
Nous avons donc une séquence, qui dans l'ordre va repérer les intentions pour :
|
||||||
|
1. Générer un profil utilisateur par défaut (API)
|
||||||
|
2. Discuter de manière générale avec le LLM
|
||||||
|
3. Demander au LLM la signification d'un prénom
|
||||||
|
4. Récupérer les informations d'une ville Suisse depuis un NPA (API)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.1"
|
||||||
|
rules:
|
||||||
|
- rule: rule__randomuser
|
||||||
|
steps:
|
||||||
|
- intent: intent_randomuser
|
||||||
|
- action: action_randomuser
|
||||||
|
|
||||||
|
- rule: rule_swiss_zipcode
|
||||||
|
steps:
|
||||||
|
- intent: intent_swiss_zipcode
|
||||||
|
- action: action_swiss_zipcode
|
||||||
|
|
||||||
|
- rule: rule_firstname_signification_by_llama
|
||||||
|
steps:
|
||||||
|
- intent: intent_firstname_signification_by_llama
|
||||||
|
- action: action_firstname_signification_by_llama
|
||||||
|
|
||||||
|
- rule: General question redirect to LLM
|
||||||
|
steps:
|
||||||
|
- intent: intent_ask_llama
|
||||||
|
- action: action_ask_llama
|
||||||
|
```
|
||||||
|
|
||||||
|
> Il est tout à fait possible de complexifier les rules comme :
|
||||||
|
> - Créer des boucles (remplissage de formulaires, input
|
||||||
|
> - Rajouter des conditions
|
||||||
|
|
||||||
|
### domain.yml
|
||||||
|
Le fichier `domain.ym` définit les éléments essentiels de l'application Rasa, y compris les intentions, les entités, les actions, les réponses et les configurations de dialogue, permettant ainsi au modèle de gérer les interactions avec les utilisateurs.
|
||||||
|
|
||||||
|
Il faut renseigner les éléments dans le fichier `domain.ym`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.1"
|
||||||
|
|
||||||
|
intents:
|
||||||
|
- intent_randomuser
|
||||||
|
- intent_ask_llama
|
||||||
|
- intent_swiss_zipcode
|
||||||
|
- intent_firstname_signification_by_llama
|
||||||
|
|
||||||
|
actions:
|
||||||
|
- action_randomuser
|
||||||
|
- action_ask_llama
|
||||||
|
- action_swiss_zipcode
|
||||||
|
- action_firstname_signification_by_llama
|
||||||
|
```
|
||||||
|
|
||||||
|
### actions.py
|
||||||
|
Le fichier `actions.py` contient les actions personnalisées que le modèle Rasa peut exécuter en réponse à des requêtes utilisateur. Ce fichier permet de définir des fonctions qui réalisent des tâches spécifiques, comme l'appel à des API, le traitement de données ou l'interaction avec des bases de données.
|
||||||
|
|
||||||
|
On retrouve nos fonctions :
|
||||||
|
|
||||||
|
- L'appel à `action_ask_llama`pour les questions générales
|
||||||
|
```python
|
||||||
|
# Action to ask to the Llama model
|
||||||
|
class ActionAskLlama(Action):
|
||||||
|
def name(self):
|
||||||
|
return "action_ask_llama"
|
||||||
|
|
||||||
|
def run(self, dispatcher, tracker, domain):
|
||||||
|
user_input = tracker.latest_message.get('text')
|
||||||
|
|
||||||
|
# Call API (Streaming)
|
||||||
|
url = "http://localhost:11434/api/generate"
|
||||||
|
payload = {
|
||||||
|
"model": "llama3.1",
|
||||||
|
"prompt": user_input
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, json=payload, stream=True)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
llm_response = ""
|
||||||
|
# Read the response line by line
|
||||||
|
for line in response.iter_lines():
|
||||||
|
if line:
|
||||||
|
json_line = line.decode('utf-8')
|
||||||
|
json_data = json.loads(json_line)
|
||||||
|
|
||||||
|
# Done flag for defining the end of the response
|
||||||
|
if json_data.get("done"):
|
||||||
|
break
|
||||||
|
llm_response += json_data.get("response", "")
|
||||||
|
dispatcher.utter_message(text=llm_response.strip())
|
||||||
|
else:
|
||||||
|
dispatcher.utter_message(text=f"Erreur lors de l'appel à Ollama: {response.status_code} - {response.text}")
|
||||||
|
except Exception as e:
|
||||||
|
dispatcher.utter_message(text=f"Une exception est survenue : {str(e)}")
|
||||||
|
|
||||||
|
return []
|
||||||
|
```
|
||||||
|
- L'appel à `action_randomuser`pour générer un profil aléatoire (API)
|
||||||
|
```python
|
||||||
|
class ActionRandomuser(Action):
|
||||||
|
def name(self):
|
||||||
|
return "action_randomuser"
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
- L'appel à `action_swiss_zipcode`pour récupérer les information d'une ville Suisse depuis un NPA
|
||||||
|
```python
|
||||||
|
class ActionGetZipcode(Action):
|
||||||
|
|
||||||
|
def name(self) -> str:
|
||||||
|
return "action_swiss_zipcode"
|
||||||
|
|
||||||
|
def run(self, dispatcher, tracker, domain):
|
||||||
|
zipcode = next(tracker.get_latest_entity_values("zipcode"), None)
|
||||||
|
with open('../logs.txt', 'a') as f:
|
||||||
|
f.write(zipcode + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
if zipcode:
|
||||||
|
url = f"https://api.zippopotam.us/ch/{zipcode}"
|
||||||
|
response = requests.get(url)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
places = data.get("places", [])
|
||||||
|
if places:
|
||||||
|
place_info = places[0]
|
||||||
|
city = place_info.get("place name")
|
||||||
|
state = place_info.get("state")
|
||||||
|
message = f"Le code postal {zipcode} correspond à {city}, {state}."
|
||||||
|
else:
|
||||||
|
message = f"Aucune information trouvée pour le code postal {zipcode}."
|
||||||
|
else:
|
||||||
|
message = f"Erreur lors de l'appel à l'API : {response.status_code}."
|
||||||
|
else:
|
||||||
|
message = "Je n'ai pas pu extraire le code postal."
|
||||||
|
|
||||||
|
dispatcher.utter_message(text=message)
|
||||||
|
return []
|
||||||
|
```
|
||||||
|
|
||||||
|
- L'appel à `action_firstname_signification_by_llama`pour connaître la signification d'un prénom.
|
||||||
|
```python
|
||||||
|
class ActionFirstnameSignificationLlama(Action):
|
||||||
|
def name(self):
|
||||||
|
return "action_firstname_signification_by_llama"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Entraîner le modèle rasa
|
||||||
|
Pour entraîner le modèle Rasa, utilisez la commande suivante :
|
||||||
|
```sh
|
||||||
|
rasa train
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tester le chatbot
|
||||||
|
### Lancer le chatbot
|
||||||
|
Pour teser le projet, exécuter la commande suivantes :
|
||||||
|
```sh
|
||||||
|
rasa run actions & rasa shell
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette commande :
|
||||||
|
- Démarre le serveur des actions
|
||||||
|
- Exécuter un shell interractif
|
||||||
|
|
||||||
|
### Tester le chabot
|
||||||
|

|
||||||
|
|
||||||
|
> À noter qu'une des fonctionnalités d'un NLU est l'automatisation et la transparence de la langue. C'est pourquoi la question en anglais est comprise, même si l'intention est en français.
|
||||||
|
|
|
||||||
BIN
doc_assets/chatbot_test.png
Normal file
BIN
doc_assets/chatbot_test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 321 KiB |
|
|
@ -1,5 +1 @@
|
||||||
rasa
|
rasa
|
||||||
fastapi
|
|
||||||
uvicorn
|
|
||||||
smtplib
|
|
||||||
pymilvus
|
|
||||||
Loading…
Reference in New Issue
Block a user