Spaces:
Running
on
T4
Running
on
T4
thomasht86
commited on
Commit
•
368feb2
1
Parent(s):
d446962
Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- backend/vespa_app.py +10 -55
- frontend/app.py +133 -34
- main.py +1 -1
- static/full_images/02b30f947c2530e86fcc6f1617b284cb.jpg +0 -0
- static/full_images/04a954607e09c13ca53d62c9506b454d.jpg +0 -0
- static/full_images/0754449971c2415d0993dba99b610fb8.jpg +0 -0
- static/full_images/15441af3f266efefee2e1fa65da0ad5f.jpg +0 -0
- static/full_images/2722b68e9863dec57bd14b18ec5b6597.jpg +0 -0
- static/full_images/2e20778433bb7b41f2b3ff9d273ddedd.jpg +0 -0
- static/full_images/428d4ccc84859c8407ceaf66b5caebb1.jpg +0 -0
- static/full_images/470037d1296e5e9634a47d9e3c1c25e8.jpg +0 -0
- static/full_images/573506dd06553465e28617136e1aef34.jpg +0 -0
- static/full_images/641cf96aed6c75a938ca0303ed0723fb.jpg +0 -0
- static/full_images/65babd1b1ae12a8be4af8621473595cb.jpg +0 -0
- static/full_images/6be2405bc05a52291cb13d47f529ee03.jpg +0 -0
- static/full_images/6d5eac97f945ec5241c00eb3fa1eb348.jpg +0 -0
- static/full_images/95f14a79b6df72466b8ed6473758a23c.jpg +0 -0
- static/full_images/98db7f03fac252c78f142dc26780d7e1.jpg +0 -0
- static/full_images/a2b1647b5ff2a8485933a51866473a91.jpg +0 -0
- static/full_images/b23c60be45be26509dafd38e9fc77d6f.jpg +0 -0
- static/full_images/cb7e8833775e2cbe11bc116219f7e09d.jpg +0 -0
- static/full_images/e491fa7c526511cf6420ca54665e52a4.jpg +0 -0
- static/full_images/ea2bb0b2de938854888ac8e52124b077.jpg +0 -0
- static/full_images/f7785696541fc185bc1d10c8608b8100.jpg +0 -0
- static/img/colpali_child.png +0 -0
- static/img/visual-retrieval-demoapp-arch.png +0 -0
- static/sim_maps/-1764568205672507394_0_10.png +0 -0
- static/sim_maps/-1764568205672507394_0_11.png +0 -0
- static/sim_maps/-1764568205672507394_0_12.png +0 -0
- static/sim_maps/-1764568205672507394_0_14.png +0 -0
- static/sim_maps/-1764568205672507394_0_15.png +0 -0
- static/sim_maps/-1764568205672507394_0_16.png +0 -0
- static/sim_maps/-1764568205672507394_0_17.png +0 -0
- static/sim_maps/-1764568205672507394_0_3.png +0 -0
- static/sim_maps/-1764568205672507394_0_4.png +0 -0
- static/sim_maps/-1764568205672507394_0_5.png +0 -0
- static/sim_maps/-1764568205672507394_0_6.png +0 -0
- static/sim_maps/-1764568205672507394_0_7.png +0 -0
- static/sim_maps/-1764568205672507394_0_9.png +0 -0
- static/sim_maps/-1764568205672507394_1_10.png +0 -0
- static/sim_maps/-1764568205672507394_1_11.png +0 -0
- static/sim_maps/-1764568205672507394_1_12.png +0 -0
- static/sim_maps/-1764568205672507394_1_14.png +0 -0
- static/sim_maps/-1764568205672507394_1_15.png +0 -0
- static/sim_maps/-1764568205672507394_1_16.png +0 -0
- static/sim_maps/-1764568205672507394_1_17.png +0 -0
- static/sim_maps/-1764568205672507394_1_3.png +0 -0
- static/sim_maps/-1764568205672507394_1_4.png +0 -0
- static/sim_maps/-1764568205672507394_1_5.png +0 -0
- static/sim_maps/-1764568205672507394_1_6.png +0 -0
backend/vespa_app.py
CHANGED
@@ -104,54 +104,6 @@ class VespaQueryClient:
|
|
104 |
self.logger.debug(result_text)
|
105 |
return response.json
|
106 |
|
107 |
-
async def query_vespa_default(
|
108 |
-
self,
|
109 |
-
query: str,
|
110 |
-
q_emb: torch.Tensor,
|
111 |
-
hits: int = 3,
|
112 |
-
timeout: str = "10s",
|
113 |
-
sim_map: bool = False,
|
114 |
-
**kwargs,
|
115 |
-
) -> dict:
|
116 |
-
"""
|
117 |
-
Query Vespa using the default ranking profile.
|
118 |
-
This corresponds to the "Hybrid ColPali+BM25" radio button in the UI.
|
119 |
-
|
120 |
-
Args:
|
121 |
-
query (str): The query text.
|
122 |
-
q_emb (torch.Tensor): Query embeddings.
|
123 |
-
hits (int, optional): Number of hits to retrieve. Defaults to 3.
|
124 |
-
timeout (str, optional): Query timeout. Defaults to "10s".
|
125 |
-
|
126 |
-
Returns:
|
127 |
-
dict: The formatted query results.
|
128 |
-
"""
|
129 |
-
async with self.app.asyncio(connections=1) as session:
|
130 |
-
query_embedding = self.format_q_embs(q_emb)
|
131 |
-
|
132 |
-
start = time.perf_counter()
|
133 |
-
response: VespaQueryResponse = await session.query(
|
134 |
-
body={
|
135 |
-
"yql": (
|
136 |
-
f"select {self.get_fields(sim_map=sim_map)} from {self.VESPA_SCHEMA_NAME} where userQuery();"
|
137 |
-
),
|
138 |
-
"ranking": self.get_rank_profile("default", sim_map),
|
139 |
-
"query": query,
|
140 |
-
"timeout": timeout,
|
141 |
-
"hits": hits,
|
142 |
-
"input.query(qt)": query_embedding,
|
143 |
-
"presentation.timing": True,
|
144 |
-
**kwargs,
|
145 |
-
},
|
146 |
-
)
|
147 |
-
assert response.is_successful(), response.json
|
148 |
-
stop = time.perf_counter()
|
149 |
-
self.logger.debug(
|
150 |
-
f"Query time + data transfer took: {stop - start} s, Vespa reported searchtime was "
|
151 |
-
f"{response.json.get('timing', {}).get('searchtime', -1)} s"
|
152 |
-
)
|
153 |
-
return self.format_query_results(query, response)
|
154 |
-
|
155 |
async def query_vespa_bm25(
|
156 |
self,
|
157 |
query: str,
|
@@ -286,12 +238,14 @@ class VespaQueryClient:
|
|
286 |
|
287 |
rank_method = ranking.split("_")[0]
|
288 |
sim_map: bool = len(ranking.split("_")) > 1 and ranking.split("_")[1] == "sim"
|
289 |
-
if rank_method == "
|
290 |
-
result = await self.
|
291 |
-
query, q_embs, sim_map=sim_map
|
|
|
|
|
|
|
|
|
292 |
)
|
293 |
-
elif rank_method == "bm25+colpali":
|
294 |
-
result = await self.query_vespa_default(query, q_embs, sim_map=sim_map)
|
295 |
elif rank_method == "bm25":
|
296 |
result = await self.query_vespa_bm25(query, q_embs, sim_map=sim_map)
|
297 |
else:
|
@@ -419,9 +373,10 @@ class VespaQueryClient:
|
|
419 |
else:
|
420 |
return ranking
|
421 |
|
422 |
-
async def
|
423 |
self,
|
424 |
query: str,
|
|
|
425 |
q_emb: torch.Tensor,
|
426 |
target_hits_per_query_tensor: int = 100,
|
427 |
hnsw_explore_additional_hits: int = 300,
|
@@ -467,7 +422,7 @@ class VespaQueryClient:
|
|
467 |
f"select {self.get_fields(sim_map=sim_map)} from {self.VESPA_SCHEMA_NAME} where {nn_string} or userQuery()"
|
468 |
),
|
469 |
"ranking.profile": self.get_rank_profile(
|
470 |
-
|
471 |
),
|
472 |
"timeout": timeout,
|
473 |
"hits": hits,
|
|
|
104 |
self.logger.debug(result_text)
|
105 |
return response.json
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
async def query_vespa_bm25(
|
108 |
self,
|
109 |
query: str,
|
|
|
238 |
|
239 |
rank_method = ranking.split("_")[0]
|
240 |
sim_map: bool = len(ranking.split("_")) > 1 and ranking.split("_")[1] == "sim"
|
241 |
+
if rank_method == "colpali": # ColPali
|
242 |
+
result = await self.query_vespa_colpali(
|
243 |
+
query=query, ranking=rank_method, q_emb=q_embs, sim_map=sim_map
|
244 |
+
)
|
245 |
+
elif rank_method == "hybrid": # Hybrid ColPali+BM25
|
246 |
+
result = await self.query_vespa_colpali(
|
247 |
+
query=query, ranking=rank_method, q_emb=q_embs, sim_map=sim_map
|
248 |
)
|
|
|
|
|
249 |
elif rank_method == "bm25":
|
250 |
result = await self.query_vespa_bm25(query, q_embs, sim_map=sim_map)
|
251 |
else:
|
|
|
373 |
else:
|
374 |
return ranking
|
375 |
|
376 |
+
async def query_vespa_colpali(
|
377 |
self,
|
378 |
query: str,
|
379 |
+
ranking: str,
|
380 |
q_emb: torch.Tensor,
|
381 |
target_hits_per_query_tensor: int = 100,
|
382 |
hnsw_explore_additional_hits: int = 300,
|
|
|
422 |
f"select {self.get_fields(sim_map=sim_map)} from {self.VESPA_SCHEMA_NAME} where {nn_string} or userQuery()"
|
423 |
),
|
424 |
"ranking.profile": self.get_rank_profile(
|
425 |
+
ranking=ranking, sim_map=sim_map
|
426 |
),
|
427 |
"timeout": timeout,
|
428 |
"hits": hits,
|
frontend/app.py
CHANGED
@@ -1,7 +1,30 @@
|
|
1 |
from typing import Optional
|
2 |
from urllib.parse import quote_plus
|
3 |
|
4 |
-
from fasthtml.components import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
from fasthtml.xtend import A, Script
|
6 |
from lucide_fasthtml import Lucide
|
7 |
from shad4fast import Badge, Button, Input, Label, RadioGroup, RadioGroupItem, Separator
|
@@ -175,7 +198,7 @@ def ShareButtons():
|
|
175 |
)
|
176 |
|
177 |
|
178 |
-
def SearchBox(with_border=False, query_value="", ranking_value="
|
179 |
grid_cls = "grid gap-2 items-center p-3 bg-muted w-full"
|
180 |
|
181 |
if with_border:
|
@@ -203,7 +226,7 @@ def SearchBox(with_border=False, query_value="", ranking_value="nn+colpali"):
|
|
203 |
Span("Ranking by:", cls="text-muted-foreground text-xs font-semibold"),
|
204 |
RadioGroup(
|
205 |
Div(
|
206 |
-
RadioGroupItem(value="
|
207 |
Label("ColPali", htmlFor="ColPali"),
|
208 |
cls="flex items-center space-x-2",
|
209 |
),
|
@@ -213,7 +236,7 @@ def SearchBox(with_border=False, query_value="", ranking_value="nn+colpali"):
|
|
213 |
cls="flex items-center space-x-2",
|
214 |
),
|
215 |
Div(
|
216 |
-
RadioGroupItem(value="
|
217 |
Label("Hybrid ColPali + BM25", htmlFor="Hybrid ColPali + BM25"),
|
218 |
cls="flex items-center space-x-2",
|
219 |
),
|
@@ -308,48 +331,124 @@ def Home():
|
|
308 |
)
|
309 |
|
310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
def AboutThisDemo():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
312 |
return Div(
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
322 |
),
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
alt="Vespa and ColPali",
|
327 |
-
cls="object-contain h-[377px]",
|
328 |
-
),
|
329 |
-
cls="grid justify-center",
|
330 |
),
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
cls="text-base",
|
335 |
-
),
|
336 |
-
P(
|
337 |
-
"The application uses a combination of neural networks and traditional search algorithms to retrieve relevant documents based on visual and textual queries.",
|
338 |
-
cls="text-base",
|
339 |
-
),
|
340 |
-
cls="grid gap-2 text-center",
|
341 |
),
|
342 |
-
cls="
|
343 |
),
|
344 |
-
cls="grid gap-
|
345 |
),
|
346 |
-
cls="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
)
|
348 |
|
349 |
|
350 |
def Search(request, search_results=[]):
|
351 |
query_value = request.query_params.get("query", "").strip()
|
352 |
-
ranking_value = request.query_params.get("ranking", "
|
353 |
return Div(
|
354 |
Div(
|
355 |
Div(
|
|
|
1 |
from typing import Optional
|
2 |
from urllib.parse import quote_plus
|
3 |
|
4 |
+
from fasthtml.components import (
|
5 |
+
H1,
|
6 |
+
H2,
|
7 |
+
H3,
|
8 |
+
Br,
|
9 |
+
Div,
|
10 |
+
Form,
|
11 |
+
Img,
|
12 |
+
NotStr,
|
13 |
+
P,
|
14 |
+
Hr,
|
15 |
+
Span,
|
16 |
+
A,
|
17 |
+
Script,
|
18 |
+
Button,
|
19 |
+
Label,
|
20 |
+
RadioGroup,
|
21 |
+
RadioGroupItem,
|
22 |
+
Separator,
|
23 |
+
Ul,
|
24 |
+
Li,
|
25 |
+
Strong,
|
26 |
+
Iframe,
|
27 |
+
)
|
28 |
from fasthtml.xtend import A, Script
|
29 |
from lucide_fasthtml import Lucide
|
30 |
from shad4fast import Badge, Button, Input, Label, RadioGroup, RadioGroupItem, Separator
|
|
|
198 |
)
|
199 |
|
200 |
|
201 |
+
def SearchBox(with_border=False, query_value="", ranking_value="hybrid"):
|
202 |
grid_cls = "grid gap-2 items-center p-3 bg-muted w-full"
|
203 |
|
204 |
if with_border:
|
|
|
226 |
Span("Ranking by:", cls="text-muted-foreground text-xs font-semibold"),
|
227 |
RadioGroup(
|
228 |
Div(
|
229 |
+
RadioGroupItem(value="colpali", id="colpali"),
|
230 |
Label("ColPali", htmlFor="ColPali"),
|
231 |
cls="flex items-center space-x-2",
|
232 |
),
|
|
|
236 |
cls="flex items-center space-x-2",
|
237 |
),
|
238 |
Div(
|
239 |
+
RadioGroupItem(value="hybrid", id="hybrid"),
|
240 |
Label("Hybrid ColPali + BM25", htmlFor="Hybrid ColPali + BM25"),
|
241 |
cls="flex items-center space-x-2",
|
242 |
),
|
|
|
331 |
)
|
332 |
|
333 |
|
334 |
+
def LinkResource(text, href):
|
335 |
+
return Li(
|
336 |
+
A(
|
337 |
+
Lucide(icon="external-link", size="18"),
|
338 |
+
text,
|
339 |
+
href=href,
|
340 |
+
target="_blank",
|
341 |
+
cls="flex items-center gap-1.5 hover:underline bold text-md",
|
342 |
+
),
|
343 |
+
)
|
344 |
+
|
345 |
+
|
346 |
def AboutThisDemo():
|
347 |
+
resources = [
|
348 |
+
{
|
349 |
+
"text": "Vespa Blog: How we built this demo",
|
350 |
+
"href": "https://blog.vespa.ai/visual-rag-in-practice",
|
351 |
+
},
|
352 |
+
{
|
353 |
+
"text": "Notebook to set up Vespa application and feed dataset",
|
354 |
+
"href": "https://pyvespa.readthedocs.io/en/latest/examples/visual_pdf_rag_with_vespa_colpali_cloud.html",
|
355 |
+
},
|
356 |
+
{
|
357 |
+
"text": "Web App (FastHTML) Code",
|
358 |
+
"href": "https://github.com/vespa-engine/sample-apps/tree/master/visual-retrieval-colpali",
|
359 |
+
},
|
360 |
+
{
|
361 |
+
"text": "Vespa Blog: Scaling ColPali to Billions",
|
362 |
+
"href": "https://blog.vespa.ai/scaling-colpali-to-billions/",
|
363 |
+
},
|
364 |
+
{
|
365 |
+
"text": "Vespa Blog: Retrieval with Vision Language Models",
|
366 |
+
"href": "https://blog.vespa.ai/retrieval-with-vision-language-models-colpali/",
|
367 |
+
},
|
368 |
+
]
|
369 |
return Div(
|
370 |
+
H1(
|
371 |
+
"About This Demo",
|
372 |
+
cls="text-3xl md:text-5xl font-bold tracking-wide md:tracking-wider",
|
373 |
+
),
|
374 |
+
P(
|
375 |
+
"This demo showcases a Visual Retrieval-Augmented Generation (RAG) application over PDFs using ColPali embeddings in Vespa, built entirely in Python, using FastHTML. The code is fully open source.",
|
376 |
+
cls="text-base",
|
377 |
+
),
|
378 |
+
Img(
|
379 |
+
src="/static/img/colpali_child.png",
|
380 |
+
alt="Example of token level similarity map",
|
381 |
+
cls="w-full",
|
382 |
+
),
|
383 |
+
H2("Resources", cls="text-2xl font-semibold"),
|
384 |
+
Ul(
|
385 |
+
*[
|
386 |
+
LinkResource(resource["text"], resource["href"])
|
387 |
+
for resource in resources
|
388 |
+
],
|
389 |
+
cls="space-y-2 list-disc pl-5",
|
390 |
+
),
|
391 |
+
H2("Architecture Overview", cls="text-2xl font-semibold"),
|
392 |
+
Img(
|
393 |
+
src="/static/img/visual-retrieval-demoapp-arch.png",
|
394 |
+
alt="Architecture Overview",
|
395 |
+
cls="w-full",
|
396 |
+
),
|
397 |
+
Ul(
|
398 |
+
Li(
|
399 |
+
Strong("Vespa Application: "),
|
400 |
+
"Vespa Application that handles indexing, search, ranking and queries, leveraging features like phased ranking and multivector MaxSim calculations.",
|
401 |
+
),
|
402 |
+
Li(
|
403 |
+
Strong("Frontend: "),
|
404 |
+
"Built with FastHTML, offering a professional and responsive user interface without the complexity of separate frontend frameworks.",
|
405 |
+
),
|
406 |
+
Li(
|
407 |
+
Strong("Backend: "),
|
408 |
+
"Also built with FastHTML. Handles query embedding inference using ColPali, serves static files, and is responsible for orchestrating interactions between Vespa and the frontend.",
|
409 |
+
),
|
410 |
+
Li(
|
411 |
+
Strong("Gemini API: "),
|
412 |
+
"VLM for the AI response, providing responses based on the top results from Vespa.",
|
413 |
+
cls="list-disc list-inside",
|
414 |
+
),
|
415 |
+
H2("User Experience Highlights", cls="text-2xl font-semibold"),
|
416 |
+
Ul(
|
417 |
+
Li(
|
418 |
+
Strong("Fast and Responsive: "),
|
419 |
+
"Optimized for quick loading times, with phased content delivery to display essential information immediately while loading detailed data in the background.",
|
420 |
),
|
421 |
+
Li(
|
422 |
+
Strong("Similarity Maps: "),
|
423 |
+
"Provides visual highlights of the most relevant parts of a page in response to a query, enhancing interpretability.",
|
|
|
|
|
|
|
|
|
424 |
),
|
425 |
+
Li(
|
426 |
+
Strong("Type-Ahead Suggestions: "),
|
427 |
+
"Offers query suggestions to assist users in formulating effective searches.",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
),
|
429 |
+
cls="list-disc list-inside",
|
430 |
),
|
431 |
+
cls="grid gap-5",
|
432 |
),
|
433 |
+
H2("Dataset", cls="text-2xl font-semibold"),
|
434 |
+
P(
|
435 |
+
"The dataset used in this demo is retrieved from reports published by the Norwegian Government Pension Fund Global. It contains 6,992 pages from 116 PDF reports (2000–2024). The information is often presented in visual formats, making it an ideal dataset for visual retrieval applications.",
|
436 |
+
cls="text-base",
|
437 |
+
),
|
438 |
+
Iframe(
|
439 |
+
src="https://huggingface.co/datasets/vespa-engine/gpfg-QA/embed/viewer",
|
440 |
+
frameborder="0",
|
441 |
+
width="100%",
|
442 |
+
height="500",
|
443 |
+
),
|
444 |
+
Hr(), # To add some margin to bottom. Probably a much better way to do this, but the mb-[16vh] class doesn't seem to be applied
|
445 |
+
cls="w-full h-full max-w-screen-md gap-4 mx-auto mt-[8vh] mb-[16vh] grid gap-8 content-start",
|
446 |
)
|
447 |
|
448 |
|
449 |
def Search(request, search_results=[]):
|
450 |
query_value = request.query_params.get("query", "").strip()
|
451 |
+
ranking_value = request.query_params.get("ranking", "hybrid")
|
452 |
return Div(
|
453 |
Div(
|
454 |
Div(
|
main.py
CHANGED
@@ -156,7 +156,7 @@ def get():
|
|
156 |
|
157 |
|
158 |
@rt("/search")
|
159 |
-
def get(request, query: str = "", ranking: str = "
|
160 |
logger.info(f"/search: Fetching results for query: {query}, ranking: {ranking}")
|
161 |
|
162 |
# Always render the SearchBox first
|
|
|
156 |
|
157 |
|
158 |
@rt("/search")
|
159 |
+
def get(request, query: str = "", ranking: str = "hybrid"):
|
160 |
logger.info(f"/search: Fetching results for query: {query}, ranking: {ranking}")
|
161 |
|
162 |
# Always render the SearchBox first
|
static/full_images/02b30f947c2530e86fcc6f1617b284cb.jpg
ADDED
static/full_images/04a954607e09c13ca53d62c9506b454d.jpg
ADDED
static/full_images/0754449971c2415d0993dba99b610fb8.jpg
ADDED
static/full_images/15441af3f266efefee2e1fa65da0ad5f.jpg
ADDED
static/full_images/2722b68e9863dec57bd14b18ec5b6597.jpg
ADDED
static/full_images/2e20778433bb7b41f2b3ff9d273ddedd.jpg
ADDED
static/full_images/428d4ccc84859c8407ceaf66b5caebb1.jpg
ADDED
static/full_images/470037d1296e5e9634a47d9e3c1c25e8.jpg
ADDED
static/full_images/573506dd06553465e28617136e1aef34.jpg
ADDED
static/full_images/641cf96aed6c75a938ca0303ed0723fb.jpg
ADDED
static/full_images/65babd1b1ae12a8be4af8621473595cb.jpg
ADDED
static/full_images/6be2405bc05a52291cb13d47f529ee03.jpg
ADDED
static/full_images/6d5eac97f945ec5241c00eb3fa1eb348.jpg
ADDED
static/full_images/95f14a79b6df72466b8ed6473758a23c.jpg
ADDED
static/full_images/98db7f03fac252c78f142dc26780d7e1.jpg
ADDED
static/full_images/a2b1647b5ff2a8485933a51866473a91.jpg
ADDED
static/full_images/b23c60be45be26509dafd38e9fc77d6f.jpg
ADDED
static/full_images/cb7e8833775e2cbe11bc116219f7e09d.jpg
ADDED
static/full_images/e491fa7c526511cf6420ca54665e52a4.jpg
ADDED
static/full_images/ea2bb0b2de938854888ac8e52124b077.jpg
ADDED
static/full_images/f7785696541fc185bc1d10c8608b8100.jpg
ADDED
static/img/colpali_child.png
ADDED
static/img/visual-retrieval-demoapp-arch.png
ADDED
static/sim_maps/-1764568205672507394_0_10.png
ADDED
static/sim_maps/-1764568205672507394_0_11.png
ADDED
static/sim_maps/-1764568205672507394_0_12.png
ADDED
static/sim_maps/-1764568205672507394_0_14.png
ADDED
static/sim_maps/-1764568205672507394_0_15.png
ADDED
static/sim_maps/-1764568205672507394_0_16.png
ADDED
static/sim_maps/-1764568205672507394_0_17.png
ADDED
static/sim_maps/-1764568205672507394_0_3.png
ADDED
static/sim_maps/-1764568205672507394_0_4.png
ADDED
static/sim_maps/-1764568205672507394_0_5.png
ADDED
static/sim_maps/-1764568205672507394_0_6.png
ADDED
static/sim_maps/-1764568205672507394_0_7.png
ADDED
static/sim_maps/-1764568205672507394_0_9.png
ADDED
static/sim_maps/-1764568205672507394_1_10.png
ADDED
static/sim_maps/-1764568205672507394_1_11.png
ADDED
static/sim_maps/-1764568205672507394_1_12.png
ADDED
static/sim_maps/-1764568205672507394_1_14.png
ADDED
static/sim_maps/-1764568205672507394_1_15.png
ADDED
static/sim_maps/-1764568205672507394_1_16.png
ADDED
static/sim_maps/-1764568205672507394_1_17.png
ADDED
static/sim_maps/-1764568205672507394_1_3.png
ADDED
static/sim_maps/-1764568205672507394_1_4.png
ADDED
static/sim_maps/-1764568205672507394_1_5.png
ADDED
static/sim_maps/-1764568205672507394_1_6.png
ADDED