Skip to content

Best Practices

Guidelines for getting the most accurate diagnoses and building robust integrations.


Image Quality

Do's

  • Use natural lighting - Outdoor daylight provides the best color accuracy
  • Focus on symptoms - Get close-ups of affected areas
  • Include context - Show both healthy and affected parts
  • Keep steady - Avoid motion blur
  • Multiple angles - When possible, capture different views

Don'ts

  • Avoid flash - Can wash out colors and create shadows
  • Avoid backlighting - Don't shoot against the sun
  • Avoid extreme zoom - Very zoomed images lose context
  • Avoid filters - Don't apply Instagram-style filters
  • Avoid screenshots - Upload original photos, not screenshots

Example: Good vs Bad Images

Good Bad
Clear, focused close-up of leaf Blurry, out of focus
Natural daylight Dark, shadowy
Shows affected area clearly Symptom too small in frame
Original photo Screenshot of photo

Provide Context

The more context you provide, the more accurate the diagnosis:

Always Include (When Known)

Parameter Impact on Accuracy
crop_type High - Diseases are crop-specific
region High - Some diseases are region-specific
growth_stage Medium - Symptoms vary by plant maturity
description Medium - Your observations help AI focus

Example: Context Matters

# Basic request - less accurate
result = diagnose(image)

# With context - more accurate
result = diagnose(
    image,
    crop_type="tomato",
    region="Kenya",
    growth_stage="flowering",
    description="Yellow spots appeared after heavy rain last week"
)

Choose the Right Detail Level

Level Best For What You Get
simple Farmers, field workers Plain language, key actions only
standard Extension officers, technicians Balanced technical info
expert Agronomists, researchers Full scientific detail

Example Outputs

Simple:

Your tomato plant has a fungus problem. Remove the bad leaves and spray with copper-based fungicide every week.

Standard:

Early Blight (Alternaria solani) detected with 87% confidence. The disease affects lower leaves first. Treat with chlorothalonil or copper hydroxide, applying every 7-10 days.

Expert:

Alternaria solani infection confirmed. Pathogen thrives at 24-29°C with >90% RH. Recommended treatment: Chlorothalonil (1.5kg/ha) or Mancozeb (2kg/ha) at 7-10 day intervals. Consider resistance management with fungicide rotation.


Handle Responses Properly

Always Check These Fields

result = diagnose(image)

# 1. Is it a plant?
if not result['is_plant']:
    print("Please upload a photo of a plant")
    return

# 2. Any image quality issues?
if result['image_quality_issue']:
    print(f"Image problem: {result['image_quality_issue']}")
    return

# 3. Could health be determined?
if result['crop_health'] == 'unknown':
    print("Could not determine plant health")
    return

# 4. Any diagnoses found?
if not result['diagnoses']:
    print("No diseases detected - plant appears healthy")
    return

# 5. Process diagnoses by confidence
for diagnosis in result['diagnoses']:
    if diagnosis['confidence'] >= 0.7:
        print(f"Likely: {diagnosis['name']}")
    elif diagnosis['confidence'] >= 0.4:
        print(f"Possible: {diagnosis['name']}")

Confidence Score Interpretation

Score Interpretation Action
0.8+ High confidence Proceed with treatment
0.5-0.8 Moderate Consider treatment, monitor
0.3-0.5 Low Monitor, get second opinion
<0.3 Very low Likely not this disease

Error Handling

Implement Retry Logic

import time
from functools import wraps

def with_retry(max_attempts=3, backoff_factor=2):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            last_error = None
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last_error = e
                    if attempt < max_attempts - 1:
                        wait = backoff_factor ** attempt
                        time.sleep(wait)
            raise last_error
        return wrapper
    return decorator

@with_retry(max_attempts=3)
def diagnose_plant(image_path):
    # Your diagnosis code
    pass

Handle Specific Errors

def diagnose_safely(image_path, **kwargs):
    try:
        result = client.diagnose(image_path, **kwargs)

        if result.get('error'):
            # Analysis-level error
            return handle_analysis_error(result['error'])

        return result

    except requests.exceptions.Timeout:
        return {"error": "Request timed out. Please try again."}

    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 429:
            return {"error": "Rate limit exceeded. Please wait."}
        elif e.response.status_code == 400:
            return {"error": f"Invalid request: {e.response.json().get('detail')}"}
        else:
            return {"error": f"Server error: {e.response.status_code}"}

    except Exception as e:
        return {"error": f"Unexpected error: {str(e)}"}

Performance Optimization

1. Compress Images Client-Side

Large images increase upload time without improving accuracy:

from PIL import Image
import io

def optimize_image(image_path, max_dimension=1920, quality=85):
    """Optimize image for API upload."""
    img = Image.open(image_path)

    # Resize if too large
    if max(img.size) > max_dimension:
        ratio = max_dimension / max(img.size)
        new_size = tuple(int(dim * ratio) for dim in img.size)
        img = img.resize(new_size, Image.LANCZOS)

    # Convert to RGB if needed
    if img.mode in ('RGBA', 'P'):
        img = img.convert('RGB')

    # Save to buffer
    buffer = io.BytesIO()
    img.save(buffer, format='JPEG', quality=quality, optimize=True)
    buffer.seek(0)

    return buffer

2. Use Connection Pooling

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# Create session with retry logic
session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))

# Reuse session for all requests
def diagnose(image_path):
    return session.post(
        'https://api.tajirifarm.com/diagnosis/',
        files={'image': open(image_path, 'rb')}
    ).json()

3. Cache Results

from functools import lru_cache
import hashlib

def get_image_hash(image_path):
    with open(image_path, 'rb') as f:
        return hashlib.md5(f.read()).hexdigest()

@lru_cache(maxsize=100)
def diagnose_cached(image_hash, crop_type=None, region=None):
    # This caches results for identical images
    return client.diagnose(image_hash, crop_type=crop_type, region=region)

Security

Validate User Uploads

import magic  # python-magic library

ALLOWED_MIMES = {'image/jpeg', 'image/png', 'image/webp'}
MAX_SIZE = 10 * 1024 * 1024  # 10MB

def validate_upload(file_path):
    """Validate uploaded file before sending to API."""
    # Check file size
    import os
    if os.path.getsize(file_path) > MAX_SIZE:
        raise ValueError("File too large (max 10MB)")

    # Check actual MIME type (not just extension)
    mime = magic.from_file(file_path, mime=True)
    if mime not in ALLOWED_MIMES:
        raise ValueError(f"Invalid file type: {mime}")

    return True

Don't Log Sensitive Data

import logging

# Good - log request metadata
logging.info(f"Diagnosis request: crop={crop_type}, region={region}")

# Bad - don't log full image data
# logging.info(f"Image data: {image_bytes}")

Testing

Use Health Check

def check_api_availability():
    """Check if API is available before processing."""
    try:
        response = requests.get(
            'https://api.tajirifarm.com/health',
            timeout=5
        )
        return response.json().get('status') == 'healthy'
    except:
        return False

# Before batch processing
if not check_api_availability():
    print("API is unavailable. Please try later.")
    exit(1)

Save Request IDs

def diagnose_with_logging(image_path, **kwargs):
    """Diagnose and log request ID for debugging."""
    response = requests.post(
        'https://api.tajirifarm.com/diagnosis/',
        files={'image': open(image_path, 'rb')},
        data=kwargs
    )

    request_id = response.headers.get('X-Request-ID')
    logging.info(f"Request ID: {request_id}")

    result = response.json()
    result['_request_id'] = request_id  # Store for later reference

    return result