Compare commits

..

2 Commits

Author SHA1 Message Date
github-actions[bot] b1f7b1d30b bump: version 0.40.0 → 0.41.0 2025-11-17 05:57:12 +00:00
Chris Coutinho b8bdbb499f Merge pull request #315 from cbcoutinho/feature/cleanup
Feature/cleanup
2025-11-17 06:56:43 +01:00
9 changed files with 40 additions and 50 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
[submodule "oidc"]
path = third_party/oidc
url = https://github.com/cbcoutinho/oidc
[submodule "third_party/oidc"] [submodule "third_party/oidc"]
path = third_party/oidc path = third_party/oidc
url = https://github.com/cbcoutinho/oidc url = https://github.com/cbcoutinho/oidc
[submodule "third_party/notes"]
path = third_party/notes
url = https://github.com/cbcoutinho/notes
+13
View File
@@ -1,3 +1,16 @@
## v0.41.0 (2025-11-17)
### Feat
- add configurable fusion algorithms for BM25 hybrid search
- add chunk position tracking to vector indexing and search
- add vector viz template and chunk context endpoint
### Fix
- prevent infinite loop in DocumentChunker with position tracking
- Relax SearchResult validation to support DBSF fusion scores > 1.0
## v0.40.0 (2025-11-16) ## v0.40.0 (2025-11-16)
### Feat ### Feat
+2 -2
View File
@@ -2,8 +2,8 @@ apiVersion: v2
name: nextcloud-mcp-server name: nextcloud-mcp-server
description: A Helm chart for Nextcloud MCP Server - enables AI assistants to interact with Nextcloud description: A Helm chart for Nextcloud MCP Server - enables AI assistants to interact with Nextcloud
type: application type: application
version: 0.40.0 version: 0.41.0
appVersion: "0.40.0" appVersion: "0.41.0"
keywords: keywords:
- nextcloud - nextcloud
- mcp - mcp
@@ -186,9 +186,9 @@
</select> </select>
</div> </div>
<div class="viz-control-group" style="margin-bottom: 0;"> <div class="viz-control-group" style="margin-bottom: 0;" x-show="algorithm === 'bm25_hybrid'">
<label>Fusion Method</label> <label>Fusion Method</label>
<select x-model="fusion" :disabled="algorithm !== 'bm25_hybrid'" :style="algorithm !== 'bm25_hybrid' ? 'opacity: 0.5; cursor: not-allowed;' : ''"> <select x-model="fusion">
<option value="rrf" selected>RRF (Reciprocal Rank Fusion)</option> <option value="rrf" selected>RRF (Reciprocal Rank Fusion)</option>
<option value="dbsf">DBSF (Distribution-Based Score Fusion)</option> <option value="dbsf">DBSF (Distribution-Based Score Fusion)</option>
</select> </select>
@@ -211,39 +211,24 @@
<div class="viz-advanced-grid"> <div class="viz-advanced-grid">
<div class="viz-control-group"> <div class="viz-control-group">
<label style="display: block; margin-bottom: 8px;">Document Types</label> <label>Document Types</label>
<div style="display: grid; grid-template-columns: 1fr; gap: 6px;"> <select x-model="docTypes" multiple>
<label style="display: flex; align-items: center; cursor: pointer; font-weight: normal;"> <option value="">All Types (cross-app search)</option>
<input type="checkbox" x-model="docTypes" value="" style="margin-right: 8px;"> <option value="note">Notes</option>
<span>All Types</span> <option value="file">Files</option>
</label> <option value="calendar">Calendar Events</option>
<label style="display: flex; align-items: center; cursor: pointer; font-weight: normal;"> <option value="contact">Contacts</option>
<input type="checkbox" x-model="docTypes" value="note" style="margin-right: 8px;"> <option value="deck">Deck Cards</option>
<span>Notes</span> </select>
</label> <small style="color: #666; display: block; margin-top: 4px;">
<label style="display: flex; align-items: center; cursor: pointer; font-weight: normal;"> Hold Ctrl/Cmd to select multiple
<input type="checkbox" x-model="docTypes" value="file" style="margin-right: 8px;"> </small>
<span>Files</span>
</label>
<label style="display: flex; align-items: center; cursor: pointer; font-weight: normal;">
<input type="checkbox" x-model="docTypes" value="calendar" style="margin-right: 8px;">
<span>Calendar Events</span>
</label>
<label style="display: flex; align-items: center; cursor: pointer; font-weight: normal;">
<input type="checkbox" x-model="docTypes" value="contact" style="margin-right: 8px;">
<span>Contacts</span>
</label>
<label style="display: flex; align-items: center; cursor: pointer; font-weight: normal;">
<input type="checkbox" x-model="docTypes" value="deck" style="margin-right: 8px;">
<span>Deck Cards</span>
</label>
</div>
</div> </div>
<div> <div>
<div class="viz-control-group"> <div class="viz-control-group">
<label>Score Threshold (Semantic/Hybrid)</label> <label>Score Threshold (Semantic/Hybrid)</label>
<input type="number" x-model.number="scoreThreshold" min="0" max="1" step="any" /> <input type="number" x-model.number="scoreThreshold" min="0" max="1" step="0.1" />
</div> </div>
<div class="viz-control-group"> <div class="viz-control-group">
@@ -299,8 +284,7 @@
</a> </a>
<div style="font-size: 14px; color: #666; margin-top: 4px;" x-text="result.excerpt"></div> <div style="font-size: 14px; color: #666; margin-top: 4px;" x-text="result.excerpt"></div>
<div style="font-size: 12px; color: #999; margin-top: 4px;"> <div style="font-size: 12px; color: #999; margin-top: 4px;">
Raw Score: <span x-text="result.original_score.toFixed(3)"></span> Score: <span x-text="result.score.toFixed(3)"></span> |
(<span x-text="(result.score * 100).toFixed(0)"></span>% relative) |
Type: <span x-text="result.doc_type"></span> Type: <span x-text="result.doc_type"></span>
</div> </div>
+1 -1
View File
@@ -737,7 +737,7 @@ async def user_info_html(request: Request) -> HTMLResponse:
y: coordinates.map(c => c[1]), y: coordinates.map(c => c[1]),
mode: 'markers', mode: 'markers',
type: 'scatter', type: 'scatter',
text: results.map(r => `${{r.title}}<br>Raw Score: ${{r.original_score.toFixed(3)}} (${{(r.score * 100).toFixed(0)}}% relative)`), text: results.map(r => `${{r.title}}<br>Score: ${{r.score.toFixed(3)}}`),
marker: {{ marker: {{
// Multi-channel encoding: size + opacity + color for visual hierarchy // Multi-channel encoding: size + opacity + color for visual hierarchy
// Power scaling (score^2) amplifies visual differences dramatically // Power scaling (score^2) amplifies visual differences dramatically
+3 -9
View File
@@ -184,7 +184,7 @@ async def vector_visualization_search(request: Request) -> JSONResponse:
search_results = all_results[:limit] search_results = all_results[:limit]
search_duration = time.perf_counter() - search_start search_duration = time.perf_counter() - search_start
# Store original scores and normalize for visualization # Normalize scores relative to this result set for better visualization
# (best result = 1.0, worst result = 0.0 within THIS result set) # (best result = 1.0, worst result = 0.0 within THIS result set)
# This makes visual encoding meaningful regardless of RRF normalization # This makes visual encoding meaningful regardless of RRF normalization
if search_results: if search_results:
@@ -197,11 +197,8 @@ async def vector_visualization_search(request: Request) -> JSONResponse:
f"→ [0.0, 1.0]" f"→ [0.0, 1.0]"
) )
# Store original score and rescale to 0-1 for visualization # Rescale each result's score to 0-1 within this result set
for r in search_results: for r in search_results:
# Store original score before normalization
r.original_score = r.score
# Rescale for visual encoding
r.score = (r.score - min_score) / score_range r.score = (r.score - min_score) / score_range
if not search_results: if not search_results:
@@ -320,10 +317,7 @@ async def vector_visualization_search(request: Request) -> JSONResponse:
"doc_type": r.doc_type, "doc_type": r.doc_type,
"title": r.title, "title": r.title,
"excerpt": r.excerpt, "excerpt": r.excerpt,
"score": r.score, # Normalized score for visual encoding (0-1) "score": r.score,
"original_score": getattr(
r, "original_score", r.score
), # Raw score from algorithm
"chunk_start_offset": r.chunk_start_offset, "chunk_start_offset": r.chunk_start_offset,
"chunk_end_offset": r.chunk_end_offset, "chunk_end_offset": r.chunk_end_offset,
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "nextcloud-mcp-server" name = "nextcloud-mcp-server"
version = "0.40.0" version = "0.41.0"
description = "Model Context Protocol (MCP) server for Nextcloud integration - enables AI assistants to interact with Nextcloud data" description = "Model Context Protocol (MCP) server for Nextcloud integration - enables AI assistants to interact with Nextcloud data"
authors = [ authors = [
{name = "Chris Coutinho", email = "chris@coutinho.io"} {name = "Chris Coutinho", email = "chris@coutinho.io"}
Submodule third_party/notes deleted from ce08e985a7
Generated
+1 -1
View File
@@ -1857,7 +1857,7 @@ wheels = [
[[package]] [[package]]
name = "nextcloud-mcp-server" name = "nextcloud-mcp-server"
version = "0.40.0" version = "0.41.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiosqlite" }, { name = "aiosqlite" },