feat: semantic search with Qdrant + Ollama embeddings

- Add SemanticSearchService with embed() + searchQdrant() methods
- Add GET /api/search/semantic endpoint (?q=query&k=5)
- Wire SemanticSearchService into router and cmd/server/main.go
- Add SemanticSearch React page with results + similarity scores
- Add 'Semantic Search' nav link in App.tsx
- Add unit tests with mocked Ollama + Qdrant HTTP servers (4 tests, all passing)
- Add GitHub issue templates (bug report, feature request)
- Add pull request template
This commit is contained in:
Christopher Mayor
2026-04-24 11:13:50 -07:00
parent 97c502a5f9
commit 468519fde1
9 changed files with 646 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ const Activity = lazy(() => import('./pages/Activity'))
const Blocklist = lazy(() => import('./pages/Blocklist'))
const Settings = lazy(() => import('./pages/Settings'))
const Search = lazy(() => import('./pages/Search'))
const SemanticSearch = lazy(() => import('./pages/SemanticSearch'))
const navItems = [
{ to: '/', label: 'Dashboard' },
@@ -23,6 +24,7 @@ const navItems = [
{ to: '/calendar', label: 'Calendar' },
{ to: '/queue', label: 'Queue' },
{ to: '/search', label: 'Search' },
{ to: '/semantic-search', label: 'Semantic Search' },
{ to: '/activity', label: 'Activity' },
{ to: '/requests', label: 'Requests' },
{ to: '/blocklist', label: 'Blocklist' },
@@ -62,6 +64,7 @@ export default function App() {
<Route path="/library/:type/:id" element={<MediaDetail />} />
<Route path="/queue" element={<Queue />} />
<Route path="/search" element={<Search />} />
<Route path="/semantic-search" element={<SemanticSearch />} />
<Route path="/activity" element={<Activity />} />
<Route path="/requests" element={<Requests />} />
<Route path="/blocklist" element={<Blocklist />} />