Spaces:
Runtime error
Runtime error
| import { useState } from "react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Input } from "@/components/ui/input"; | |
| import { Label } from "@/components/ui/label"; | |
| import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; | |
| import { Checkbox } from "@/components/ui/checkbox"; | |
| import { Search, Loader2 } from "lucide-react"; | |
| import { type SearchRequest } from "@shared/schema"; | |
| interface SearchInterfaceProps { | |
| onSearch: (request: SearchRequest) => void; | |
| isLoading?: boolean; | |
| } | |
| export default function SearchInterface({ onSearch, isLoading }: SearchInterfaceProps) { | |
| const [query, setQuery] = useState(""); | |
| const [searchType, setSearchType] = useState<"semantic" | "keyword" | "hybrid">("semantic"); | |
| const [sourceTypes, setSourceTypes] = useState<string[]>(["pdf", "web", "academic", "code"]); | |
| const handleSubmit = (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| if (!query.trim()) return; | |
| onSearch({ | |
| query: query.trim(), | |
| searchType, | |
| filters: { | |
| sourceTypes: sourceTypes.length > 0 ? sourceTypes : undefined, | |
| }, | |
| limit: 10, | |
| offset: 0, | |
| }); | |
| }; | |
| const handleSourceTypeChange = (sourceType: string, checked: boolean) => { | |
| setSourceTypes(prev => | |
| checked | |
| ? [...prev, sourceType] | |
| : prev.filter(type => type !== sourceType) | |
| ); | |
| }; | |
| const handleKeyDown = (e: React.KeyboardEvent) => { | |
| if (e.key === "Enter" && !e.shiftKey) { | |
| e.preventDefault(); | |
| handleSubmit(e); | |
| } else if (e.key === "Escape") { | |
| setQuery(""); | |
| } | |
| }; | |
| return ( | |
| <div className="bg-white dark:bg-slate-800 rounded-xl shadow-sm border border-slate-200 dark:border-slate-700 p-6 mb-6"> | |
| <form onSubmit={handleSubmit}> | |
| <div className="flex flex-col lg:flex-row gap-4"> | |
| <div className="flex-1"> | |
| <Label htmlFor="knowledge-search" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2"> | |
| Search Knowledge Base | |
| </Label> | |
| <div className="relative"> | |
| <Input | |
| id="knowledge-search" | |
| type="text" | |
| placeholder="Enter your query to find relevant documents... (Press Enter to search, Esc to clear)" | |
| value={query} | |
| onChange={(e) => setQuery(e.target.value)} | |
| onKeyDown={handleKeyDown} | |
| className="pl-11 focus:ring-2 focus:ring-blue-500 focus:border-blue-500" | |
| disabled={isLoading} | |
| aria-label="Search knowledge base" | |
| /> | |
| <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400 w-4 h-4" /> | |
| </div> | |
| </div> | |
| <div className="lg:w-auto"> | |
| <Label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2"> | |
| Search Type | |
| </Label> | |
| <Select value={searchType} onValueChange={(value: any) => setSearchType(value)}> | |
| <SelectTrigger className="w-full lg:w-40"> | |
| <SelectValue /> | |
| </SelectTrigger> | |
| <SelectContent> | |
| <SelectItem value="semantic">Semantic Search</SelectItem> | |
| <SelectItem value="keyword">Keyword Search</SelectItem> | |
| <SelectItem value="hybrid">Hybrid Search</SelectItem> | |
| </SelectContent> | |
| </Select> | |
| </div> | |
| <div className="lg:w-auto flex items-end"> | |
| <Button | |
| type="submit" | |
| disabled={!query.trim() || isLoading} | |
| className="px-6 py-3 bg-blue-600 hover:bg-blue-700 focus:ring-2 focus:ring-blue-600 focus:ring-offset-2" | |
| aria-label={isLoading ? "Searching knowledge base" : "Search knowledge base"} | |
| > | |
| {isLoading ? ( | |
| <> | |
| <Loader2 className="w-4 h-4 mr-2 animate-spin" aria-hidden="true" /> | |
| Searching... | |
| </> | |
| ) : ( | |
| <> | |
| <Search className="w-4 h-4 mr-2" aria-hidden="true" /> | |
| Search | |
| </> | |
| )} | |
| </Button> | |
| </div> | |
| </div> | |
| {/* Search Filters */} | |
| <div className="mt-4 pt-4 border-t border-slate-200 dark:border-slate-700"> | |
| <div className="flex flex-wrap gap-6"> | |
| {[ | |
| { id: "pdf", label: "PDFs" }, | |
| { id: "web", label: "Web Pages" }, | |
| { id: "academic", label: "Academic Papers" }, | |
| { id: "code", label: "Code Repositories" } | |
| ].map(({ id, label }) => ( | |
| <div key={id} className="flex items-center space-x-2"> | |
| <Checkbox | |
| id={`filter-${id}`} | |
| checked={sourceTypes.includes(id)} | |
| onCheckedChange={(checked) => handleSourceTypeChange(id, !!checked)} | |
| /> | |
| <Label | |
| htmlFor={`filter-${id}`} | |
| className="text-sm text-slate-600 dark:text-slate-400 cursor-pointer" | |
| > | |
| {label} | |
| </Label> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| </form> | |
| {/* AI Development Tools */} | |
| <div className="mt-4 pt-4 border-t border-slate-200 dark:border-slate-700"> | |
| <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3"> | |
| <div> | |
| <h3 className="text-sm font-medium text-slate-700 dark:text-slate-300">AI Development Tools</h3> | |
| <p className="text-xs text-slate-500 dark:text-slate-400">Access external AI platforms and services</p> | |
| </div> | |
| <div className="flex flex-wrap gap-2"> | |
| <Button | |
| type="button" | |
| variant="outline" | |
| size="sm" | |
| onClick={() => window.open('https://studio.nebius.com/', '_blank')} | |
| className="text-xs hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/20" | |
| > | |
| ๐ Nebius Studio | |
| </Button> | |
| <Button | |
| type="button" | |
| variant="outline" | |
| size="sm" | |
| onClick={() => window.open('https://platform.openai.com/playground', '_blank')} | |
| className="text-xs hover:bg-green-50 hover:border-green-300 dark:hover:bg-green-900/20" | |
| > | |
| ๐ค OpenAI Playground | |
| </Button> | |
| <Button | |
| type="button" | |
| variant="outline" | |
| size="sm" | |
| onClick={() => window.open('https://huggingface.co/spaces', '_blank')} | |
| className="text-xs hover:bg-orange-50 hover:border-orange-300 dark:hover:bg-orange-900/20" | |
| > | |
| ๐ค HuggingFace Spaces | |
| </Button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |