Fix mixed content: route all requests through backend API
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3527e5b135
commit
11c9b64e14
2 changed files with 44 additions and 53 deletions
21
app.py
21
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)
|
||||
|
|
|
|||
|
|
@ -681,7 +681,7 @@
|
|||
<div class="panel-body">
|
||||
<div class="settings-row">
|
||||
<label>Server:</label>
|
||||
<input type="text" id="ollama-url" value="http://83.228.200.109:11434" placeholder="http://83.228.200.109:11434">
|
||||
<input type="text" id="ollama-url" value="" placeholder="Backend API (automatisch)" disabled style="opacity:0.6;">
|
||||
<button class="btn btn-secondary btn-small" id="check-ollama">Prüfen</button>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
|
|
@ -838,18 +838,23 @@ Falls ein Feld nicht erkennbar ist, setze den Wert auf null.</textarea>
|
|||
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.</textarea>
|
|||
_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.</textarea>
|
|||
|
||||
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');
|
||||
|
|
|
|||
Loading…
Reference in a new issue