이미지 전송 방식
import base64
from openai import OpenAI
from pathlib import Path
client = OpenAI()
# 방법 1: URL로 전송
def analyze_image_url(image_url: str, prompt: str) -> str:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": {"url": image_url}},
]
}],
max_tokens=1000,
)
return response.choices[0].message.content
# 방법 2: base64로 로컬 파일 전송
def analyze_local_image(image_path: str, prompt: str) -> str:
with open(image_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
# MIME 타입 감지
suffix = Path(image_path).suffix.lower()
mime_type = {"jpg": "jpeg", "jpeg": "jpeg", "png": "png", "gif": "gif", "webp": "webp"}.get(suffix[1:], "jpeg")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": {
"url": f"data:image/{mime_type};base64,{image_data}"
}},
]
}],
)
return response.choices[0].message.content
영수증/문서 구조화
from pydantic import BaseModel
from typing import Optional
class ReceiptItem(BaseModel):
name: str
quantity: int
unit_price: int
total: int
class Receipt(BaseModel):
store_name: str
date: str
items: list[ReceiptItem]
subtotal: int
tax: Optional[int] = None
total: int
def extract_receipt(image_path: str) -> Receipt:
with open(image_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "이 영수증에서 정보를 추출해주세요."},
{"type": "image_url", "image_url": {
"url": f"data:image/jpeg;base64,{image_data}"
}},
]
}],
response_format=Receipt,
)
return response.choices[0].message.parsed
# 사용
receipt = extract_receipt("receipt.jpg")
print(f"가게: {receipt.store_name}")
print(f"합계: {receipt.total:,}원")
for item in receipt.items:
print(f" - {item.name}: {item.unit_price:,}원 × {item.quantity}")
차트/그래프 분석
def analyze_chart(image_path: str) -> dict:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{
"type": "text",
"text": """이 차트를 분석해주세요:
1. 차트 종류와 제목
2. X축, Y축 의미
3. 주요 데이터 포인트나 트렌드
4. 핵심 인사이트 (2~3가지)
JSON 형식으로 응답해주세요."""
},
{"type": "image_url", "image_url": {
"url": f"data:image/png;base64,{encode_image(image_path)}"
}},
]
}],
response_format={"type": "json_object"},
)
return json.loads(response.choices[0].message.content)
여러 이미지 비교
def compare_images(image_paths: list[str], question: str) -> str:
content = [{"type": "text", "text": question}]
for i, path in enumerate(image_paths):
content.append({
"type": "text",
"text": f"이미지 {i+1}:"
})
content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{encode_image(path)}"}
})
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": content}],
)
return response.choices[0].message.content
# 사용: 제품 이미지 A/B 비교
result = compare_images(
["product_v1.jpg", "product_v2.jpg"],
"두 제품 디자인의 차이점을 분석하고, 어느 것이 더 사용자 친화적인지 평가해주세요."
)
Claude로 이미지 분석
import anthropic
import httpx
client = anthropic.Anthropic()
# URL에서 바이트로 다운로드
def analyze_with_claude(image_url: str, prompt: str) -> str:
image_data = base64.standard_b64encode(
httpx.get(image_url).content
).decode("utf-8")
message = client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
messages=[{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image_data,
},
},
{"type": "text", "text": prompt}
],
}],
)
return message.content[0].text
정리
| 방식 | 장점 | 단점 |
|---|---|---|
| URL 전송 | 간단 | 외부 접근 가능해야 함 |
| base64 | 로컬 파일 가능 | 요청 크기 증가 |
| Structured Output | 타입 안전 | 복잡한 구조 |
다음 편에서는 이미지 생성 — DALL-E 3와 Stable Diffusion으로 이미지를 생성하는 방법을 배웁니다.