leafittome/lib/features/locations/data/location_analysis_service.dart
cschlaefke f0b420b656 V3: Stellplatz-Bewertung (Standort-Analyse per Foto + Eignungs-Sterne auf Abruf)
Letzter Roadmap-Punkt von V3. Foto-basierte Lichtverhältnis-Analyse pro
Stellplatz (Cloud Function analyzeLocation) und darauf aufbauende, rein
textbasierte Eignungs-Bewertung einer Pflanze (assessPlantFit) — beides
ausschließlich auf Abruf, nicht automatisch (Kostenkontrolle, eigener
Anthropic-Key). Neue Stellplatz-Detailseite, Verlinkung im Pflanzen-Detail,
Erkennung veralteter Bewertungen bei Umzug/Neuanalyse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 00:17:18 +02:00

73 lines
2.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'dart:typed_data';
import 'package:cloud_functions/cloud_functions.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../household/data/household_providers.dart';
/// Ergebnis der Standort-Analyse (Cloud Function analyzeLocation).
class LocationAnalysisResult {
const LocationAnalysisResult({
required this.lightCategory,
required this.description,
});
final String lightCategory;
final String description;
}
class LocationAnalysisService {
LocationAnalysisService(
this._functionsGetter,
this._storage,
this._householdIdGetter,
);
// Lazy, damit Widget-Tests ohne initialisiertes Firebase auskommen —
// FirebaseFunctions.instanceFor wirft sonst schon beim Erzeugen.
final FirebaseFunctions Function() _functionsGetter;
final FirebaseStorage _storage;
final String? Function() _householdIdGetter;
/// Lädt das Stellplatz-Foto in den Haushalts-Ordner in Storage und
/// liefert die URL.
Future<String> uploadPhoto(Uint8List imageBytes) async {
final householdId = _householdIdGetter();
if (householdId == null) {
throw StateError('Kein Haushalt geladen Aktion nicht möglich.');
}
final ref = _storage.ref(
'households/$householdId/location-photos/'
'${DateTime.now().millisecondsSinceEpoch}.jpg',
);
await ref.putData(
imageBytes,
SettableMetadata(contentType: 'image/jpeg'),
);
return ref.getDownloadURL();
}
/// Schickt das Foto an die Cloud Function (Claude) dauert einige Sekunden.
Future<LocationAnalysisResult> analyze(Uint8List imageBytes) async {
final callable = _functionsGetter().httpsCallable('analyzeLocation');
final response = await callable.call<Map<String, dynamic>>({
'imageBase64': base64Encode(imageBytes),
});
final data = response.data;
return LocationAnalysisResult(
lightCategory: data['lightCategory'] as String? ?? '',
description: data['description'] as String? ?? '',
);
}
}
final locationAnalysisServiceProvider =
Provider<LocationAnalysisService>((ref) {
return LocationAnalysisService(
() => FirebaseFunctions.instanceFor(region: 'europe-west3'),
FirebaseStorage.instance,
() => ref.read(householdIdProvider).value,
);
});