-
Notifications
You must be signed in to change notification settings - Fork 142
/
index.ts
159 lines (133 loc) · 5.53 KB
/
index.ts
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
151
152
153
154
155
156
157
158
159
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Import required packages
import { config } from 'dotenv';
import * as path from 'path';
import * as restify from 'restify';
import axios from 'axios';
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
import { ActivityTypes, ConfigurationServiceClientCredentialFactory, MemoryStorage, TurnContext } from 'botbuilder';
import { AdaptiveCardSearchResult, Application, TurnState, TeamsAdapter } from '@microsoft/teams-ai';
import { createDynamicSearchCard, createStaticSearchCard } from './cards';
// Read botFilePath and botFileSecret from .env file.
const ENV_FILE = path.join(__dirname, '..', '.env');
config({ path: ENV_FILE });
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new TeamsAdapter(
{},
new ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: process.env.BOT_ID,
MicrosoftAppPassword: process.env.BOT_PASSWORD,
MicrosoftAppType: 'MultiTenant'
})
);
// Catch-all for errors.
const onTurnErrorHandler = async (context: TurnContext, error: any) => {
// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${error}`);
console.log(error);
// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity(
'OnTurnError Trace',
`${error}`,
'https://www.botframework.com/schemas/error',
'TurnError'
);
// Send a message to the user
await context.sendActivity('The bot encountered an error or bug.');
await context.sendActivity('To continue to run this bot, please fix the bot source code.');
};
// Set the onTurnError for the singleton CloudAdapter.
adapter.onTurnError = onTurnErrorHandler;
// Create HTTP server.
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\n${server.name} listening to ${server.url}`);
console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator');
console.log('\nTo test your bot in Teams, sideload the app manifest.json within Teams Apps.');
});
// Define storage and application
const storage = new MemoryStorage();
const app = new Application({
storage
});
// Listen for new members to join the conversation
app.conversationUpdate('membersAdded', async (context, _state) => {
const membersAdded = context.activity.membersAdded || [];
for (let member = 0; member < membersAdded.length; member++) {
// Ignore the bot joining the conversation
if (membersAdded[member].id !== context.activity.recipient.id) {
await context.sendActivity(
`Hello and welcome! With this sample you can see the functionality of static and dynamic search in adaptive card`
);
}
}
});
// Listen for messages that trigger returning an adaptive card
app.message(/dynamic/i, async (context, _state) => {
const attachment = createDynamicSearchCard();
await context.sendActivity({ attachments: [attachment] });
});
app.message(/static/i, async (context, _state) => {
const attachment = createStaticSearchCard();
await context.sendActivity({ attachments: [attachment] });
});
// Listen for query from dynamic search card
app.adaptiveCards.search('npmpackages', async (context: TurnContext, state: TurnState, query) => {
// Execute query
const searchQuery = query.parameters['queryText'] ?? '';
const count = query.count ?? 10;
const response = await axios.get(
`http://registry.npmjs.com/-/v1/search?${new URLSearchParams({
text: searchQuery,
size: count.toString()
}).toString()}`
);
interface DataObject {
package: {
name: string;
description: string;
};
}
// Format search results
const npmPackages: AdaptiveCardSearchResult[] = [];
response.data.objects.forEach((obj: DataObject) => {
const result: AdaptiveCardSearchResult = {
title: obj.package.name,
value: `${obj.package.name} - ${obj.package.description}`
};
npmPackages.push(result);
});
// Return search results
return npmPackages;
});
interface DynamicSubmitData {
dynamicSelect?: string;
}
interface SubmitData {
choiceSelect?: string;
}
// Listen for submit buttons
app.adaptiveCards.actionSubmit('DynamicSubmit', async (context, _state, data: DynamicSubmitData) => {
await context.sendActivity(`Dynamically selected option is: ${data.dynamicSelect}`);
});
app.adaptiveCards.actionSubmit('StaticSubmit', async (context, _state, data: SubmitData) => {
await context.sendActivity(`Statically selected option is: ${data.choiceSelect}`);
});
// Listen for ANY message to be received. MUST BE AFTER ANY OTHER HANDLERS
app.activity(ActivityTypes.Message, async (context, _state) => {
await context.sendActivity(`Try saying "static search" or "dynamic search".`);
});
// Listen for incoming server requests.
server.post('/api/messages', async (req, res) => {
// Route received a request to adapter for processing
await adapter.process(req, res as any, async (context) => {
// Dispatch to application for routing
await app.run(context);
});
});