fix: Update viz routes to use BM25 hybrid search after refactor
- Remove obsolete search algorithm imports (Fuzzy, Keyword, Hybrid) - Update UI to only show Semantic and BM25 Hybrid algorithms - Replace manual weight controls with RRF fusion info message - Update default algorithm from "hybrid" to "bm25_hybrid" - Remove weight parameters (semantic_weight, keyword_weight, fuzzy_weight) - Update score_threshold default from 0.7 to 0.0 for RRF scoring - Document ty type checker in CLAUDE.md Fixes unresolved-import type errors after BM25 refactor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,13 +15,17 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
- **Use Python 3.10+ union syntax**: `str | None` instead of `Optional[str]`
|
- **Use Python 3.10+ union syntax**: `str | None` instead of `Optional[str]`
|
||||||
- **Use lowercase generics**: `dict[str, Any]` instead of `Dict[str, Any]`
|
- **Use lowercase generics**: `dict[str, Any]` instead of `Dict[str, Any]`
|
||||||
- **Type all function signatures** - Parameters and return types
|
- **Type all function signatures** - Parameters and return types
|
||||||
- **No explicit type checker configured** - Ruff handles linting only
|
- **Type checker**: `ty` is configured for static type checking
|
||||||
|
```bash
|
||||||
|
uv run ty check -- nextcloud_mcp_server
|
||||||
|
```
|
||||||
|
|
||||||
### Code Quality
|
### Code Quality
|
||||||
- **Run ruff before committing**:
|
- **Run ruff and ty before committing**:
|
||||||
```bash
|
```bash
|
||||||
uv run ruff check
|
uv run ruff check
|
||||||
uv run ruff format
|
uv run ruff format
|
||||||
|
uv run ty check -- nextcloud_mcp_server
|
||||||
```
|
```
|
||||||
- **Ruff configuration** in pyproject.toml (extends select: ["I"] for import sorting)
|
- **Ruff configuration** in pyproject.toml (extends select: ["I"] for import sorting)
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ from starlette.responses import HTMLResponse, JSONResponse
|
|||||||
|
|
||||||
from nextcloud_mcp_server.config import get_settings
|
from nextcloud_mcp_server.config import get_settings
|
||||||
from nextcloud_mcp_server.search import (
|
from nextcloud_mcp_server.search import (
|
||||||
FuzzySearchAlgorithm,
|
BM25HybridSearchAlgorithm,
|
||||||
HybridSearchAlgorithm,
|
|
||||||
KeywordSearchAlgorithm,
|
|
||||||
SemanticSearchAlgorithm,
|
SemanticSearchAlgorithm,
|
||||||
)
|
)
|
||||||
from nextcloud_mcp_server.vector.pca import PCA
|
from nextcloud_mcp_server.vector.pca import PCA
|
||||||
@@ -208,10 +206,8 @@ async def vector_visualization_html(request: Request) -> HTMLResponse:
|
|||||||
<div class="viz-control-group" style="margin-bottom: 0;">
|
<div class="viz-control-group" style="margin-bottom: 0;">
|
||||||
<label>Algorithm</label>
|
<label>Algorithm</label>
|
||||||
<select x-model="algorithm">
|
<select x-model="algorithm">
|
||||||
<option value="semantic">Semantic (Vector Similarity)</option>
|
<option value="semantic">Semantic (Dense Vectors)</option>
|
||||||
<option value="keyword">Keyword (Token Matching)</option>
|
<option value="bm25_hybrid" selected>BM25 Hybrid (Dense + Sparse RRF)</option>
|
||||||
<option value="fuzzy">Fuzzy (Character Overlap)</option>
|
|
||||||
<option value="hybrid" selected>Hybrid (RRF Fusion)</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -259,25 +255,13 @@ async def vector_visualization_html(request: Request) -> HTMLResponse:
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hybrid Weights (only when hybrid selected) -->
|
<!-- Info: BM25 Hybrid uses native RRF fusion (no manual weights) -->
|
||||||
<div x-show="algorithm === 'hybrid'" style="margin-top: 16px; padding: 12px; background: #e9ecef; border-radius: 4px;">
|
<div x-show="algorithm === 'bm25_hybrid'" style="margin-top: 16px; padding: 12px; background: #e9ecef; border-radius: 4px;">
|
||||||
<label style="margin-bottom: 12px; display: block;">Hybrid Algorithm Weights</label>
|
<p style="margin: 0; font-size: 14px; color: #666;">
|
||||||
|
<strong>BM25 Hybrid Search:</strong> Uses Qdrant's native Reciprocal Rank Fusion (RRF)
|
||||||
<div style="margin-bottom: 8px;">
|
to automatically combine dense semantic vectors with sparse BM25 keyword vectors.
|
||||||
<label style="display: inline-block; width: 100px; font-weight: normal;">Semantic:</label>
|
No manual weight tuning required.
|
||||||
<input type="range" x-model.number="semanticWeight" min="0" max="1" step="0.1" style="width: 200px; display: inline-block;">
|
</p>
|
||||||
<span class="viz-weight-display" x-text="semanticWeight.toFixed(1)"></span>
|
|
||||||
</div>
|
|
||||||
<div style="margin-bottom: 8px;">
|
|
||||||
<label style="display: inline-block; width: 100px; font-weight: normal;">Keyword:</label>
|
|
||||||
<input type="range" x-model.number="keywordWeight" min="0" max="1" step="0.1" style="width: 200px; display: inline-block;">
|
|
||||||
<span class="viz-weight-display" x-text="keywordWeight.toFixed(1)"></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display: inline-block; width: 100px; font-weight: normal;">Fuzzy:</label>
|
|
||||||
<input type="range" x-model.number="fuzzyWeight" min="0" max="1" step="0.1" style="width: 200px; display: inline-block;">
|
|
||||||
<span class="viz-weight-display" x-text="fuzzyWeight.toFixed(1)"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -364,12 +348,9 @@ async def vector_visualization_search(request: Request) -> JSONResponse:
|
|||||||
|
|
||||||
# Parse query parameters
|
# Parse query parameters
|
||||||
query = request.query_params.get("query", "")
|
query = request.query_params.get("query", "")
|
||||||
algorithm = request.query_params.get("algorithm", "hybrid")
|
algorithm = request.query_params.get("algorithm", "bm25_hybrid")
|
||||||
limit = int(request.query_params.get("limit", "50"))
|
limit = int(request.query_params.get("limit", "50"))
|
||||||
score_threshold = float(request.query_params.get("score_threshold", "0.7"))
|
score_threshold = float(request.query_params.get("score_threshold", "0.0"))
|
||||||
semantic_weight = float(request.query_params.get("semantic_weight", "0.5"))
|
|
||||||
keyword_weight = float(request.query_params.get("keyword_weight", "0.3"))
|
|
||||||
fuzzy_weight = float(request.query_params.get("fuzzy_weight", "0.2"))
|
|
||||||
|
|
||||||
# Parse doc_types (comma-separated list, None = all types)
|
# Parse doc_types (comma-separated list, None = all types)
|
||||||
doc_types_param = request.query_params.get("doc_types", "")
|
doc_types_param = request.query_params.get("doc_types", "")
|
||||||
@@ -433,16 +414,8 @@ async def vector_visualization_search(request: Request) -> JSONResponse:
|
|||||||
# Create search algorithm
|
# Create search algorithm
|
||||||
if algorithm == "semantic":
|
if algorithm == "semantic":
|
||||||
search_algo = SemanticSearchAlgorithm(score_threshold=score_threshold)
|
search_algo = SemanticSearchAlgorithm(score_threshold=score_threshold)
|
||||||
elif algorithm == "keyword":
|
elif algorithm == "bm25_hybrid":
|
||||||
search_algo = KeywordSearchAlgorithm()
|
search_algo = BM25HybridSearchAlgorithm(score_threshold=score_threshold)
|
||||||
elif algorithm == "fuzzy":
|
|
||||||
search_algo = FuzzySearchAlgorithm()
|
|
||||||
elif algorithm == "hybrid":
|
|
||||||
search_algo = HybridSearchAlgorithm(
|
|
||||||
semantic_weight=semantic_weight,
|
|
||||||
keyword_weight=keyword_weight,
|
|
||||||
fuzzy_weight=fuzzy_weight,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
{"success": False, "error": f"Unknown algorithm: {algorithm}"},
|
{"success": False, "error": f"Unknown algorithm: {algorithm}"},
|
||||||
|
|||||||
Reference in New Issue
Block a user