Skip to content

Commit

Permalink
Issue/19 edge adapter (#36)
Browse files Browse the repository at this point in the history
* message adapter

* Invalid Input Error

* change adapter load mode to simple registry mode

* Create registry

* adjust lint

* Suport adapter query param
  • Loading branch information
ralphg6 committed Feb 4, 2020
1 parent 138d743 commit bfb535c
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 11 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ clean:
rm -rf docs/_build

formatter:
isort -rc -q david tests
black david tests

lint:
Expand Down
22 changes: 19 additions & 3 deletions david/__main__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from flask import Flask, jsonify, request
from flask import Flask, abort, jsonify, make_response, request
from flask_cors import CORS

from david.assistant import Assistant
from david.dialog import fetch_dialog
from david.googleadap import GoogleWebHook
from david.registry import Registry

# from david.brain import fetch_model, fetch_know

Expand All @@ -13,6 +14,8 @@
assistant = Assistant()
googleWH = GoogleWebHook(assistant)

registry = Registry.get_instance()


@app.route("/")
def hi():
Expand All @@ -27,8 +30,21 @@ def train():

@app.route("/dialog", methods=["POST"])
def dialog():
data = request.get_json()
return jsonify(assistant.respond(data["input"]).__dict__)
requestData = request.get_json()

adapterName = request.args.get("adapter")
adapter = registry.getAdapter(adapterName)

if not adapter:
abort(400, "Invalid adapter")

if not adapter.validade_data(requestData):
abort(400, "Invalid input")

messageIn = adapter.input(requestData)
messageOut = assistant.respond(messageIn)
responseData = adapter.output(messageOut)
return jsonify(responseData)


@app.route("/google", methods=["POST"])
Expand Down
36 changes: 36 additions & 0 deletions david/adapters/adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import json
from typing import Dict, List, Text

from david.typing import Message


class Adapter:
@property
def name(self):
"""The name property is a function of the class - its __name__."""

return self.__class__.__name__

def validade_data(self, payload: Dict) -> bool:
raise NotImplementedError

def input(self, payload: Dict) -> Message:
raise NotImplementedError

def output(self, message: Message) -> Dict:
raise NotImplementedError


class MessageAdapter(Adapter):
@property
def name(self):
return "message"

def validade_data(self, payload: Dict) -> bool:
return "input" in payload and "text" in payload["input"]

def input(self, payload: Dict) -> Message:
return Message.build(payload=payload)

def output(self, message: Message) -> Dict:
return message.__dict__
13 changes: 10 additions & 3 deletions david/assistant.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from david.brain import Brain
from david.constants import CONTEXT_ATTRIBUTE, ENTITIES_ATTRIBUTE, INTENTS_ATTRIBUTE
from david.constants import (
CONTEXT_ATTRIBUTE,
ENTITIES_ATTRIBUTE,
INTENTS_ATTRIBUTE,
TEXT_ATTRIBUTE,
)
from david.dialog import Dialog


Expand All @@ -13,8 +18,10 @@ def train(self):
self.brain.train()
self.dialog.train()

def respond(self, input, context={}):
message = self.brain.process(input)
def respond(self, message, context={}):
text = message.get(TEXT_ATTRIBUTE)

message = self.brain.process(text)

intents = message.get(INTENTS_ATTRIBUTE)
entities = message.get(ENTITIES_ATTRIBUTE)
Expand Down
4 changes: 2 additions & 2 deletions david/components/nlu/simplenlu.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import david.util as util
from david.components import Component
from david.config import DavidConfig
from david.constants import INTENTS_ATTRIBUTE
from david.constants import INTENTS_ATTRIBUTE, TEXT_ATTRIBUTE
from david.typing import Message, TrainingData
from david.typing.model import Metadata

Expand Down Expand Up @@ -91,7 +91,7 @@ def persist(self, file_name: Text, model_dir: Text) -> Optional[Dict[Text, Any]]

def process(self, message: Message, **kwargs: Any) -> None:

input = message.text
input = message.get(TEXT_ATTRIBUTE)

tokens = util.tokenize(input)
# print ("tokens", tokens)
Expand Down
38 changes: 38 additions & 0 deletions david/registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from david.adapters.adapter import Adapter, MessageAdapter


# [TODO] refactory as generic registry
class Registry:

_instance = None

adapters = {}

def __init__(self, defaultAdapter=None):

messageAdapter = MessageAdapter()
self.registryAdapter(messageAdapter)

if defaultAdapter:
self.defaultAdapter = defaultAdapter
else:
self.defaultAdapter = messageAdapter.name

@classmethod
def get_instance(cls):
if not cls._instance:
cls._instance = Registry()
return cls._instance

def registryAdapter(self, adapter: Adapter):
self.adapters[adapter.name] = adapter

def getAdapter(self, adapterName=None):

if not adapterName:
adapterName = self.defaultAdapter

if adapterName in self.adapters:
return self.adapters[adapterName]

return
16 changes: 13 additions & 3 deletions david/typing/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

class Message:
def __init__(self, text: Text, context=None, data={}, time=None):
self.text = text
self.input = {}
self.input["text"] = text
self.context = context
self.time = time
self.data = data
Expand All @@ -26,19 +27,28 @@ def set(self, prop, info, add_to_output=False) -> None:

def get(self, prop, default=None) -> Any:
if prop == TEXT_ATTRIBUTE:
return self.text
return self.input["text"]
return self.data.get(prop, default)

@classmethod
def build(cls, text, intents=None, entities=None, context=None) -> "Message":
def build(
cls, text=None, intents=None, entities=None, context=None, payload=None
) -> "Message":
data = {}

if intents:
# split_intent, response_key = cls.separate_intent_response_key(intent)
data[INTENTS_ATTRIBUTE] = intents
# if response_key:
# data[RESPONSE_KEY_ATTRIBUTE] = response_key

if entities:
data[ENTITIES_ATTRIBUTE] = entities

if context:
data[CONTEXT_ATTRIBUTE] = context

if not text:
text = payload["input"]["text"]

return cls(text, data)

0 comments on commit bfb535c

Please sign in to comment.