Skip to content

Commit

Permalink
Merge pull request microsoft#26 from Microsoft/johtaylo/adapter
Browse files Browse the repository at this point in the history
Merge johtaylo/adapter
  • Loading branch information
johnataylor authored Feb 22, 2018
2 parents b9554de + 19b0da4 commit 744570b
Show file tree
Hide file tree
Showing 18 changed files with 224 additions and 159 deletions.
1 change: 1 addition & 0 deletions libraries/botbuilder-ai/microsoft/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)
1 change: 1 addition & 0 deletions libraries/botbuilder-ai/microsoft/botbuilder/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)
16 changes: 16 additions & 0 deletions libraries/botbuilder-ai/microsoft/botbuilder/ai/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# coding=utf-8
#------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#------------------------------------------------------------------------

from .language_map import LanguageMap
from .qna_maker import QnAMaker, QnAMakerOptions, MetaData, QueryResult, QueryResults

__all__ = ['LanguageMap',
'QnAMaker',
'QnAMakerOptions',
'MetaData',
'QueryResult',
'QueryResults']
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ class QnAMaker:

def __init__(self, options, http_client):

self.__http_client = _http_client or raise TypeError('HTTP Client failed')
self.__options = options or raise TypeError('Options config error')
self.__http_client = _http_client or False
if not self.__http_client:
raise TypeError('HTTP Client failed')
self.__options = options or False
if not self.__options:
raise TypeError('Options config error')

self.__answerUrl = "%s%s/generateanswer" % (__qnaMakerServiceEndpoint,options.knowledge_base_id)

Expand All @@ -29,7 +33,7 @@ def __init__(self, options, http_client):

async def get_answers(question): # HTTP call
headers = {
__api_management_header : self.__options.subscription_key
__api_management_header : self.__options.subscription_key,
"Content-Type" : __json_mime_type
}

Expand Down
Empty file.
2 changes: 2 additions & 0 deletions libraries/botbuilder-ai/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[bdist_wheel]
universal=0
20 changes: 20 additions & 0 deletions libraries/botbuilder-ai/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from setuptools import setup, find_packages

setup(
name='microsoft-botbuilder-ai',
version='4.0.0-a0',
url='https://www.github.com/Microsoft/botbuilder-python',
long_description='Cognitive services extensions for Microsoft BotBuilder.',
license='MIT',
author='Microsoft',
author_email='bf-reports@microsoft.com',
description='',
packages=find_packages(),
classifiers=[
'Programming Language :: Python',
'Intended Audience :: Bot Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3'
]
)
20 changes: 6 additions & 14 deletions libraries/botbuilder/microsoft/botbuilder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,13 @@
# --------------------------------------------------------------------------


from .activity import ACTIVITY_TYPES, ATTACHMENT_LAYOUTS, END_OF_CONVERSATION_CODES, TEXT_FORMATS
from .activity_adapter import ActivityAdapter
from .card_styler import CardStyler, ContentTypes
from .assertions import BotAssert
from .bot_framework_adapter import BotFrameworkAdapter
from .card_styler import CardStyler, ContentTypes

__all__ = ['activity',
'activity_adapter',
'assertions',
'card_styler',
'ACTIVITY_TYPES',
'ATTACHMENT_LAYOUTS',
'END_OF_CONVERSATION_CODES',
'TEXT_FORMATS',
'ActivityAdapter',
__all__ = ['ActivityAdapter',
'BotAssert',
'BotFrameworkAdapter',
'CardStyler',
'ContentTypes',
'BotAssert']

'ContentTypes',]
97 changes: 0 additions & 97 deletions libraries/botbuilder/microsoft/botbuilder/activity.py

This file was deleted.

26 changes: 6 additions & 20 deletions libraries/botbuilder/microsoft/botbuilder/activity_adapter.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from abc import ABC, abstractmethod
from typing import List
from microsoft.botbuilder.schema import Activity

from abc import ABCMeta, abstractmethod


class ActivityAdapter(ABCMeta):
class ActivityAdapter(ABC):
@abstractmethod
def on_receive(cls, activity):
"""
Handler that returns incoming activities to a single consumer. The `Bot` will set this
when the adapter is passed to its constructor. Just keep in mind that should the bots
adapter be replaced (like when running unit tests) this handler can end up being set
back to undefined.
:param activity:
:return:
"""
pass
def send(self, activities: List[Activity]): pass

@abstractmethod
def post(cls, activities):
"""
Called by a consumer to send outgoing set of activities to a user.
:param activities:
:return:
"""
pass
def receive(self, auth_header: str, activity: Activity): pass
33 changes: 33 additions & 0 deletions libraries/botbuilder/microsoft/botbuilder/bot_framework_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import asyncio
from typing import List
from microsoft.botbuilder.schema import Activity
from microsoft.botframework.connector import ConnectorClient
from microsoft.botframework.connector.auth import (MicrosoftAppCredentials,
JwtTokenValidation, SimpleCredentialProvider)

from .activity_adapter import ActivityAdapter

