Vision & documents
Two tiers accept image input alongside text:
| Tier | Best for |
|---|---|
| ps/see | General vision — describe images, answer questions, read screenshots, reason over charts and UIs |
| ps/docs | Document extraction — turn document images into clean text/structure (OCR-style) |
Both use the standard OpenAI multimodal message format. Images go inline in the message — no separate upload endpoint.
Sending an image
Add an image_url part to the content array of a user message, alongside your text prompt. Images can be base64 data-URIs or public URLs.
curl -X POST https://api.pinstripes.io/v1/chat/completions \
-H "Authorization: Bearer sk-ps-..." \
-H "Content-Type: application/json" \
-d '{
"model": "ps/see",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "What does this screenshot show?"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}
]
}]
}'Python (base64)
import base64
from openai import OpenAI
client = OpenAI(base_url="https://api.pinstripes.io/v1", api_key="sk-ps-...")
with open("screenshot.png", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
resp = client.chat.completions.create(
model="ps/see",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "What does this screenshot show?"},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
],
}],
)
print(resp.choices[0].message.content)Public URL instead of base64
{
"type": "image_url",
"image_url": { "url": "https://example.com/chart.png" }
}Either works. Data-URIs are convenient for local files; public URLs keep request size down (the image must be reachable from the internet).
Multiple images
ps/see accepts more than one image per message — add more image_url parts:
"content": [
{"type": "text", "text": "What changed between these two screenshots?"},
{"type": "image_url", "image_url": {"url": before_uri}},
{"type": "image_url", "image_url": {"url": after_uri}},
]Document extraction with ps/docs
ps/docs is tuned for reading document images and returning their text and structure. Usage is identical — send the page as an image:
resp = client.chat.completions.create(
model="ps/docs",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Extract all text from this document."},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{page_b64}"}},
],
}],
)
print(resp.choices[0].message.content)Working with PDFs
ps/docs takes images, not raw PDF bytes — rasterize each page first:
from pdf2image import convert_from_path # pip install pdf2image (needs poppler)
pages = convert_from_path("invoice.pdf", dpi=200)
for i, page in enumerate(pages):
page.save(f"page_{i}.png")
# send each page_{i}.png to ps/docs as aboveRender at 150–300 DPI for reliable text extraction. Process pages individually and stitch results on your side.
