import asyncio import base64 import os import time import uuid import logging import sys from concurrent.futures import ThreadPoolExecutor from pathlib import Path import google.generativeai as genai from fastcore.parallel import threaded from fasthtml.common import ( Aside, Div, FileResponse, HighlightJS, Img, JSONResponse, Link, Main, P, RedirectResponse, Script, StreamingResponse, fast_app, serve, ) from PIL import Image from shad4fast import ShadHead from vespa.application import Vespa from backend.colpali import SimMapGenerator from backend.vespa_app import VespaQueryClient from frontend.app import ( AboutThisDemo, ChatResult, Home, Search, SearchBox, SearchResult, SimMapButtonPoll, SimMapButtonReady, ) 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") # Get log level from environment variable, default to INFO LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper() # Configure logger logger = logging.getLogger("vespa_app") handler = logging.StreamHandler(sys.stdout) handler.setFormatter( logging.Formatter( "%(levelname)s: \t %(asctime)s \t %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) ) logger.addHandler(handler) logger.setLevel(getattr(logging, LOG_LEVEL)) 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(logger=logger) 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 can't find enough relevant information on these pages to answer your question.". Your response should be HTML formatted, but only simple tags, such as .

, ,