102 lines
4.3 KiB
Python
Raw Permalink Normal View History

# Plant detection Lambda code - uses Nova Premier to analyze plant images
import json
import boto3
import base64
def lambda_handler(event, context):
try:
print(f"Received event keys: {list(event.keys())}")
# Extract inputs
image_path = event.get('image_path')
image_data = event.get('image_data')
print(f"image_path present: {bool(image_path)}")
print(f"image_data present: {bool(image_data)}")
if not image_path and not image_data:
return {
'statusCode': 400,
'body': json.dumps({'error': 'Either image_path or image_data required'})
}
# Process image input - FIXED LOGIC
image_bytes = None
if image_data:
# Handle base64 image data
print("Processing image_data...")
try:
image_bytes = base64.b64decode(image_data)
print(f"✅ Decoded base64 image: {len(image_bytes)} bytes")
except Exception as e:
return {'statusCode': 400, 'body': json.dumps({'error': f'Invalid base64: {e}'})}
elif image_path:
# Handle image path (S3 or URL only)
print(f"Processing image_path: {image_path}")
if image_path.startswith('s3://'):
try:
s3_client = boto3.client('s3')
bucket = image_path.split('/')[2]
key = '/'.join(image_path.split('/')[3:])
response = s3_client.get_object(Bucket=bucket, Key=key)
image_bytes = response['Body'].read()
print(f"✅ Loaded from S3: {len(image_bytes)} bytes")
except Exception as e:
return {'statusCode': 500, 'body': json.dumps({'error': f'S3 error: {e}'})}
else:
return {'statusCode': 404, 'body': json.dumps({'error': f'Only S3 paths supported: {image_path}'})}
if not image_bytes:
return {'statusCode': 400, 'body': json.dumps({'error': 'No image data processed'})}
# Detect format - CORRECTED
if image_bytes.startswith(b'\xff\xd8\xff'):
image_format = 'jpeg'
elif image_bytes.startswith(b'\x89PNG\r\n\x1a\n'):
image_format = 'png'
else:
image_format = 'jpeg' # Default
print(f"✅ Detected format: {image_format}")
# Call Nova
bedrock_client = boto3.client("bedrock-runtime", region_name="us-east-1")
response = bedrock_client.converse(
modelId="us.amazon.nova-premier-v1:0",
messages=[{
"role": "user",
"content": [
{"image": {"format": image_format, "source": {"bytes": image_bytes}}},
{"text": "Analyze this plant image and provide ONLY valid JSON format: {'plant_type': 'name', 'health_analysis': 'detailed analysis'}. Use specific plant names you inferred from the data, such as: sweet_potato_leaf, tomato, bean, lettuce, pepper, cucumber, spinach, okra, sweet potato, carrot, onion, garlic, herbs. For health_analysis, describe in detail: leaf color (green, yellow, brown, purple), spots (black spots, brown spots, white spots), wilting, malnutrition signs, holes or other symptoms of pest damage, disease symptoms, nutrient deficiency, overall plant condition."}
]
}],
inferenceConfig={"temperature": 0.1, "maxTokens": 300}
)
output = response['output']['message']['content'][0]['text']
try:
json_start = output.find('{')
json_end = output.rfind('}') + 1
json_part = output[json_start:json_end]
parsed = json.loads(json_part)
except:
parsed = {"plant_type": "unknown", "health_analysis": "Parse error"}
return {
'statusCode': 200,
'body': json.dumps({
"plant_name": parsed.get('plant_type', 'unknown'),
"health_issues": parsed.get('health_analysis', 'No analysis')
})
}
except Exception as e:
print(f"Lambda error: {str(e)}")
return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}