Skip to content

Commit 3aefc8f

Browse files
committed
updating readme, making search case-insentive, add css for select models section, add filename
1 parent 4e1ee66 commit 3aefc8f

File tree

3 files changed

+123
-51
lines changed

3 files changed

+123
-51
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,16 @@ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh |
133133
export NVM_DIR="$HOME/.nvm"
134134
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
135135
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
136+
```
137+
138+
139+
```
136140
nvm install v8.9.0
137141
nvm use 8.9.0
138142
```
139143

140144
Also install [ffmpeg](https://www.ffmpeg.org/) using on of the following command, depending on your operating system. ffmpeg enables the app to receive metadata describing the analyzed videos.
145+
This may take a while (10-15 minutes)
141146
```
142147
# OS X
143148
brew install ffmpeg
@@ -152,6 +157,10 @@ To run the dashboard locally, we'll need to install a few node libraries which a
152157

153158
These libraries can be installed by entering the following commands in a terminal.
154159

160+
```
161+
cd visual_insights_dashboard
162+
```
163+
155164
```
156165
cd backend
157166
npm install

frontend/src/App.vue

Lines changed: 108 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
<vue-button type="default" v-on:click="showInvokeModal({'function': 'init_user', 'fields': ['ID'], 'title': 'Create User'})">Create User</vue-button> -->
2020
<div style="margin-top:10px">
2121
<vue-button type="default" v-on:click="goHome">Home</vue-button>
22-
<vue-button type="default" v-on:click="filenames = [] ; showModal({'name': 'upload-modal', 'title': 'Upload'})">Upload Image(s)</vue-button>
22+
<vue-button type="default" v-on:click="filenames = [] ; files = [] ; showModal({'name': 'upload-modal', 'title': 'Upload'})">Upload Image(s)</vue-button>
2323
<vue-button type="default" v-on:click="showModal({'name': 'login-modal', 'fields': ['URL', 'Username', 'Password'], 'title': 'Login'})">Login</vue-button>
24-
<vue-button type="default" v-on:click="downloadImages">Download Image(s)</vue-button>
24+
<vue-button type="default" v-on:click="downloadImages">Export Image(s)</vue-button>
2525
</div>
2626

2727

@@ -54,6 +54,7 @@
5454
<md-field style="width:500px; margin: auto; ">
5555
<label>Search</label>
5656
<md-input @keyup.enter="search" v-model="query"></md-input>
57+
<md-icon v-on:click="search">search</md-icon>
5758
<!-- <span class="md-helper-text">Helper text</span> -->
5859
</md-field>
5960
<template v-if="inferences.length > 0">
@@ -79,6 +80,8 @@
7980
<template v-if="Object.keys(inference).includes('heatmap')">
8081
<img :src="inference['heatmap']">
8182
<img :src="url + inference['thumbnail_path']">
83+
<!-- <img style="position: absolute; opacity: 0.2" :src="inference['heatmap']"> -->
84+
<!-- <img style="position: absolute" :src="url + inference['thumbnail_path']"> -->
8285
</template>
8386
<template v-else>
8487
<img :src="url + inference['thumbnail_path']">
@@ -87,8 +90,19 @@
8790

8891
<md-card-content>
8992
<!-- <template v-if="'processed_frames' in Object.keys(inference)"> -->
90-
<div class="md-subhead">Status: {{inference['status']}}</div>
91-
<div class="md-subhead">Progress: {{inference['percent_complete'].toFixed(2)}} %</div>
93+
Status: <div class="md-subhead">{{inference['status']}}</div>
94+
Progress: <div class="md-subhead">{{inference['percent_complete'].toFixed(2)}} %</div>
95+
96+
Filename:
97+
<template v-if="Object.keys(inference).includes('filename')">
98+
<div class="md-subhead">{{inference['filename']}}</div>
99+
</template>
100+
<template v-else>
101+
<div class="md-subhead">{{inference['video_in'].split('/').slice(-1)[0]}}</div>
102+
</template>
103+
104+
105+
92106
<!-- </template> -->
93107
</md-card-content>
94108

@@ -99,10 +113,11 @@
99113

100114

101115
<template v-if="inferenceDetails && (Object.keys(inferenceDetails).length > 0) && inferenceDetails[inference._id]">
102-
<div class="md-subhead">Detected Objects / Classes</div>
116+
Detected Objects / Classes
117+
<!-- <div class="md-subhead"></div> -->
103118
<!-- <div>All: {{inferenceDetails[inference._id]}}</div> -->
104119
<template v-if="inference._id.includes('-')">
105-
<div>{{Object.keys(inferenceDetails[inference._id]).join(", ")}}</div>
120+
<div class="md-subhead">{{Object.keys(inferenceDetails[inference._id]).join(", ")}}</div>
106121
</template>
107122
<template v-else>
108123
<template v-for="(value, key) in Object.keys(inferenceDetails[inference._id])">
@@ -130,18 +145,34 @@
130145
</br>
131146
<div>
132147
<template v-if="inferences.length > 0">
148+
{{inferences[0]}}
133149
<!-- <md-card
134150
color="green"
135151
title="Inferences"
136152
text="Inferences"
137153
> -->
138-
<!-- <md-table v-model="inferences">
139-
<md-table-row>
140-
141-
</md-table-row>
142-
</md-table> -->
154+
<!-- <md-table md-sort-order="asc" md-card md-fixed-header>
155+
<md-table-toolbar>
156+
<h1 class="md-title">Inferences</h1>
157+
</md-table-toolbar>
158+
<md-table-row>
159+
<template v-for="header in Object.keys(inferences[0])">
160+
<md-table-head>{{header}}</md-table-head>
161+
</template>
162+
</md-table-row>
163+
<template v-for="inference in inferences">
164+
<md-table-row>
165+
<template v-for="header in Object.keys(inferences[0])">
166+
<md-table-cell>
167+
{{inference[header]}}
168+
</md-table-cell>
169+
</template>
170+
</md-table-row>
171+
</template>
172+
</md-table> -->
143173

144-
<data-table :data=inferences :items-per-page="5" class="elevation-1">
174+
<!-- {{inferences[0]}} -->
175+
<data-table :data=inferences :headers="[{ text: '_id', value: '_id' }]" :items-per-page="5">
145176
</data-table>
146177

147178
<!-- </md-card> -->
@@ -181,7 +212,7 @@
181212
</modal>
182213

183214
<modal name="upload-modal" height="auto">
184-
<h2 align="center"> Upload Files(s) </h2>
215+
<h2 align="center" style="margin-top:20px;margin-bottom:20px"> Upload Files(s) </h2>
185216
<div id="drop_zone" v-on:drop="dropHandler" v-on:dragover="dragOverHandler">
186217
<p align="center">Drag and drop files here</p>
187218
<template v-if="filenames.length > 0">
@@ -191,27 +222,32 @@
191222
</template>
192223

193224
<!-- <v-select v-model="selectedModel" :options="models"></v-select> -->
194-
<!-- <md-select v-model="selectedModel" name="selectedModel" id="selectedModel">
195-
<template v-for="m in models">
196-
{{m}}
197-
<md-option value=m._id> {{m._id}} {{m._name}} </md-option>
198-
</template>
199-
</md-select> -->
200225
</div>
201-
<div style="width: 100%; margin: 0 auto;">
226+
<div style="width: 100%; margin: 0 auto;margin-top:20px">
202227
<h3 align="center">Select Model</h3>
203-
<div style="width: 100%; margin: 0 auto;">
204-
<select id="selectedModel">
228+
<div style="width: 80%; margin: 0 auto;">
229+
230+
<select style="margin-top:10px;margin-bottom:30px" class="select-css" id="selectedModel">
205231
<template v-for="m in models">
206-
<!-- <option value="volvo">Volvo</option> -->
207232
<option :value=m._id> {{m.name}} ({{m._id}}) </option>
208233
</template>
209234
</select>
235+
236+
<!-- <md-field style="z-index:1000">
237+
<md-select v-model="selectedModel" name="selectedModel" id="selectedModel">
238+
<template v-for="m in models">
239+
<md-option style="z-index:1000" value=m._id> {{m._id}} {{m._name}} </md-option>
240+
</template>
241+
</md-select>
242+
</md-field> -->
243+
210244
</div>
211245
</div>
212-
<div>
213-
<vue-button type="default" v-on:click="hideModal({'name': 'upload-modal'})">Cancel</vue-button>
214-
<vue-button type="default" v-on:click="submitInference() ; hideModal({'name': 'upload-modal'})">Upload</vue-button>
246+
<div style="width:35%; margin: 0 auto; margin-bottom: 20px">
247+
<!-- <div> -->
248+
<vue-button type="default" v-on:click="hideModal({'name': 'upload-modal'})">Cancel</vue-button>
249+
<vue-button type="success" v-on:click="submitInference() ; hideModal({'name': 'upload-modal'})">Upload</vue-button>
250+
<!-- </div> -->
215251
</div>
216252
</modal>
217253

@@ -539,7 +575,7 @@
539575
console.log('File(s) dropped');
540576
// Prevent default behavior (Prevent file from being opened)
541577
ev.preventDefault();
542-
this.$data.filenames = []
578+
// this.$data.filenames = []
543579
if (ev.dataTransfer.items) {
544580
// Use DataTransferItemList interface to access the file(s)
545581
for (var i = 0; i < ev.dataTransfer.items.length; i++) {
@@ -700,11 +736,14 @@
700736
} else {
701737
var heatmap = ""
702738
}
739+
// TODO, have to store this locally since pictures are not returned with other inferences
740+
var filename = endpoint.split('/').slice(-1)[0]
703741
var inference = {
704742
_id: result.imageMd5,
705743
created_date: (new Date().toJSON()),
706744
thumbnail_path: '/uploads' + endpoint,
707745
status: result['result'],
746+
filename: filename,
708747
model: result['webAPIId'],
709748
heatmap: heatmap,
710749
percent_complete: 100
@@ -723,30 +762,10 @@
723762
})
724763
if (f_idx == (this.$data.files.length - 1)) {
725764
this.$data.files = []
765+
this.$data.filenames = []
726766
}
727767
})
728768
},
729-
postInference() {
730-
var options = {
731-
method: "POST",
732-
body: file
733-
// headers: {
734-
// 'Accept': 'application/json',
735-
// 'Content-Type': 'application/json'
736-
// }
737-
}
738-
const input = document.getElementById('fileinput');
739-
const file = input.files[0]
740-
fetch("http://localhost:30000/inferences", options).then((response) => {
741-
response.json().then((json) => {
742-
// TODO filter is only here to ignore shared inferences
743-
this.$data.inferences = inf; // json
744-
this.$data.renderInferences = inf //.filter(i => i.model_id == '3ac091c7-66ef-450a-8b7d-fa9e0cc748e6 ') // only need to do this initially
745-
console.log("inferences received")
746-
// localStorage.setItem('inferences', inferences)
747-
})
748-
})
749-
},
750769
getInferences() {
751770
return new Promise((resolve, reject) => {
752771
var options = {
@@ -795,7 +814,7 @@
795814
796815
},
797816
search() {
798-
var query = this.$data.query
817+
var query = this.$data.query.toLowerCase()
799818
console.log("performing search for: " + query)
800819
var a = []
801820
// TODO, allow multi search, split by query and
@@ -804,7 +823,7 @@
804823
this.$data.inferences.map((inference) => {
805824
// Object.values(inference).map( (v) => {
806825
// console.log(JSON.stringify(this.$data.inferenceDetails[inference._id]))
807-
if (JSON.stringify(inference).includes(query) || (this.$data.inferenceDetails[inference._id] && JSON.stringify(this.$data.inferenceDetails[inference._id]).includes(query))) {
826+
if (JSON.stringify(inference).toLowerCase().includes(query) || (this.$data.inferenceDetails[inference._id] && JSON.stringify(this.$data.inferenceDetails[inference._id]).toLowerCase().includes(query))) {
808827
// if (typeof(v) == "object" && v.includes(query)) {
809828
a.push(inference)
810829
}
@@ -990,6 +1009,45 @@
9901009
appearance: none;
9911010
} */
9921011
1012+
/* */
1013+
.imageWrapper {
1014+
position: relative;
1015+
}
1016+
.overlayImage {
1017+
position: absolute;
1018+
top: 0;
1019+
left: 0;
1020+
}
1021+
1022+
1023+
.select-css {
1024+
display: block;
1025+
font-size: 16px;
1026+
font-family: sans-serif;
1027+
font-weight: 700;
1028+
color: #444;
1029+
line-height: 1.3;
1030+
padding: .6em 1.4em .5em .8em;
1031+
width: 100%;
1032+
max-width: 100%;
1033+
box-sizing: border-box;
1034+
margin: 0;
1035+
border: 1px solid #aaa;
1036+
box-shadow: 0 1px 0 1px rgba(0,0,0,.04);
1037+
border-radius: .5em;
1038+
-moz-appearance: none;
1039+
-webkit-appearance: none;
1040+
appearance: none;
1041+
background-color: #fff;
1042+
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'),
1043+
linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%);
1044+
background-repeat: no-repeat, repeat;
1045+
background-position: right .7em top 50%, 0 0;
1046+
background-size: .65em auto, 100%;
1047+
}
1048+
1049+
@import url("https://fonts.googleapis.com/css?family=Material+Icons");
1050+
9931051
</style>
9941052

9951053
<style lang="scss" scoped>

frontend/src/main.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import 'vuetify/dist/vuetify.min.css'
2828

2929
import 'vue-material/dist/vue-material.min.css'
3030
import 'vue-material/dist/theme/default.css'
31-
// import VueMaterial from 'vue-material'
31+
32+
import VueMaterial from 'vue-material'
3233
const VueUploadComponent = require('vue-upload-component')
3334
// Vue.use(VueMaterial)
3435
import { Plotly } from 'vue-plotly'
@@ -47,6 +48,10 @@ Vue.use(MdField)
4748
Vue.use(MdRipple)
4849
Vue.use(MdTable)
4950

51+
Vue.use(VueMaterial)
52+
53+
// Vue.use(MdSelect)
54+
5055
Vue.config.productionTip = false
5156

5257
Vue.use(DataTable)

0 commit comments

Comments
 (0)