Images and video
Pass images and videos in media, and refer to them in the state as <image:1>, <image:2>, <video:1>, … in order, each one once.
Images
from simoai import Client, Noul, Choice, Extract, Locate, image
c = Client()
r = c.ask(
state={"task": "Sign up for the newsletter", "screen": "<image:1>"},
media=[image("screenshot.png")],
questions={
"done": Noul("The sign-up is complete"),
"next": Choice("What should the agent do next?",
{"click": "click something", "scroll": "scroll down", "stop": "stop"},
args={"click": {"target": Extract("the label of the element to click")}}),
"button": Locate("the Sign up button"),
})
r["done"].noul # 0.04
r["next"].choice # "click"
r["next"].arg_values # {"target": "Sign up"}
r["button"].center # [912.0, 404.5] <- pixels of YOUR screenshot.png, ready to clickIMG=$(base64 -w0 screenshot.png)
curl https://api.temprl.org/v1/ask \
-H "Authorization: Bearer $SIMO_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{"model": "simo-1-pro",
"state": {"task": "Sign up for the newsletter", "screen": "<image:1>"},
"media": [{"type": "image", "data": "data:image/png;base64,$IMG"}],
"questions": {
"done": {"type": "noul", "instructions": "The sign-up is complete"},
"button": {"type": "extract", "kind": "coordinates", "instructions": "the Sign up button",
"image": 1, "scale": "rel1000", "max_tokens": 64}}}
EOFimport { readFile } from "node:fs/promises";
const png = (await readFile("screenshot.png")).toString("base64");
const res = await fetch("https://api.temprl.org/v1/ask", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.SIMO_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
model: "simo-1-pro",
state: { task: "Sign up for the newsletter", screen: "<image:1>" },
media: [{ type: "image", data: `data:image/png;base64,${png}` }],
questions: {
done: { type: "noul", instructions: "The sign-up is complete" },
button: { type: "extract", kind: "coordinates", instructions: "the Sign up button", image: 1, scale: "rel1000", max_tokens: 64 },
},
}),
});
const { answers } = await res.json();
console.log(answers.button.center); // [x, y] in the pixels of the image sentimage() accepts a file path, an http(s) URL (downloaded by the SDK), a data: URI, raw bytes or a PIL image:
Python
image("photo.jpg")
image("https://example.com/parcel.png")
image(open("scan.png", "rb").read())
image(pil_image)Several images
Python
r = c.ask(state="Before: <image:1>\nAfter: <image:2>",
media=[image("before.png"), image("after.png")],
questions={"changed": Noul("Something changed between the two pictures"),
"where": Locate("what changed", image=2)}) # locate in the second pictureGood to know
- Size. Send images at their natural size.
image()pads them on white to a shape the model reads without resampling, so small text stays legible. Locate answers are mapped back to your original pixels automatically. - Not found.
Locatereturnscoordinates=Noneandcenter=Nonewhen the thing is not visible;image_sizeis still set. Checkcenter is not Nonebefore clicking. - Placeholder order. The SDK warns when placeholders don't match
media(wrong order, missing or extra), and the API rejects such requests withInvalidRequest. - Limits. At most 16 pictures per request, video frames included, and 25 MB per request body. Images are sent as PNG, so a few large screenshots add up. The SDK checks the 25 MB limit before uploading. See Limits.
Video
Python
from simoai import video, video_file
# From a file: sampled at 1 frame per second, at most 32 frames (needs simoai[video])
clip = video_file("entrance.mp4", fps=1.0)
# Or from frames you already have, with the rate they were sampled at
clip = video([frame1, frame2, frame3], fps=2.0)
r = c.ask(state={"camera": "Warehouse door", "clip": "<video:1>"}, media=[clip],
questions={"entered": Noul("A person enters the restricted area"),
"count": Fill("how many people appear", kind="int")})The model sees the frames with their timestamps. The service keeps at most 16 frames per video, spread evenly. Ask "did it happen?", not "at which exact frame?".
Over HTTP, a video is {"type": "video", "frames": ["data:image/png;base64,...", ...], "fps": 1.0}.