Spaces:
Running
on
L40S
Running
on
L40S
File size: 6,622 Bytes
8ce4d25 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
from urllib.parse import quote_plus
from fasthtml.components import Div, H1, P, Img, H2, Form, Span
from fasthtml.xtend import Script, A
from lucide_fasthtml import Lucide
from shad4fast import Button, Input, Badge
def check_input_script():
return Script(
"""
window.onload = function() {
const input = document.getElementById('search-input');
const button = document.querySelector('[data-button="search-button"]');
function checkInputValue() { button.disabled = input.value.trim() === ""; }
input.addEventListener('input', checkInputValue);
checkInputValue();
};
"""
)
def SearchBox(with_border=False, query_value=""):
grid_cls = "grid gap-2 items-center p-3 bg-muted/80 dark:bg-muted/40 w-full"
if with_border:
grid_cls = "grid gap-2 p-3 rounded-md border border-input bg-muted/80 dark:bg-muted/40 w-full ring-offset-background focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:border-input"
return Form(
Div(
Lucide(icon="search", cls="absolute left-2 top-2 text-muted-foreground"),
Input(
placeholder="Enter your search query...",
name="query",
value=query_value,
id="search-input",
cls="text-base pl-10 border-transparent ring-offset-transparent ring-0 focus-visible:ring-transparent",
style="font-size: 1rem",
autofocus=True,
),
cls="relative",
),
Div(
Span("controls", cls="text-muted-foreground"),
Button(
Lucide(icon="arrow-right", size="21"),
size="sm",
type="submit",
data_button="search-button",
disabled=True,
),
cls="flex justify-between",
),
check_input_script(),
action=f"/search?query={quote_plus(query_value)}", # This takes the user to /search with the loading message
method="GET",
hx_get=f"/fetch_results?query={quote_plus(query_value)}", # This fetches the results asynchronously
hx_trigger="load", # Trigger this after the page loads
hx_target="#search-results", # Update the search results div dynamically
hx_swap="outerHTML", # Replace the search results div entirely
hx_indicator="#loading-indicator", # Show the loading indicator while fetching results
cls=grid_cls,
)
def SampleQueries():
sample_queries = [
"What is the future of energy storage?",
"What is sustainable energy?",
"How to reduce carbon emissions?",
]
query_badges = []
for query in sample_queries:
query_badges.append(
A(
Badge(
Div(
Lucide(
icon="text-search", size="18", cls="text-muted-foreground"
),
Span(query, cls="text-base font-normal"),
cls="flex gap-2 items-center",
),
variant="outline",
cls="text-base font-normal text-muted-foreground",
),
href=f"/search?query={quote_plus(query)}",
cls="no-underline",
)
)
return Div(*query_badges, cls="grid gap-2 justify-items-center")
def Hero():
return Div(
H1(
"Vespa.Ai + ColPali",
cls="text-5xl md:text-7xl font-bold tracking-wide md:tracking-wider bg-clip-text text-transparent bg-gradient-to-r from-black to-gray-700 dark:from-white dark:to-gray-300 animate-fade-in",
),
P(
"Efficient Document Retrieval with Vision Language Models",
cls="text-lg md:text-2xl text-muted-foreground md:tracking-wide",
),
cls="grid gap-5 text-center",
)
def Home():
return Div(
Div(
Hero(),
SearchBox(with_border=True),
SampleQueries(),
cls="grid gap-8 -mt-[34vh]",
),
cls="grid w-full h-full max-w-screen-md items-center gap-4 mx-auto",
)
def Search(request, search_results=[]):
query_value = request.query_params.get("query", "").strip()
return Div(
Div(
SearchBox(
query_value=query_value
), # Pass the query value to pre-fill the SearchBox
Div(
LoadingMessage(), # Show the loading message initially
id="search-results", # This will be replaced by the search results
),
cls="grid",
),
cls="grid",
)
def LoadingMessage():
return Div(
P("Loading... Please wait.", cls="text-base text-center"),
cls="p-10 text-center text-muted-foreground",
id="loading-indicator",
)
def SearchResult(results=[]):
if not results:
return Div(
P(
"No results found for your query.",
cls="text-muted-foreground text-base text-center",
),
cls="grid p-10",
)
# Otherwise, display the search results
result_items = []
for result in results:
fields = result["fields"] # Extract the 'fields' part of each result
base64_image = (
f"data:image/jpeg;base64,{fields['image']}" # Format base64 image
)
# Print the fields that start with 'sim_map'
for key, value in fields.items():
if key.startswith("sim_map"):
print(f"{key}")
result_items.append(
Div(
Div(
Img(src=base64_image, alt=fields["title"], cls="max-w-full h-auto"),
cls="bg-background px-3 py-5",
),
Div(
Div(
H2(fields["title"], cls="text-xl font-semibold"),
P(
fields["text"], cls="text-muted-foreground"
), # Use the URL as the description
cls="text-sm grid gap-y-4",
),
cls="bg-background px-3 py-5",
),
cls="grid grid-cols-subgrid col-span-2",
)
)
return Div(
*result_items,
cls="grid grid-cols-2 gap-px bg-border",
id="search-results", # This will be the target for HTMX updates
)
|