fix: statut IA — suppression endpoint redondant + lecture runtime des clés API
Problème: l'indicateur affichait 'IA non configurée' alors que les actions AI fonctionnaient. Causes: 1. Deux endpoints /api/ai/status en conflit (main.py + ai_routes.py) 2. ai_routes.py lisait PROVIDERS évalué à l'import (os.getenv figé) 3. Cache côté frontend (_aiStatusChecked) empêchait de re-vérifier Fixes: - Suppression de l'endpoint redondant dans main.py - ai_routes.py: lecture os.getenv au runtime (pas depuis PROVIDERS) - sync.js: _checkAIStatus() appelée à chaque ouverture du panneau
This commit is contained in:
+1
-1
@@ -39,7 +39,7 @@ OBSIGATE_ADMIN_PASSWORD=chab30
|
||||
# AI_DEFAULT_PROVIDER=deepseek # deepseek | openrouter | gemini
|
||||
|
||||
# DeepSeek (recommandé, bon marché)
|
||||
DEEPSEEK_API_KEY=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
|
||||
DEEPSEEK_API_KEY=sk-87d93019602e4c279679dfe80d504bc3
|
||||
DEEPSEEK_MODEL=deepseek-v4-pro
|
||||
|
||||
# OpenRouter (accès à plusieurs modèles)
|
||||
|
||||
+2
-2
@@ -162,7 +162,7 @@
|
||||
- [x] **Section IA dans panneau sync** : statut (configurée/non configurée/traitement en cours) avec icône et couleur
|
||||
- [x] **Endpoint `/api/ai/status`** : vérifie si au moins un provider AI est configuré
|
||||
|
||||
### 11b. Page d'accueil de voute — FAIT
|
||||
### 12. Page d'accueil de voute — FAIT
|
||||
- **Effort** : 1 jour | **Impact** : 🟡
|
||||
- Une page d'accueil qui affiche les fichiers de la voute actuelle dans l'ordre du plus récent au plus ancien. Si l'utilisateur change de répertoire dans cette voute, la liste devrait se mettre à jour automatiquement. ✅
|
||||
- **Fichiers** : `backend/main.py` (`/api/vault/{vault}/files`), `frontend/js/vaulthome.js`, `frontend/js/sidebar.js`, `frontend/style.css`
|
||||
@@ -172,7 +172,7 @@
|
||||
- [x] **Mise à jour automatique** : quand on clique sur un dossier dans l'arborescence, la page se met à jour
|
||||
- [x] **Déclenchement** : affiché automatiquement quand un vault spécifique est sélectionné
|
||||
|
||||
### ✅ 12. Indexation non-bloquante — FAIT
|
||||
### ✅ 13. Indexation non-bloquante — FAIT
|
||||
- **Effort** : 0.5 jour | **Impact** : 🟡
|
||||
- L'étape "Building inverted index..." au démarrage bloquait l'event loop asyncio, empêchant le serveur de répondre aux requêtes HTTP (navigation, refresh) jusqu'à la fin de l'indexation.
|
||||
- **Fichiers** : `backend/main.py`, `backend/search.py`
|
||||
|
||||
+15
-4
@@ -19,12 +19,23 @@ router = APIRouter(prefix="/api/ai", tags=["AI"])
|
||||
|
||||
@router.get("/status")
|
||||
async def api_status():
|
||||
"""Check if AI is configured and which providers are available."""
|
||||
"""Check if AI is configured and which providers are available.
|
||||
|
||||
Reads environment variables at runtime so that changes to
|
||||
.env or Docker environment are reflected immediately.
|
||||
"""
|
||||
import os as _os
|
||||
provider_keys = {
|
||||
"deepseek": "DEEPSEEK_API_KEY",
|
||||
"openrouter": "OPENROUTER_API_KEY",
|
||||
"gemini": "GEMINI_API_KEY",
|
||||
}
|
||||
providers = {}
|
||||
for name, cfg in PROVIDERS.items():
|
||||
for name, env_var in provider_keys.items():
|
||||
has_key = bool(_os.getenv(env_var, "").strip())
|
||||
providers[name] = {
|
||||
"available": bool(cfg["api_key"]),
|
||||
"model": cfg["model"] if cfg["api_key"] else None,
|
||||
"available": has_key,
|
||||
"model": PROVIDERS[name]["model"] if has_key else None,
|
||||
}
|
||||
return {
|
||||
"configured": any(p["available"] for p in providers.values()),
|
||||
|
||||
@@ -2165,21 +2165,6 @@ async def api_file_restore(
|
||||
raise HTTPException(status_code=500, detail=f"Error restoring file: {str(e)}")
|
||||
|
||||
|
||||
@app.get("/api/ai/status")
|
||||
async def api_ai_status(current_user=Depends(require_auth)):
|
||||
"""Return the AI configuration status.
|
||||
|
||||
Checks whether any AI provider API key is configured.
|
||||
Does NOT expose the key itself, only a boolean 'configured' flag.
|
||||
"""
|
||||
providers = ["DEEPSEEK_API_KEY", "OPENROUTER_API_KEY", "GEMINI_API_KEY"]
|
||||
configured = any(
|
||||
os.environ.get(env_var, "").strip()
|
||||
for env_var in providers
|
||||
)
|
||||
return {"configured": configured, "providers_checked": providers}
|
||||
|
||||
|
||||
@app.get("/api/file/{vault_name}/backlinks")
|
||||
async def api_file_backlinks(
|
||||
vault_name: str,
|
||||
|
||||
@@ -337,19 +337,16 @@ function _renderSyncPanel(panel) {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
let _aiProcessing = false;
|
||||
let _aiStatusChecked = false;
|
||||
let _aiConfigured = null; // null = unknown, true/false
|
||||
|
||||
/** Check if AI is configured by calling the status endpoint. */
|
||||
async function _checkAIStatus() {
|
||||
if (_aiStatusChecked) return;
|
||||
try {
|
||||
const resp = await api('/api/ai/status');
|
||||
_aiConfigured = !!(resp && resp.configured);
|
||||
} catch (e) {
|
||||
_aiConfigured = false;
|
||||
}
|
||||
_aiStatusChecked = true;
|
||||
}
|
||||
|
||||
function _renderAIStatusSection(panel) {
|
||||
|
||||
Reference in New Issue
Block a user