class BotFrameworkAdapter(ActivityAdapter):

def __init__(self, app_id: str, app_password: str):
self._credentials = MicrosoftAppCredentials(app_id, app_password)
self._credential_provider = SimpleCredentialProvider(app_id, app_password)
self.on_receive = None

def send(self, activities: List[Activity]):
for activity in activities:
connector = ConnectorClient(self._credentials, base_url=activity.service_url)
connector.conversations.send_to_conversation(activity.conversation.id, activity)

def receive(self, auth_header: str, activity: Activity):
loop = asyncio.new_event_loop()
try:
loop.run_until_complete(JwtTokenValidation.assert_valid_activity(
activity, auth_header, self._credential_provider))
finally:
loop.close()
if self.on_receive is not None:
self.on_receive(activity)
4 changes: 2 additions & 2 deletions libraries/botbuilder/microsoft/botbuilder/card_styler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
# Licensed under the MIT License.


import enum
from enum import Enum
from copy import deepcopy


class ContentTypes(enum):
class ContentTypes(Enum):
"""List of content types for each card style."""
adaptive_card = 'application/vnd.microsoft.card.adaptive'
animation_card = 'application/vnd.microsoft.card.animation'
Expand Down
9 changes: 9 additions & 0 deletions samples/Echo.Connector.Bot.Adapter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#### Echo Connector Bot

To run this sample:

```
python main.py
```

and you can test with the Bot FRamework Emulator by connecting to http://localhost:9000
32 changes: 32 additions & 0 deletions samples/Echo.Connector.Bot.Adapter/bot_framework_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import asyncio
from typing import List
from microsoft.botbuilder.schema import Activity
from microsoft.botframework.connector import ConnectorClient
from microsoft.botframework.connector.auth import (MicrosoftAppCredentials,
JwtTokenValidation, SimpleCredentialProvider)


class BotFrameworkAdapter:

def __init__(self, app_id: str, app_password: str):
self._credentials = MicrosoftAppCredentials(app_id, app_password)
self._credential_provider = SimpleCredentialProvider(app_id, app_password)
self.on_receive = None

def send(self, activities: List[Activity]):
for activity in activities:
connector = ConnectorClient(self._credentials, base_url=activity.service_url)
connector.conversations.send_to_conversation(activity.conversation.id, activity)

def receive(self, auth_header: str, activity: Activity):
loop = asyncio.new_event_loop()
try:
loop.run_until_complete(JwtTokenValidation.assert_valid_activity(
activity, auth_header, self._credential_provider))
finally:
loop.close()
if self.on_receive is not None:
self.on_receive(activity)
65 changes: 65 additions & 0 deletions samples/Echo.Connector.Bot.Adapter/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import http.server
import json
import asyncio
from microsoft.botbuilder.schema import (Activity, ActivityTypes, ChannelAccount)
from microsoft.botbuilder import BotFrameworkAdapter

APP_ID = ''
APP_PASSWORD = ''


class BotRequestHandler(http.server.BaseHTTPRequestHandler):

@staticmethod
def __create_reply_activity(request_activity, text):
return Activity(
type=ActivityTypes.message,
channel_id=request_activity.channel_id,
conversation=request_activity.conversation,
recipient=request_activity.from_property,
from_property=request_activity.recipient,
text=text,
service_url=request_activity.service_url)

def __handle_conversation_update_activity(self, activity: Activity):
self.send_response(202)
self.end_headers()
if activity.members_added[0].id != activity.recipient.id:
self._adapter.send([BotRequestHandler.__create_reply_activity(activity, 'Hello and welcome to the echo bot!')])

def __handle_message_activity(self, activity: Activity):
self.send_response(200)
self.end_headers()
self._adapter.send([BotRequestHandler.__create_reply_activity(activity, 'You said: %s' % activity.text)])

def __unhandled_activity(self):
self.send_response(404)
self.end_headers()

def on_receive(self, activity: Activity):
if activity.type == ActivityTypes.conversation_update.value:
self.__handle_conversation_update_activity(activity)
elif activity.type == ActivityTypes.message.value:
self.__handle_message_activity(activity)
else:
self.__unhandled_activity()

def do_POST(self):
body = self.rfile.read(int(self.headers['Content-Length']))
data = json.loads(str(body, 'utf-8'))
activity = Activity.deserialize(data)
self._adapter = BotFrameworkAdapter(APP_ID, APP_PASSWORD)
self._adapter.on_receive = getattr(self, 'on_receive')
self._adapter.receive(self.headers.get("Authorization"), activity)


try:
SERVER = http.server.HTTPServer(('localhost', 9000), BotRequestHandler)
print('Started http server')
SERVER.serve_forever()
except KeyboardInterrupt:
print('^C received, shutting down server')
SERVER.socket.close()
2 changes: 2 additions & 0 deletions samples/Echo.Connector.Bot.Adapter/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
../../libraries/botbuilder-schema/
../../libraries/botframework-connector/
Loading

0 comments on commit 744570b

Please sign in to comment.