image
Extract text from images using a vision LLM
Install
npx skills add https://github.com/axoviq-ai/synthadoc/tree/main/synthadoc/skills/image
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install axoviq-ai-synthadoc@llmmart
git clone https://github.com/axoviq-ai/synthadoc.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole axoviq-ai/synthadoc collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Image Skill
Base64-encodes the image and passes it to a vision-capable LLM that extracts
all text and key information. Returns the LLM's response as result.text.
Setup
No pip dependency — the skill uses only the Python standard library plus a
LLM provider you supply at construction time. The provider can be any object
that implements the complete() interface (see below).
Standalone usage
import asyncio
from synthadoc.skills.image.scripts.main import ImageSkill
# ImageSkill REQUIRES a vision-capable provider — calling extract() without
# one raises ValueError immediately.
skill = ImageSkill(provider=my_provider)
async def main():
result = await skill.extract("/path/to/screenshot.png")
print(result.text) # extracted text from the image
print(result.metadata) # {"tokens_input": N, "tokens_output": N}
asyncio.run(main())
Provider interface — any object with this async method:
async def complete(
messages: list, # list of Message objects from synthadoc.skills.base
system: str | None = None,
temperature: float = 0.0,
max_tokens: int = 4096,
) -> object # must have .text (str), .input_tokens (int), .output_tokens (int)
Build the provider with any vision-capable model. Message is importable
from synthadoc.skills.base — no dependency on synthadoc.providers:
from synthadoc.skills.base import Message
Supported image formats: .png, .jpg/.jpeg, .webp, .gif, .tiff
When this skill is used
- Source path ends with
.png,.jpg,.jpeg,.webp,.gif, or.tiff - User intent contains:
image,screenshot,diagram,photo
Files (synthadoc)
-
scripts
-
main.py 2.2 KB
# SPDX-License-Identifier: AGPL-3.0-or-later # Copyright (C) 2026 Paul Chen / axoviq.com import base64 from pathlib import Path from synthadoc.skills.base import BaseSkill, ExtractedContent, SkillMeta _VISION_PROMPT = ( "Extract all text and key information from this image. " "Return plain text only, preserving the structure and content faithfully." ) _MEDIA_MAP = { "jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "webp": "image/webp", "gif": "image/gif", "tiff": "image/tiff", } class ImageSkill(BaseSkill): meta = SkillMeta(name="image", description="Extract text from images using a vision LLM", extensions=[".png", ".jpg", ".jpeg", ".webp", ".gif", ".tiff"]) def __init__(self, provider=None) -> None: super().__init__() self._provider = provider async def extract(self, source: str) -> ExtractedContent: if self._provider is None: raise ValueError( "ImageSkill requires a vision-capable provider. " "Pass provider= when constructing ImageSkill." ) if not getattr(self._provider, "supports_vision", True): raise NotImplementedError( "Image extraction requires a vision-capable model. " "Switch to anthropic (claude-*) or openai (gpt-4o) for image sources." ) data = Path(source).read_bytes() suffix = Path(source).suffix.lower().lstrip(".") media_type = _MEDIA_MAP.get(suffix, "image/png") b64 = base64.b64encode(data).decode() from synthadoc.skills.base import Message resp = await self._provider.complete( messages=[Message(role="user", content=[ {"type": "image", "source": { "type": "base64", "media_type": media_type, "data": b64, }}, {"type": "text", "text": _VISION_PROMPT}, ])], temperature=0.0, ) return ExtractedContent( text=resp.text, source_path=source, metadata={ "tokens_input": resp.input_tokens, "tokens_output": resp.output_tokens, }, ) -
__init__.py 0 B
-
-
SKILL.md 2.1 KB
--- name: image version: "1.0" description: Extract text from images using a vision LLM entry: script: scripts/main.py class: ImageSkill triggers: extensions: - ".png" - ".jpg" - ".jpeg" - ".webp" - ".gif" - ".tiff" intents: - "image" - "screenshot" - "diagram" - "photo" requires: [] # no pip packages; a vision LLM provider must be passed at construction time author: axoviq.com license: AGPL-3.0-or-later --- # Image Skill Base64-encodes the image and passes it to a vision-capable LLM that extracts all text and key information. Returns the LLM's response as `result.text`. ## Setup No pip dependency — the skill uses only the Python standard library plus a LLM provider you supply at construction time. The provider can be any object that implements the `complete()` interface (see below). ## Standalone usage ```python import asyncio from synthadoc.skills.image.scripts.main import ImageSkill # ImageSkill REQUIRES a vision-capable provider — calling extract() without # one raises ValueError immediately. skill = ImageSkill(provider=my_provider) async def main(): result = await skill.extract("/path/to/screenshot.png") print(result.text) # extracted text from the image print(result.metadata) # {"tokens_input": N, "tokens_output": N} asyncio.run(main()) ``` **Provider interface** — any object with this async method: ```python async def complete( messages: list, # list of Message objects from synthadoc.skills.base system: str | None = None, temperature: float = 0.0, max_tokens: int = 4096, ) -> object # must have .text (str), .input_tokens (int), .output_tokens (int) ``` Build the provider with any vision-capable model. `Message` is importable from `synthadoc.skills.base` — no dependency on `synthadoc.providers`: ```python from synthadoc.skills.base import Message ``` **Supported image formats:** `.png`, `.jpg`/`.jpeg`, `.webp`, `.gif`, `.tiff` ## When this skill is used - Source path ends with `.png`, `.jpg`, `.jpeg`, `.webp`, `.gif`, or `.tiff` - User intent contains: `image`, `screenshot`, `diagram`, `photo`
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.