> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Product Photo Alt Text Writer

> Generate accessible alt text and tags for product images

# Product Photo Alt Text Writer

Generate SEO-friendly, accessible alt text and tags for product images.

## Problem Statement

**Who:** E-commerce teams, content managers, accessibility specialists\
**Why:** Good alt text improves accessibility and SEO. Manual writing is time-consuming at scale.

## What You'll Build

A recipe that analyzes product images and generates descriptive alt text with relevant tags.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Input[🖼️ Product Image] --> Analyze[Analyze Image]
    Analyze --> Generate[Generate Alt Text]
    Generate --> Tags[Extract Tags]
    Tags --> Output[📝 Alt Text + Tags]

    classDef input fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff

    class Input,Output input
    class Analyze,Generate,Tags process
```

### Input/Output Contract

| Input | Type | Required | Description |
| - | - | - | - |
| `image_path` | string | Yes | Path to product image |
| `brand_tone` | string | No | Brand voice (default: `neutral`) |
| `locale` | string | No | Target locale (default: `en-US`) |

| Output | Type | Description |
| - | - | - |
| `alt_text` | string | Generated alt text |
| `tags` | array | Relevant product tags |
| `ok` | boolean | Success indicator |

## Prerequisites

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export OPENAI_API_KEY=your_key_here
pip install praisonaiagents
```

## Step-by-Step Build

**1. Create Recipe Directory**

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
mkdir -p ~/.praisonai/templates/product-photo-alt-text-writer
cd ~/.praisonai/templates/product-photo-alt-text-writer
```

**2. Create TEMPLATE.yaml**

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
name: product-photo-alt-text-writer
version: "1.0.0"
description: "Generate accessible alt text for product images"
author: "PraisonAI"
license: "MIT"

tags:
  - image
  - accessibility
  - ecommerce
  - seo

requires:
  env:
    - OPENAI_API_KEY
  packages:
    - praisonaiagents

inputs:
  image_path:
    type: string
    description: "Path to the product image"
    required: true
  brand_tone:
    type: string
    description: "Brand voice for alt text"
    required: false
    default: "neutral"
    enum:
      - neutral
      - luxury
      - casual
      - technical
  locale:
    type: string
    description: "Target locale for alt text"
    required: false
    default: "en-US"

outputs:
  alt_text:
    type: string
    description: "Generated alt text"
  tags:
    type: array
    description: "Relevant product tags"
  ok:
    type: boolean
    description: "Success indicator"

cli:
  command: "praison recipes run product-photo-alt-text-writer"
  examples:
    - 'praison recipes run product-photo-alt-text-writer --input ''{"image_path": "product.jpg"}'''

safety:
  dry_run_default: false
  requires_consent: false
  overwrites_files: false
  network_access: true
  pii_handling: false
```

**3. Create recipe.py**

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# recipe.py
import os
from praisonaiagents import Agent, Task, AgentTeam

def run(input_data: dict, config: dict = None) -> dict:
    """Generate alt text for product images."""
    image_path = input_data.get("image_path")
    brand_tone = input_data.get("brand_tone", "neutral")
    locale = input_data.get("locale", "en-US")
    
    if not image_path:
        return {"ok": False, "error": {"code": "MISSING_INPUT", "message": "image_path is required"}}
    
    if not os.path.exists(image_path):
        return {"ok": False, "error": {"code": "FILE_NOT_FOUND", "message": f"Image not found: {image_path}"}}
    
    try:
        tone_guidelines = {
            "neutral": "Clear, factual descriptions",
            "luxury": "Elegant, sophisticated language emphasizing quality",
            "casual": "Friendly, approachable descriptions",
            "technical": "Precise specifications and features"
        }
        
        # Create vision agent
        vision_agent = Agent(
            name="Product Analyst",
            role="Visual Product Expert",
            goal="Analyze product images accurately",
            instructions=f"""
            You are a product image analyst.
            - Identify the product type and category
            - Note colors, materials, and features
            - Describe the product's appearance
            - Consider the {brand_tone} tone: {tone_guidelines[brand_tone]}
            """,
        )
        
        # Create alt text writer
        alt_writer = Agent(
            name="Alt Text Writer",
            role="Accessibility Specialist",
            goal="Write effective alt text for screen readers",
            instructions=f"""
            You are an accessibility expert writing alt text.
            - Keep alt text under 125 characters
            - Be descriptive but concise
            - Include key product details
            - Use {brand_tone} tone
            - Write for {locale} audience
            - Don't start with "Image of" or "Picture of"
            """,
        )
        
        # Create tag generator
        tagger = Agent(
            name="Product Tagger",
            role="E-commerce SEO Specialist",
            goal="Generate relevant product tags",
            instructions="""
            You are an e-commerce tagging expert.
            - Generate 5-10 relevant tags
            - Include category, color, material, style
            - Use lowercase, hyphenated format
            - Focus on searchable terms
            """,
        )
        
        # Define tasks
        analyze_task = Task(
            name="analyze_image",
            description=f"Analyze the product image at: {image_path}",
            expected_output="Detailed product description",
            agent=vision_agent,
        )
        
        alt_task = Task(
            name="write_alt_text",
            description="Write accessible alt text based on the analysis",
            expected_output="Alt text under 125 characters",
            agent=alt_writer,
            context=[analyze_task],
        )
        
        tag_task = Task(
            name="generate_tags",
            description="Generate product tags for SEO",
            expected_output="List of 5-10 tags",
            agent=tagger,
            context=[analyze_task],
        )
        
        # Execute
        agents = AgentTeam(
            agents=[vision_agent, alt_writer, tagger],
            tasks=[analyze_task, alt_task, tag_task],
        )
        
        result = agents.start()
        
        # Parse tags
        tags_text = result.get("generate_tags", "")
        tags = [t.strip().lower().replace(" ", "-") for t in tags_text.split(",") if t.strip()]
        if not tags:
            tags = [t.strip() for t in tags_text.split("\n") if t.strip() and not t.startswith("-")]
        
        return {
            "ok": True,
            "alt_text": result.get("write_alt_text", "").strip()[:125],
            "tags": tags[:10],
            "artifacts": [],
            "warnings": [],
        }
        
    except Exception as e:
        return {"ok": False, "error": {"code": "PROCESSING_ERROR", "message": str(e)}}
