philippurbschat.de/plants/test_prompt.php

228 lines
9.3 KiB
PHP

<!-- Version: 24.09.2025 22:10 -->
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prompt-Vergleich</title>
<style>
body {
font-family: sans-serif;
margin: 2em;
line-height: 1.6;
background-color: #f4f4f9;
color: #333;
}
.container {
display: flex;
gap: 20px;
margin-top: 20px;
flex-wrap: wrap;
}
.panel {
flex: 1;
min-width: 300px;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
h1, h2 {
color: #5E8C61;
}
pre {
background-color: #eee;
padding: 15px;
border-radius: 6px;
white-space: pre-wrap;
word-wrap: break-word;
font-size: 0.9em;
}
.loading-bar {
width: 0;
height: 4px;
background-color: #5E8C61;
transition: width 0.4s ease;
margin-top: 10px;
}
.controls {
margin-bottom: 20px;
}
.controls input[type="file"] {
margin-right: 10px;
}
.controls button {
padding: 10px 15px;
background-color: #5E8C61;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Prompt-Vergleich</h1>
<p>Lade ein Bild hoch und vergleiche die Ergebnisse mit dem alten und dem neuen Prompt.</p>
<div class="controls">
<input type="file" id="imageInput" accept="image/*">
<button id="runTestBtn">Test starten</button>
</div>
<div id="loadingStatus" style="display: none;">
<p>Analysiere mit beiden Prompts...</p>
<div class="loading-bar"></div>
</div>
<div class="container">
<div class="panel">
<h2>Alter Prompt</h2>
<div id="oldPromptResult"></div>
</div>
<div class="panel">
<h2>Finaler Profi-Prompt (V6)</h2>
<div id="newPromptResult"></div>
</div>
</div>
<script>
const imageInput = document.getElementById('imageInput');
const runTestBtn = document.getElementById('runTestBtn');
const loadingStatus = document.getElementById('loadingStatus');
const loadingBar = loadingStatus.querySelector('.loading-bar');
const oldPromptResult = document.getElementById('oldPromptResult');
const newPromptResult = document.getElementById('newPromptResult');
const PROXY_URL = 'api_proxy.php';
const oldPrompt = `
Du bist ein liebevoller Pflanzenexperte. Analysiere das Bild dieser Pflanze. Gib mir die folgenden Informationen als sauberen JSON-String zurück, ohne zusätzlichen Text oder Markdown.
- "name": Der gebräuchliche Name der Pflanze.
- "latin_name": Der botanische (lateinische) Name der Pflanze.
- "watering_interval_days": Das Gießintervall in Tagen (nur die Zahl).
- "fertilizing_interval_days": Das Düngeintervall in Tagen (nur die Zahl).
- "care_tips": Gib mir 3 kurze und liebevoll formulierte Pflegetipps.
WICHTIGE REGELN FÜR DIE FORMARTIERUNG DER TIPPS:
1. Jeder Tipp MUSS mit einem passenden Emoji und einem Titel beginnen (z.B. "☀️ Licht:").
2. Zwischen den einzelnen Tipps MUSS sich ein doppelter Zeilenumbruch (\\n\\n) befinden.
Falls du die Pflanze nicht sicher erkennen kannst, setze den Wert für "name" und "latin_name" auf "Unbekannt".
`;
const newPrompt = `
Du bist ein kritischer Botaniker. Deine Aufgabe ist es, die Pflanze auf dem Bild wissenschaftlich und so exakt wie möglich zu identifizieren.
Gib das Ergebnis als sauberen JSON-String zurück, ohne zusätzlichen Text oder Markdown.
- "name": Der gebräuchlichste Name der Pflanze (nicht zwingend der deutsche).
- "latin_name": Der botanische (lateinische) Name der Pflanze.
- "plant_family": Die Pflanzenfamilie (z.B. "Araceae").
- "plant_genus": Die Pflanzengattung (z.B. "Monstera").
- "confidence_score": Bewerte deine Sicherheit bei der Identifizierung KRITISCH und ehrlich auf einer Skala von 0 (geraten) bis 100 (absolut sicher). Sei nicht übermäßig selbstbewusst. Ein Score von 95+ sollte nur bei perfekter Bildqualität und eindeutigen Merkmalen vergeben werden.
- "identification_notes": Gib eine sehr kurze Notiz, welche Merkmale zur Identifizierung geführt haben (z.B. "Herzförmige Blätter mit silbernen Flecken").
- "watering_interval_days": Das Gießintervall in Tagen (nur die Zahl).
- "fertilizing_interval_days": Das Düngeintervall in Tagen (nur die Zahl).
- "care_tips": Gib mir 3 kurze Pflegetipps.
WICHTIGE REGELN FÜR DIE TIPPS:
1. Formuliere die Tipps charmant aus der Ich-Perspektive der Pflanze (z.B. "☀️ Licht: Stell mich an einen hellen Ort, aber ohne direkte Mittagssonne.").
2. Jeder Tipp MUSS mit einem passenden Emoji und einem Titel beginnen (z.B. "☀️ Licht:").
3. Zwischen den Tipps MUSS sich ein doppelter Zeilenumbruch (\\n\\n) befinden.
WICHTIG: Falls dein confidence_score unter 75 liegt, setze "name", "latin_name", "plant_family", "plant_genus" auf "Unbekannt" und gib bei "identification_notes" den Grund für die Unsicherheit an (z.B. "Geringe Zuversicht aufgrund von schlechter Bildqualität.").
`;
runTestBtn.addEventListener('click', async () => {
const file = imageInput.files[0];
if (!file) {
alert('Bitte wähle zuerst ein Bild aus.');
return;
}
oldPromptResult.innerHTML = '';
newPromptResult.innerHTML = '';
runTestBtn.disabled = true;
loadingStatus.style.display = 'block';
loadingBar.style.width = '0%';
try {
const base64Image = await fileToBase64(file);
const analyzeWithProgress = async (prompt, resultElement) => {
try {
const result = await analyzeImage(base64Image, prompt);
displayResult(resultElement, result);
} catch (error) {
displayResult(resultElement, { error: error.message });
} finally {
loadingBar.style.width = (parseInt(loadingBar.style.width) + 50) + '%';
}
};
await Promise.all([
analyzeWithProgress(oldPrompt, oldPromptResult),
analyzeWithProgress(newPrompt, newPromptResult)
]);
} catch (error) {
console.error('Test failed:', error);
alert('Fehler beim Test: ' + error.message);
} finally {
runTestBtn.disabled = false;
loadingStatus.style.display = 'none';
loadingBar.style.width = '0%';
}
});
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = error => reject(error);
});
}
async function analyzeImage(base64Image, prompt) {
const requestPayload = {
"contents": [
{
"parts": [
{ "text": prompt },
{ "inline_data": { "mime_type": "image/jpeg", "data": base64Image } }
]
}
]
};
const response = await fetch(PROXY_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payload: requestPayload })
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`API error! status: ${response.status}, body: ${errorBody}`);
}
return response.json();
}
function displayResult(element, result) {
if (result.error) {
element.innerHTML = `<p style="color:red;">API Fehler:<br><pre>${result.error}</pre></p>`;
return;
}
try {
const textResponse = result.candidates[0].content.parts[0].text;
const jsonString = textResponse.replace(/```json|```/g, '').trim();
const plantData = JSON.parse(jsonString);
element.innerHTML = `<pre>${JSON.stringify(plantData, null, 2)}</pre>`;
} catch (e) {
element.innerHTML = `<p style="color:red;">Fehler beim Parsen der Antwort. Rohe Antwort:<br><pre>${JSON.stringify(result, null, 2)}</pre></p>`;
}
}
</script>
</body>
</html>