feat: Enhance vector visualization UI and parallelize search verification

Vector Visualization Improvements:
- Add interactive vector viz tab with Alpine.js and Plotly.js to user info page
- Refactor viz route CSS for better scoping and maintainability
- Remove unused nextcloud_host variable

Performance Optimizations:
- Parallelize access verification in fuzzy and keyword search algorithms
- Use asyncio.gather() to verify multiple documents concurrently
- Add exception handling with return_exceptions=True for resilience

Dependencies:
- Update third_party/oidc submodule to include RFC 9728 resource_url support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2025-11-15 05:39:07 +01:00
co-authored by Claude
parent e3153822f7
commit ed0825e661
5 changed files with 280 additions and 214 deletions
+35 -15
View File
@@ -160,26 +160,46 @@ class FuzzySearchAlgorithm(SearchAlgorithm):
top_results = scored_results[: limit * 2] # Get extra for access verification
# Verify access with Nextcloud (optional, for security)
# Parallelize verification to avoid sequential HTTP calls
final_results = []
if nextcloud_client:
for result in top_results:
verified = await self._verify_access(
from asyncio import gather
# Create verification coroutines for all top results
verification_coros = [
self._verify_access(
nextcloud_client, result["doc_id"], result["doc_type"]
)
if verified:
final_results.append(
SearchResult(
id=result["doc_id"],
doc_type=result["doc_type"],
title=result["title"],
excerpt=result["excerpt"],
score=result["score"],
metadata={
**verified.get("metadata", {}),
"match_location": result["match_location"],
},
)
for result in top_results
]
# Execute all verifications in parallel
# return_exceptions=True prevents one failure from canceling others
verification_results = await gather(
*verification_coros, return_exceptions=True
)
# Build final results from verified documents
for result, verified in zip(top_results, verification_results):
# Skip if verification failed or raised exception
if isinstance(verified, Exception) or verified is None:
continue
final_results.append(
SearchResult(
id=result["doc_id"],
doc_type=result["doc_type"],
title=result["title"],
excerpt=result["excerpt"],
score=result["score"],
metadata={
**verified.get("metadata", {}),
"match_location": result["match_location"],
},
)
)
# Stop once we have enough results
if len(final_results) >= limit:
break
else:
+32 -12
View File
@@ -156,23 +156,43 @@ class KeywordSearchAlgorithm(SearchAlgorithm):
top_results = scored_results[: limit * 2] # Get extra for access verification
# Verify access with Nextcloud (optional, for security)
# Parallelize verification to avoid sequential HTTP calls
final_results = []
if nextcloud_client:
for result in top_results:
verified = await self._verify_access(
from asyncio import gather
# Create verification coroutines for all top results
verification_coros = [
self._verify_access(
nextcloud_client, result["doc_id"], result["doc_type"]
)
if verified:
final_results.append(
SearchResult(
id=result["doc_id"],
doc_type=result["doc_type"],
title=result["title"],
excerpt=result["excerpt"],
score=result["score"],
metadata=verified.get("metadata", {}),
)
for result in top_results
]
# Execute all verifications in parallel
# return_exceptions=True prevents one failure from canceling others
verification_results = await gather(
*verification_coros, return_exceptions=True
)
# Build final results from verified documents
for result, verified in zip(top_results, verification_results):
# Skip if verification failed or raised exception
if isinstance(verified, Exception) or verified is None:
continue
final_results.append(
SearchResult(
id=result["doc_id"],
doc_type=result["doc_type"],
title=result["title"],
excerpt=result["excerpt"],
score=result["score"],
metadata=verified.get("metadata", {}),
)
)
# Stop once we have enough results
if len(final_results) >= limit:
break
else: