-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
327 lines (283 loc) · 11.3 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
// Import required packages
import * as restify from "restify";
import path from "path";
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
import {
CloudAdapter,
ConfigurationServiceClientCredentialFactory,
ConfigurationBotFrameworkAuthentication,
TurnContext,
MemoryStorage,
UserState,
CardFactory,
Attachment,
AttachmentLayoutTypes,
MessageFactory,
} from "botbuilder";
import {
Application,
ConversationHistory,
DefaultPromptManager,
DefaultTurnState,
OpenAIModerator,
AzureOpenAIPlanner,
AI,
DefaultConversationState,
} from "@microsoft/teams-ai";
import { OAuthPromptSettings } from "botbuilder-dialogs";
import { MailData } from "./models/mailData";
import { SiteData } from "./models/siteData";
import { SearchResultData } from "./models/searchResultData";
import { AdaptiveCards } from "@microsoft/adaptivecards-tools";
// This bot's main dialog.
import { TeamsBot } from "./teamsBot";
import config from "./config";
import {
MessageBuilder,
TeamsBotSsoPrompt,
TeamsBotSsoPromptSettings,
} from "@microsoft/teamsfx";
import authConfig from "./authConfig";
import { GraphService } from "./services/graphService";
import mailCard from "./adaptiveCards/email.json";
import siteCard from "./adaptiveCards/site.json";
import searchResultCard from "./adaptiveCards/searchResult.json";
type ApplicationTurnState = DefaultTurnState<ConversationState>;
type TData = Record<string, any>;
interface ConversationState extends DefaultConversationState {
searchResults: any;
searchQuery: string;
documentText: string;
docChunk: string;
events: any;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about adapters.
const credentialsFactory = new ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: config.botId,
MicrosoftAppPassword: config.botPassword,
MicrosoftAppType: "MultiTenant",
});
const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(
{},
credentialsFactory
);
const adapter = new CloudAdapter(botFrameworkAuthentication);
// Catch-all for errors.
const onTurnErrorHandler = async (context: TurnContext, error: Error) => {
// 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}`);
// 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 unhandled error:\n ${error.message}`
);
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;
const memoryStorage = new MemoryStorage();
const userState = new UserState(memoryStorage);
//this.dialogState = this.conversationState.createProperty("DialogState");
console.log("OpenAIEndpoint: " + config.openAIEndpoint);
console.log("OpenAIKey: " + config.openAIKey);
const planner = new AzureOpenAIPlanner({
apiKey: config.openAIKey,
defaultModel: "gpt-byod",
logRequests: true,
endpoint: config.openAIEndpoint,
});
const promptManager = new DefaultPromptManager<ApplicationTurnState>(
path.join(__dirname, "./prompts")
);
// Define storage and application
const storage = new MemoryStorage();
const app = new Application<ApplicationTurnState>({
storage,
ai: {
planner,
// moderator,
promptManager,
prompt: "chat",
history: {
assistantHistoryType: "text",
},
},
authentication: {
connectionName: config.connectionName,
text: "Please Sign In",
title: "Sign In",
timeout: 300000,
},
});
app.message("/history", async (context, state) => {
const history = ConversationHistory.toString(state, 2000, "\n\n");
await context.sendActivity(history);
});
app.ai.action(
"readMail",
async (context: TurnContext, state: ApplicationTurnState) => {
console.log("reading mail");
const graphService = new GraphService(state.temp.value.authToken);
const mail = await graphService.getUsersMail();
const mailCards = createMailCards(mail);
await context.sendActivity({
text: "Here's your last 10 emails:",
attachments: mailCards,
attachmentLayout: AttachmentLayoutTypes.Carousel,
});
return true;
}
);
function createMailCards(mailResponse): Attachment[] {
let cards = [];
mailResponse.value.forEach(function (mail) {
// "speak": "<s>Your meeting about \"Adaptive Card design session\"<break strength='weak'/> is starting at ${formatDateTime(start.dateTime, 'HH:mm')}pm</s><s>Do you want to snooze <break strength='weak'/> or do you want to send a late notification to the attendees?</s>",
let adaptiveCard = CardFactory.adaptiveCard(
AdaptiveCards.declare(mailCard).render(mail)
);
cards.push(adaptiveCard);
});
return cards;
}
//app.ai.prompts.addFunction("listSites", async (context, state) => {
app.ai.action(
"listSites",
async (context: TurnContext, state: ApplicationTurnState, data: TData) => {
const searchQuery = data.query;
const graphService = new GraphService(state.temp.value.authToken);
const mail = await graphService.getSites(searchQuery);
const siteCards = createSiteCards(mail);
await context.sendActivity({
text: "Here's all the sites:",
attachments: siteCards,
attachmentLayout: AttachmentLayoutTypes.Carousel,
});
return true;
}
);
function createSiteCards(siteResponse): Attachment[] {
let cards = [];
siteResponse.value.forEach(function (site) {
// "speak": "<s>Your meeting about \"Adaptive Card design session\"<break strength='weak'/> is starting at ${formatDateTime(start.dateTime, 'HH:mm')}pm</s><s>Do you want to snooze <break strength='weak'/> or do you want to send a late notification to the attendees?</s>",
let adaptiveCard = CardFactory.adaptiveCard(
AdaptiveCards.declare(siteCard).render(site)
);
cards.push(adaptiveCard);
});
return cards;
}
app.ai.action(
"searchFiles",
async (context: TurnContext, state: ApplicationTurnState, data: TData) => {
/*const searchResultCards = createSearchCards(searchResults);
await context.sendActivity({
text: "Here's your search results:",
attachments: searchResultCards,
attachmentLayout: AttachmentLayoutTypes.Carousel,
});*/
state.conversation.value.searchQuery = data.query;
await app.ai.chain(context, state, 'summarizeSearch');
return true;
}
);
app.ai.prompts.addFunction('searchFilesForSearchQuery', async (context: TurnContext, state: ApplicationTurnState) => {
const conversation = state.conversation.value;
const graphService = new GraphService(state.temp.value.authToken);
const searchResults = await graphService.searchFiles(conversation.searchQuery);
console.log(JSON.stringify(searchResults));
return JSON.stringify(searchResults);
});
app.ai.prompts.addFunction('summariseDocumentChunk', async (context: TurnContext, state: ApplicationTurnState) => {
const conversation = state.conversation.value;
const graphService = new GraphService(state.temp.value.authToken);
const searchResults = await graphService.searchFiles(conversation.searchQuery);
console.log(JSON.stringify(searchResults));
return JSON.stringify(searchResults);
});
app.ai.action(
"summariseDocument",
async (context: TurnContext, state: ApplicationTurnState, data: TData) => {
const filePath = data.docLink;
const graphService = new GraphService(state.temp.value.authToken);
let fileContents = await graphService.getFileContents('/sites/Conferences', '/general/commsverse/2023/No%20desk,%20no%20problem%20-%20empowering%20Frontline%20workers%20with%20Microsoft%20365.pptx');
state.conversation.value.docChunk = 'Lorem ipsum dolor sit amet. Qui sint odit vel fugit harum aut soluta explicabo quo laborum assumenda et rerum voluptatem id obcaecati necessitatibus et tenetur quam. Et nostrum praesentium sed laudantium ratione qui quaerat rerum aut rerum unde sed repellat repudiandae. </p><p>A quaerat omnis eos voluptatem omnis eum laborum magnam eum pariatur dolorem. Ut necessitatibus explicabo At debitis rerum ea tempora sint et porro consequatur sed sapiente soluta sit dolor earum eos sunt iure. Et dolore laudantium ea eligendi dolorum ex veritatis nesciunt? Et corporis dolorum est inventore maiores et possimus consequatur et autem adipisci sit laudantium dicta id alias cumque. </p><p>Et libero perferendis qui molestias asperiores qui numquam molestiae. Aut fuga iusto quo labore aperiam ut tenetur enim aut quaerat doloremque! Vel ipsa dolorem id dicta soluta ad voluptatem nesciunt id odit quasi et eius asperiores.';
let response = await app.ai.prompts.invokeFunction(context, state, 'summariseDocumentChunk');
state.conversation.value.documentText = response;
await app.ai.chain(context, state, 'summarizeDocument');
// End the current chain
return false;
}
);
app.ai.action(
"analyzeCalendar",
async (context: TurnContext, state: ApplicationTurnState) => {
const graphService = new GraphService(state.temp.value.authToken);
let events = await graphService.getNextTwoWeeksCalendars();
state.conversation.value.events = events;
await app.ai.chain(context, state, 'analyzeCalendar');
// End the current chain
return false;
}
);
function createSearchCards(siteResponse): Attachment[] {
let cards = [];
siteResponse.value[0].hitsContainers[0].hits.forEach(function (searchResult) {
// "speak": "<s>Your meeting about \"Adaptive Card design session\"<break strength='weak'/> is starting at ${formatDateTime(start.dateTime, 'HH:mm')}pm</s><s>Do you want to snooze <break strength='weak'/> or do you want to send a late notification to the attendees?</s>",
let adaptiveCard = CardFactory.adaptiveCard(
AdaptiveCards.declare(searchResultCard).render(searchResult)
);
cards.push(adaptiveCard);
});
return cards;
}
// Register a handler to handle unknown actions that might be predicted
app.ai.action(
AI.UnknownActionName,
async (
context: TurnContext,
state: ApplicationTurnState,
data: TData,
action: string | undefined
) => {
await context.sendActivity(
"Not sure what to say about that. Hopefully soon we can just have a chat but not quite now."
);
return false;
}
);
// List for /reset command and then delete the conversation state
app.message("/reset", async (context, state) => {
state.conversation.delete();
await context.sendActivity("Cleared the current conversation");
});
// Create HTTP server.
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\nBot Started, ${server.name} listening to ${server.url}`);
});
// Listen for incoming requests.
server.post("/api/messages", async (req, res) => {
await adapter.process(req, res, async (context) => {
console.log("incoming!");
try {
await app.run(context);
}
catch(e) {
console.log(e);
}
});
});