Switch shared worker to basic service worker (#191)
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 33s

Shared workers seem to cause problems with iOS (and sharing wasn't really required anyway), so this PR changes the shared workers to non-shared workers.  As a benefit, it preloads the full model and video models simultaneously which iproves performance when starting the video and running post video detection.

Signed-off-by: Justin Georgi <justin.georgi@gmail.com>

Reviewed-on: #191
This commit is contained in:
2024-07-29 00:54:15 +00:00
parent 0fab2da693
commit 1a703b0100
3 changed files with 63 additions and 56 deletions

View File

@@ -1,45 +1,39 @@
import * as tf from '@tensorflow/tfjs' import * as tf from '@tensorflow/tfjs'
import { f7 } from 'framework7-vue'
let model = null let model = null
self.onconnect = (e) => { onmessage = function (e) {
const port = e.ports[0]; switch (e.data.call) {
case 'loadModel':
port.onmessage = function (e) { loadModel('.' + e.data.weights,e.data.preload).then(() => {
switch (e.data.call) { postMessage({success: 'model'})
case 'loadModel': }).catch((err) => {
loadModel('.' + e.data.weights,e.data.preload).then(() => { postMessage({error: true, message: err.message})
port.postMessage({success: 'model'}) })
}).catch((err) => { break
port.postMessage({error: true, message: err.message}) case 'localDetect':
}) localDetect(e.data.image).then((dets) => {
break postMessage({success: 'detection', detections: dets})
case 'localDetect': }).catch((err) => {
localDetect(e.data.image).then((dets) => { //throw (err)
port.postMessage({success: 'detection', detections: dets}) postMessage({error: true, message: err.message})
}).catch((err) => { })
port.postMessage({error: true, message: err.message}) e.data.image.close()
}) break
e.data.image.close() case 'videoFrame':
break videoFrame(e.data.image).then((frameDet) =>{
case 'videoFrame': postMessage({succes: 'frame', coords: frameDet.cds, modelWidth: frameDet.mW, modelHeight: frameDet.mH})
videoFrame(e.data.image).then((frameDet) =>{ }).catch((err) => {
port.postMessage({succes: 'frame', coords: frameDet.cds, modelWidth: frameDet.mW, modelHeight: frameDet.mH}) postMessage({error: true, message: err.message})
}).catch((err) => { })
port.postMessage({error: true, message: err.message}) e.data.image.close()
}) break
e.data.image.close() default:
break console.log('Worker message incoming:')
default: console.log(e)
console.log('Worker message incoming:') postMessage({result1: 'First result', result2: 'Second result'})
console.log(e) break
port.postMessage({result1: 'First result', result2: 'Second result'})
break
}
} }
port.start()
} }
async function loadModel(weights, preload) { async function loadModel(weights, preload) {

View File

@@ -1,7 +1,5 @@
import { f7 } from 'framework7-vue' import { f7 } from 'framework7-vue'
import detectionWorker from '../assets/detect-worker.js?sharedworker'
export default { export default {
methods: { methods: {
async openCamera(imContain) { async openCamera(imContain) {
@@ -44,15 +42,19 @@ export default {
this.getImage(tempCVS.toDataURL()) this.getImage(tempCVS.toDataURL())
}, },
async videoFrameDetect (vidData) { async videoFrameDetect (vidData) {
const vidWorker = new detectionWorker() const startDetection = () => {
vidWorker.port.onmessage = (eVid) => { createImageBitmap(vidData).then(imVideoFrame => {
self = this this.vidWorker.postMessage({call: 'videoFrame', image: imVideoFrame}, [imVideoFrame])
})
}
vidData.addEventListener('resize',startDetection,{once: true})
this.vidWorker.onmessage = (eVid) => {
if (eVid.data.error) { if (eVid.data.error) {
console.log(eVid.data.message) console.log(eVid.data.message)
f7.dialog.alert(`ALVINN AI model error: ${eVid.data.message}`) f7.dialog.alert(`ALVINN AI model error: ${eVid.data.message}`)
} else if (this.videoAvailable) { } else if (this.videoAvailable) {
createImageBitmap(vidData).then(imVideoFrame => { createImageBitmap(vidData).then(imVideoFrame => {
vidWorker.port.postMessage({call: 'videoFrame', image: imVideoFrame}, [imVideoFrame]) this.vidWorker.postMessage({call: 'videoFrame', image: imVideoFrame}, [imVideoFrame])
}) })
if (eVid.data.coords) { if (eVid.data.coords) {
imageCtx.clearRect(0,0,imCanvas.width,imCanvas.height) imageCtx.clearRect(0,0,imCanvas.width,imCanvas.height)
@@ -67,7 +69,6 @@ export default {
} }
} }
vidWorker.port.postMessage({call: 'loadModel', weights: this.miniLocation, preload: true})
const imCanvas = this.$refs.image_cvs const imCanvas = this.$refs.image_cvs
const imageCtx = imCanvas.getContext("2d") const imageCtx = imCanvas.getContext("2d")
const target = this.$refs.target_image const target = this.$refs.target_image

View File

@@ -140,7 +140,7 @@
import detectionMixin from './detection-mixin' import detectionMixin from './detection-mixin'
import cameraMixin from './camera-mixin' import cameraMixin from './camera-mixin'
import detectionWorker from '../assets/detect-worker.js?sharedworker' import detectionWorker from '../assets/detect-worker.js?worker'
export default { export default {
mixins: [submitMixin, detectionMixin, cameraMixin], mixins: [submitMixin, detectionMixin, cameraMixin],
@@ -179,7 +179,9 @@
videoDeviceAvailable: false, videoDeviceAvailable: false,
videoAvailable: false, videoAvailable: false,
cameraStream: null, cameraStream: null,
infoLinkPos: {} infoLinkPos: {},
detectWorker: null,
vidWorker: null
} }
}, },
setup() { setup() {
@@ -216,8 +218,8 @@
if (loadServerSettings) this.serverSettings = JSON.parse(loadServerSettings) if (loadServerSettings) this.serverSettings = JSON.parse(loadServerSettings)
}, },
mounted () { mounted () {
const mountWorker = new detectionWorker() this.detectWorker = new detectionWorker()
mountWorker.port.onmessage = (eMount) => { this.detectWorker.onmessage = (eMount) => {
self = this self = this
if (eMount.data.error) { if (eMount.data.error) {
console.log(eMount.data.message) console.log(eMount.data.message)
@@ -225,13 +227,22 @@
} }
self.modelLoading = false self.modelLoading = false
} }
this.vidWorker = new detectionWorker()
this.vidWorker.onmessage = (eMount) => {
self = this
if (eMount.data.error) {
console.log(eMount.data.message)
f7.dialog.alert(`ALVINN AI nano model error: ${eMount.data.message}`)
}
}
if (this.serverSettings && this.serverSettings.use) { if (this.serverSettings && this.serverSettings.use) {
this.getRemoteLabels() this.getRemoteLabels()
this.modelLoading = false this.modelLoading = false
} else { } else {
this.modelLoading = true this.modelLoading = true
mountWorker.port.postMessage({call: 'loadModel', weights: this.modelLocation, preload: true}) this.detectWorker.postMessage({call: 'loadModel', weights: this.modelLocation, preload: true})
this.vidWorker.postMessage({call: 'loadModel', weights: this.miniLocation, preload: true})
} }
window.onresize = (e) => { if (this.$refs.image_cvs) this.selectChip('redraw') } window.onresize = (e) => { if (this.$refs.image_cvs) this.selectChip('redraw') }
}, },
@@ -293,12 +304,13 @@
return `--chip-media-gradient: conic-gradient(from ${270 - (confFactor * 360 / 2)}deg, hsl(${confFactor * 120}deg, 100%, 50%) ${confFactor}turn, hsl(${confFactor * 120}deg, 50%, 66%) ${confFactor}turn)` return `--chip-media-gradient: conic-gradient(from ${270 - (confFactor * 360 / 2)}deg, hsl(${confFactor * 120}deg, 100%, 50%) ${confFactor}turn, hsl(${confFactor * 120}deg, 50%, 66%) ${confFactor}turn)`
}, },
async setData () { async setData () {
const detectWorker = new detectionWorker() //const detectWorker = new detectionWorker()
detectWorker.port.onmessage = (eDetect) => { this.detectWorker.onmessage = (eDetect) => {
self = this self = this
if (eDetect.data.error) { if (eDetect.data.error) {
self.detecting = false self.detecting = false
self.resultData = {} self.resultData = {}
loadFailure()
f7.dialog.alert(`ALVINN structure finding error: ${eDetect.data.message}`) f7.dialog.alert(`ALVINN structure finding error: ${eDetect.data.message}`)
} else if (eDetect.data.success == 'detection') { } else if (eDetect.data.success == 'detection') {
self.detecting = false self.detecting = false
@@ -308,8 +320,8 @@
} }
self.uploadDirty = true self.uploadDirty = true
} else if (eDetect.data.success == 'model') { } else if (eDetect.data.success == 'model') {
this.reloadModel = false self.reloadModel = false
loadSuccess(true) loadSuccess()
} }
} }
@@ -319,9 +331,9 @@
loadSuccess = res loadSuccess = res
loadFailure = rej loadFailure = rej
if (this.reloadModel) { if (this.reloadModel) {
detectWorker.port.postMessage({call: 'loadModel', weights: this.modelLocation}) this.detectWorker.postMessage({call: 'loadModel', weights: this.modelLocation})
} else { } else {
loadSuccess(true) loadSuccess()
} }
}) })
@@ -329,7 +341,7 @@
this.remoteDetect() this.remoteDetect()
} else { } else {
Promise.all([modelReloading,createImageBitmap(this.imageView)]).then(res => { Promise.all([modelReloading,createImageBitmap(this.imageView)]).then(res => {
detectWorker.port.postMessage({call: 'localDetect', image: res[1]}, [res[1]]) this.detectWorker.postMessage({call: 'localDetect', image: res[1]}, [res[1]])
}) })
} }
}, },