Skip to content
This repository has been archived by the owner on Jun 30, 2022. It is now read-only.

Add IT Service Management skill #2078

Merged
merged 15 commits into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/_docs/reference/skills/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,34 @@ The Weather skill provides a basic Skill that integrates with [AccuWeather](http

The Music skill integrates with [Spotify](https://developer.spotify.com/documentation/web-api/libraries/) to look up playlists and artists and open via the Spotify app. Provide credentials after you [create a Spotify client](https://developer.spotify.com/dashboard/) in the appsettings to configure the skill.

## IT Service Management Skill

The [IT Service Management skill](https://github.com/microsoft/AI/tree/next/skills/src/csharp/experimental/itsmskill) provides a basic skill that provides ticket and knowledge base related capabilities and supports SerivceNow.

To test this skill, one should setup the following:

* Create a ServiceNow instance in [Developers](https://developer.servicenow.com/app.do#!/instance) and update the serviceNowUrl of appsettings.json: `"serviceNowUrl": "https://YOUR_INSTANCE_NAME.service-now.com"`
* Create a [scripted REST API](https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/integrate/custom_web_services/task/t_CreateAScriptedRESTService.html) to get current user's sys_id and please raise an issue if simpler way is found
- In System Web Services/Scripted REST APIs, click New to create an API
- In API's Resources, click New to add a resource
- In the resource, select GET for HTTP method and input `(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) { return gs.getUserID(); })(request, response);` in Script
- Update the serviceNowGetUserId of appsetting.json: `"serviceNowGetUserId": "YOUR_API_NAMESPACE/YOUR_API_ID"`
* Set up endpoint by [this document](https://docs.servicenow.com/bundle/london-platform-administration/page/administer/security/task/t_CreateEndpointforExternalClients.html#t_CreateEndpointforExternalClients) for Client id and Client secret to be used in the following OAuth Connection
- Redirect URL is https://token.botframework.com/.auth/web/redirect
* Add an OAuth Connection in the Settings of Web App Bot named 'ServiceNow' with Service Provider 'Generic Oauth 2'
xieofxie marked this conversation as resolved.
Show resolved Hide resolved
- Authorization URL as https://instance.service-now.com/oauth_auth.do
xieofxie marked this conversation as resolved.
Show resolved Hide resolved
- Token URL, Refresh URL as https://instance.service-now.com/oauth_token.do
- No Scopes are needed
- Click Test Connection to verify

To test this skill in VA, one should setup the following:

* Add https://botbuilder.myget.org/F/aitemplates/api/v3/index.json as NuGet package source
* Update VA's Microsoft.Bot.Builder.Solutions and Microsoft.Bot.Builder.Skills to 4.6.0-daily27 as this skill
* Add VA's appId to AppsWhitelist of SimpleWhitelistAuthenticationProvider under Utilities
* Add OAuth Connection as skill
* The remaining steps are same as normal skills

xieofxie marked this conversation as resolved.
Show resolved Hide resolved
## Experimental Skill Deployment

The Experimental Skills require the following dependencies for end to end operation which are created through an ARM script which you can modify as required.
Expand Down
12 changes: 12 additions & 0 deletions skills/src/csharp/Skills.sln
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicSkill", "experimental\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventSkill", "experimental\eventskill\EventSkill.csproj", "{5BF2293A-6E56-464A-8355-EDC8972F7E09}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ITSMSkill", "experimental\itsmskill\ITSMSkill.csproj", "{3DEE3053-5DCC-4263-8692-2E96C7010997}"
EndProject

Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU
Expand Down Expand Up @@ -187,6 +190,14 @@ Global
{5BF2293A-6E56-464A-8355-EDC8972F7E09}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{5BF2293A-6E56-464A-8355-EDC8972F7E09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5BF2293A-6E56-464A-8355-EDC8972F7E09}.Release|Any CPU.Build.0 = Release|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DEE3053-5DCC-4263-8692-2E96C7010997}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -209,6 +220,7 @@ Global
{0EFEA4F2-DC7E-436E-B951-E9B566AFF7F0} = {3665D242-1A88-4860-B148-BAB695B7B5E4}
{A2ECB4BF-FD59-4746-B699-F1C326D561BB} = {3665D242-1A88-4860-B148-BAB695B7B5E4}
{5BF2293A-6E56-464A-8355-EDC8972F7E09} = {3665D242-1A88-4860-B148-BAB695B7B5E4}
{3DEE3053-5DCC-4263-8692-2E96C7010997} = {3665D242-1A88-4860-B148-BAB695B7B5E4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7B849B7E-CCF5-4031-91F7-CA835433B457}
Expand Down
15 changes: 15 additions & 0 deletions skills/src/csharp/experimental/itsmskill/.filenesting.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"help": "https://go.microsoft.com/fwlink/?linkid=866610",
"dependentFileProviders": {
"add": {
"pathSegment": {
"add": {
".*": [
".json",
".resx"
]
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Globalization;
using ITSMSkill.Responses.Shared;
using ITSMSkill.Services;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Skills;
using Microsoft.Bot.Builder.Solutions.Middleware;
using Microsoft.Bot.Builder.Solutions.Responses;
using Microsoft.Bot.Schema;

namespace ITSMSkill.Adapters
{
public class CustomSkillAdapter : SkillWebSocketBotAdapter
{
public CustomSkillAdapter(
BotSettings settings,
UserState userState,
ConversationState conversationState,
ResponseManager responseManager,
IBotTelemetryClient telemetryClient)
{
OnTurnError = async (context, exception) =>
{
CultureInfo.CurrentUICulture = new CultureInfo(context.Activity.Locale);
await context.SendActivityAsync(responseManager.GetResponse(SharedResponses.ErrorMessage));
await context.SendActivityAsync(new Activity(type: ActivityTypes.Trace, text: $"Skill Error: {exception.Message} | {exception.StackTrace}"));
telemetryClient.TrackException(exception);
};

// Uncomment the following line for local development without Azure Storage
// Use(new TranscriptLoggerMiddleware(new MemoryTranscriptStore()));
Use(new TranscriptLoggerMiddleware(new AzureBlobTranscriptStore(settings.BlobStorage.ConnectionString, settings.BlobStorage.Container)));
Use(new TelemetryLoggerMiddleware(telemetryClient, logPersonalInformation: true));
Use(new SetLocaleMiddleware(settings.DefaultLocale ?? "en-us"));
Use(new EventDebuggerMiddleware());
Use(new SkillMiddleware(userState, conversationState, conversationState.CreateProperty<DialogState>(nameof(DialogState))));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Globalization;
using ITSMSkill.Responses.Shared;
using ITSMSkill.Services;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.Solutions.Middleware;
using Microsoft.Bot.Builder.Solutions.Responses;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;

namespace ITSMSkill.Bots
{
public class DefaultAdapter : BotFrameworkHttpAdapter
{
public DefaultAdapter(
BotSettings settings,
ICredentialProvider credentialProvider,
IBotTelemetryClient telemetryClient,
ResponseManager responseManager)
: base(credentialProvider)
{
OnTurnError = async (context, exception) =>
{
CultureInfo.CurrentUICulture = new CultureInfo(context.Activity.Locale);
await context.SendActivityAsync(responseManager.GetResponse(SharedResponses.ErrorMessage));
await context.SendActivityAsync(new Activity(type: ActivityTypes.Trace, text: $"Skill Error: {exception.Message} | {exception.StackTrace}"));
telemetryClient.TrackException(exception);
};

// Uncomment the following line for local development without Azure Storage
// Use(new TranscriptLoggerMiddleware(new MemoryTranscriptStore()));
Use(new TranscriptLoggerMiddleware(new AzureBlobTranscriptStore(settings.BlobStorage.ConnectionString, settings.BlobStorage.Container)));
Use(new TelemetryLoggerMiddleware(telemetryClient, logPersonalInformation: true));
Use(new ShowTypingMiddleware());
Use(new SetLocaleMiddleware(settings.DefaultLocale ?? "en-us"));
Use(new EventDebuggerMiddleware());
}
}
}
46 changes: 46 additions & 0 deletions skills/src/csharp/experimental/itsmskill/Bots/DialogBot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.DependencyInjection;

namespace ITSMSkill.Bots
{
public class DialogBot<T> : IBot
where T : Dialog
{
private readonly Dialog _dialog;
private readonly BotState _conversationState;
private readonly BotState _userState;
private readonly IBotTelemetryClient _telemetryClient;

public DialogBot(IServiceProvider serviceProvider, T dialog)
{
_dialog = dialog;
_conversationState = serviceProvider.GetService<ConversationState>();
_userState = serviceProvider.GetService<UserState>();
_telemetryClient = serviceProvider.GetService<IBotTelemetryClient>();
}

public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
// Client notifying this bot took to long to respond (timed out)
if (turnContext.Activity.Code == EndOfConversationCodes.BotTimedOut)
{
_telemetryClient.TrackTrace($"Timeout in {turnContext.Activity.ChannelId} channel: Bot took too long to respond.", Severity.Information, null);
return;
}

await _dialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);

// Save any state changes that might have occured during the turn.
await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"type": "AdaptiveCard",
"id": "TicketCard",
"body": [
{
"type": "Container",
"items": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"verticalContentAlignment": "Center",
"items": [
{
"type": "TextBlock",
"horizontalAlignment": "Left",
"size": "Medium",
"color": "Default",
"text": "{Title}",
"wrap": true
}
],
"width": "stretch"
}
]
},
{
"type": "TextBlock",
"size": "Small",
"color": "Default",
"text": "{UpdatedTime}"
},
{
"type": "TextBlock",
"size": "Small",
"color": "Default",
"text": "{Number}"
}
]
},
{
"type": "TextBlock",
"wrap": true,
"text": "{Content}",
"maxLines": 5
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "{UrlTitle}",
"url": "{UrlLink}"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0",
"speak": "{Speak}"
}
Loading