Slide 1

Slide 1 text

Has your puppy joined the dark side? Michelle Sandford Microsoft Developer Engagement Lead Emerging Communities (Students/Career-Change/Data- Science+AI)

Slide 2

Slide 2 text

Michelle Sandford Developer Engagement Lead www.linkedin.com/in/michellesandford/ https://github.com/codess-aus Twitter: @codess_aus Instagram: @codess_aus TikTok: @codess_aus #Technorama

Slide 3

Slide 3 text

#Technorama @codess_aus

Slide 4

Slide 4 text

These are my puppies #Technorama

Slide 5

Slide 5 text

Those are not Puppies Bing Image Search #Technorama @codess_aus

Slide 6

Slide 6 text

Choices: Uh, what kind of App do I build? Low Code/No Code Native Web – Static/Dynamic Progressive Web App Mobile Can we just skip to the good part? #Technorama @codess_aus

Slide 7

Slide 7 text

Progressive Web Apps Discoverable Installable Safe Re-engageable Offline Responsive Linkable Progressive #Technorama @codess_aus

Slide 8

Slide 8 text

Progressive Web App Concept HTTPS Web App Manifest Service Worker #Technorama @codess_aus

Slide 9

Slide 9 text

Scaffold the App #Technorama @codess_aus

Slide 10

Slide 10 text

Has Your Puppy Joined the Dark Side? #Technorama @codess_aus

Slide 11

Slide 11 text

Train your machine learning model #Technorama @codess_aus

Slide 12

Slide 12 text

Conceptual Overview HTTPS Web App Manifest Service Worker CICD #Technorama @codess_aus

Slide 13

Slide 13 text

#Technorama @codess_aus Step 1 – Retitle the App

Slide 14

Slide 14 text

App.vue
Vue logo
import HelloWorld from './components/HelloWorld.vue' export default { name: 'App', components: { HelloWorld } }
import DetectImage from './components/DetectImage.vue' export default { name: 'App', components: { DetectImage } } Rename HelloWorld.vue and change all references to it #Technorama @codess_aus

Slide 15

Slide 15 text

Step 2 – Replace image and links #Technorama @codess_aus

Slide 16

Slide 16 text

Create images Folder and replace links with image and button DetectImage.vue

{{ msg }}

For a guide and recipes on how to configure / customize this project,
check out the vue-cli documentation.

Installed CLI Plugins

  • babel
  • {{ msg }}

    Next
    #Technorama @codess_aus

Slide 17

Slide 17 text

