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 <noreply@anthropic.com>
This commit is contained in:
Stephan Kerkman 2026-05-31 12:51:28 +02:00
parent 70c2213d98
commit 92b682a1bd
3 changed files with 22 additions and 1 deletions

View file

@ -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]
]

View file

@ -20,6 +20,12 @@
data-idx="{{ forloop.counter0 }}"
data-name="{{ m.scientific_name }}"
onclick="selectMatch(this)">
{% if m.image_url %}
<img src="{{ m.image_url }}" alt="{{ m.scientific_name }}"
style="width:64px;height:64px;object-fit:cover;border-radius:8px;flex-shrink:0;">
{% else %}
<div style="width:64px;height:64px;background:#e9ecef;border-radius:8px;flex-shrink:0;"></div>
{% endif %}
<div class="flex-grow-1">
<div class="fw-bold">{{ m.scientific_name }}</div>
{% if m.common_names %}

View file

@ -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'])