8000 Merge pull request #509 from microsoft/josh/searchExtension · mmtrucefacts/botbuilder-python@8ff979a · GitHub
[go: up one dir, main page]

Skip to content

Commit 8ff979a

Browse files
authored
Merge pull request microsoft#509 from microsoft/josh/searchExtension
adding search extension scenario
2 parents ca8c2d1 + be2693b commit 8ff979a

File tree

9 files changed

+358
-0
lines changed

9 files changed

+358
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# RosterBot
2+
3+
Bot Framework v4 teams roster bot sample.
4+
5+
This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back.
6+
7+
## Running the sample
8+
- Clone the repository
9+
```bash
10+
git clone https://github.com/Microsoft/botbuilder-python.git
11+
```
12+
- Activate your desired virtual environment
13+
- Bring up a terminal, navigate to `botbuilder-python\samples\roster` folder
14+
- In the terminal, type `pip install -r requirements.txt`
15+
- In the terminal, type `python app.py`
16+
17+
## Testing the bot using Bot Framework Emulator
18+
[Microsoft Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
19+
20+
- Install the Bot Framework emulator from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)
21+
22+
### Connect to bot using Bot Framework Emulator
23+
- Launch Bot Framework Emulator
24+
- Paste this URL in the emulator window - http://localhost:3978/api/messages
25+
26+
## Further reading
27+
28+
- [Bot Framework Documentation](https://docs.botframework.com)
29+
- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0)
30+
- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import json
2+
import sys
3+
from datetime import datetime
4+
5+
from aiohttp import web
6+
from aiohttp.web import Request, Response, json_response
7+
8+
from botbuilder.core import (
9+
BotFrameworkAdapterSettings,
10+
TurnContext,
11+
BotFrameworkAdapter,
12+
)
13+
14+
from botbuilder.schema import Activity, ActivityTypes
15+
from bots import SearchBasedMessagingExtension
16+
from config import DefaultConfig
17+
18+
CONFIG = DefaultConfig()
19+
20+
# Create adapter.
21+
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
22+
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
23+
ADAPTER = BotFrameworkAdapter(SETTINGS)
24+
25+
# Catch-all for errors.
26+
async def on_error(context: TurnContext, error: Exception):
27+
# This check writes out errors to console log .vs. app insights.
28+
# NOTE: In production environment, you should consider logging this to Azure
29+
# application insights.
30+
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
31+
32+
# Send a message to the user
33+
await context.send_activity("The bot encountered an error or bug.")
34+
await context.send_activity(
35+
"To continue to run this bot, please fix the bot source code."
36+
)
37+
# Send a trace activity if we're talking to the Bot Framework Emulator
38+
if context.activity.channel_id == "emulator":
39+
# Create a trace activity that contains the error object
40+
trace_activity = Activity(
41+
label="TurnError",
42+
name="on_turn_error Trace",
43+
timestamp=datetime.utcnow(),
44+
type=ActivityTypes.trace,
45+
value=f"{error}",
46+
value_type="https://www.botframework.com/schemas/error",
47+
)
48+
49+
# Send a trace activity, which will be displayed in Bot Framework Emulator
50+
await context.send_activity(trace_activity)
51+
52+
ADAPTER.on_turn_error = on_error
53+
54+
# Create the Bot
55+
BOT = SearchBasedMessagingExtension()
56+
57+
# Listen for incoming requests on /api/messages
58+
async def messages(req: Request) -> Response:
59+
# Main bot message handler.
60+
if "application/json" in req.headers["Content-Type"]:
61+
body = await req.json()
62+
else:
63+
return Response(status=415)
64+
65+
activity = Activity().deserialize(body)
66+
auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""
67+
68+
try:
69+
response = await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
70+
if response:
71+
return json_response(data=response.body, status=response.status)
72+
return Response(status=201)
73+
except Exception as exception:
74+
raise exception
75+
76+
APP = web.Application()
77+
APP.router.add_post("/api/messages", messages)
78+
79+
if __name__ == "__main__":
80+
try:
81+
web.run_app(APP, host="localhost", port=CONFIG.PORT)
82+
except Exception as error:
83+
raise error
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from .search_based_messaging_extension import SearchBasedMessagingExtension
5+
6+
__all__ = ["SearchBasedMessagingExtension"]
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from botbuilder.core import CardFactory, MessageFactory, TurnContext
5+
from botbuilder.schema import ChannelAccount, ThumbnailCard, CardImage, HeroCard, Attachment, CardAction
6+
from botbuilder.schema.teams import AppBasedLinkQuery, MessagingExtensionAttachment, MessagingExtensionQuery, MessagingExtensionResult, MessagingExtensionResponse
7+
from botbuilder.core.teams import TeamsActivityHandler, TeamsInfo
8+
9+
from typing import List
10+
import requests
11+
12+
class SearchBasedMessagingExtension(TeamsActivityHandler):
13+
async def on_message_activity(self, turn_context: TurnContext):
14+
await turn_context.send_activities(MessageFactory.text(f"Echo: {turn_context.activi 10000 ty.text}"))
15+
16+
async def on_teams_messaging_extension_query(self, turn_context: TurnContext, query: MessagingExtensionQuery):
17+
search_query = str(query.parameters[0].value)
18+
response = requests.get(f"http://registry.npmjs.com/-/v1/search",params={"text":search_query})
19+
data = response.json()
20+
21+
attachments = []
22+
23+
for obj in data["objects"]:
24+
hero_card = HeroCard(
25+
title=obj["package"]["name"],
26+
tap=CardAction(
27+
type="invoke",
28+
value=obj["package"]
29+
),
30+
preview=[CardImage(url=obj["package"]["links"]["npm"])]
31+
)
32+
33+
attachment = MessagingExtensionAttachment(
34+
content_type=CardFactory.content_types.hero_card,
35+
content=HeroCard(title=obj["package"]["name"]),
36+
preview=CardFactory.hero_card(hero_card)
37+
)
38+
attachments.append(attachment)
39+
return MessagingExtensionResponse(
40+
compose_extension=MessagingExtensionResult(
41+
type="result",
42+
attachment_layout="list",
43+
attachments=attachments
44+
)
45+
)
46+
47+
48+
49+
async def on_teams_messaging_extension_select_item(self, turn_context: TurnContext, query) -> MessagingExtensionResponse:
50+
hero_card = HeroCard(
51+
title=query["name"],
52+
subtitle=query["description"],
53+
buttons=[
54+
CardAction(
55+
type="openUrl",
56+
value=query["links"]["npm"]
57+
)
58+
]
59+
)
60+
attachment = MessagingExtensionAttachment(
61+
content_type=CardFactory.content_types.hero_card,
62+
content=hero_card
63+
)
64+
65+
return MessagingExtensionResponse(
66+
compose_extension=MessagingExtensionResult(
67+
type="result",
68+
attachment_layout="list",
69+
attachments=[attachment]
70+
)
71+
)
72+
73+
def _create_messaging_extension_result(self, attachments: List[MessagingExtensionAttachment]) -> MessagingExtensionResult:
74+
return MessagingExtensionResult(
75+
type="result",
76+
attachment_layout="list",
77+
attachments=attachments
78+
)
79+
80+
def _create_search_result_attachment(self, search_query: str) -> MessagingExtensionAttachment:
81+
card_text = f"You said {search_query}"
82+
bf_logo = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU"
83+
84+
button = CardAction(
85+
type="openUrl",
86+
title="Click for more Information",
87+
value="https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/bots/bots-overview"
88+
)
89+
90+
images = [CardImage(url=bf_logo)]
91+
buttons = [button]
92+
93+
hero_card = HeroCard(
94+
title="You searched for:",
95+
text=card_text,
96+
images=images,
97+
buttons=buttons
98+
)
99+
100+
return MessagingExtensionAttachment(
101+
content_type=CardFactory.content_types.hero_card,
102+
content=hero_card,
103+
preview=CardFactory.hero_card(hero_card)
104+
)
105+
106+
def _create_dummy_search_result_attachment(self) -> MessagingExtensionAttachment:
107+
card_text = "https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/bots/bots-overview"
108+
bf_logo = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU"
109+
110+
button = CardAction(
111+
type = "openUrl",
112+
title = "Click for more Information",
113+
value = "https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/bots/bots-overview"
114+
)
115+
116+
images = [CardImage(url=bf_logo)]
117+
118+
buttons = [button]
119+
120+
121+
hero_card = HeroCard(
122+
title="Learn more about Teams:",
123+
text=card_text, images=images,
124+
buttons=buttons
125+
)
126+
127+
preview = HeroCard(
128+
title="Learn more about Teams:",
129+
text=card_text,
130+
images=images
131+
)
132+
133+
return MessagingExtensionAttachment(
134+
content_type = CardFactory.content_types.hero_card,
135+
content = hero_card,
136+
preview = CardFactory.hero_card(preview)
137+
)
138+
139+
def _create_select_items_result_attachment(self, search_query: str) -> MessagingExtensionAttachment:
140+
card_text = f"You said {search_query}"
141+
bf_logo = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU"
142+
143+
buttons = CardAction(
144+
type="openUrl",
145+
title="Click for more Information",
146+
value="https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/bots/bots-overview"
147+
)
148+
149+
images = [CardImage(url=bf_logo)]
150+
buttons = [buttons]
151+
152+
select_item_tap = CardAction(
153+
type="invoke",
154+
value={"query": search_query}
155+
)
156+
157+
hero_card = HeroCard(
158+
title="You searched for:",
159+
text=card_text,
160+
images=images,
161+
buttons=buttons
162+
)
163+
164+
preview = HeroCard(
165+
title=card_text,
166+
text=card_text,
167+
images=images,
168+
tap=select_item_tap
169+
)
170+
171+
return MessagingExtensionAttachment(
172+
content_type=CardFactory.content_types.hero_card,
173+
content=hero_card,
174+
preview=CardFactory.hero_card(preview)
175+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License.
4+
5+
import os
6+
7+
8+
class DefaultConfig:
9+
""" Bot Configuration """
10+
11+
PORT = 3978
12+
APP_ID = os.environ.get("MicrosoftAppId", "")
13+
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
botbuilder-core>=4.4.0b1
2+
flask>=1.0.3
Loading
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
3+
"manifestVersion": "1.5",
4+
"version": "1.0",
5+
"id": "<<YOUR-MICROSOFT-BOT-ID>>",
6+
"packageName": "com.microsoft.teams.samples.searchExtension",
7+
"developer": {
8+
"name": "Microsoft Corp",
9+
"websiteUrl": "https://example.azurewebsites.net",
10+
"privacyUrl": "https://example.azurewebsites.net/privacy",
11+
"termsOfUseUrl": "https://example.azurewebsites.net/termsofuse"
12+
},
13+
"name": {
14+
"short": "search-extension-settings",
15+
"full": "Microsoft Teams V4 Search Messaging Extension Bot and settings"
16+
},
17+
"description": {
18+
"short": "Microsoft Teams V4 Search Messaging Extension Bot and settings",
19+
"full": "Sample Search Messaging Extension Bot using V4 Bot Builder SDK and V4 Microsoft Teams Extension SDK"
20+
},
21+
"icons": {
22+
"outline": "icon-outline.png",
23+
"color": "icon-color.png"
24+
},
25+
"accentColor": "#abcdef",
26+
"composeExtensions": [
27+
{
28+
"botId": "<<YOUR-MICROSOFT-BOT-ID>>",
29+
"canUpdateConfiguration": true,
30+
"commands": [
31+
{
32+
"id": "searchQuery",
33+
"context": [ "compose", "commandBox" ],
34+
"description": "Test command to run query",
35+
"title": "Search",
36+
"type": "query",
37+
"parameters": [
38+
{
39+
"name": "searchQuery",
40+
"title": "Search Query",
41+
"description": "Your search query",
42+
"inputType": "text"
43+
}
44+
]
45+
}
46+
]
47+
}
48+
]
49+
}
Loading

0 commit comments

Comments
 (0)
0