fix: hover foncé + /api/ai/status + cache toolbar si pas de clé API
This commit is contained in:
+17
-1
@@ -10,13 +10,29 @@ from backend.ai import (
|
|||||||
ai_simplify, ai_change_tone, ai_translate, ai_explain, ai_summarize,
|
ai_simplify, ai_change_tone, ai_translate, ai_explain, ai_summarize,
|
||||||
ai_continue_writing, ai_custom_rewrite, ai_convert_to_list,
|
ai_continue_writing, ai_custom_rewrite, ai_convert_to_list,
|
||||||
ai_convert_to_table, ai_generate_frontmatter, ai_inline_complete,
|
ai_convert_to_table, ai_generate_frontmatter, ai_inline_complete,
|
||||||
ai_convert_to_canvas,
|
ai_convert_to_canvas, DEFAULT_PROVIDER, PROVIDERS,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger("obsigate.ai_routes")
|
logger = logging.getLogger("obsigate.ai_routes")
|
||||||
router = APIRouter(prefix="/api/ai", tags=["AI"])
|
router = APIRouter(prefix="/api/ai", tags=["AI"])
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/status")
|
||||||
|
async def api_status():
|
||||||
|
"""Check if AI is configured and which providers are available."""
|
||||||
|
providers = {}
|
||||||
|
for name, cfg in PROVIDERS.items():
|
||||||
|
providers[name] = {
|
||||||
|
"available": bool(cfg["api_key"]),
|
||||||
|
"model": cfg["model"] if cfg["api_key"] else None,
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"configured": any(p["available"] for p in providers.values()),
|
||||||
|
"default_provider": DEFAULT_PROVIDER,
|
||||||
|
"providers": providers,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class AIRequest(BaseModel):
|
class AIRequest(BaseModel):
|
||||||
text: str = Field(..., description="Input text to process", min_length=1)
|
text: str = Field(..., description="Input text to process", min_length=1)
|
||||||
instruction: Optional[str] = Field(None, description="Custom instruction for rewrite")
|
instruction: Optional[str] = Field(None, description="Custom instruction for rewrite")
|
||||||
|
|||||||
+20
-5
@@ -111,7 +111,7 @@ function createMenu(items, parentEl) {
|
|||||||
el.appendChild(arrow);
|
el.appendChild(arrow);
|
||||||
}
|
}
|
||||||
el.addEventListener('mouseenter', () => {
|
el.addEventListener('mouseenter', () => {
|
||||||
el.style.background = 'var(--bg-secondary)';
|
el.style.background = 'rgba(255,255,255,0.06)';
|
||||||
// Show submenu
|
// Show submenu
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
const sub = el.querySelector('.ai-submenu');
|
const sub = el.querySelector('.ai-submenu');
|
||||||
@@ -171,7 +171,7 @@ function createSubMenu(items, parentEl) {
|
|||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
});
|
});
|
||||||
el.innerHTML = item.label;
|
el.innerHTML = item.label;
|
||||||
el.addEventListener('mouseenter', () => { el.style.background = 'var(--bg-secondary)'; });
|
el.addEventListener('mouseenter', () => { el.style.background = 'rgba(255,255,255,0.06)'; });
|
||||||
el.addEventListener('mouseleave', () => { el.style.background = ''; });
|
el.addEventListener('mouseleave', () => { el.style.background = ''; });
|
||||||
el.addEventListener('click', (e) => {
|
el.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -186,7 +186,22 @@ function createSubMenu(items, parentEl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Main AI Toolbar ──
|
// ── Main AI Toolbar ──
|
||||||
export function createAIToolbar(container, getEditorView) {
|
export async function createAIToolbar(container, getEditorView) {
|
||||||
|
// Check if AI is configured
|
||||||
|
let aiConfigured = false;
|
||||||
|
try {
|
||||||
|
const status = await api('/api/ai/status');
|
||||||
|
aiConfigured = status.configured;
|
||||||
|
} catch { aiConfigured = false; }
|
||||||
|
|
||||||
|
if (!aiConfigured) {
|
||||||
|
const hint = document.createElement('div');
|
||||||
|
hint.style.cssText = 'padding:6px 12px;font-size:0.7rem;color:var(--text-muted);border-bottom:1px solid var(--border-color)';
|
||||||
|
hint.textContent = '⚠️ AI non configuré — ajouter DEEPSEEK_API_KEY, OPENROUTER_API_KEY ou GEMINI_API_KEY dans .env';
|
||||||
|
container.appendChild(hint);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const toolbar = document.createElement('div');
|
const toolbar = document.createElement('div');
|
||||||
toolbar.className = 'ai-toolbar';
|
toolbar.className = 'ai-toolbar';
|
||||||
Object.assign(toolbar.style, {
|
Object.assign(toolbar.style, {
|
||||||
@@ -195,7 +210,7 @@ export function createAIToolbar(container, getEditorView) {
|
|||||||
gap: '2px',
|
gap: '2px',
|
||||||
padding: '4px 8px',
|
padding: '4px 8px',
|
||||||
borderBottom: '1px solid var(--border-color)',
|
borderBottom: '1px solid var(--border-color)',
|
||||||
background: 'var(--bg-secondary)',
|
background: '#2a2a2a',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -347,7 +362,7 @@ function createDropdownBtn(text, items) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
createMenu(items, btn);
|
createMenu(items, btn);
|
||||||
});
|
});
|
||||||
btn.addEventListener('mouseenter', () => { btn.style.background = 'var(--bg-hover)'; });
|
btn.addEventListener('mouseenter', () => { btn.style.background = 'rgba(255,255,255,0.08)'; });
|
||||||
btn.addEventListener('mouseleave', () => { btn.style.background = ''; });
|
btn.addEventListener('mouseleave', () => { btn.style.background = ''; });
|
||||||
return btn;
|
return btn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ async function openEditor(vaultName, filePath) {
|
|||||||
|
|
||||||
// Set up AI toolbar (recreate each time editor opens)
|
// Set up AI toolbar (recreate each time editor opens)
|
||||||
const container = document.getElementById('ai-toolbar-container');
|
const container = document.getElementById('ai-toolbar-container');
|
||||||
if (container && !container.querySelector('.ai-toolbar')) {
|
if (container && !container.querySelector('.ai-toolbar') && !container.querySelector('div')) {
|
||||||
createAIToolbar(container, () => state.editorView || null);
|
createAIToolbar(container, () => state.editorView || null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user