import asyncio import base64 import io import os import time from concurrent.futures import ThreadPoolExecutor from functools import partial from pathlib import Path import uuid import google.generativeai as genai from fasthtml.common import * from PIL import Image from shad4fast import * from vespa.application import Vespa from backend.cache import LRUCache from backend.colpali import ( add_sim_maps_to_result, get_query_embeddings_and_token_map, is_special_token, ) from backend.modelmanager import ModelManager from backend.vespa_app import VespaQueryClient from frontend.app import ( ChatResult, Home, Search, SearchBox, SearchResult, SimMapButtonPoll, SimMapButtonReady, WhatIsThis, ) from frontend.layout import Layout highlight_js_theme_link = Link(id="highlight-theme", rel="stylesheet", href="") highlight_js_theme = Script(src="/static/js/highlightjs-theme.js") highlight_js = HighlightJS( langs=["python", "javascript", "java", "json", "xml"], dark="github-dark", light="github", ) overlayscrollbars_link = Link( rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/overlayscrollbars/2.10.0/styles/overlayscrollbars.min.css", type="text/css", ) overlayscrollbars_js = Script( src="https://cdnjs.cloudflare.com/ajax/libs/overlayscrollbars/2.10.0/browser/overlayscrollbars.browser.es5.min.js" ) awesomplete_link = Link( rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.7/awesomplete.min.css", type="text/css", ) awesomplete_js = Script( src="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.7/awesomplete.min.js" ) sselink = Script(src="https://unpkg.com/htmx-ext-sse@2.2.1/sse.js") app, rt = fast_app( htmlkw={"cls": "grid h-full"}, pico=False, hdrs=( highlight_js, highlight_js_theme_link, highlight_js_theme, overlayscrollbars_link, overlayscrollbars_js, awesomplete_link, awesomplete_js, sselink, ShadHead(tw_cdn=False, theme_handle=True), ), ) vespa_app: Vespa = VespaQueryClient() result_cache = LRUCache(max_size=20) # Each result can be ~10MB task_cache = LRUCache( max_size=1000 ) # Map from query_id to boolean value - False if not all results are ready. thread_pool = ThreadPoolExecutor() # Gemini config genai.configure(api_key=os.getenv("GEMINI_API_KEY")) GEMINI_SYSTEM_PROMPT = """If the user query is a question, try your best to answer it based on the provided images. If the user query can not be interpreted as a question, or if the answer to the query can not be inferred from the images, answer with the exact phrase "I am sorry, I do not have enough information in the image to answer your question.". Your response should be HTML formatted, but only simple tags, such as .

, ,