feat(image-gen): add Atlas Cloud as a third image provider - #39
Open
binyangzhu000-sudo wants to merge 1 commit into
Open
binyangzhu000-sudo wants to merge 1 commit into
binyangzhu000-sudo wants to merge 1 commit into
Conversation
IMAGE_GEN_PROVIDER already switches between openrouter and google. This adds
`atlas`, which serves the same model families (nano-banana-pro, gpt-image-2,
seedream) through its own API.
It is a separate branch rather than an IMAGE_GEN_BASE_URL override on the
openrouter path for a verified reason: Atlas's image models are not reachable
from /v1/chat/completions — that returns 400, with or without
`modalities: ["image","text"]`. Images go through an async media API instead
(POST /generateImage, then poll /prediction/{id}), so _call_model_atlas()
implements submit → poll → download and returns the same (bytes, mime) tuple
as the other two branches. Retry count and backoff match the existing paths.
Custom styles keep working on this provider: the style-processing LLM call
still gets an OpenAI client, pointed at Atlas's OpenAI-compatible chat
endpoint, so `--style custom` is not silently degraded the way it is on the
google branch (where self.client is None).
Measured behaviour, documented in README and .env.example rather than left to
be rediscovered:
- Size controls differ per model family: nano-banana models ignore `size` and
honour `aspect_ratio` (IMAGE_GEN_ASPECT_RATIO, default 16:9 for slides),
while seedream models honour an explicit `size` (IMAGE_GEN_SIZE) and reject
anything under 921600 pixels. The payload sends whichever the configured
model actually reads.
- Reference figures travel in one newline-separated `images` field, and the
model id selects the task, so a run with references switches to the model's
/edit task automatically.
- The container is not fixed: the same model returned PNG on one call and JPEG
on the next, so the mime type comes from the response Content-Type with a
byte-signature fallback instead of being assumed.
- api.atlascloud.ai answers some clients' default User-Agent with 403 (error
code 1010), so requests send an explicit one.
Verified end to end through ImageGenerator: a text-only slide render returned a
1376x768 PNG, and the same call with a reference figure switched to
/edit and returned a 1376x768 JPEG.
Signed-off-by: binyangzhu000-sudo <224954946+binyangzhu000-sudo@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
IMAGE_GEN_PROVIDERalready switches betweenopenrouterandgoogle. This adds a third value,atlas, which serves the same model families (nano-banana-pro, gpt-image-2, seedream) throughAtlas Cloud.
Defaults are unchanged: without
IMAGE_GEN_PROVIDER=atlasnothing behaves differently.Why a separate branch instead of just an
IMAGE_GEN_BASE_URLoverrideI tried the cheap version first — point the existing
openrouterpath at Atlas and change the modelid. It does not work, and I verified that against the live service: Atlas's image models return
400from/v1/chat/completions, with and withoutextra_body={"modalities": ["image","text"]}.Images go through an async media API instead (
POST /generateImage, then poll/prediction/{id}), so_call_model_atlas()implements submit → poll → download and returns thesame
(bytes, mime_type)tuple as the other two branches. Retry count and backoff match theexisting paths.
Custom styles are not silently degraded
process_custom_style()needs a chat client. On thegooglebranchself.clientisNone, so--style customcannot work there. Foratlasthe client is still constructed, pointed at Atlas'sOpenAI-compatible chat endpoint (that one does work), so custom styles keep functioning on this
provider.
Measured behaviour, written down rather than left to be rediscovered
nano-bananamodels ignoresizeand honouraspect_ratio(IMAGE_GEN_ASPECT_RATIO, default16:9for slides);seedreammodels honour an explicitsize(IMAGE_GEN_SIZE)1024x576came back asimage size must be at least 921600 pixelsimagesfield; the model id selects the task, so a run with references switches to the model's/edittask automaticallyContent-Typewith a byte-signature fallback instead of being assumedapi.atlascloud.aianswers some clients' defaultUser-Agentwith403 error code 1010, so requests send an explicit oneThe payload sends whichever size control the configured model actually reads, so a caller does not
have to remember which family they picked.
Validation
Run end to end through
ImageGenerator(not by calling the API directly):/edit, returned 1376×768 JPEG, 554 KB.provider=atlas, default modelgoogle/nano-banana-pro/text-to-image,media base URL defaulted, chat client constructed.
.env.exampleand the README's "Image Generation Providers" section document the new provider andthe per-family size controls. Keys are placeholders throughout; no credentials in the diff.
🤝 Partnership & contact
This PR comes from the Atlas Cloud team. Beyond the integration above, we'd love to explore a closer collaboration with Paper2Slides — for example co-marketing or a featured integration.
If that sounds interesting, reach out anytime:
And of course, happy to revise this PR to match your project's conventions — just leave a comment. 🙌