Vision API, ניתוח תמונות ומסמכים עם Claude

📚 פיתוח עם Claude, Claude Code & API ⏱️ 7 דק׳ 🎓 מתקדם ✓ חינם לגמרי
Vision API, ניתוח תמונות ומסמכים עם Claude

למה Vision API הוא לא רק OCR

רוב המפתחים מתייחסים ל-Vision API כמנוע OCR יקר. זאת טעות. Claude לא רק קורא טקסט מתמונה, הוא מבין הקשר, מנתח מבנה, ויכול לנמק על מה שהוא רואה. תמונת חשבונית היא לא רשימת מילים, זו מסמך עם מבנה היררכי, מספרים שמסתכמים, וספק שיש לו כתובת. Claude מבין את כל זה בבקשה אחת.

כפי שמסביר מדריך המפתחים של GetStream: "Unlike dedicated OCR tools or computer vision models that only extract specific features, Claude understands images holistically, it can read text, interpret charts, describe visual layouts, identify objects, and reason about relationships between visual elements all in a single API call."

שיעור זה מכסה: base64 לעומת URL לעומת Files API, חישוב עלויות, Opus 4.7 high-res, וטכניקות prompting שמפרידות בין תוצאה שמישה לתוצאה שצריך לזרוק.

שיטות שליחת תמונות, base64, URL, Files API

יש שלוש דרכים לשלוח תמונה ל-Claude API. הבחירה משפיעה על עלות, latency ואבטחה.

שיטה מתי להשתמש חיסרון
base64 תמונות מקומיות, פנימיות, סודיות מנפח את ה-payload (עד 32MB מגבלה)
URL תמונות ציבוריות, CDN חייב להיות publicly accessible
Files API תמונה שנשלחת שוב ושוב בפיפליין דורש העלאה מוקדמת
# base64, תמונה מקומית
import anthropic, base64
from pathlib import Path

client = anthropic.Anthropic()

def send_image_base64(image_path: str, prompt: str) -> str:
    img_bytes = Path(image_path).read_bytes()
    b64 = base64.standard_b64encode(img_bytes).decode("utf-8")
    ext = Path(image_path).suffix.lower()
    media_map = {".jpg": "image/jpeg", ".jpeg": "image/jpeg",
                 ".png": "image/png", ".webp": "image/webp", ".gif": "image/gif"}
    media_type = media_map.get(ext, "image/jpeg")

    resp = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": [
            {"type": "image", "source": {
                "type": "base64", "media_type": media_type, "data": b64
            }},
            {"type": "text", "text": prompt}  # תמונה לפני טקסט!
        ]}]
    )
    return resp.content[0].text

# URL, תמונה ציבורית
resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    messages=[{"role": "user", "content": [
        {"type": "image", "source": {"type": "url",
            "url": "https://example.com/invoice.png"}},
        {"type": "text", "text": "חלץ את הנתונים כJSON"}
    ]}]
)

עלויות, חישוב מדויק

כל תמונה צורכת טוקנים לפי הנוסחה: width × height / 750. לתמונת 1000×1000 px זה ~1,334 טוקנים, ובמחיר Sonnet 4.6 ($3/M טוקנים), כ-$0.004 לתמונה. אלף תמונות = $4. זה נשמע זול, אבל בפיפליין של 50,000 חשבוניות ביום, זה $200/יום רק על הtokens של התמונות.

שדרוג חשוב: Claude Opus 4.7 תומך ב-2576 px (long edge), לעומת 1568 px בכל המודלים האחרים. תמיכה זו אוטומטית, אין צורך בheader מיוחד. ל-OCR על מסמכים צפופים (חוזים, טפסים ממשלתיים), Opus 4.7 מחזיר תוצאות משמעותית טובות יותר. החיסרון: עד 4,784 טוקנים לתמונה (פי ~3 ממודלים אחרים). אם אינך צריך את הfidelity הגבוה, downsample לפני שליחה.

Claude לא יכול לקרוא עברית בתמונות
כל בקשה עם base64 תתקרב למגבלת ה-32MB, צריך לעבור ל-Files API לשימוש חוזר, או לדחוס את התמונות לפני שליחה
Vision API לא תומך ב-JPEG, רק PNG
Claude לא יכול לעבד יותר מ-10 תמונות ביום

Prompting לvision, ההבדל בין "מה בתמונה" ל"מה צריך לעשות"

הטעות הנפוצה ביותר: שואלים "מה בתמונה?" ומקבלים תיאור. מבקשים "חלץ כJSON" ומקבלים מבנה שמיש. Claude הוא מנוע מימוש, לא מנוע תצפית, תנו לו הנחיה ברורה לפעולה.

מה יש בתמונה הזו?
זו חשבונית עסקית ישראלית. חלץ את הנתונים הבאים כ-JSON תקני: { "invoice_number": "string", "date": "YYYY-MM-DD", "vendor_name": "string", "items": [{"desc": "string", "qty": number, "unit_price": number}], "subtotal": number, "vat": number, "total": number } אם שדה לא קריא, השתמש ב-null. החזר JSON בלבד, ללא הסבר.

שלושה כללי prompting לvision:

דוגמה ישראלית: pipeline לעיבוד חשבוניות בחברת לוגיסטיקה

חברת לוגיסטיקה ישראלית מעבדת 200 חשבוניות ספקים ביום, מסרוקים, PDFs שצולמו בנייד, ותמונות מ-WhatsApp. הפיפליין הבסיסי:

import json, csv
from pathlib import Path

def extract_invoice(image_path: str) -> dict:
    """חלץ נתוני חשבונית לdict מובנה"""
    prompt = (
        "חשבונית עסקית ישראלית. חלץ כ-JSON:\n"
        '{"invoice_number":"...","date":"YYYY-MM-DD",'
        '"vendor":"...","total":0.0,"vat":0.0}\n'
        "החזר JSON בלבד. שדה לא קריא = null."
    )
    raw = send_image_base64(image_path, prompt)

    # הגנה מפני Claude שמוסיף טקסט לפני/אחרי JSON
    start = raw.find("{")
    end = raw.rfind("}") + 1
    return json.loads(raw[start:end])

# עיבוד תיקיה
results = []
for img in Path("invoices/").glob("*.png"):
    try:
        data = extract_invoice(str(img))
        data["source_file"] = img.name
        results.append(data)
    except json.JSONDecodeError:
        print(f"Failed: {img.name}")

# שמירה ל-CSV
if results:
    with open("invoices_output.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=results[0].keys())
        writer.writeheader()
        writer.writerows(results)

שימו לב: החילוץ של JSON מתוך התשובה (find+rfind) מגן מפני המקרה שClaude מוסיף הקדמה כמו "הנה ה-JSON:" לפני המבנה, טעות נפוצה בproduction.

שימושים מעבר ל-OCR

Vision API שימושי בהרבה יותר מחילוץ טקסט:

רוצה ללמוד עם מעקב התקדמות, קוויזים ותעודה?

כל 130 השיעורים פתוחים בחינם, כולל נגן אינטראקטיבי, שמירת התקדמות ותעודה דיגיטלית בסיום.