> ## Documentation Index
> Fetch the complete documentation index at: https://docs.praison.ai/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

<Steps>
  <Step title="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
    ```
  </Step>

  <Step title="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
    ```
  </Step>

  <Step title="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)}}
    ```
  </Step>

  <Step title="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
    ```
  </Step>
</Steps>

## 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

<Tabs>
  <Tab title="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>

  <Tab title="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>

  <Tab title="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>

  <Tab title="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>

  <Tab title="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>

  <Tab title="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"
        })
    ```
  </Tab>
</Tabs>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Alt text too generic">
    Try using a more specific brand\_tone or ensure the image is clear and well-lit.
  </Accordion>

  <Accordion title="Missing product details">
    The vision model works best with clear, well-composed product photos on neutral backgrounds.
  </Accordion>
</AccordionGroup>

## Next Steps

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