From 92b682a1bd9a7510cc1863d918c738aedd560b65 Mon Sep 17 00:00:00 2001 From: Stephan Kerkman Date: Sun, 31 May 2026 12:51:28 +0200 Subject: [PATCH] feat: show Pl@ntNet reference images on confirm screen + save as thumbnail Extract image_url from Pl@ntNet API response (medium size). Show thumbnail in each match card on identify_confirm. On plant creation, download the selected match's reference image and save as PlantPhoto thumbnail. Scan photos saved as gallery photos (non-thumbnail) with fallback to first scan photo as thumbnail when Pl@ntNet has no image. Co-Authored-By: Claude Sonnet 4.6 --- plants/services/plantnet.py | 1 + plants/templates/plants/identify_confirm.html | 6 ++++++ plants/views/identify.py | 16 +++++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/plants/services/plantnet.py b/plants/services/plantnet.py index 945bb49..5a508b3 100644 --- a/plants/services/plantnet.py +++ b/plants/services/plantnet.py @@ -62,6 +62,7 @@ def identify(images): 'gbif_id': (r.get('gbif') or {}).get('id'), 'family': r['species'].get('family', {}).get('scientificNameWithoutAuthor', ''), 'genus': r['species'].get('genus', {}).get('scientificNameWithoutAuthor', ''), + 'image_url': ((r.get('images') or [{}])[0].get('url') or {}).get('m'), } for r in results[:5] ] diff --git a/plants/templates/plants/identify_confirm.html b/plants/templates/plants/identify_confirm.html index ffa2f4a..a64539a 100644 --- a/plants/templates/plants/identify_confirm.html +++ b/plants/templates/plants/identify_confirm.html @@ -20,6 +20,12 @@ data-idx="{{ forloop.counter0 }}" data-name="{{ m.scientific_name }}" onclick="selectMatch(this)"> + {% if m.image_url %} + {{ m.scientific_name }} + {% else %} +
+ {% endif %}
{{ m.scientific_name }}
{% if m.common_names %} diff --git a/plants/views/identify.py b/plants/views/identify.py index ddf0c50..9c4282f 100644 --- a/plants/views/identify.py +++ b/plants/views/identify.py @@ -1,6 +1,7 @@ import logging import os import uuid +import requests from django.shortcuts import render, redirect from django.core.files.base import ContentFile from django.core.files.storage import default_storage @@ -172,6 +173,19 @@ def identify_fields(request): plant = Plant.objects.create(name=name, species=species) try: + # Download Pl@ntNet reference image as thumbnail + plantnet_img_url = selected.get('image_url') + if plantnet_img_url: + try: + r = requests.get(plantnet_img_url, timeout=10) + r.raise_for_status() + thumb_filename = f'plantnet_{uuid.uuid4().hex}.jpg' + thumb = PlantPhoto(plant=plant, is_thumbnail=True) + thumb.image.save(thumb_filename, ContentFile(r.content), save=True) + except Exception: + logger.exception('identify_fields: failed to download Pl@ntNet image') + + # Save uploaded scan photos; only first becomes thumbnail if no Pl@ntNet image image_paths = request.session.get('identify_image_paths', []) for i, p in enumerate(image_paths): if not default_storage.exists(p['path']): @@ -180,7 +194,7 @@ def identify_fields(request): with default_storage.open(p['path'], 'rb') as fh: data = fh.read() filename = os.path.basename(p['path']) - photo = PlantPhoto(plant=plant, is_thumbnail=(i == 0)) + photo = PlantPhoto(plant=plant, is_thumbnail=(i == 0 and not plantnet_img_url)) photo.image.save(filename, ContentFile(data), save=True) except Exception: logger.exception('identify_fields: failed to save photo %s', p['path'])