在实际开发中,我们经常需要向不同的AI模型发送非文本输入(图片、PDF),但各大厂商API的接口设计各异。本文将展示如何编写一个通用的Python函数,用统一的方式向OpenAI、Claude和Gemini发送图像与PDF文件,并提取文本响应。
1. **统一输入格式**:将图片或PDF统一转换为Base64编码的字符串,并附上MIME类型。 2. **封装API调用**:为每个模型编写适配器,由主函数根据`provider`参数选择调用的API端点。 3. **处理多模态内容**:在消息体中以`content`列表的形式同时传递文本提示和文件数据。
首先,我们编写一个通用的方法,将任何本地文件转换为Base64字符串:
python
import base64
from pathlib import Path
def encode_file_to_base64(file_path: str) -> str: with open(file_path, "rb") as f: return base64.b64encode(f.read()).decode("utf-8") ```
对于PDF文件,建议先将其转换为图片(例如每页转为JPEG),再按图片处理。下面是一个简单的PDF转图片示例(需要安装`pdf2image`):
python
from pdf2image import convert_from_path
import io
from PIL import Image
def pdf_to_images(pdf_path: str, dpi: int = 200): images = convert_from_path(pdf_path, dpi=dpi) return images # 返回PIL Image列表 ```
不同API对多模态内容的格式有细微差异,但都可以利用“消息列表”结构。下面展示一个统一的构建函数:
python
def build_multimodal_message(prompt: str, base64_data: str, mime_type: str):
# 通用格式:将文本与base64数据组合
return {
"role": "user",
"content": [
{"type": "text", "text": prompt},
{
"type": "image_url" if mime_type.startswith("image/") else "file",
"image_url" if mime_type.startswith("image/") else "file": {
"url": f"data:{mime_type};base64,{base64_data}"
}
}
]
}
注意:OpenAI和Claude支持`image_url`格式,Gemini则使用`inline_data`。可以在适配器中分别处理。
#### OpenAI (gpt-4o / gpt-4-turbo)
python
def call_openai(api_key, model, messages):
from openai import OpenAI
client = OpenAI(api_key=api_key)
response = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=1024
)
return response.choices[0].message.content
#### Anthropic Claude (claude-3-opus-20240229)
Claude的API使用`anthropic`库,且要求`content`列表中的`source`字段:
python
def call_claude(api_key, model, messages):
import anthropic
client = anthropic.Anthropic(api_key=api_key)
# 将通用消息转换为Claude格式
claude_messages = []
for msg in messages:
if isinstance(msg["content"], list):
# 重新构建为Claude可接受的结构
claude_messages.append({
"role": msg["role"],
"content": [
{"type": "text", "text": item["text"]} if item["type"] == "text"
else {
"type": "image",
"source": {
"type": "base64",
"media_type": item["image_url"]["url"].split(";")[0].replace("data:", ""),
"data": item["image_url"]["url"].split(",")[1]
}
}
for item in msg["content"]
]
})
else:
claude_messages.append(msg)
response = client.messages.create(
model=model,
max_tokens=1024,
messages=claude_messages
)
return response.content[0].text
#### Google Gemini (gemini-1.5-pro)
Gemini使用`google-generativeai`库,内联数据需放在`parts`中:
python
def call_gemini(api_key, model, messages):
import google.generativeai as genai
genai.configure(api_key=api_key)
model = genai.GenerativeModel(model)
# 提取最新用户消息
last_user_msg = messages[-1]["content"]
text_part = ""
image_parts = []
for item in last_user_msg:
if item["type"] == "text":
text_part = item["text"]
elif item["type"] == "image_url":
# Gemini需要单独提取base64
raw_url = item["image_url"]["url"]
mime_type = raw_url.split(";")[0].replace("data:", "")
base64_data = raw_url.split(",")[1]
image_parts.append({
"mime_type": mime_type,
"data": base64_data
})
# 构建content
content_parts = [text_part]
for img in image_parts:
content_parts.append(genai.upload_file_from_bytes(
io.BytesIO(base64.b64decode(img["data"])),
mime_type=img["mime_type"]
))
response = model.generate_content(content_parts)
return response.text
最后,用一个入口函数根据`provider`路由:
python
def send_multimodal(provider: str, api_key: str, model: str, prompt: str, file_path: str):
if file_path.lower().endswith(".pdf"):
# 将PDF第一页转为JPEG
images = pdf_to_images(file_path)
img_buffer = io.BytesIO()
images[0].save(img_buffer, format="JPEG")
base64_data = base64.b64encode(img_buffer.getvalue()).decode("utf-8")
mime_type = "image/jpeg"
else:
base64_data = encode_file_to_base64(file_path)
mime_type = f"image/{Path(file_path).suffix[1:]}" # 简易判断
msg = build_multimodal_message(prompt, base64_data, mime_type) messages = [msg]
if provider == "openai": return call_openai(api_key, model, messages) elif provider == "claude": return call_claude(api_key, model, messages) elif provider == "gemini": return call_gemini(api_key, model, messages) else: raise ValueError("Unsupported provider") ```
python
result = send_multimodal(
provider="openai",
api_key="sk-...",
model="gpt-4o",
prompt="请描述这张图片中的内容",
file_path="photo.jpg"
)
print(result)
——
出处:How to send images and PDFs to OpenAI, Claude, and Gemini APIs using the same Python code
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。