-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
219 changed files
with
13,650 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
name: Build and deploy .NET Functions application to App name feedbackbot_AZURE_FUNCTIONS_NAME using profile in secret feedbackbot_PUBLISH_PROFILE_FUNCTIONS | ||
on: | ||
push: | ||
branches: | ||
- main | ||
env: | ||
AZURE_FUNC_PACKAGE_PATH: Functions\publish | ||
CONFIGURATION: Release | ||
DOTNET_CORE_VERSION: 8.0.x | ||
WORKING_DIRECTORY_FUNC: src\Functions | ||
jobs: | ||
build: | ||
runs-on: windows-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Setup .NET SDK | ||
uses: actions/setup-dotnet@v3 | ||
with: | ||
dotnet-version: ${{ env.DOTNET_CORE_VERSION }} | ||
- name: Restore Functions App | ||
run: dotnet restore "${{ env.WORKING_DIRECTORY_FUNC }}" | ||
- name: Build Functions App | ||
run: dotnet build "${{ env.WORKING_DIRECTORY_FUNC }}" --configuration ${{ env.CONFIGURATION }} --no-restore | ||
- name: Publish Functions App | ||
run: dotnet publish "${{ env.WORKING_DIRECTORY_FUNC }}" --configuration ${{ env.CONFIGURATION }} --no-build --output "${{ env.AZURE_FUNC_PACKAGE_PATH }}" | ||
|
||
- name: Publish function | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: func | ||
path: ${{ env.AZURE_FUNC_PACKAGE_PATH }} | ||
deploy: | ||
runs-on: windows-latest | ||
needs: build | ||
steps: | ||
- name: Download Functions App artifact from build job | ||
uses: actions/download-artifact@v3 | ||
with: | ||
name: func | ||
path: ${{ env.AZURE_FUNC_PACKAGE_PATH }} | ||
- name: Deploy Functions App to Azure WebApp | ||
uses: azure/webapps-deploy@v2 | ||
with: | ||
app-name: ${{ env.feedbackbot_AZURE_FUNCTIONS_NAME }} | ||
publish-profile: ${{ secrets.feedbackbot_PUBLISH_PROFILE_FUNCTIONS }} | ||
package: ${{ env.AZURE_FUNC_PACKAGE_PATH }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
name: Build and deploy .NET web + webjob to Web App name feedbackbot_AZURE_WEBAPP_NAME using profile found in secret feedbackbot_PUBLISH_PROFILE | ||
on: | ||
push: | ||
branches: | ||
- main | ||
env: | ||
AZURE_WEBAPP_PACKAGE_PATH_WEB: Web\publish | ||
AZURE_WEBAPP_PACKAGE_PATH_WEBJOB: Web\publish\app_data\Jobs\Triggered\ActivityImporter.ConsoleApp | ||
CONFIGURATION: Release | ||
DOTNET_CORE_VERSION: 8.0.x | ||
WORKING_DIRECTORY_WEB: src\Web | ||
WORKING_DIRECTORY_WEBJOB: src\ActivityImporter.ConsoleApp | ||
jobs: | ||
build: | ||
runs-on: windows-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Setup .NET SDK | ||
uses: actions/setup-dotnet@v3 | ||
with: | ||
dotnet-version: ${{ env.DOTNET_CORE_VERSION }} | ||
- name: Restore Web | ||
run: dotnet restore "${{ env.WORKING_DIRECTORY_WEB }}" | ||
- name: Build Web | ||
run: dotnet build "${{ env.WORKING_DIRECTORY_WEB }}" --configuration ${{ env.CONFIGURATION }} --no-restore | ||
- name: Test | ||
run: dotnet test "${{ env.WORKING_DIRECTORY_WEB }}" --no-build | ||
- name: Publish Web | ||
run: dotnet publish "${{ env.WORKING_DIRECTORY_WEB }}" --configuration ${{ env.CONFIGURATION }} --no-build --output "${{ env.AZURE_WEBAPP_PACKAGE_PATH_WEB }}" | ||
|
||
- name: Restore WebJob | ||
run: dotnet restore "${{ env.WORKING_DIRECTORY_WEBJOB }}" | ||
- name: Build WebJob | ||
run: dotnet build "${{ env.WORKING_DIRECTORY_WEBJOB }}" --configuration ${{ env.CONFIGURATION }} --no-restore | ||
- name: Publish WebJob | ||
run: dotnet publish "${{ env.WORKING_DIRECTORY_WEBJOB }}" --configuration ${{ env.CONFIGURATION }} --no-build --output "${{ env.AZURE_WEBAPP_PACKAGE_PATH_WEBJOB }}" | ||
|
||
- name: Publish WebJob & Web Artifacts | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: webjobandweb | ||
path: | | ||
${{ env.AZURE_WEBAPP_PACKAGE_PATH_WEB }} | ||
${{ env.AZURE_WEBAPP_PACKAGE_PATH_WEBJOB }} | ||
deploy: | ||
runs-on: windows-latest | ||
needs: build | ||
steps: | ||
- name: Download webjobandweb artifact from build job | ||
uses: actions/download-artifact@v3 | ||
with: | ||
name: webjobandweb | ||
path: ${{ env.AZURE_WEBAPP_PACKAGE_PATH_WEB }} | ||
- name: Deploy webjob and web to Azure WebApp | ||
uses: azure/webapps-deploy@v2 | ||
with: | ||
app-name: ${{ env.feedbackbot_AZURE_WEBAPP_NAME }} | ||
publish-profile: ${{ secrets.feedbackbot_PUBLISH_PROFILE }} | ||
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH_WEB }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
################################################################################ | ||
# This .gitignore file was automatically created by Microsoft(R) Visual Studio. | ||
################################################################################ | ||
|
||
/.github/workflows/feedbackbotdgittest1.yml | ||
/.vs | ||
/src/Functions/Properties/serviceDependencies.copilotfeedback-function-ag - Zip Deploy.json | ||
__azurite* | ||
/Teams App/*.zip | ||
src/Web/Properties/ServiceDependencies/copilotfeedback-ag - Web Deploy/*.* | ||
src/Functions/Properties/ServiceDependencies/copilotfeedback-function-ag - Zip Deploy/*.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,121 @@ | ||
# copilot-feedback-bot | ||
# Copilot Feedback Bot | ||
Get real feedback from your organisations users about how copilot is helping, with "Copilot Feedback Bot". | ||
|
||
![Copilot Feedback Bot says 'Hiii!'](imgs/bot-salute-small.png) | ||
|
||
This is a bot that collects user feedback about copilot use within M365 so you can see exactly what your users think about it. Do your users love copilot? Does it really save them time? Doing what actions? Do some groups of people like it more than others? | ||
|
||
More importantly: is it worth the investment? This is the question this system seeks to quantify in more detail than anything else. | ||
|
||
![User Satisfaction Dashboard](imgs/report1.png) | ||
|
||
Copilot events are detected automatically, and each user that used copilot will be surveyed about how that interaction went through a Teams bot. | ||
|
||
![Teams Prompt from Bot](imgs/botconvo.jpg) | ||
|
||
User responses are stored in a database and visualised in Power BI. | ||
|
||
![User Satisfaction Report](imgs/report2.png) | ||
This is an automated way to get real feedback from your users about what they think of copilot in Office 365. | ||
|
||
All data is stored in your own SQL Server. | ||
|
||
## Usage | ||
**Quick version**: run the activity import and let the bot do the rest. The functions app will look for users that have used copilot and then survey them. | ||
|
||
When deployed, a web-job will read the Office 365 Activity API to determine copilot interactions - whom, and what. It runs automatically once a day. | ||
|
||
A functions app will then find users that have new activity and start a new conversation with them to ask if they could review the activity in question with copilot. | ||
|
||
Once surveyed they won't be surveyed again for that specific interaction (even if they don't answer). | ||
|
||
If the user doesn't have the bot installed in Teams already, it'll be installed automatically. | ||
|
||
If the user says anything to the bot outside the normal dialogue flow, the assumption is they want to leave a copilot review. Surveys don't necessarily have to correlate to a specific interaction, the user can just leave general feedback too. | ||
|
||
### Testing the Bot | ||
Copilot activity can be faked by sending a **POST** to ```/api/Triggers/GenerateFakeActivityFor?upn={**UPN**}``` (no body required). This will create a fake meeting & file activity for that user. | ||
|
||
The bot can also be forced to check and send for pending surveys to be sent everyone with a **POST** to ```/api/Triggers/SendSurveys``` (no body required). | ||
|
||
To test-install the bot for a user and force a "hi!" from the bot, independently of if they have pending surveys or not, **POST** to ```/api/Triggers/InstallBotForUser?upn={**UPN**}``` (no body required). | ||
|
||
Otherwise, the longer version is to use copilot in a file or team meeting, wait a few minutes, run (manually or automatically) the import job and then wait for the timer function to run the "_FindAndProcessNewSurveyEventsAllUsers_" method. | ||
|
||
## How Does it Work? | ||
Easy. There's a web-job/process that reads O365 audit events for SharePoint and copilot activity. We read SharePoint to know what happened with files (edit/view/etc) and the copilot to know what users have done with copilot. The information we get from copilot events is limited; "User A chatted to copilot in an app, and it involved this file/meeting", so hence we read SP logs too to link what actually was going on. | ||
|
||
Note: SharePoint events that are saved can be filtered so we don't accidentally store sensitive file activity data in table "import_url_filter". | ||
|
||
In addition we also read aggregated activity reports for users for OneDrive, SharePoint, Outlook and Teams. That way we can find users that are active in O365 but not using Copilot. | ||
|
||
Finally the solution reads user metadata from Entra ID (Azure AD) copilot activity & satisfaction by demographics can be analysed - job title, office location, etc. | ||
|
||
# Setup Steps | ||
For this, we assume a decent knowledge of Teams apps deployment, .Net, and Azure PaaS. | ||
|
||
## Create Bot and Deploy Teams App | ||
Note, that for all these steps you can do them all in PowerShell if you wish. I’m not a sysadmin so this is what works best for me. | ||
|
||
You need Teams admin rights and rights to assign sensitive privileges for this setup to work. It's a bot that proactively installs itself and asks users. | ||
|
||
1. Go to: https://dev.teams.microsoft.com/bots and create a new bot (or alternatively in the Azure Portal, create a new Azure bot - the 1st link doesn't require an Azure subscription). | ||
2. Create a new client secret for the bot application registration. Note down the client ID & the secret of the bot. | ||
3. Grant permissions (specified below) and have an admin grant consent. | ||
4. Optional: you can create another app registration for the more sensitive privileges if you need (service account). The config supports having x2 accounts, but one can be used for both. | ||
|
||
Next, create a Teams app from the template: | ||
4. In "Teams App" root dir, copy file "manifest-template.json" to "manifest.json". | ||
5. Edit "manifest.json" and update all instances of ```<<BOT_APP_ID>>``` with your app registration client ID. | ||
6. Make a zip file from "color.png", "manifest.json", and "outline.png" files in that folder. Make sure all files are in the root of the zip. | ||
7. Deploy that zip file to your apps catalog in Teams admin. | ||
8. Once deployed, copy the "App ID" generated. We'll need that ID for bot configuration. | ||
|
||
## Create Azure Resources | ||
Create these resources: | ||
|
||
* Required - App service & plan. B1 level recommended for small environments. | ||
* Required - Functions app - consumption plan recommended. May require it's own resource-group. | ||
* Application Insights (link app service & functions app to it) | ||
* Required - Storage account. | ||
* Required - Service bus namespace. | ||
* SQL Database (and server) - the PaaS version. You could use an on-premises SQL if you wanted. | ||
|
||
## Required Configuration | ||
These configuration settings are needed in the app service & functions app: | ||
|
||
Name | Description | ||
--------------- | ----------- | ||
AppCatalogTeamAppId | Teams app ID once deployed to the internal catalog | ||
MicrosoftAppId | ID of bot Azure AD application | ||
MicrosoftAppPassword | Bot app secret | ||
WebAppURL | Root URL of app service | ||
AuthConfig:ClientId | Service account | ||
AuthConfig:ClientSecret | Service account | ||
AuthConfig:TenantId | Service account | ||
ConnectionStrings:Redis | Redis connection string, used for caching delta tokens | ||
ConnectionStrings:ServiceBusRoot | Used for async processing of various things | ||
ConnectionStrings:SQL | The database connection string. | ||
ConnectionStrings:Storage | Connection string. Conversation cache and other table storage | ||
|
||
ConnectionStrings go in their own section in App Services (and prefix "ConnectionStrings:" to the name you give there for .Net). | ||
|
||
_Important:_ **If any values are missing, the process will crash at start-up**. Check the local VM application log if you get a start-up error (in Kudu for app services). | ||
|
||
## Application Permissions | ||
Graph permissions needed (application): | ||
* User.Read.All - for looking up user metadata, allowing activity & survey slicing by demographics (job title, location etc) | ||
* Reports.Read.All - for reading activity data so we can cross-check who's active but not using copilot. | ||
* TeamsAppInstallation.ReadWriteForUser.All - so the bot can proactively install itself into users Teams, to start a new conversation. | ||
|
||
Office 365 Management APIs | ||
* ActivityFeed.Read - for detecting copilot events. | ||
|
||
All these permissions need administrator consent to be effective. | ||
|
||
## Deploy Solution | ||
There are GitHub actions in ".github\workflows\" that will build and deploy the app service & webjob in one WF and the functions app in another. | ||
|
||
The workflows require secrets "feedbackbot_PUBLISH_PROFILE" and "feedbackbot_AZURE_FUNCTIONS_NAME" for deploy to work. | ||
|
||
Quick hack: publish from Visual Studio is also a (temporary) solution. |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json", | ||
"version": "1.0.0", | ||
"manifestVersion": "1.16", | ||
"id": "<<BOT_APP_ID>>", | ||
"packageName": "com.copilotfeedback.bot", | ||
"name": { | ||
"short": "Copilot Feedback bot", | ||
"full": "Copilot Feedback bot - get real value feedback for copilot usage" | ||
}, | ||
"developer": { | ||
"name": "Sam Betts", | ||
"mpnId": "", | ||
"websiteUrl": "https://github.com/sambetts", | ||
"privacyUrl": "https://github.com/sambetts", | ||
"termsOfUseUrl": "https://github.com/sambetts" | ||
}, | ||
"description": { | ||
"short": "Copilot Feedback bot - get real value feedback for copilot usage", | ||
"full": "Copilot Feedback bot surveys users how their interactions with M365 Copilot was to compile full and realistic value stats" | ||
}, | ||
"icons": { | ||
"outline": "outline.png", | ||
"color": "color.png" | ||
}, | ||
"accentColor": "#335484", | ||
"bots": [ | ||
{ | ||
"botId": "<<BOT_APP_ID>>", | ||
"scopes": [ | ||
"personal" | ||
], | ||
"isNotificationOnly": false, | ||
"supportsFiles": false | ||
} | ||
], | ||
"permissions": [ | ||
"identity", | ||
"messageTeamMembers" | ||
], | ||
"validDomains": [ | ||
"token.botframework.com" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json", | ||
"version": "1.0.0", | ||
"manifestVersion": "1.16", | ||
"id": "e2cc65ef-2390-4579-b950-83b01dcae815", | ||
"packageName": "com.copilotfeedback.bot", | ||
"name": { | ||
"short": "Copilot Feedback bot", | ||
"full": "Copilot Feedback bot - get real value feedback for copilot usage" | ||
}, | ||
"developer": { | ||
"name": "Sam Betts", | ||
"mpnId": "", | ||
"websiteUrl": "https://github.com/sambetts", | ||
"privacyUrl": "https://github.com/sambetts", | ||
"termsOfUseUrl": "https://github.com/sambetts" | ||
}, | ||
"description": { | ||
"short": "Copilot Feedback bot - get real value feedback for copilot usage", | ||
"full": "Copilot Feedback bot surveys users how their interactions with M365 Copilot was to compile full and realistic value stats" | ||
}, | ||
"icons": { | ||
"outline": "outline.png", | ||
"color": "color.png" | ||
}, | ||
"accentColor": "#335484", | ||
"bots": [ | ||
{ | ||
"botId": "e2cc65ef-2390-4579-b950-83b01dcae815", | ||
"scopes": [ | ||
"personal" | ||
], | ||
"isNotificationOnly": false, | ||
"supportsFiles": false | ||
} | ||
], | ||
"permissions": [ | ||
"identity", | ||
"messageTeamMembers" | ||
], | ||
"validDomains": [ | ||
"token.botframework.com" | ||
] | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
############################################################################### | ||
# Set default behavior to automatically normalize line endings. | ||
############################################################################### | ||
* text=auto | ||
|
||
############################################################################### | ||
# Set default behavior for command prompt diff. | ||
# | ||
# This is need for earlier builds of msysgit that does not have it on by | ||
# default for csharp files. | ||
# Note: This is only used by command line | ||
############################################################################### | ||
#*.cs diff=csharp | ||
|
||
############################################################################### | ||
# Set the merge driver for project and solution files | ||
# | ||
# Merging from the command prompt will add diff markers to the files if there | ||
# are conflicts (Merging from VS is not affected by the settings below, in VS | ||
# the diff markers are never inserted). Diff markers may cause the following | ||
# file extensions to fail to load in VS. An alternative would be to treat | ||
# these files as binary and thus will always conflict and require user | ||
# intervention with every merge. To do so, just uncomment the entries below | ||
############################################################################### | ||
#*.sln merge=binary | ||
#*.csproj merge=binary | ||
#*.vbproj merge=binary | ||
#*.vcxproj merge=binary | ||
#*.vcproj merge=binary | ||
#*.dbproj merge=binary | ||
#*.fsproj merge=binary | ||
#*.lsproj merge=binary | ||
#*.wixproj merge=binary | ||
#*.modelproj merge=binary | ||
#*.sqlproj merge=binary | ||
#*.wwaproj merge=binary | ||
|
||
############################################################################### | ||
# behavior for image files | ||
# | ||
# image files are treated as binary by default. | ||
############################################################################### | ||
#*.jpg binary | ||
#*.png binary | ||
#*.gif binary | ||
|
||
############################################################################### | ||
# diff behavior for common document formats | ||
# | ||
# Convert binary document formats to text before diffing them. This feature | ||
# is only available from the command line. Turn it on by uncommenting the | ||
# entries below. | ||
############################################################################### | ||
#*.doc diff=astextplain | ||
#*.DOC diff=astextplain | ||
#*.docx diff=astextplain | ||
#*.DOCX diff=astextplain | ||
#*.dot diff=astextplain | ||
#*.DOT diff=astextplain | ||
#*.pdf diff=astextplain | ||
#*.PDF diff=astextplain | ||
#*.rtf diff=astextplain | ||
#*.RTF diff=astextplain |
Oops, something went wrong.