Add a data method DetectImage.vue export default { name: 'HelloWorld', props: { msg: String } } export default { name: "DetectImage", props: { msg: String }, // create a placeholder for the data data() { return { image: 0, numImages: 21 }; }, }; #Technorama @codess_aus

Slide 18

Slide 18 text

Create a Computed Property to return the index of an image DetectImage.vue data() { return { image: 0, numImages: 21 }; }, data() { return { image: 0, numImages: 21 }; }, // return the index of the image computed: { getImgIndex() { return this.image.toString(); }, disable() { if (this.image == this.numImages) { return true; } else return false; }, }, } #Technorama @codess_aus

Slide 19

Slide 19 text

Create a Methods Object to capture user interaction DetectImage.vue // return the index of the image computed: { getImgIndex() { return this.image.toString(); }, disable() { if (this.image == this.numImages) { return true; } else return false; } }, computed: { getImgIndex() { return this.image.toString(); }, disable() { if (this.image == this.numImages) { return true; } else return false; } }, // capture user interaction methods: { next() { this.image++; this.predictions = []; setTimeout(this.predict, 500); } } }; #Technorama @codess_aus

Slide 20

Slide 20 text

Let’s update those styles DetectImage.vue h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } h3 { margin: 40px 0 0; } .image { min-height: 500px; max-height: 500px; max-width: 100%; } .button { width: 200px; height: 50px; border-radius: 5px; background-color: blueviolet; color: white; font-size: 20pt; margin: 10px; } .button:disabled, .button[disabled] { border: 1px solid #999999; background-color: #cccccc; color: #666666; } #Technorama @codess_aus

Slide 21

Slide 21 text

Install the custom vision package Package.json "dependencies": { "core-js": "^3.6.5", "register-service-worker": "^1.7.1", "vue": "^2.6.11" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.15", "@vue/cli-plugin-eslint": "~4.5.15", "@vue/cli-plugin-pwa": "~4.5.15", "@vue/cli-service": "~4.5.15", "babel-eslint": "^10.1.0", "eslint": "^6.7.2", "eslint-plugin-vue": "^6.2.2", "vue-template-compiler": "^2.6.11" }, "dependencies": { "core-js": "^3.6.5", "register-service-worker": "^1.7.1", "customvision-tfjs": "^1.0.1", "vue": "^2.6.11" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.15", "@vue/cli-plugin-eslint": "~4.5.15", "@vue/cli-plugin-pwa": "~4.5.15", "@vue/cli-service": "~4.5.15", "babel-eslint": "^10.1.0", "eslint": "^6.7.2", "eslint-plugin-vue": "^6.2.2", "raw-loader": "^4.0.0", "webpack-cli": "^3.3.10", "vue-template-compiler": "^2.6.11" }, #Technorama @codess_aus

Slide 22

Slide 22 text

Integrate the custom vision package DetectImage.vue export default { name: "DetectImage", props: { msg: String }, <script> //integrate the customvision packages import * as cvstfjs from "customvision-tfjs"; import labels from "raw-loader!../../public/models/labels.txt"; export default { name: "DetectImage", props: { msg: String }, #Technorama @codess_aus

Slide 23

Slide 23 text

Read the labels.txt file Webpack.config.js module.exports = { module: { rules: [ { test: /\.txt$/i, use: 'raw-loader', }, ], }, }; #Technorama @codess_aus

Slide 24

Slide 24 text

Complete the Data elements section DetectImage.vue // create a placeholder for the data data() { return { image: 0, numImages: 21 }; }, // data elements data() { return { labels: labels, model: null, predictions: [], image: 0, numImages: 21 }; }, #Technorama @codess_aus

Slide 25

Slide 25 text

Add a mounted lifecycle hook DetectImage.vue // return the index of the image computed: { getImgIndex() { return this.image.toString(); }, disable() { if (this.image == this.numImages) { return true; } else return false; } }, // return the index of the image computed: { getImgIndex() { return this.image.toString(); }, disable() { if (this.image == this.numImages) { return true; } else return false; } }, // load the model async mounted() { this.image++; //load up a new model this.model = new cvstfjs.ClassificationModel(); await this.model.loadModelAsync("models/model.json"); //parse labels this.labels = labels.split("\n").map(e => { return e.trim(); }); //run prediction this.predict(); }, #Technorama @codess_aus

Slide 26

Slide 26 text

Add the asynchronous method DetectImage.vue // capture user interaction methods: { next() { this.image++; this.predictions = []; setTimeout(this.predict, 500); } } }; methods: { async predict() { //execute inference let prediction = await this.model.executeAsync(this.$refs.img); let label = prediction[0]; //build up a predictions object by parsing details to labels and probability this.predictions = label.map((p, i) => { return { index: i, label: this.labels[i], probability: p * 100 }; }); }, // capture user interaction next() { this.image++; this.predictions = []; //this.predict(); setTimeout(this.predict, 500); } } }; }, #Technorama @codess_aus

Slide 27

Slide 27 text

Show the confidence level in the UI DetectImage.vue

{{ msg }}

Next

{{ msg }}

Next
{{ pred.label }}: {{ pred.probability.toFixed(0) + '%' }}
hmm.....
#Technorama @codess_aus

Slide 28

Slide 28 text

Run on windows Web.config #Technorama @codess_aus

Slide 29

Slide 29 text

GitHub Actions #Technorama @codess_aus

Slide 30

Slide 30 text

Create a Static Web App and Deploy to Azure with GitHub Actions #Technorama @codess_aus

Slide 31

Slide 31 text

Static Web Apps #Technorama @codess_aus

Slide 32

Slide 32 text

https://lively-ocean-00408a000.1.azurestaticapps.net/ #Technorama @codess_aus

Slide 33

Slide 33 text

Resources Code https://aka.ms/GitHubEwok Ewok or Chouleke App https://aka.ms/ewok Side by Side Code Changes https://aka.ms/PWAChange MS Learn Path (long version) https://aka.ms/LearnPWA #Technorama @codess_aus

Slide 34

Slide 34 text

Michelle Sandford Developer Engagement Lead www.linkedin.com/in/michellesandford/ https://github.com/codess-aus Twitter: @codess_aus Instagram: @codess_aus TikTok: @codess_aus #Technorama