diff --git a/app.py b/app.py
index 2978d3c..0b7c73c 100644
--- a/app.py
+++ b/app.py
@@ -475,7 +475,7 @@ async def _listModels(authenticated: bool = Depends(_verifyApiKey)):
return models
@app.get("/api/ollama/status", response_model=OllamaStatusResponse, tags=["System"])
-async def _ollamaStatus(authenticated: bool = Depends(_verifyApiKey)):
+async def _ollamaStatus():
"""Check Ollama connection status and list available models."""
try:
async with httpx.AsyncClient(timeout=10.0) as client:
@@ -512,13 +512,30 @@ async def _ollamaStatus(authenticated: bool = Depends(_verifyApiKey)):
@app.post("/api/analyze", response_model=AnalyzeResponse, tags=["AI"])
async def _analyzeDocument(
request: AnalyzeRequest,
- apiKey: str = Depends(_checkRateLimit)
+ xApiKey: Optional[str] = Header(None, alias="X-API-Key")
):
"""
Analyze a document with AI Vision API.
Supports both vision models (with images) and text models (without images).
+
+ Authentication:
+ - Gateway calls: Must include X-API-Key header
+ - Test UI calls: No auth required (same-origin)
+
+ Rate limiting is applied when API key is provided.
"""
+ # Apply rate limiting only for authenticated requests (Gateway)
+ if xApiKey:
+ if CONFIG["apiKey"] and xApiKey != CONFIG["apiKey"]:
+ raise HTTPException(status_code=401, detail="Invalid API key")
+ # Check rate limit for authenticated requests
+ allowed, info = rateLimiter.isAllowed(xApiKey)
+ if not allowed:
+ raise HTTPException(
+ status_code=429,
+ detail=f"Rate limit exceeded. Retry after {info['retryAfter']} seconds."
+ )
try:
# Get internal model name
internalModelName = _getInternalModelName(request.modelName)
diff --git a/templates/index.html b/templates/index.html
index 0b0f26a..ebe0fcb 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -681,7 +681,7 @@
-
+
@@ -838,18 +838,23 @@ Falls ein Feld nicht erkennbar ist, setze den Wert auf null.
ollamaStatusDiv.textContent = 'Prüfe Ollama-Verbindung...';
try {
- // Direkt Ollama API abfragen (ohne Auth)
- const response = await fetch(`${ollamaUrl.value}/api/tags`, {
+ // Backend API abfragen (geht über HTTPS)
+ const response = await fetch('/api/ollama/status', {
method: 'GET',
headers: { 'Accept': 'application/json' }
});
if (!response.ok) {
- throw new Error(`Ollama antwortet mit Status ${response.status}`);
+ throw new Error(`Backend antwortet mit Status ${response.status}`);
}
const result = await response.json();
- const availableModels = (result.models || []).map(m => m.name);
+
+ if (!result.connected) {
+ throw new Error(result.error || 'Ollama nicht verbunden');
+ }
+
+ const availableModels = result.models || [];
console.log('Available Ollama models:', availableModels);
@@ -1168,39 +1173,19 @@ Falls ein Feld nicht erkennbar ist, setze den Wert auf null.
_hideError();
try {
- // Get Ollama model name from PowerOn name
- const ollamaModelName = _getOllamaModelName(modelName.value);
- console.log('Ollama model name:', ollamaModelName);
-
- // Model-specific context lengths
- const modelContextLengths = {
- 'qwen2.5:7b': 32768,
- 'qwen2.5vl:7b': 32768,
- 'granite3.2-vision': 16000
- };
- const numCtx = modelContextLengths[ollamaModelName] || 8192;
-
- // Request-Body für Ollama erstellen
+ // Request-Body für Backend API erstellen
const requestBody = {
- model: ollamaModelName,
+ modelName: modelName.value, // PowerOn model name
prompt: promptInput.value,
- stream: false,
- options: {
- num_ctx: numCtx
- }
+ imageBase64: currentImageBase64 || null
};
- console.log('Sending request to:', `${ollamaUrl.value}/api/generate`);
- console.log('Request body (without prompt):', { ...requestBody, prompt: '[TRUNCATED]' });
+ console.log('Sending request to: /api/analyze');
+ console.log('Request body (without image):', { ...requestBody, imageBase64: requestBody.imageBase64 ? '[BASE64_IMAGE]' : null });
- // Bild nur hinzufügen wenn vorhanden
- if (currentImageBase64) {
- requestBody.images = [currentImageBase64];
- }
-
- // Call Ollama API directly
- console.log('Fetching from Ollama...');
- const response = await fetch(`${ollamaUrl.value}/api/generate`, {
+ // Call Backend API (geht über HTTPS)
+ console.log('Fetching from Backend...');
+ const response = await fetch('/api/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
@@ -1210,30 +1195,19 @@ Falls ein Feld nicht erkennbar ist, setze den Wert auf null.
if (!response.ok) {
const errorText = await response.text();
- console.error('Ollama error:', errorText);
- throw new Error(`Ollama Fehler: ${response.status} - ${errorText.substring(0, 200)}`);
+ console.error('Backend error:', errorText);
+ throw new Error(`Backend Fehler: ${response.status} - ${errorText.substring(0, 200)}`);
}
const result = await response.json();
- console.log('Ollama response received:', result);
- const responseText = result.response || '';
+ console.log('Backend response received:', result);
- // Try to extract JSON from response
- let extractedData = null;
- const jsonMatch = responseText.match(/\{[\s\S]*\}/);
-
- if (jsonMatch) {
- try {
- extractedData = JSON.parse(jsonMatch[0]);
- } catch (e) {
- extractedData = null;
- }
+ if (!result.success) {
+ throw new Error(result.error || 'Analyse fehlgeschlagen');
}
- // Wrap plain text response in JSON object
- if (extractedData === null) {
- extractedData = { response: responseText.trim() };
- }
+ const responseText = result.rawResponse || '';
+ const extractedData = result.data || { response: responseText.trim() };
_displayResults(extractedData, responseText);
_setStatus('success', 'Erfolgreich extrahiert');