"use client" import * as React from "react" import { Search, X, ImagePlus, ArrowLeft, Clock, Sparkles } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { getHistory, clearHistory } from "@/lib/history" // The embedding model is trained on natural-language questions (SimpleQA-style), // which retrieve the target page most precisely — Ask mode leans on that. The // search grid deliberately uses bare, slightly ambiguous titles instead: "The // Starry Night" fans out to Van Gogh + Munch + Millet + the Dutch Sterrennacht, // a far more striking visual spread than one painting repeated five times. const EXAMPLE_QUERIES = [ "The Starry Night", "Periodic table", "Taj Mahal", "The Great Wave off Kanagawa", "清明上河图", ] // The first two are verified "ChatGPT gets these wrong" questions: the answers // live in table/infobox cells (match-stats table, RTO code box) that parametric // memory and text scraping both fumble — but reading the rendered page nails. const ASK_EXAMPLES = [ "How many shots on target did Inter have in the 2010 Champions League final?", "Which district in Nagaland has the RTO code NL-03?", "Explain Van Gogh's The Starry Night", "介绍一下兵马俑", ] interface SearchBarProps { onSearch: (query: string, image?: string) => void onReset?: () => void isLoading: boolean hasResults?: boolean defaultValue?: string mode?: "search" | "ask" } export function SearchBar({ onSearch, onReset, isLoading, hasResults, defaultValue = "", mode = "search" }: SearchBarProps) { const [query, setQuery] = React.useState(defaultValue) const [imageData, setImageData] = React.useState() const [imageName, setImageName] = React.useState("") const [isDragOver, setIsDragOver] = React.useState(false) const fileInputRef = React.useRef(null) const inputWrapperRef = React.useRef(null) const [showHistory, setShowHistory] = React.useState(false) const [history, setHistory] = React.useState([]) const blurTimeoutRef = React.useRef | null>(null) // Refresh history from localStorage whenever dropdown might show function refreshHistory() { setHistory(getHistory()) } // Cmd+K / Ctrl+K global shortcut to focus search input React.useEffect(() => { const handleKey = (e: KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault() const input = inputWrapperRef.current?.querySelector("input") input?.focus() } } window.addEventListener("keydown", handleKey) return () => window.removeEventListener("keydown", handleKey) }, []) function handleFile(file: File) { if (!file.type.startsWith("image/")) return setImageName(file.name) const reader = new FileReader() reader.onload = (e) => { setImageData(e.target?.result as string) } reader.readAsDataURL(file) } function handleSubmit(e: React.FormEvent) { e.preventDefault() if (!query.trim() && !imageData) return onSearch(query.trim(), imageData) } function clearImage() { setImageData(undefined) setImageName("") if (fileInputRef.current) fileInputRef.current.value = "" } function handleDrop(e: React.DragEvent) { e.preventDefault() setIsDragOver(false) const file = e.dataTransfer.files[0] if (file) handleFile(file) } function handleDragOver(e: React.DragEvent) { e.preventDefault() setIsDragOver(true) } function handleDragLeave(e: React.DragEvent) { e.preventDefault() setIsDragOver(false) } function handlePaste(e: React.ClipboardEvent) { const file = Array.from(e.clipboardData.items) .find((it) => it.type.startsWith("image/")) ?.getAsFile() if (file) { e.preventDefault() handleFile(file) } } return (
{hasResults && onReset && ( )} {imageData && (
{/* eslint-disable-next-line @next/next/no-img-element */} {imageName}
)}
setQuery(e.target.value)} onFocus={() => { refreshHistory() setShowHistory(true) }} onBlur={() => { blurTimeoutRef.current = setTimeout(() => setShowHistory(false), 150) }} placeholder={mode === "ask" ? "Ask anything about Wikipedia..." : "Search Wikipedia with pixels..."} className="w-full border-0 bg-transparent pr-10 shadow-none focus-visible:ring-0 focus-visible:border-transparent" /> ⌘K
{ const file = e.target.files?.[0] if (file) handleFile(file) }} /> {mode === "search" && ( )}
{/* History dropdown */} {showHistory && !query && !hasResults && history.length > 0 && (
{history.map((item) => ( ))}
)} {!hasResults &&
Try:
{(mode === "ask" ? ASK_EXAMPLES : EXAMPLE_QUERIES).map((q) => ( ))}
}
) }