feat: wire frontend to vision pipeline search and tags
- Add search API client (POST /photos/search) and useSearchQuery hook for hybrid FTS + semantic search with RRF ranking - Extend Tag type with kind, source, representative_photo_id fields - Add tags.merge() API method - Update useTagsQuery to accept optional kind filter - Add People section to sidebar (face clusters from GET /tags?kind=face_cluster) - Sidebar Tags count now shows user tags only; People shows face clusters The existing GET /photos?q= flow is preserved for browsing; the new search hook activates when the search box has a non-empty query. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
frontend/src/hooks/useSearchQuery.ts
Normal file
37
frontend/src/hooks/useSearchQuery.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { search, type SearchResult } from '../services/api'
|
||||
import { useFilterStore } from '../store/filterStore'
|
||||
|
||||
/**
|
||||
* Hybrid search hook — fires POST /photos/search when the user has a
|
||||
* non-empty search query. Returns results ranked by RRF (FTS + semantic).
|
||||
*
|
||||
* When `q` is empty, this hook is disabled and returns no data — the
|
||||
* normal usePhotosQuery takes over for browse mode.
|
||||
*/
|
||||
export function useSearchQuery() {
|
||||
const q = useFilterStore((s) => s.q)
|
||||
const tagIds = useFilterStore((s) => s.tagIds)
|
||||
const dateFrom = useFilterStore((s) => s.dateFrom)
|
||||
const dateTo = useFilterStore((s) => s.dateTo)
|
||||
|
||||
const hasQuery = q.trim().length > 0
|
||||
|
||||
return useQuery<SearchResult[]>({
|
||||
queryKey: ['search', q, tagIds, dateFrom, dateTo],
|
||||
queryFn: async () => {
|
||||
const resp = await search.query({
|
||||
q: q.trim(),
|
||||
filters: {
|
||||
tag_ids: tagIds.length > 0 ? tagIds : undefined,
|
||||
date_from: dateFrom ?? undefined,
|
||||
date_to: dateTo ?? undefined,
|
||||
},
|
||||
limit: 200,
|
||||
})
|
||||
return resp.results
|
||||
},
|
||||
enabled: hasQuery,
|
||||
staleTime: 30_000,
|
||||
})
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { tags as tagsApi, type Tag } from '../services/api'
|
||||
import { tags as tagsApi, type Tag, type TagKind } from '../services/api'
|
||||
|
||||
export const TAGS_QUERY_KEY = ['tags'] as const
|
||||
|
||||
export function useTagsQuery() {
|
||||
export function useTagsQuery(kind?: TagKind) {
|
||||
return useQuery<Tag[]>({
|
||||
queryKey: TAGS_QUERY_KEY,
|
||||
queryFn: tagsApi.list,
|
||||
queryKey: kind ? ['tags', kind] : TAGS_QUERY_KEY,
|
||||
queryFn: () => tagsApi.list(kind),
|
||||
staleTime: 30_000,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user