forked from microsoft/BotBuilder-Samples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
150 lines (126 loc) · 5.02 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import sys
import traceback
from datetime import datetime
from aiohttp import web
from aiohttp.web import Request, Response
from botbuilder.core import (
BotFrameworkAdapterSettings,
ConversationState,
MemoryStorage,
TurnContext,
BotFrameworkAdapter,
)
from botbuilder.core.integration import (
aiohttp_channel_service_routes,
aiohttp_error_middleware,
)
from botbuilder.core.skills import SkillHandler
from botbuilder.schema import Activity, ActivityTypes
from botframework.connector.auth import (
AuthenticationConfiguration,
SimpleCredentialProvider,
)
from bots.root_bot import ACTIVE_SKILL_PROPERTY_NAME
from skill_http_client import SkillHttpClient
from skill_conversation_id_factory import SkillConversationIdFactory
from authentication import AllowedSkillsClaimsValidator
from bots import RootBot
from config import DefaultConfig, SkillConfiguration
CONFIG = DefaultConfig()
SKILL_CONFIG = SkillConfiguration()
# Whitelist skills from SKILL_CONFIG
ALLOWED_CALLER_IDS = {s.app_id for s in [*SKILL_CONFIG.SKILLS.values()]}
CLAIMS_VALIDATOR = AllowedSkillsClaimsValidator(ALLOWED_CALLER_IDS)
AUTH_CONFIG = AuthenticationConfiguration(
claims_validator=CLAIMS_VALIDATOR.validate_claims
)
# Create adapter.
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
SETTINGS = BotFrameworkAdapterSettings(
app_id=CONFIG.APP_ID,
app_password=CONFIG.APP_PASSWORD,
auth_configuration=AUTH_CONFIG,
)
ADAPTER = BotFrameworkAdapter(SETTINGS)
STORAGE = MemoryStorage()
CONVERSATION_STATE = ConversationState(STORAGE)
ID_FACTORY = SkillConversationIdFactory(STORAGE)
CREDENTIAL_PROVIDER = SimpleCredentialProvider(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
CLIENT = SkillHttpClient(CREDENTIAL_PROVIDER, ID_FACTORY)
# Catch-all for errors.
async def on_error(context: TurnContext, error: Exception):
# This check writes out errors to console log .vs. app insights.
# NOTE: In production environment, you should consider logging this to Azure
# application insights.
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
traceback.print_exc()
# Send a message to the user
await context.send_activity("The bot encountered an error or bug.")
await context.send_activity(
"To continue to run this bot, please fix the bot source code."
)
# Send a trace activity if we're talking to the Bot Framework Emulator
if context.activity.channel_id == "emulator":
# Create a trace activity that contains the error object
trace_activity = Activity(
label="TurnError",
name="on_turn_error Trace",
timestamp=datetime.utcnow(),
type=ActivityTypes.trace,
value=f"{error}",
value_type="https://www.botframework.com/schemas/error",
)
await context.send_activity(trace_activity)
# Inform the active skill that the conversation is ended so that it has
# a chance to clean up.
# Note: ActiveSkillPropertyName is set by the RooBot while messages are being
# forwarded to a Skill.
active_skill_id = await CONVERSATION_STATE.create_property(ACTIVE_SKILL_PROPERTY_NAME).get(context)
if active_skill_id:
end_of_conversation = Activity(
type=ActivityTypes.end_of_conversation, code="RootSkillError"
)
TurnContext.apply_conversation_reference(
end_of_conversation,
TurnContext.get_conversation_reference(context.activity),
is_incoming=True
)
await CONVERSATION_STATE.save_changes(context, True)
await CLIENT.post_activity(
CONFIG.APP_ID,
SKILL_CONFIG.SKILLS[active_skill_id],
SKILL_CONFIG.SKILL_HOST_ENDPOINT,
end_of_conversation,
)
# Clear out state
await CONVERSATION_STATE.delete(context)
ADAPTER.on_turn_error = on_error
# Create the Bot
BOT = RootBot(CONVERSATION_STATE, SKILL_CONFIG, CLIENT, CONFIG)
SKILL_HANDLER = SkillHandler(
ADAPTER, BOT, ID_FACTORY, CREDENTIAL_PROVIDER, AuthenticationConfiguration()
)
# Listen for incoming requests on /api/messages
async def messages(req: Request) -> Response:
# Main bot message handler.
if "application/json" in req.headers["Content-Type"]:
body = await req.json()
else:
return Response(status=415)
activity = Activity().deserialize(body)
auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""
try:
await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
return Response(status=201)
except Exception as exception:
raise exception
APP = web.Application(middlewares=[aiohttp_error_middleware])
APP.router.add_post("/api/messages", messages)
APP.router.add_routes(aiohttp_channel_service_routes(SKILL_HANDLER, "/api/skills"))
if __name__ == "__main__":
try:
web.run_app(APP, host="localhost", port=CONFIG.PORT)
except Exception as error:
raise error