// Version: 01.10.2025 11:45 (FINAL FIX) const API_URL = 'api.php'; // --- Hilfsfunktion für Fehlerbehandlung --- async function handleResponse(response) { if (!response.ok) { const errorData = await response.json().catch(() => ({ error: 'Unbekannter API-Fehler' })); throw new Error(errorData.error || `HTTP-Fehler! Status: ${response.status}`); } return response.json(); } // --- Nutzer-Funktionen --- export async function getUserSettings() { const response = await fetch(`${API_URL}?action=get_user_settings`); return handleResponse(response); } export async function updateUserSettings(settings) { const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ request_type: 'update_user_settings', settings: settings }), }); return handleResponse(response); } // --- Lexikon-Funktionen --- export async function getLexiconEntries() { const response = await fetch(`${API_URL}?action=get_lexicon_entries`); return handleResponse(response); } export async function getLexiconEntryDetails(latinName) { const response = await fetch(`${API_URL}?action=get_lexicon_entry_details&latin_name=${encodeURIComponent(latinName)}`); return handleResponse(response); } // --- Pflanzen-Funktionen --- export async function getPlants() { const response = await fetch(`${API_URL}?action=get_plants`); return handleResponse(response); } export async function savePlant(formData) { const response = await fetch(API_URL, { method: 'POST', body: formData }); return handleResponse(response); } export async function deletePlant(plantId) { const response = await fetch(`${API_URL}?id=${plantId}`, { method: 'DELETE' }); return handleResponse(response); } export async function recordCareAction(plantId, action) { const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ request_type: 'care_action', id: plantId, action }), }); return handleResponse(response); } export async function setProfilePicture(plantId, photoPath) { const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ request_type: 'set_profile_picture', plant_id: plantId, photo_path: photoPath }), }); return handleResponse(response); } // --- Tagebuch-Funktionen --- export async function getDiaryEntries(plantId) { const response = await fetch(`${API_URL}?action=get_diary&plant_id=${plantId}`); return handleResponse(response); } export async function addDiaryEntry(formData) { formData.append('action', 'add_diary_entry'); const response = await fetch(API_URL, { method: 'POST', body: formData }); return handleResponse(response); } export async function deleteDiaryEntry(entryId) { const response = await fetch(`${API_URL}?diary_entry_id=${entryId}`, { method: 'DELETE' }); return handleResponse(response); } // --- KI-Funktionen --- // Schritt 1: Identifikation & Foto-Analyse export async function performInitialAnalysis(base64Image, excludedLatinNames = []) { let prompt = ` Du bist ein Botaniker und Foto-Analyst. Führe ZWEI Aufgaben aus und gib das Ergebnis als EINEN einzigen, sauberen JSON-String zurück. Das JSON-Objekt muss zwei Hauptschlüssel haben: "identification" und "photo_analysis". 1. **Im "identification"-Objekt:** Identifiziere die Pflanze. - "name": Der gebräuchlichste Name, so wie er im deutschen Einzelhandel genutzt wird. - "latin_name": Der korrekte, zweiteilige botanische Name. - "confidence_score": Bewerte deine Sicherheit KRITISCH (0-100). - "identification_notes": Kurze Notiz zur Identifizierung. - REGEL: Falls dein confidence_score < 75 ist, setze alle Werte auf "Unbekannt" oder 0. 2. **Im "photo_analysis"-Objekt:** Analysiere die Fotoqualität. - "photo_quality_score" (integer): Bewerte die Qualität KRITISCH (0-100). - "is_high_quality" (boolean): true, wenn photo_quality_score > 70 ist. - "rejection_reason" (string): Kurzer Grund, falls is_high_quality false ist, sonst null. - "photo_type" (string): 'whole_plant', 'leaf_detail', 'flower_detail', oder 'other'. - "focal_point" (object): Ein Objekt mit "x"- und "y"-Koordinaten (Prozent von 0-100) des visuellen Mittelpunkts. - "dominant_color_hex" (string): Der dominante Farbton des Hauptmotivs als HEX-Code. `; if (excludedLatinNames.length > 0) { prompt += ` Ignoriere dabei diese falschen Vorschläge: ${excludedLatinNames.join(', ')}.`; } const payload = { request_type: 'ai_identification', payload: { "contents": [{ "parts": [ { "text": prompt }, { "inline_data": { "mime_type": "image/jpeg", "data": base64Image } } ] }] } }; const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await handleResponse(response); const resultText = result.candidates[0].content.parts[0].text; return JSON.parse(resultText.replace(/```json|```/g, '').trim()); } // Schritt 2: Detaillierte Anreicherung export async function aiEnrich(latinName) { const prompt = ` Du bist ein Botanik-Experte. Gib detaillierte Pflegedaten für "${latinName}" als sauberen JSON-String zurück. ANWEISUNGEN FÜR DEN INHALT: - Für "description_full": Erstelle einen ausführlichen, enzyklopädischen Text. **Verwende KEINE einleitenden Grußformeln, Willkommenssätze oder persönlichen Anreden wie "Du"**. Gliedere den Text in Abschnitte mit Titeln (z.B. 'Standort & Licht:') und spreche den Leser neutral an (z.B. "Diese Pflanze benötigt..."). Die Titel dürfen KEIN Markdown enthalten. - Für "care_tips": Erstelle genau drei kurze, prägnante Tipps aus der Ich-Perspektive der Pflanze. - Für "tags": Gib 3-5 passende Schlagwörter als kommaseparierten String an (z.B. "Anfängerfreundlich, Haustier-sicher, Buntblatt"). Das JSON-Objekt MUSS die folgenden Schlüssel enthalten, auch wenn der Wert null ist: "plant_family", "plant_genus", "description_full", "watering_interval_days", "fertilizing_interval_days", "care_tips", "light_requirement", "water_requirement", "humidity_requirement", "care_difficulty", "growth_habit", "mature_size", "toxicity", "edibility", "temperature_preference", "flowering_period", "substrate_recommendation", "native_to", "tags". WICHTIGE REGELN FÜR KATEGORIEN: - Für "substrate_recommendation": Wähle einen oder MEHRERE passende Werte aus der Liste und gib sie als kommaseparierten String zurück: 'Universal-Erde', 'Sukkulenten/Kakteen-Erde', 'Anzucht-Erde', 'Kräuter-Erde', 'Saurer Boden (Moorbeet-Erde)', 'Orchideen-Substrat', 'Hydrokultur/Pon', 'Erde-frei (Aroid-Mix)'. - Für die folgenden Felder, wähle EXAKT EINEN der angegebenen Werte in Kleinbuchstaben: - "light_requirement": 'wenig', 'mittel', 'viel'. - "water_requirement": 'niedrig', 'mittel', 'hoch'. - "humidity_requirement": 'normal', 'erhöht'. - "care_difficulty": 'einfach', 'mittel', 'schwer'. - "growth_habit": 'kletternd', 'hängend', 'aufrecht', 'buschig', 'rosette'. - "mature_size": 'klein', 'mittel', 'groß'. - "toxicity": 'ungiftig', 'leicht giftig', 'giftig'. - "edibility": 'essbar', 'nicht essbar', 'zierfrüchte'. - "temperature_preference": 'zimmerwarm', 'kühl', 'winterhart'. - "flowering_period": 'frühling', 'sommer', 'herbst', 'winter', 'ganzjährig', 'selten', oder null. FORMATIERUNGSREGELN für "care_tips": 1. Jeder Tipp MUSS mit einem passenden Emoji und einem Titel beginnen (z.B. "☀️ Licht:"). 2. Zwischen den Tipps MUSS sich ein doppelter Zeilenumbruch (\\n\\n) befinden.`; const payload = { request_type: 'ai_enrichment', payload: { "contents": [{ "parts": [ { "text": prompt } ] }] } }; const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await handleResponse(response); const resultText = result.candidates[0].content.parts[0].text; return JSON.parse(resultText.replace(/```json|```/g, '').trim()); }