```

**4. Create test\_recipe.py**

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# test_recipe.py
import pytest
from recipe import run

def test_missing_image_path():
    result = run({})
    assert result["ok"] is False
    assert result["error"]["code"] == "MISSING_INPUT"

def test_file_not_found():
    result = run({"image_path": "/nonexistent.jpg"})
    assert result["ok"] is False
    assert result["error"]["code"] == "FILE_NOT_FOUND"

def test_brand_tones():
    valid_tones = ["neutral", "luxury", "casual", "technical"]
    for tone in valid_tones:
        assert tone in valid_tones

@pytest.mark.integration
def test_end_to_end():
    import os
    test_image = os.environ.get("TEST_IMAGE_PATH")
    if not test_image:
        pytest.skip("No test image available")
    
    result = run({"image_path": test_image, "brand_tone": "neutral"})
    assert result["ok"] is True
    assert len(result["alt_text"]) <= 125
    assert len(result["tags"]) > 0
```

## Run Locally

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Basic usage
praison recipes run product-photo-alt-text-writer \
  --input '{"image_path": "shoe.jpg"}'

# With brand tone
praison recipes run product-photo-alt-text-writer \
  --input '{"image_path": "watch.png", "brand_tone": "luxury", "locale": "en-GB"}'
```

## Deploy & Integrate: 6 Integration Models

> [tab] Model 1: Embedded SDK
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonai import recipe
>
> result = recipe.run(
>     "product-photo-alt-text-writer",
>     input={"image_path": "product.jpg", "brand_tone": "luxury"}
> )
>
> if result.ok:
>     print(f"Alt: {result.output['alt_text']}")
>     print(f"Tags: {result.output['tags']}")
> ```

> [tab] Model 2: CLI Invocation
>
> ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> # Batch process product images
> for img in products/*.jpg; do
>   praison recipes run product-photo-alt-text-writer \
>     --input "{\"image_path\": \"$img\"}" --json
> done
> ```

> [tab] Model 3: Plugin Mode
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> class AltTextPlugin:
>     def generate(self, image_path, tone="neutral"):
>         from praisonai import recipe
>         return recipe.run(
>             "product-photo-alt-text-writer",
>             input={"image_path": image_path, "brand_tone": tone}
>         )
> ```

> [tab] Model 4: Local HTTP Sidecar
>
> ```javascript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> const response = await fetch('http://localhost:8765/recipes/product-photo-alt-text-writer/run', {
>   method: 'POST',
>   body: JSON.stringify({ image_path: '/uploads/product.jpg' })
> });
> ```

> [tab] Model 5: Remote Managed Runner
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> response = requests.post(
>     "https://api.ecommerce-tools.com/alt-text",
>     headers={"Authorization": f"Bearer {api_key}"},
>     json={"image_url": "https://cdn.example.com/product.jpg"}
> )
> ```

> [tab] Model 6: Event-Driven
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> def on_product_image_uploaded(event):
>     import queue as q
>     job_queue = q.Queue()  # Replace with SQS/RabbitMQ in production
>     job_queue.put({
>         "recipe": "product-photo-alt-text-writer",
>         "input": {"image_path": event['image_path']},
>         "callback_url": f"https://api.example.com/products/{event['product_id']}/alt-text"
>     })
> ```

## Troubleshooting

> [accordion] Alt text too generic
>
> Try using a more specific brand\_tone or ensure the image is clear and well-lit.

> [accordion] Missing product details
>
> The vision model works best with clear, well-composed product photos on neutral backgrounds.

## Next Steps

* **[Document Summarizer](https://praison.ai/docs/examples/recipe-examples/document-summarizer-with-citations.md)** - Summarize product descriptions
* **[Customer Support Reply Drafter](https://praison.ai/docs/examples/recipe-examples/customer-support-reply-drafter.md)** - Handle product inquiries


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.