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
3 changed files
with
208 additions
and
0 deletions.
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,191 @@ | ||
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> | ||
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script> | ||
|
||
<div id="demo-embed"> | ||
<table class="embeddingInput"> | ||
|
||
<tr> | ||
<td>Hover on an image</td> | ||
<td> | ||
<div class="gallery"> | ||
<img @mouseover="query='https://picsum.photos/id/'+image.id+'/50'" class="gallery-image" | ||
:src="'https://picsum.photos/id/'+image.id+'/80'" v-for="image in images"> | ||
</div> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>Input a sentence (or an image URL)</td> | ||
<td><textarea v-model="query" | ||
placeholder="Input a sentence or an image URL" | ||
style="width: 80%" | ||
rows="6" | ||
maxlength="1000"> | ||
</textarea></td> | ||
</tr> | ||
</table> | ||
|
||
|
||
<div v-if="query && embedding" class="embeddingChart"> | ||
|
||
<div> | ||
<p>Done in {{elapsed}}ms</p> | ||
<span>Showing embedding for</span> | ||
<span> | ||
<img class="thumbnail" v-if="isUrl" :src="query" :alt="query + 'is not a valid image'"> | ||
<code v-else>{{query}}</code> | ||
</span> | ||
</div> | ||
|
||
<div class="embeddingBlock" v-for="value in embedding" v-bind:style="{opacity: normalize_value(value)}" | ||
v-bind:title="value"> | ||
<span v-if="showValue">{{value.toString().charAt(3)}}</span> | ||
</div> | ||
|
||
<div> | ||
|
||
<input type="checkbox" id="checkbox" v-model="showValue"/> | ||
<label for="checkbox">Show embedding values (that visually make no sense but people like it as it was doing | ||
some real science stuff)</label> | ||
</div> | ||
|
||
</div> | ||
</div> | ||
|
||
<style> | ||
#demo-embed { | ||
font-family: var(--font-stack) !important; | ||
} | ||
|
||
.gallery-image:hover { | ||
opacity: 100%; | ||
} | ||
|
||
.gallery-image { | ||
opacity: 50%; | ||
transition: opacity 0.3s; | ||
-webkit-transition: opacity 0.3s; | ||
cursor: pointer; | ||
} | ||
|
||
.thumbnail { | ||
max-width: 150px; | ||
max-height: 150px; | ||
} | ||
|
||
|
||
.embeddingBlock { | ||
width: 8px; | ||
height: 8px; | ||
display: inline-flex; | ||
background: green; | ||
border-style: solid; | ||
border-color: white; | ||
border-width: 1px; | ||
font-size: 1vmin; | ||
color: white; | ||
text-align: center; | ||
vertical-align: middle; | ||
justify-content: center; | ||
align-items: center; | ||
transition: opacity 0.3s; | ||
-webkit-transition: opacity 0.3s; | ||
cursor: pointer; | ||
} | ||
|
||
.embeddingBlock:hover { | ||
border-color: green; | ||
} | ||
|
||
|
||
</style> | ||
|
||
<script> | ||
function randomIntFromInterval(min, max) { // min and max included | ||
return Math.floor(Math.random() * (max - min + 1) + min) | ||
} | ||
|
||
var app = new Vue({ | ||
el: '#demo-embed', | ||
data: { | ||
serverAddress: `http://demo-cas.jina.ai:51001`, | ||
query: 'First do it, then do it right, then do it better', | ||
embedding: [1, 1, 1], | ||
max_embed_value: 0, | ||
min_embed_value: 0, | ||
elapsed: 0, | ||
showValue: true, | ||
images: [] | ||
}, | ||
computed: { | ||
isUrl: function () { | ||
let url; | ||
|
||
try { | ||
url = new URL(this.query); | ||
} catch (_) { | ||
return false; | ||
} | ||
|
||
return url.protocol === "http:" || url.protocol === "https:"; | ||
}, | ||
// get only | ||
payload: function () { | ||
return { | ||
data: [this.isUrl ? { | ||
uri: this.query | ||
} : { | ||
text: this.query | ||
}], | ||
exec_endpoint: '/', | ||
} | ||
} | ||
}, | ||
mounted: function () { | ||
this.$nextTick(function () { | ||
app.callJina(); | ||
|
||
$.getJSON("https://picsum.photos/v2/list?page=" + randomIntFromInterval(1, 10) + "&limit=40", function (json) { | ||
app.images = json | ||
}); | ||
|
||
}) | ||
}, | ||
watch: { | ||
query: function (newQ, oldQ) { | ||
this.callJina() | ||
} | ||
}, | ||
methods: { | ||
normalize_value(val) { | ||
r = (val - this.min_embed_value) / (this.max_embed_value - this.min_embed_value) | ||
r = (r * 10).toFixed(0) / 10 | ||
return r | ||
}, | ||
callJina: function () { | ||
|
||
$.ajax({ | ||
type: "POST", | ||
url: this.serverAddress + "/post", | ||
data: JSON.stringify(this.payload), | ||
contentType: "application/json; charset=utf-8", | ||
dataType: "json", | ||
}).success(function (data, textStatus, jqXHR) { | ||
// data.data[0].embedding | ||
app.embedding = data.data[0].embedding | ||
app.max_embed_value = Math.max.apply(null, app.embedding) | ||
app.min_embed_value = Math.min.apply(null, app.embedding) | ||
|
||
date1 = new Date(data.routes[0].startTime) | ||
date2 = new Date(data.routes[0].endTime) | ||
app.elapsed = date2 - date1 | ||
|
||
console.log('returned!') | ||
|
||
}).fail(function () { | ||
console.error("bad connection!") | ||
}); | ||
} | ||
} | ||
}) | ||
|
||
</script> |
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
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,9 @@ | ||
# Text & Image Embedding | ||
|
||
Embedding is a basic task in CLIP-as-service. It means converting your input sentence or image into a fixed-length vector. In this demo, you can choose a picture, input a sentence in the textbox, or copy-paste your image URL into the text box to get a rough feeling how CLIP-as-service works. | ||
|
||
This is *not* a search task. The images are random stock images and are related to any search results, they are mainly for saving your time on finding some random internet cat pictures. | ||
|
||
The model is `ViT-L/14-336px` on one GPU. | ||
|
||
<iframe frameborder="0" allowtransparency="true" scrolling="no" src="../../_static/demo-embed.html" style="overflow:hidden;overflow-x:hidden;overflow-y:hidden;height:100vh;width:100%"></iframe> |