Skip to content

feat(image-gen): add Atlas Cloud as a third image provider - #39

Open
binyangzhu000-sudo wants to merge 1 commit into
HKUDS:mainfrom
binyangzhu000-sudo:feat/atlascloud-image-provider
Open

binyangzhu000-sudo wants to merge 1 commit into
HKUDS:mainfrom
binyangzhu000-sudo:feat/atlascloud-image-provider

Conversation

@binyangzhu000-sudo

Copy link
Copy Markdown

Summary

IMAGE_GEN_PROVIDER already switches between openrouter and google. This adds a third value,
atlas, which serves the same model families (nano-banana-pro, gpt-image-2, seedream) through
Atlas Cloud.
Defaults are unchanged: without IMAGE_GEN_PROVIDER=atlas nothing behaves differently.

Why a separate branch instead of just an IMAGE_GEN_BASE_URL override

I tried the cheap version first — point the existing openrouter path at Atlas and change the model
id. It does not work, and I verified that against the live service: Atlas's image models return
400 from /v1/chat/completions, with and without extra_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 the
same (bytes, mime_type) tuple as the other two branches. Retry count and backoff match the
existing paths.

Custom styles are not silently degraded

process_custom_style() needs a chat client. On the google branch self.client is None, so
--style custom cannot work there. For atlas the client is still constructed, pointed at Atlas's
OpenAI-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

Finding Detail
Size controls differ per model family nano-banana models ignore size and honour aspect_ratio (IMAGE_GEN_ASPECT_RATIO, default 16:9 for slides); seedream models honour an explicit size (IMAGE_GEN_SIZE)
seedream has a floor Anything under 921600 pixels is rejected — 1024x576 came back as image size must be at least 921600 pixels
Reference figures Travel in one newline-separated images field; the model id selects the task, so a run with references switches to the model's /edit task automatically
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
Edge rejects default agents api.atlascloud.ai answers some clients' default User-Agent with 403 error code 1010, so requests send an explicit one

The 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):

  • Text-only slide render → 1376×768 PNG, 661 KB.
  • Same call with a reference figure → switched to /edit, returned 1376×768 JPEG, 554 KB.
  • Provider wiring checked: provider=atlas, default model google/nano-banana-pro/text-to-image,
    media base URL defaulted, chat client constructed.

.env.example and the README's "Image Generation Providers" section document the new provider and
the 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. 🙌

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant