למה 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 לפני שליחה.
Prompting לvision, ההבדל בין "מה בתמונה" ל"מה צריך לעשות"
הטעות הנפוצה ביותר: שואלים "מה בתמונה?" ומקבלים תיאור. מבקשים "חלץ כJSON" ומקבלים מבנה שמיש. Claude הוא מנוע מימוש, לא מנוע תצפית, תנו לו הנחיה ברורה לפעולה.
שלושה כללי prompting לvision:
- תמונה לפני טקסט, לפי התיעוד הרשמי, Claude מגיע לתוצאות טובות יותר כאשר הimage content block מגיע לפני הtext block באותה הודעה.
- Graceful degradation, הוסיפו: "אם שדה לא קריא בבירור, כתוב null", זה מונע hallucination של מספרים שלא קיימים.
- PNG על פני JPEG לטקסט, דחיסת JPEG גורמת לאובדן חדות. לצילומי מסך ומסמכים, PNG תמיד.
דוגמה ישראלית: 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 שימושי בהרבה יותר מחילוץ טקסט:
- UI/UX Review, שלחו screenshot של מסך ובקשו "3 בעיות UX עיקריות, ממוינות לפי חומרה"
- ניתוח גרפים, גרף מ-Google Analytics + "מה המגמה העיקרית? מתי ה-peak?"
- השוואת גרסאות עיצוב, שתי תמונות בבקשה אחת + "מה ההבדלים? מה יעבוד טוב יותר?"
- קריאת לוחות מחוונים, dashboard של Grafana/Power BI + "מה הcount של שגיאות ב-24 שעות האחרונות?"
- בדיקת תוכן חזותי, בנר פרסומי + "האם הטקסט קריא? האם הCTA בולט מספיק?"
