8000 Merge pull request #26 from Microsoft/johtaylo/adapter · microsoft/botbuilder-python@744570b · GitHub
[go: up one dir, main page]

Skip to content

Commit 744570b

Browse files
authored
Merge pull request #26 from Microsoft/johtaylo/adapter
Merge johtaylo/adapter
2 parents b9554de + 19b0da4 commit 744570b

File tree

18 files changed

+224
-159
lines changed

18 files changed

+224
-159
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__import__('pkg_resources').declare_namespace(__name__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__import__('pkg_resources').declare_namespace(__name__)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# coding=utf-8
2+
#------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See License.txt in the project root for
5+
# license information.
6+
#------------------------------------------------------------------------
7+
8+
from .language_map import LanguageMap
9+
from .qna_maker import QnAMaker, QnAMakerOptions, MetaData, QueryResult, QueryResults
10+
11+
__all__ = ['LanguageMap',
12+
'QnAMaker',
13+
'QnAMakerOptions',
14+
'MetaData',
15+
'QueryResult',
16+
'QueryResults']

libraries/botbuilder-ai/microsoft/botbuilder/qna_maker.py renamed to libraries/botbuilder-ai/microsoft/botbuilder/ai/qna_maker.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ class QnAMaker:
1010

1111
def __init__(self, options, http_client):
1212

13-
self.__http_client = _http_client or raise TypeError('HTTP Client failed')
14-
self.__options = options or raise TypeError('Options config error')
13+
self.__http_client = _http_client or False
14+
if not self.__http_client:
15+
raise TypeError('HTTP Client failed')
16+
self.__options = options or False
17+
if not self.__options:
18+
raise TypeError('Options config error')
1519

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

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

3034
async def get_answers(question): # HTTP call
3135
headers = {
32-
__api_management_header : self.__options.subscription_key
36+
__api_management_header : self.__options.subscription_key,
3337
"Content-Type" : __json_mime_type
3438
}
3539

libraries/botbuilder-ai/requirements.txt

Whitespace-only changes.

libraries/botbuilder-ai/setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[bdist_wheel]
2+
universal=0

libraries/botbuilder-ai/setup.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from setuptools import setup, find_packages
2+
3+
setup(
4+
name='microsoft-botbuilder-ai',
5+
version='4.0.0-a0',
6+
url='https://www.github.com/Microsoft/botbuilder-python',
7+
long_description='Cognitive services extensions for Microsoft BotBuilder.',
8+
license='MIT',
9+
author='Microsoft',
10+
author_email='bf-reports@microsoft.com',
11+
description='',
12+
packages=find_packages(),
13+
classifiers=[
14+
'Programming Language :: Python',
15+
'Intended Audience :: Bot Developers',
16+
'License :: OSI Approved :: MIT License',
17+
'Operating System :: OS Independent',
18+
'Programming Language :: Python :: 3'
19+
]
20+
)

libraries/botbuilder/microsoft/botbuilder/__init__.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,13 @@
66
# --------------------------------------------------------------------------
77

88

9-
from .activity import ACTIVITY_TYPES, ATTACHMENT_LAYOUTS, END_OF_CONVERSATION_CODES, TEXT_FORMATS
109
from .activity_adapter import ActivityAdapter
11-
from .card_styler import CardStyler, ContentTypes
1210
from .assertions import BotAssert
11+
from .bot_framework_adapter import BotFrameworkAdapter
12+
from .card_styler import CardStyler, ContentTypes
1313

14-
__all__ = ['activity',
15-
'activity_adapter',
16-
'assertions',
17-
'card_styler',
18-
'ACTIVITY_TYPES',
19-
'ATTACHMENT_LAYOUTS',
20-
'END_OF_CONVERSATION_CODES',
21-
'TEXT_FORMATS',
22-
'ActivityAdapter',
14+
__all__ = ['ActivityAdapter',
15+
'BotAssert',
16+
'BotFrameworkAdapter',
2317
'CardStyler',
24-
'ContentTypes',
25-
'BotAssert']
26-
18+
'ContentTypes',]

libraries/botbuilder/microsoft/botbuilder/activity.py

Lines changed: 0 additions & 97 deletions
This file was deleted.
Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,14 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4+
from abc import ABC, abstractmethod
5+
from typing import List
6+
from microsoft.botbuilder.schema import Activity
47

5-
from abc import ABCMeta, abstractmethod
68

7-
8-
class ActivityAdapter(ABCMeta):
9+
class ActivityAdapter(ABC):
910
@abstractmethod
10-
def on_receive(cls, activity):
11-
"""
12-
Handler that returns incoming activities to a single consumer. The `Bot` will set this
13-
when the adapter is passed to its constructor. Just keep in mind that should the bots
14-
adapter be replaced (like when running unit tests) this handler can end up being set
15-
back to undefined.
16-
:param activity:
17-
:return:
18-
"""
19-
pass
11+
def send(self, activities: List[Activity]): pass
2012

2113
@abstractmethod
22-
def post(cls, activities):
23-
"""
24-
Called by a consumer to send outgoing set of activities to a user.
25-
:param activities:
26-
:return:
27-
"""
28-
pass
14+
def receive(self, auth_header: str, activity: Activity): pass
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import asyncio
5+
from typing import List
6+
from microsoft.botbuilder.schema import Activity
7+
from microsoft.botframework.connector import ConnectorClient
8+
from microsoft.botframework.connector.auth import (MicrosoftAppCredentials,
9+
JwtTokenValidation, SimpleCredentialProvider)
10+
11+
from .activity_adapter import ActivityAdapter
12+
13+
class BotFrameworkAdapter(ActivityAdapter):
14+
15+
def __init__(self, app_id: str, app_password: str):
16+
self._credentials = MicrosoftAppCredentials(app_id, app_password)
17+
self._credential_provider = SimpleCredentialProvider(app_id, app_password)
18+
self.on_receive = None
19+
20+
def send(self, activities: List[Activity]):
21+
for activity in activities:
22+
connector = ConnectorClient(self._credentials, base_url=activity.service_url)
23+
connector.conversations.send_to_conversation(activity.conversation.id, activity)
24+
25+
def receive(self, auth_header: str, activity: Activity):
26+
loop = asyncio.new_event_loop()
27+
try:
28+
loop.run_until_complete(JwtTokenValidation.assert_valid_activity(
29+
activity, auth_header, self._credential_provider))
30+
finally:
31+
loop.close()
32+
if self.on_receive is not None:
33+
self.on_receive(activity)

libraries/botbuilder/microsoft/botbuilder/card_styler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
# Licensed under the MIT License.
33

44

5-
import enum
5+
from enum import Enum
66
from copy import deepcopy
77

88

9-
class ContentTypes(enum):
9+
class ContentTypes(Enum):
1010
"""List of content types for each card style."""
1111
adaptive_card = 'application/vnd.microsoft.card.adaptive'
1212
animation_card = 'application/vnd.microsoft.card.animation'
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#### Echo Connector Bot
2+
3+
To run this sample:
4+
5+
```
6+
python main.py
7+
```
8+
9+
and you can test with the Bot FRamework Emulator by connecting to http://localhost:9000
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import asyncio
5+
from typing import List
6+
from microsoft.botbuilder.schema import Activity
7+
from microsoft.botframework.connector import ConnectorClient
8+
from microsoft.botframework.connector.auth import (MicrosoftAppCredentials,
9+
JwtTokenValidation, SimpleCredentialProvider)
10+
11+
12+
class BotFrameworkAdapter:
13+
14+
def __init__(self, app_id: str, app_password: str):
15+
self._credentials = MicrosoftAppCredentials(app_id, app_password)
16+
self._credential_provider = SimpleCredentialProvider(app_id, app_password)
17+
self.on_receive = None
18+
19+
def send(self, activities: List[Activity]):
20+
for activity in activities:
21+
connector = ConnectorClient(self._credentials, base_url=activity.service_url)
22+
connector.conversations.send_to_conversation(activity.conversation.id, activity)
23+
24+
def receive(self, auth_header: str, activity: Activity):
25+
loop = asyncio.new_event_loop()
26+
try:
27+
loop.run_until_complete(JwtTokenValidation.assert_valid_activity(
28+
activity, auth_header, self._credential_provider))
29+
finally:
30+
loop.close()
31+
if self.on_receive is not None:
32+
self.on_receive(activity)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import http.server
5+
import json
6+
import asyncio
7+
from microsoft.botbuilder.schema import (Activity, ActivityTypes, ChannelAccount)
8+
from microsoft.botbuilder import BotFrameworkAdapter
9+
10+
APP_ID = ''
11+
APP_PASSWORD = ''
12+
13+
14+
class BotRequestHandler(http.server.BaseHTTPRequestHandler):
15+
16+
@staticmethod
17+
def __create_reply_activity(request_activity, text):
18+
return Activity(
19+
type=ActivityTypes.message,
20+
channel_id=request_activity.channel_id,
21+
conversation=request_activity.conversation,
22+
recipient=request_activity.from_property,
23+
from_property=request_activity.recipient,
24+
text=text,
25+
service_url=request_activity.service_url)
26+
27+
def __handle_conversation_update_activity(self, activity: Activity):
28+
self.send_response(202)
29+
self.end_headers()
30+
if activity.members_added[0].id != activity.recipient.id:
31+
self._adapter.send([BotRequestHandler.__create_reply_activity(activity, 'Hello and welcome to the echo bot!')])
32+
33+
def __handle_message_activity(self, activity: Activity):
34+
self.send_response(200)
35+
self.end_headers()
36+
self._adapter.send([BotRequestHandler.__create_reply_activity(activity, 'You said: %s' % activity.text)])
37+
38+
def __unhandled_activity(self):
39+
self.send_response(404)
40+
self.end_headers()
41+
42+
def on_receive(self, activity: Activity):
43+
if activity.type == ActivityTypes.conversation_update.value:
44+
self.__handle_conversation_update_activity(activity)
45+
elif activity.type == ActivityTypes.message.value:
46+
self.__handle_message_activity(activity)
47+
else:
48+
self.__unhandled_activity()
49+
50+
def do_POST(self):
51+
body = self.rfile.read(int(self.headers['Content-Length']))
52+
data = json.loads(str(body, 'utf-8'))
53+
activity = Activity.deserialize(data)
54+
self._adapter = BotFrameworkAdapter(APP_ID, APP_PASSWORD)
55+
self._adapter.on_receive = getattr(self, 'on_receive')
56+
self._adapter.receive(self.headers.get("Authorization"), activity)
57+
58+
59+
try:
60+
SERVER = http.server.HTTPServer(('localhost', 9000), BotRequestHandler)
61+
print('Started http server')
62+
SERVER.serve_forever()
63+
except KeyboardInterrupt:
64+
print('^C received, shutting down server')
65+
SERVER.socket.close()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
../../libraries/botbuilder-schema/
2+
../../libraries/botframework-connector/

0 commit comments

Comments
 (0)
0