Skip to content

Commit 5c96b68

Browse files
authored
Issue/16 legacy code (#54)
* Refactory dialog to Watson alternative component * #16 Create Google adapter * #16 adjust output field
1 parent d20cbe9 commit 5c96b68

File tree

17 files changed

+168
-159
lines changed

17 files changed

+168
-159
lines changed

david/__main__.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
import david.config
55
from david.adapters.adapter import MessageAdapter
66
from david.assistant import Assistant
7-
from david.dialog import fetch_dialog
8-
from david.googleadap import GoogleWebHook
7+
from david.constants import CONFIG_DEFAULT_ADAPTER
98
from david.registry import Registry
109

1110
# from david.brain import fetch_model, fetch_know
@@ -14,14 +13,10 @@
1413
CORS(app)
1514

1615
# [TODO] This kwargs must from CLI args
17-
kwargs = {"default_adapter": MessageAdapter.name()}
16+
kwargs = {CONFIG_DEFAULT_ADAPTER: MessageAdapter.name()}
1817

1918
config = david.config.load(None, **kwargs)
20-
21-
Registry.registryAdapter(MessageAdapter)
22-
2319
assistant = Assistant(config)
24-
googleWH = GoogleWebHook(assistant)
2520

2621

2722
@app.route("/")
@@ -54,21 +49,6 @@ def dialog():
5449
return jsonify(responseData)
5550

5651

57-
@app.route("/google", methods=["POST"])
58-
def google():
59-
data = request.get_json()
60-
return jsonify(googleWH.handle(data))
61-
62-
63-
# @app.route('/data/dialog')
64-
# def data_dialog():
65-
# return jsonify(fetch_dialog())
66-
67-
# @app.route('/data/know')
68-
# def data_know():
69-
# return jsonify(fetch_know())
70-
71-
7252
def main() -> None:
7353
app.run(host="0.0.0.0")
7454

david/adapters/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from david.adapters.adapter import Adapter, MessageAdapter
2+
from david.adapters.adapters.google import GoogleAdapter

david/adapters/adapter.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from abc import abstractmethod
33
from typing import Dict, List, Text
44

5-
from david.registry import Module
5+
from david.registry import Module, Registry
66
from david.typing import Message
77

88

@@ -38,3 +38,6 @@ def input(cls, payload: Dict) -> Message:
3838
@classmethod
3939
def output(cls, message: Message) -> Dict:
4040
return message.__dict__
41+
42+
43+
Registry.registryAdapter(MessageAdapter)

david/adapters/adapters/__init__.py

Whitespace-only changes.

david/adapters/adapters/google.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from typing import Dict
2+
3+
from david.adapters.adapter import Adapter
4+
from david.constants import OUTPUT_TEXT_ATTRIBUTE
5+
from david.registry import Registry
6+
from david.typing import Message
7+
8+
9+
class GoogleAdapter(Adapter):
10+
@classmethod
11+
def name(cls):
12+
return "google"
13+
14+
@classmethod
15+
def validade_data(cls, payload: Dict) -> bool:
16+
return "queryResult" in payload and "queryText" in payload["queryResult"]
17+
18+
@classmethod
19+
def input(cls, payload: Dict) -> Message:
20+
input = payload["queryResult"]["queryText"]
21+
return Message.build(input)
22+
23+
@classmethod
24+
def output(cls, message: Message) -> Dict:
25+
text = message.get(OUTPUT_TEXT_ATTRIBUTE)
26+
return {"fulfillmentText": text}
27+
28+
29+
Registry.registryAdapter(GoogleAdapter)

david/assistant.py

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,33 @@
1-
from david.brain import Brain
1+
from david.components.dialogue import WatsonAlternative
2+
from david.components.nlu import SimpleNLU
23
from david.config import DavidConfig
3-
from david.constants import (
4-
CONTEXT_ATTRIBUTE,
5-
ENTITIES_ATTRIBUTE,
6-
INTENTS_ATTRIBUTE,
7-
TEXT_ATTRIBUTE,
8-
)
9-
from david.dialog import Dialog
4+
from david.constants import DEFAULT_DATA_PATH, DEFAULT_MODELS_PATH, TEXT_ATTRIBUTE
5+
from david.training_data.formats import JsonReader
6+
from david.typing import Message
7+
8+
MODEL_FILE = "intent_model.json"
9+
DIALOG_FILE = "dialog.json"
1010

1111

1212
class Assistant:
1313
def __init__(self, config: DavidConfig):
14-
self.brain = Brain(config)
15-
self.dialog = Dialog()
14+
self.config = config
15+
self.dialog = WatsonAlternative.load(
16+
{"file": DIALOG_FILE}, model_dir=DEFAULT_DATA_PATH
17+
)
18+
self.nlu = SimpleNLU.create({}, self.config)
1619
self.train()
1720

1821
def train(self):
19-
self.brain.train()
20-
self.dialog.train()
22+
training_data = JsonReader.load(self.config)
23+
self.nlu.train(training_data, self.config)
24+
self.nlu.persist(file_name=MODEL_FILE, model_dir=DEFAULT_MODELS_PATH)
2125

2226
def respond(self, message, context={}):
2327
text = message.get(TEXT_ATTRIBUTE)
28+
message = Message.build(text)
2429

25-
message = self.brain.process(text)
26-
27-
intents = message.get(INTENTS_ATTRIBUTE)
28-
entities = message.get(ENTITIES_ATTRIBUTE)
29-
context = message.get(CONTEXT_ATTRIBUTE)
30-
31-
# print("intents", intents)
32-
dialog_node = self.dialog.dialog(input, context, intents, entities)
33-
34-
message.output = dialog_node["output"]
35-
36-
# return {
37-
# "context": context,
38-
# "intents": intents,
39-
# "entities": entities,
40-
# "output": dialog_node["output"],
41-
# }
30+
self.nlu.process(message)
31+
self.dialog.process(message)
4232

4333
return message

david/brain.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

david/components/dialogue/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from david.components.dialogue.watsonalternative import WatsonAlternative
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import json
2+
import os
3+
from typing import Any, Dict, Optional, Text
4+
5+
from david.components.component import Component
6+
from david.constants import (
7+
CONTEXT_ATTRIBUTE,
8+
ENTITIES_ATTRIBUTE,
9+
INTENTS_ATTRIBUTE,
10+
OUTPUT_TEXT_ATTRIBUTE,
11+
TEXT_ATTRIBUTE,
12+
)
13+
from david.typing import Message
14+
from david.typing.model import Metadata
15+
16+
17+
def get_dialog_welcome(dialog_nodes):
18+
return dialog_nodes[0]
19+
20+
21+
def get_dialog_anythinelse(dialog_nodes):
22+
return dialog_nodes[len(dialog_nodes) - 1]
23+
24+
25+
def evalCondition(condition, context, intent, entities):
26+
return condition == "#" + intent
27+
28+
29+
class WatsonAlternative(Component):
30+
def __init__(
31+
self,
32+
component_config: Optional[Dict[Text, Any]] = None,
33+
dialog_nodes: Dict = None,
34+
) -> None:
35+
super().__init__(component_config)
36+
37+
self.dialog_nodes = dialog_nodes
38+
39+
@classmethod
40+
def load(
41+
cls,
42+
meta: Dict[Text, Any],
43+
model_dir: Optional[Text] = None,
44+
model_metadata: Optional["Metadata"] = None,
45+
cached_component: Optional["Component"] = None,
46+
**kwargs: Any,
47+
) -> "Component":
48+
"""Load this component from file.
49+
After a component has been trained, it will be persisted by
50+
calling `persist`. When the pipeline gets loaded again,
51+
this component needs to be able to restore itself.
52+
Components can rely on any context attributes that are
53+
created by :meth:`components.Component.create`
54+
calls to components previous
55+
to this one."""
56+
57+
file_name = meta.get("file")
58+
model_file = os.path.join(model_dir, file_name)
59+
60+
if os.path.exists(model_file):
61+
with open(model_file) as f:
62+
dialog_nodes = json.load(f)
63+
return cls(meta, dialog_nodes)
64+
else:
65+
return cls(meta)
66+
67+
def process(self, message: Message, **kwargs: Any) -> None:
68+
69+
text = message.get(TEXT_ATTRIBUTE)
70+
intents = message.get(INTENTS_ATTRIBUTE)
71+
entities = message.get(ENTITIES_ATTRIBUTE)
72+
context = message.get(CONTEXT_ATTRIBUTE)
73+
74+
dialog_node = self.__dialog(text, context, intents, entities)
75+
76+
message.set(OUTPUT_TEXT_ATTRIBUTE, dialog_node["output"]["text"])
77+
78+
def __dialog(self, input, context, intents, entities):
79+
if input == "":
80+
return get_dialog_welcome(self.dialog_nodes)
81+
82+
if len(intents) > 0:
83+
intent = intents[0]["intent"]
84+
for dialog_node in self.dialog_nodes:
85+
if evalCondition(dialog_node["condition"], context, intent, entities):
86+
return dialog_node
87+
88+
return get_dialog_anythinelse(self.dialog_nodes)

david/components/nlu/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from david.components.nlu.simplenlu import SimpleNLU

david/components/nlu/simplenlu.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ def simmilarity(a, b):
2323

2424

2525
class SimpleNLU(Component):
26-
def __init__(self):
27-
print("SimpleNLU")
28-
2926
def __init__(
3027
self,
3128
component_config: Optional[Dict[Text, Any]] = None,

david/constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
OUTPUT_TEXT_ATTRIBUTE = "output_text"
2+
13
TEXT_ATTRIBUTE = "text"
24

35
INTENTS_ATTRIBUTE = "intents"
@@ -8,10 +10,14 @@
810

911
DEFAULT_DATA_PATH = "data"
1012

13+
DEFAULT_MODELS_PATH = "models"
14+
1115
DEFAULT_CONFIG_PATH = "config.yml"
1216

1317
TRAIN_DATA_FILE = "know.json"
1418

1519
DEFAULT_LOG_LEVEL = "INFO"
1620

1721
ENV_LOG_LEVEL = "LOG_LEVEL"
22+
23+
CONFIG_DEFAULT_ADAPTER = "default_adapter"

david/dialog.py

Lines changed: 0 additions & 45 deletions
This file was deleted.

david/googleadap.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)