feat(ai): menu @ instantane, selecteurs agrandis et BooksLM racine (#82)
Nouvel endpoint GET /api/vault/{vault}/paths + prechargement et filtrage client du menu @ (affichage instantane des fichiers/repertoires). Selecteurs Fournisseur/Modele agrandis (0,8rem / 34px) pour s'aligner sur le reste du site. Ajout de BooksLM au menu contextuel de la racine des vaults.
This commit is contained in:
+39
-1
@@ -136,7 +136,7 @@ from backend.services.mutations import (
|
||||
restore_backup as service_restore_backup,
|
||||
)
|
||||
from backend.services.recent import humanize_mtime, list_recent
|
||||
from backend.services.search import advanced_search_vaults, search_paths, search_vaults
|
||||
from backend.services.search import advanced_search_vaults, list_paths, search_paths, search_vaults
|
||||
from backend.services.search import list_tags as service_list_tags
|
||||
from backend.services.vaults import (
|
||||
browse_directory,
|
||||
@@ -276,6 +276,21 @@ class TreeSearchResponse(BaseModel):
|
||||
results: list[TreeSearchResult] = Field(description="Matching files and directories")
|
||||
|
||||
|
||||
class VaultPathEntry(BaseModel):
|
||||
"""A single indexed path (file or directory) in a vault."""
|
||||
vault: str = Field(description="Vault name")
|
||||
path: str = Field(description="Full relative path")
|
||||
name: str = Field(description="File or directory name")
|
||||
type: str = Field(description="'file' or 'directory'")
|
||||
|
||||
|
||||
class VaultPathsResponse(BaseModel):
|
||||
"""Flat list of every indexed path in a vault (capped)."""
|
||||
vault: str = Field(description="Vault name")
|
||||
count: int = Field(description="Number of returned entries")
|
||||
results: list[VaultPathEntry] = Field(description="Indexed files and directories")
|
||||
|
||||
|
||||
class AdvancedSearchResultItem(BaseModel):
|
||||
"""A single advanced search result with highlighted snippet."""
|
||||
vault: str = Field(description="Vault name")
|
||||
@@ -2580,6 +2595,29 @@ async def api_tree_search(
|
||||
return search_paths(q, vault)
|
||||
|
||||
|
||||
@app.get("/api/vault/{vault_name}/paths", response_model=VaultPathsResponse)
|
||||
async def api_vault_paths(
|
||||
vault_name: str,
|
||||
limit: int = Query(5000, ge=1, le=20000, description="Maximum number of indexed paths to return"),
|
||||
current_user=Depends(require_auth),
|
||||
):
|
||||
"""Return a flat list of every indexed file and directory in a vault.
|
||||
|
||||
Used by the AI assistant ``@`` mention menu to filter paths instantly on
|
||||
the client (one request instead of one per keystroke).
|
||||
|
||||
Args:
|
||||
vault_name: Name of the vault.
|
||||
limit: Maximum number of entries returned.
|
||||
|
||||
Returns:
|
||||
``VaultPathsResponse`` with the vault's indexed paths.
|
||||
"""
|
||||
if not check_vault_access(vault_name, current_user):
|
||||
raise HTTPException(status_code=403, detail=f"Accès refusé à la vault '{vault_name}'")
|
||||
return list_paths(vault_name, limit=limit)
|
||||
|
||||
|
||||
@app.get("/api/search/advanced", response_model=AdvancedSearchResponse)
|
||||
async def api_advanced_search(
|
||||
q: str = Query("", description="Advanced search query (supports tag:, vault:, title:, path:, ext: operators)"),
|
||||
|
||||
@@ -113,3 +113,32 @@ def search_paths(q: str, vault: str = "all") -> dict[str, Any]:
|
||||
})
|
||||
|
||||
return {"query": q, "vault_filter": vault, "results": results}
|
||||
|
||||
|
||||
def list_paths(vault: str, limit: int = 5000) -> dict[str, Any]:
|
||||
"""Return a flat, capped list of every indexed path in a vault.
|
||||
|
||||
Backs the AI assistant ``@`` mention menu: fetching the whole path index
|
||||
once lets the client filter files/directories instantly instead of issuing
|
||||
a request per keystroke.
|
||||
|
||||
Args:
|
||||
vault: Vault name.
|
||||
limit: Maximum number of entries returned.
|
||||
|
||||
Returns:
|
||||
``{"vault", "count", "results": [{vault, path, name, type}]}``.
|
||||
"""
|
||||
from backend.indexer import path_index
|
||||
|
||||
entries = path_index.get(vault, [])
|
||||
results = [
|
||||
{
|
||||
"vault": vault,
|
||||
"path": entry["path"],
|
||||
"name": entry["name"],
|
||||
"type": entry["type"],
|
||||
}
|
||||
for entry in entries[: max(0, limit)]
|
||||
]
|
||||
return {"vault": vault, "count": len(results), "results": results}
|
||||
|
||||
Reference in New Issue
Block a user