feat: add chatbot config and exercise
This commit is contained in:
parent
f039d6462b
commit
5996ff712a
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
FROM python:3.12.3
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY chatbot/ chatbot/
|
||||
|
||||
WORKDIR /app/chatbot
|
||||
|
||||
CMD ["python", "main.py"]
|
41
README.md
41
README.md
@ -0,0 +1,41 @@
|
||||
# Systemy dialogowe - sklep internetowy
|
||||
|
||||
## Requirements
|
||||
|
||||
Docker version 20.\*+
|
||||
|
||||
## Installation
|
||||
|
||||
Make sure that you Docker is running now.
|
||||
|
||||
`docker build -t chatbot .`
|
||||
|
||||
There is always possibilit to run it without Docker.
|
||||
List of the required library we can find inside:
|
||||
|
||||
`requirements.txt`
|
||||
|
||||
or by:
|
||||
|
||||
`pip install requirements.txt`
|
||||
|
||||
## Development and usage
|
||||
|
||||
We can run script
|
||||
|
||||
`sh run.sh`
|
||||
|
||||
or
|
||||
|
||||
`docker run -it --rm -p 8888:8888 chatbot`
|
||||
|
||||
On both cases we are mapping our src directory to workdir inside Docker to always run the newest code.
|
||||
|
||||
## Contributors
|
||||
|
||||
| Team member |
|
||||
|----------------|
|
||||
| Mikołaj Gawron |
|
||||
| |
|
||||
| |
|
||||
| |
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"data_path": "./data/intents.json"
|
||||
}
|
4
chatbot/config/config.json
Normal file
4
chatbot/config/config.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"data_path": "./data/intents.json",
|
||||
"responses_path": "./data/response.json"
|
||||
}
|
@ -1,26 +1,22 @@
|
||||
from modules.nlp import NaturalLanguageProcessor, Config
|
||||
from modules.state_monitor import DialogueStateMonitor
|
||||
from modules.strategy import DialogueStrategy
|
||||
from modules.generator import NaturalLanguageGenerator
|
||||
from pathlib import Path
|
||||
from modules.nlp import NaturalLanguageProcessor
|
||||
from modules.generator import ResponseGenerator
|
||||
from modules.config import Config
|
||||
import colorama
|
||||
from colorama import Fore, Style
|
||||
|
||||
colorama.init(autoreset=True)
|
||||
|
||||
|
||||
def chatbot_response(input_text: str, nlp: NaturalLanguageProcessor) -> str:
|
||||
dialogue_monitor = DialogueStateMonitor()
|
||||
analysis = nlp.analyze(input_text)
|
||||
dialogue_monitor.update_state(analysis['intent'])
|
||||
response = DialogueStrategy.decide_response(dialogue_monitor.state)
|
||||
final_response = NaturalLanguageGenerator.generate(response)
|
||||
def main():
|
||||
base_path = Path(__file__).resolve().parent
|
||||
config_path = base_path / 'config' / 'config.json'
|
||||
config = Config.load_config(config_path)
|
||||
|
||||
return final_response
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
config = Config()
|
||||
nlp = NaturalLanguageProcessor(config)
|
||||
generator = ResponseGenerator(config)
|
||||
|
||||
print(Fore.CYAN + "Witaj w chatbocie! Rozpocznij rozmowę.")
|
||||
print(Fore.YELLOW + "Wpisz 'quit' aby zakończyć program.\n")
|
||||
|
||||
while True:
|
||||
@ -29,4 +25,10 @@ if __name__ == "__main__":
|
||||
print(Fore.RED + "Zamykanie chatbota...")
|
||||
break
|
||||
|
||||
print(Fore.CYAN + "Bot: " + chatbot_response(user_input, nlp))
|
||||
intent = nlp.analyze(user_input)
|
||||
response = generator.generate(intent)
|
||||
print(Fore.CYAN + "Bot: " + response)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
0
chatbot/modules/__init__.py
Normal file
0
chatbot/modules/__init__.py
Normal file
24
chatbot/modules/config.py
Normal file
24
chatbot/modules/config.py
Normal file
@ -0,0 +1,24 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
data_path: Path
|
||||
responses_path: Path
|
||||
|
||||
@classmethod
|
||||
def load_config(cls, config_path: Path) -> 'Config':
|
||||
try:
|
||||
with config_path.open('r', encoding='utf-8') as config_file:
|
||||
config_data = json.load(config_file)
|
||||
return cls(**config_data)
|
||||
except FileNotFoundError:
|
||||
print("Config file not found.")
|
||||
exit(1)
|
||||
except json.JSONDecodeError:
|
||||
print("Invalid JSON.")
|
||||
exit(1)
|
||||
except ValidationError as e:
|
||||
print(f"Configuration validation error: {e}")
|
||||
exit(1)
|
@ -1,4 +1,13 @@
|
||||
class NaturalLanguageGenerator:
|
||||
@staticmethod
|
||||
def generate(response: str) -> str:
|
||||
return response
|
||||
import json
|
||||
from typing import Dict
|
||||
from .config import Config
|
||||
import random
|
||||
|
||||
|
||||
class ResponseGenerator:
|
||||
def __init__(self, config: Config):
|
||||
with config.responses_path.open('r', encoding='utf-8') as file:
|
||||
self.responses: Dict[str, list] = json.load(file)
|
||||
|
||||
def generate(self, response_key: str) -> str:
|
||||
return random.choice(self.responses.get(response_key, ["Przepraszam, nie rozumiem. Możesz to powtórzyć?"]))
|
||||
|
@ -1,38 +1,20 @@
|
||||
import json
|
||||
import os
|
||||
from typing import Any, Dict, Literal
|
||||
from typing import Dict, List, TypedDict
|
||||
from .config import Config
|
||||
|
||||
|
||||
class Config:
|
||||
def __init__(self) -> None:
|
||||
try:
|
||||
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config.json')
|
||||
with open(config_path, 'r', encoding='utf-8') as config_file:
|
||||
self.config_data: Dict[str, Any] = json.load(config_file)
|
||||
except FileNotFoundError:
|
||||
print("Config file not found.")
|
||||
self.config_data = {}
|
||||
except json.JSONDecodeError:
|
||||
print("Invalid JSON.")
|
||||
self.config_data = {}
|
||||
|
||||
def get_data_path(self) -> str:
|
||||
data_path = self.config_data.get('data_path', '')
|
||||
if not isinstance(data_path, str):
|
||||
raise ValueError("Data path must be a string.")
|
||||
return os.path.join(os.path.dirname(os.path.dirname(__file__)), data_path)
|
||||
class Intents(TypedDict):
|
||||
name_query: List[str]
|
||||
|
||||
|
||||
class NaturalLanguageProcessor:
|
||||
def __init__(self, config: Config) -> None:
|
||||
self.config = config
|
||||
data_path = self.config.get_data_path()
|
||||
with open(data_path, 'r', encoding='utf-8') as file:
|
||||
self.intents: Dict[str, Any] = json.load(file)
|
||||
def __init__(self, config: Config):
|
||||
with config.data_path.open('r', encoding='utf-8') as file:
|
||||
self.intents: Intents = json.load(file)
|
||||
|
||||
def analyze(self, input_text: str) -> Dict[str, Literal['ask_name', 'unknown']]:
|
||||
def analyze(self, input_text: str) -> str:
|
||||
lower_text = input_text.lower()
|
||||
for phrase in self.intents.get('name_query', []):
|
||||
if phrase in lower_text:
|
||||
return {"intent": "ask_name"}
|
||||
return {"intent": "unknown"}
|
||||
for intent, phrases in self.intents.items():
|
||||
if any(phrase in lower_text for phrase in phrases):
|
||||
return intent
|
||||
return "unknown"
|
||||
|
@ -1,7 +1,8 @@
|
||||
import random
|
||||
|
||||
|
||||
class DialogueStrategy:
|
||||
@staticmethod
|
||||
def decide_response(state: dict) -> str:
|
||||
if state['last_intent'] == 'ask_name':
|
||||
return "Witaj, nazywam się Dia."
|
||||
else:
|
||||
return "Przepraszam, nie rozumiem. Możesz to powtórzyć?"
|
||||
def decide_response(state: dict, responses) -> str:
|
||||
intent_responses = responses.get(state['last_intent'], ["Przepraszam, nie rozumiem. Możesz to powtórzyć?"])
|
||||
return random.choice(intent_responses)
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
import re
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from chatbot.modules.nlu import NLU
|
||||
from modules.nlu import NLU
|
||||
|
||||
rows = 0
|
||||
hits = 0
|
||||
|
0
modules/__init__.py
Normal file
0
modules/__init__.py
Normal file
@ -1,10 +1,6 @@
|
||||
import copy
|
||||
from copy import deepcopy
|
||||
import json
|
||||
import os
|
||||
import jsgf
|
||||
|
||||
|
||||
class NLU:
|
||||
def __init__(self):
|
||||
self.grammars = [
|
@ -0,0 +1,4 @@
|
||||
colorama~=0.4.6
|
||||
pydantic~=2.7.0
|
||||
pandas~=1.5.3
|
||||
numpy~=1.26.4
|
Loading…
Reference in New Issue
Block a user