ArtCraft Desktop (fresh start)

This is a fresh start for the `artcraft` repo.

The old monorepo, which included our web API gateway, job services, SRE
tools, various frontends, and more has moved to `artcraft-services`

You can find the full git history here:

https://github.com/storytold/artcraft-services

This change was motivated by the fact that the entire git history was
hundreds of gigabytes in size, which is unwieldy for anyone not in the
core team that doesn't care about support services outside of the core
artcraft app.

We wanted to keep this repo in its well-known place since we already
have users and activity here.

Please update your remotes to either `artcraft-services` or make a fresh
clone of this repo.

History can be found at the artcraft-services repo.
This commit is contained in:
Brandon Thomas
2026-09-11 14:19:51 -04:00
commit 0004726a36
5677 changed files with 520050 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
# Rust Workspace
All Rust code lives under `crates/`. The workspace is defined in `Cargo.toml` at the repo root.
## Code Style
- Two spaces for indentation (not four)
- No minimum supported Rust version; use latest stable features freely
- Never use `println!` or `eprintln!` outside of tests; use `log` crate macros instead
- Use `anyhow::Result` / `AnyhowResult` for fallible functions in application code
- Fields that are optional use the `maybe_` prefix: `maybe_creator_user_token`
- When two crates export the same type name, alias with a suffix: `use foo::Bar as BarFoo;`
- Prefer `use` imports over inline fully-qualified paths; only qualify inline for true one-offs or std prelude collisions (`Result`, `Option`, `Error`)
## File Layout
Organize for top-to-bottom reading. Important things first, details later.
1. **Constants** at the top (after imports)
2. **Primary public type** (the main struct/enum the file defines)
3. **Supporting types** below the primary type
4. **API types** in order: Request, Response, Error
5. **`impl` blocks** after their type definitions
- Constructors first, then public methods, then private helpers
- Callers above callees — follow the call chain downward
## Test Layout
Within `#[cfg(test)] mod tests { ... }`:
1. **Imports**
2. **Constants** (test IDs, URLs, fixture data) — small context that tests reference
3. **Test functions or sub-modules** grouped by category
4. **Helper functions** (builders, pipeline runners, assertions)
Constants provide small context up front. Test cases come next so engineers see *what* is
tested before *how* the helpers work.
Group related tests into sub-modules (`mod pricing_tests { ... }`) when a category has 2+
tests. Don't wrap a single test in its own module. Keep nesting to two levels max. Shared
helpers go in the parent `mod tests` so sub-modules can `use super::*`.
## Building
- Most crates: `cargo check -p {crate_name}` or `cargo test -p {crate_name}`
- Crates using SQLx: `SQLX_OFFLINE=true cargo check -p {crate_name}`
- The desktop SQLite query cache and migrations must remain in `.sqlx/` and `_database/sql/artcraft_migrations/`
## Key Crates
- `artcraft` (desktop) — Tauri desktop app
- `artcraft_router` — provider routing for image/video generation (Artcraft, Fal, KinoviWeb, Grok, GMICloud, WorldLabs)
- `artcraft_api_defs` — shared HTTP API type definitions
- `kinovi_web_client` — HTTP client for the Kinovi/KinoviWeb video generation service
- `enums` — database-backed enums stored as VARCHAR fields
- `tokens` — primary key identifiers with Stripe-like prefixes (e.g. `user_`, `mf_`)
- `sqlite_tasks` — SQLite persistence for desktop generation tasks
The workspace contains only desktop dependencies and their shared test helpers.
There is no Hakari workspace helper; keep new dependencies local to their consumers.
+1
View File
@@ -0,0 +1 @@
AGENTS.md
@@ -0,0 +1,22 @@
# artcraft_api_defs
Shared HTTP API type definitions used by both the server (`storyteller_web`) and clients.
## Structure
Organized by feature: `users/`, `media_file/`, `jobs/`, `moderation/`, etc.
## Conventions
- Request types: `#[derive(Deserialize, ToSchema)]`
- Response types: `#[derive(Serialize, ToSchema)]`
- Path params: `#[derive(Deserialize, ToSchema)]` with `PathInfo` suffix
- Query params: `#[derive(Deserialize, IntoParams)]`
## Orphan Rule
Types that need `ResponseError` impl (actix-web) CANNOT live here because of Rust's orphan rule. Keep error response types in `storyteller_web` and only put data types here.
## Dependencies
Only `serde`, `serde_derive`, `utoipa`, `chrono`, `url`, and internal schema crates (`enums`, `tokens`). No actix-web dependency.
@@ -0,0 +1 @@
AGENTS.md
@@ -0,0 +1,33 @@
[package]
name = "artcraft_api_defs"
edition = "2024"
version = "0.0.1"
authors = [
"Brandon Thomas <bt@brand.io>",
"Brandon Thomas <echelon@gmail.com>",
]
publish = false
[lib]
name = "artcraft_api_defs"
path = "src/lib.rs"
[dependencies]
# Internal
enums.workspace = true
tokens.workspace = true
# External
chrono.workspace = true
url.workspace = true
# Serialization
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
utoipa.workspace = true
[dev-dependencies]
anyhow.workspace = true
@@ -0,0 +1,117 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::app_session::AppSessionToken;
use utoipa::ToSchema;
/// This is used in Artcraft versions 0.0.1 (several) through 0.3.0
/// Clients to this version do not send generation count data (even if the endpoint supports it).
pub const LOG_ACTIVE_USER_V1_PATH: &str = "/v1/analytics/active_user";
/// This is used in Artcraft versions 0.4.0 and later.
pub const LOG_ACTIVE_USER_V2_PATH: &str = "/v1/analytics/active_user_v2";
#[derive(Serialize, Deserialize, ToSchema, Debug, Default)]
pub struct LogAppActiveUserRequest {
/// Clientside-generated session token.
/// If present, it'll be validated against an expected format.
#[serde(skip_serializing_if = "Option::is_none")]
pub maybe_app_session_token: Option<AppSessionToken>,
/// An override for the application platform/OS (windows, mac, linux).
#[serde(skip_serializing_if = "Option::is_none")]
pub maybe_os_platform: Option<String>,
/// An override for the version of the OS (e.g. 10.15.7, 11, 22.04).
#[serde(skip_serializing_if = "Option::is_none")]
pub maybe_os_version: Option<String>,
/// An override for the application name.
/// If set together with `maybe_app_version`, the two will be
/// concatenated as `{maybe_app_name}/{maybe_app_version}`.
#[serde(skip_serializing_if = "Option::is_none")]
pub maybe_app_name: Option<String>,
/// An override for the application version.
/// If set together with `maybe_app_name`, the two will be
/// concatenated as `{maybe_app_name}/{maybe_app_version}`.
#[serde(skip_serializing_if = "Option::is_none")]
pub maybe_app_version: Option<String>,
/// How long the user has been active in the app, in seconds.
#[serde(skip_serializing_if = "Option::is_none")]
pub maybe_session_duration_seconds: Option<u64>,
// ========== GENERATION COUNTS ==========
/// Number of items generated across all types.
#[serde(skip_serializing_if = "Option::is_none")]
pub total_generation_count: Option<u16>,
/// Number of images generated.
#[serde(skip_serializing_if = "Option::is_none")]
pub image_generation_count: Option<u16>,
/// Number of videos generated.
#[serde(skip_serializing_if = "Option::is_none")]
pub video_generation_count: Option<u16>,
/// Number of objects generated (meshes, etc.).
#[serde(skip_serializing_if = "Option::is_none")]
pub object_generation_count: Option<u16>,
/// Number of images generated with text to image.
#[serde(skip_serializing_if = "Option::is_none")]
pub text_to_image_count: Option<u16>,
/// Number of images generated with image to image (image edits).
#[serde(skip_serializing_if = "Option::is_none")]
pub image_to_image_count: Option<u16>,
/// Number of videos generated with text to video.
#[serde(skip_serializing_if = "Option::is_none")]
pub text_to_video_count: Option<u16>,
/// Number of videos generated with image to video.
#[serde(skip_serializing_if = "Option::is_none")]
pub image_to_video_count: Option<u16>,
/// Number of objects generated with text to object.
#[serde(skip_serializing_if = "Option::is_none")]
pub text_to_object_count: Option<u16>,
/// Number of objects generated with image to object.
#[serde(skip_serializing_if = "Option::is_none")]
pub image_to_object_count: Option<u16>,
/// Number of prompts from the image page.
#[serde(skip_serializing_if = "Option::is_none")]
pub image_page_prompt_count: Option<u16>,
/// Number of prompts from the video page.
#[serde(skip_serializing_if = "Option::is_none")]
pub video_page_prompt_count: Option<u16>,
/// Number of prompts from the edit page.
#[serde(skip_serializing_if = "Option::is_none")]
pub edit_page_prompt_count: Option<u16>,
/// Number of prompts from the stage page.
#[serde(skip_serializing_if = "Option::is_none")]
pub stage_page_prompt_count: Option<u16>,
/// Number of prompts from the object page.
#[serde(skip_serializing_if = "Option::is_none")]
pub object_page_prompt_count: Option<u16>,
/// Number of prompts from other pages.
#[serde(skip_serializing_if = "Option::is_none")]
pub other_page_prompt_count: Option<u16>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct LogAppActiveUserResponse {
pub success: bool,
/// How long to wait until the next analytics event, in milliseconds.
/// The client should honor this and is free to add jitter.
pub wait_for_retry_millis: u64,
}
@@ -0,0 +1 @@
pub mod log_active_user;
@@ -0,0 +1,42 @@
use chrono::{DateTime, Utc};
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use tokens::tokens::api_keys::ApiKeyToken;
use tokens::tokens::users::UserToken;
/// Canonical wire shape for an API key, used by the list rows and the
/// single-key GET.
///
/// NB: the full secret `api_key` is NEVER included here — only
/// `truncated_api_key` (its first 20 characters), enough to disambiguate keys
/// in a UI. The full value is returned exactly once, at creation time.
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct ApiKeyInfo {
pub token: ApiKeyToken,
/// First 20 characters of the API key. The full secret is never returned
/// after creation.
pub truncated_api_key: String,
pub name: String,
pub maybe_description: Option<String>,
pub owner_user_token: UserToken,
pub ip_address_creation: String,
pub ip_address_update: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
/// Soft-delete timestamp. `None` for live keys.
pub maybe_deleted_at: Option<DateTime<Utc>>,
}
/// Path info for endpoints addressed by the API key's `token` (NOT the secret
/// `api_key` value): `GET` / `DELETE` / `PUT` `/v1/api_keys/{api_key_token}`.
#[derive(Deserialize, ToSchema)]
pub struct ApiKeyPathInfo {
pub api_key_token: ApiKeyToken,
}
@@ -0,0 +1,28 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use tokens::tokens::api_keys::ApiKeyToken;
// ── POST /v1/api_keys/create ──
#[derive(Deserialize, ToSchema)]
pub struct CreateApiKeyRequest {
/// Display name (title) for the key.
pub name: String,
/// Optional description.
pub maybe_description: Option<String>,
}
#[derive(Serialize, ToSchema)]
pub struct CreateApiKeySuccessResponse {
pub success: bool,
/// The key's `token` — used for all subsequent management
/// (get / update / delete). Safe to store and display.
pub api_key_token: ApiKeyToken,
/// The full secret API key value. This is the ONLY time it is ever
/// returned — the caller must store it now, as it cannot be retrieved again.
pub api_key: String,
}
@@ -0,0 +1,9 @@
use serde_derive::Serialize;
use utoipa::ToSchema;
// ── DELETE /v1/api_keys/{api_key_token} ──
#[derive(Serialize, ToSchema)]
pub struct DeleteApiKeySuccessResponse {
pub success: bool,
}
@@ -0,0 +1,12 @@
use serde_derive::Serialize;
use utoipa::ToSchema;
use crate::api_keys::common::ApiKeyInfo;
// ── GET /v1/api_keys/{api_key_token} ──
#[derive(Serialize, ToSchema)]
pub struct GetApiKeySuccessResponse {
pub success: bool,
pub api_key: ApiKeyInfo,
}
@@ -0,0 +1,24 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use crate::api_keys::common::ApiKeyInfo;
// ── GET /v1/api_keys/list ──
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListApiKeysQueryParams {
/// Page size. Defaults server-side if omitted.
pub limit: Option<u32>,
/// Number of rows to skip. Defaults to 0.
pub offset: Option<u32>,
}
#[derive(Serialize, ToSchema)]
pub struct ListApiKeysSuccessResponse {
pub success: bool,
/// The user's API keys (including soft-deleted ones), newest first. Each
/// entry's key value is truncated — the full secret is never listed.
pub api_keys: Vec<ApiKeyInfo>,
}
@@ -0,0 +1,6 @@
pub mod common;
pub mod create_api_key;
pub mod delete_api_key;
pub mod get_api_key;
pub mod list_api_keys;
pub mod update_api_key;
@@ -0,0 +1,15 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
// ── PUT /v1/api_keys/{api_key_token} ──
#[derive(Deserialize, ToSchema)]
pub struct UpdateApiKeyRequest {
/// New description for the key. `None` clears it.
pub maybe_description: Option<String>,
}
#[derive(Serialize, ToSchema)]
pub struct UpdateApiKeySuccessResponse {
pub success: bool,
}
@@ -0,0 +1,32 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use enums::common::generation::common_model_type::CommonModelType;
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
/// Request body for creating a character.
#[derive(Deserialize, ToSchema)]
pub struct CreateCharacterRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// The model to create the character for.
pub model: CommonModelType,
/// The reference image media file token.
pub image_media_token: MediaFileToken,
/// Name of the character.
pub character_name: String,
/// Description of the character.
pub character_description: Option<String>,
}
/// Response body for creating a character.
#[derive(Serialize, ToSchema)]
pub struct CreateCharacterResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,16 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use tokens::tokens::characters::CharacterToken;
/// Path parameters for deleting a character.
#[derive(Deserialize, ToSchema)]
pub struct DeleteCharacterPathInfo {
pub character_token: CharacterToken,
}
/// Response body for deleting a character.
#[derive(Serialize, ToSchema)]
pub struct DeleteCharacterResponse {
pub success: bool,
}
@@ -0,0 +1,23 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use tokens::tokens::characters::CharacterToken;
/// Request body for editing a character.
#[derive(Deserialize, ToSchema)]
pub struct EditCharacterRequest {
/// The character to edit.
pub token: CharacterToken,
/// Updated name (if changing).
pub updated_name: Option<String>,
/// Updated description (if changing).
pub updated_description: Option<String>,
}
/// Response body for editing a character.
#[derive(Serialize, ToSchema)]
pub struct EditCharacterResponse {
pub success: bool,
}
@@ -0,0 +1,36 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use crate::common::responses::media_links::MediaLinks;
use enums::common::generation::common_model_type::CommonModelType;
use tokens::tokens::characters::CharacterToken;
/// Path parameters for getting a character.
#[derive(Deserialize, ToSchema)]
pub struct GetCharacterPathInfo {
pub character_token: CharacterToken,
}
/// Response body for getting a character.
#[derive(Serialize, ToSchema)]
pub struct GetCharacterResponse {
pub success: bool,
pub character: GetCharacterDetails,
}
/// Full character details returned by the get endpoint.
#[derive(Serialize, ToSchema)]
pub struct GetCharacterDetails {
pub token: CharacterToken,
/// Which models this character can be used with.
pub models: Vec<CommonModelType>,
pub name: String,
pub maybe_description: Option<String>,
pub maybe_avatar: Option<MediaLinks>,
pub maybe_full_image: Option<MediaLinks>,
}
@@ -0,0 +1,38 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use crate::common::responses::media_links::MediaLinks;
use enums::common::generation::common_model_type::CommonModelType;
use tokens::tokens::characters::CharacterToken;
/// Query string parameters for listing characters.
#[derive(Deserialize, IntoParams)]
pub struct ListCharactersQuery {
/// Optional cursor for pagination.
pub cursor: Option<u64>,
}
/// Response body for listing characters in the current session.
#[derive(Serialize, ToSchema)]
pub struct ListCharactersResponse {
pub success: bool,
pub characters: Vec<ListCharactersEntry>,
pub next_cursor: Option<u64>,
}
/// A character entry in the list response.
#[derive(Serialize, ToSchema)]
pub struct ListCharactersEntry {
pub token: CharacterToken,
/// Which models this character can be used with.
pub models: Vec<CommonModelType>,
pub name: String,
pub maybe_description: Option<String>,
pub maybe_avatar: Option<MediaLinks>,
pub maybe_full_image: Option<MediaLinks>,
}
@@ -0,0 +1,5 @@
pub mod create_character;
pub mod delete_character;
pub mod edit_character;
pub mod get_character;
pub mod list_characters;
@@ -0,0 +1 @@
pub mod responses;
@@ -0,0 +1,19 @@
use serde_derive::{Deserialize, Serialize};
use url::Url;
use utoipa::ToSchema;
// TODO(bt,2025-08-20): Replace the storyteller-web version of this.
// All it needs is the impl ported into a builder.
/// Cover image links can only be jpg, png, etc. No videos.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct CoverImageLinks {
/// Primary link to the cover image via the CDN.
pub cdn_url: Url,
/// Template to construct thumbnail URLs.
/// Replace the string `{WIDTH}` with the desired width.
/// Only relevant for image media files. (Video media files instead have
/// video previews, which, in turn, have their own thumbnail templates.)
pub thumbnail_template: String,
}
@@ -0,0 +1,33 @@
use serde::Deserialize;
use serde::Serialize;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
/// Details about submitted live portrait jobs (request arguments only)
#[derive(Serialize, Deserialize, ToSchema)]
pub struct JobDetailsLivePortraitRequest {
/// Source media token
/// This can be an image or a video media file token
/// This is what constitutes the "portrait" or the overall final video.
/// This video or image must contain a face.
pub source_media_file_token: MediaFileToken,
/// Driving media token
/// This must be a video media file token.
/// This drives the animation of the face, but the actor will disappear
/// and their facial expressions will be transferred to the source.
/// This video must contain a face.
pub face_driver_media_file_token: MediaFileToken,
}
/// Details about submitted lipsync jobs (request arguments only)
#[derive(Serialize, Deserialize, ToSchema)]
pub struct JobDetailsLipsyncRequest {
/// Media file token for the source audio.
/// This is probably an audio file, but in the future we might pull audio from video.
pub audio_source_token: MediaFileToken,
/// Media file token for the source visuals.
/// This is either an image or video.
pub image_or_video_source_token: MediaFileToken,
}
@@ -0,0 +1,44 @@
use crate::common::responses::cover_image_links::CoverImageLinks;
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
// TODO(bt,2025-08-20): Replace the storyteller-web version of this.
// We can't drop the old version just yet due to the `impl` (easy)
// and a few differing fields.
/// Everything we need to create a cover image.
/// Cover images are small descriptive images that can be set for any media file.
/// If a cover image is set, this is the path to the asset.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct MediaFileCoverImageDetails {
// /// (DEPRECATED) URL path to the media file
// #[deprecated(note="This field doesn't point to the full URL. Use media_links instead to leverage the CDN.")]
// pub maybe_cover_image_public_bucket_path: Option<String>,
// /// (DEPRECATED) Full URL to the media file
// #[deprecated(note="This points to the bucket. Use media_links instead to leverage the CDN.")]
// pub maybe_cover_image_public_bucket_url: Option<Url>,
// NB(bt,2024-09-19): I accidentally rolled this field out to production.
// I don't think this field is in use, but maybe ...
// /// (DEPRECATED) Use maybe_links instead.
// #[deprecated(note="Use `maybe_links` instead.")]
// pub maybe_media_links: Option<MediaLinks>,
/// Links to the cover image (CDN direct link, thumbnail template)
/// If a cover image is set, this is the path to the asset.
/// If a cover image is not set, use the information in `default_cover` instead.
/// Rich CDN links to the media, including thumbnails, previews, and more.
pub maybe_links: Option<CoverImageLinks>,
/// For items without a cover image, we can use one of our own.
pub default_cover: MediaFileDefaultCover,
}
/// The default cover is composed of an image and color pair that are
/// predefined by the frontend.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct MediaFileDefaultCover {
pub image_index: u8,
pub color_index: u8,
}
@@ -0,0 +1,39 @@
use serde::Deserialize;
use serde::Serialize;
use url::Url;
use utoipa::ToSchema;
/// Links to media file locations (bucket, CDN, etc.)
#[derive(Serialize, Deserialize, ToSchema, Debug, Clone, Eq, PartialEq)]
pub struct MediaLinks {
/// Primary link to the asset via the CDN.
pub cdn_url: Url,
/// Template to construct thumbnail URLs.
/// Replace the string `{WIDTH}` with the desired width.
/// Only relevant for image media files. (Video media files instead have
/// video previews, which, in turn, have their own thumbnail templates.)
pub maybe_thumbnail_template: Option<String>,
/// Video preview images (still and animated gif) for mp4 video files.
/// These are only set for video media files.
/// These are not set for "cover images" that are gif or webms, but rather video files.
pub maybe_video_previews: Option<VideoPreviews>,
}
#[derive(Serialize, Deserialize, ToSchema, Debug, Clone, Eq, PartialEq)]
pub struct VideoPreviews {
/// A static single frame preview image of the video.
pub still: Url,
/// An animated gif preview of the video.
pub animated: Url,
/// A template used to construct the still thumbnail URL.
/// Replace the string `{WIDTH}` with the desired width.
pub still_thumbnail_template: String,
/// A template used to construct the animated thumbnail URL.
/// Replace the string `{WIDTH}` with the desired width.
pub animated_thumbnail_template: String,
}
@@ -0,0 +1,8 @@
pub mod cover_image_links;
pub mod job_details;
pub mod media_file_cover_image_details;
pub mod media_links;
pub mod pagination_cursors;
pub mod simple_entity_stats;
pub mod simple_generic_json_success;
pub mod user_details_light;
@@ -0,0 +1,22 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
// TODO(bt,2026-07-09): Replace the storyteller-web version of this.
/// Pagination by cursors
/// These types of pagination are for "infinite scrolling", which do not reveal a number of pages.
/// This is good so that investors and competitors cannot reveal how many database records we have.
/// This is typically used for "discovery" type pages, not user profiles.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct PaginationCursors {
/// The "next" cursor.
/// This is an opaque (typically even encrypted) handle.
pub maybe_next: Option<String>,
/// The "previous" cursor.
/// This is an opaque (typically even encrypted) handle.
pub maybe_previous: Option<String>,
/// Details whether we're walking forward or backward.
pub cursor_is_reversed: bool,
}
@@ -0,0 +1,12 @@
use serde_derive::{Deserialize, Serialize};
// TODO(bt,2025-08-20): Replace the storyteller-web version of this.
/// Simple stats that can be attached to any entity
#[derive(Serialize, Deserialize, Debug)]
pub struct SimpleEntityStats {
/// Number of positive ratings (or "likes") for this item
pub positive_rating_count: u32,
/// Number of bookmarks for this item
pub bookmark_count: u32,
}
@@ -0,0 +1,7 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
#[derive(Serialize, Deserialize, ToSchema)]
pub struct SimpleGenericJsonSuccess {
pub success: bool,
}
@@ -0,0 +1,34 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::users::UserToken;
use utoipa::ToSchema;
/// Everything we need to refer to a user on the public web interface.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct UserDetailsLight {
/// The token for the user
pub user_token: UserToken,
/// The unique username someone logs in with
/// As of 2023-08-23, this is always lowercase
pub username: String,
/// As of 2023-08-23, this is the username with capitalization
/// (In the future, a display name can be customized by the user.)
pub display_name: String,
/// Email hash for Gravatar
/// Always set for now since login is email/username+password.
/// In the future this will need to become an optional *OR* be filled with a bogus hash.
pub gravatar_hash: String,
/// For users without a gravatar, we show one of our own avatars.
pub default_avatar: UserDefaultAvatarInfo,
// In the future, we'll also support user-uploaded avatars that we store on our servers.
}
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct UserDefaultAvatarInfo {
pub image_index: u8,
pub color_index: u8,
}
@@ -0,0 +1,20 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GetSessionCreditsResponse {
pub success: bool,
/// Any free credits the user might have
/// We might support daily free credits.
pub free_credits: u64,
/// Any monthly refilling credits the user might have
pub monthly_credits: u64,
/// Any banked credits the user might have.
pub banked_credits: u64,
/// All the credit amounts added together.
pub sum_total_credits: u64,
}
@@ -0,0 +1 @@
pub mod get_session_credits;
@@ -0,0 +1,94 @@
use chrono::{DateTime, Utc};
use serde_derive::{Deserialize, Serialize};
use url::Url;
use utoipa::ToSchema;
use enums::by_table::media_files::media_file_class::MediaFileClass;
use enums::by_table::media_files::media_file_type::MediaFileType;
use tokens::tokens::folders::FolderToken;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::users::UserToken;
// NB: The "folder media file" list-item shape lives in storyteller_web
// (see `endpoints/folders/media_files/list_folder_media_files_handler.rs`)
// because it embeds `MediaFileCoverImageDetails` and other domain types
// that depend on the request's `MediaDomain` + `ServerEnvironment`.
/// Canonical wire shape for a folder. Used by single-folder GETs, create
/// responses, list rows, and subfolder list rows.
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct FolderInfo {
pub token: FolderToken,
pub name: String,
pub owner_user_token: UserToken,
pub maybe_parent_folder_token: Option<FolderToken>,
/// The four most-recent media files added to the folder, in slot order
/// (the schema stores them as `maybe_last_media_file_token_1..4`).
/// Slots whose media file has been deleted are skipped, so the vec
/// may contain 0-4 entries.
pub last_media_thumbnails: Vec<FolderThumbnail>,
/// User-chosen cover image. When present, the frontend should use this
/// as the folder's primary thumbnail instead of the
/// `last_media_thumbnails` grid.
pub maybe_custom_cover_thumbnail: Option<FolderThumbnail>,
pub maybe_color_code: Option<String>,
pub has_star: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
/// True when `maybe_parent_folder_token` is set but the referenced
/// parent row is missing or soft-deleted.
pub is_orphaned: bool,
}
/// A compact thumbnail descriptor for a media file referenced by a
/// folder (either one of the `last_media_*` slots or the custom cover).
///
/// Intentionally narrower than `MediaLinks` / `CoverImageLinks` — folders
/// only need the bare minimum to render a thumbnail card. The CDN URL is
/// the direct asset link; `maybe_thumbnail_template` carries the resizing
/// template URL (with `{{width}}` / `{{height}}` placeholders) when the
/// media class supports it.
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct FolderThumbnail {
pub token: MediaFileToken,
pub media_class: MediaFileClass,
pub media_type: MediaFileType,
/// Direct CDN URL to the underlying media asset.
pub cdn_url: Url,
/// Resizing template URL (with `{{width}}` / `{{height}}` placeholders)
/// when the media class supports it. `None` for media classes without
/// a thumbnail variant. (Video media files instead have video previews,
/// which, in turn, have their own thumbnail templates.)
pub maybe_thumbnail_template: Option<String>,
/// Video preview images (still and animated gif) for mp4 video files.
/// These are only set for video media files.
pub maybe_video_previews: Option<FolderThumbnailVideoPreviews>,
}
/// Video preview images for a video media file referenced by a folder.
/// Mirrors the shape of `MediaLinks`' video previews, but is its own type
/// so the folder wire shape can evolve independently.
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct FolderThumbnailVideoPreviews {
/// A static single frame preview image of the video.
pub still: Url,
/// An animated gif preview of the video.
pub animated: Url,
/// A template used to construct the still thumbnail URL.
/// Replace the string `{WIDTH}` with the desired width.
pub still_thumbnail_template: String,
/// A template used to construct the animated thumbnail URL.
/// Replace the string `{WIDTH}` with the desired width.
pub animated_thumbnail_template: String,
}
@@ -0,0 +1,116 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use tokens::tokens::folders::FolderToken;
use tokens::tokens::media_files::MediaFileToken;
use crate::folders::common::FolderInfo;
// ── POST /v1/folders/create ──
#[derive(Deserialize, ToSchema)]
pub struct CreateFolderRequest {
pub name: String,
pub maybe_parent_folder_token: Option<FolderToken>,
pub maybe_color_code: Option<String>,
}
#[derive(Serialize, ToSchema)]
pub struct CreateFolderSuccessResponse {
pub success: bool,
pub folder: FolderInfo,
}
// ── GET /v1/folders/list_all ──
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListFoldersQueryParams {
pub cursor: Option<String>,
pub limit: Option<u32>,
}
#[derive(Serialize, ToSchema)]
pub struct ListFoldersSuccessResponse {
pub success: bool,
pub folders: Vec<FolderInfo>,
pub maybe_cursor: Option<String>,
}
// ── GET /v1/folders/folder/{folder_token} ──
#[derive(Deserialize, ToSchema)]
pub struct FolderPathInfo {
pub folder_token: FolderToken,
}
#[derive(Serialize, ToSchema)]
pub struct GetFolderSuccessResponse {
pub success: bool,
pub folder: FolderInfo,
}
// ── PUT /v1/folders/folder/{folder_token}/rename ──
#[derive(Deserialize, ToSchema)]
pub struct RenameFolderRequest {
pub new_name: String,
}
#[derive(Serialize, ToSchema)]
pub struct RenameFolderSuccessResponse {
pub success: bool,
}
// ── PUT /v1/folders/folder/{folder_token}/star ──
#[derive(Deserialize, ToSchema)]
pub struct SetFolderStarRequest {
pub has_star: bool,
}
#[derive(Serialize, ToSchema)]
pub struct SetFolderStarSuccessResponse {
pub success: bool,
}
// ── PUT /v1/folders/folder/{folder_token}/color_code ──
#[derive(Deserialize, ToSchema)]
pub struct SetFolderColorCodeRequest {
/// `None` clears the color tag.
pub maybe_color_code: Option<String>,
}
#[derive(Serialize, ToSchema)]
pub struct SetFolderColorCodeSuccessResponse {
pub success: bool,
}
// ── PUT /v1/folders/folder/{folder_token}/cover_image ──
#[derive(Deserialize, ToSchema)]
pub struct SetFolderCoverImageRequest {
/// `None` clears the cover image. If set, the server resolves it to a
/// usable cover-image media file token: image/video media files are
/// used directly; other types fall back to the file's own
/// `maybe_cover_image_media_file_token` (and fail if neither path
/// applies).
pub maybe_media_file_token: Option<MediaFileToken>,
}
#[derive(Serialize, ToSchema)]
pub struct SetFolderCoverImageSuccessResponse {
pub success: bool,
/// The media file token that ended up being stored as the cover image
/// (may differ from the requested token if the server resolved through
/// the file's own cover image). `None` when the cover was cleared.
pub maybe_resolved_cover_media_file_token: Option<MediaFileToken>,
}
// ── DELETE /v1/folders/folder/{folder_token} ──
#[derive(Serialize, ToSchema)]
pub struct DeleteFolderSuccessResponse {
pub success: bool,
}
@@ -0,0 +1,111 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use enums::by_table::media_files::media_file_class::MediaFileClass;
use tokens::tokens::folders::FolderToken;
use tokens::tokens::media_files::MediaFileToken;
// ── GET /v1/folders/media_files/{folder_token} ──
//
// NB: `ListFolderMediaFilesSuccessResponse` and `FolderMediaFileListItem`
// live in `storyteller_web`'s handler because the wire shape embeds
// `MediaFileCoverImageDetails` and `MediaLinks` constructors that depend
// on the request's `MediaDomain` + `ServerEnvironment`.
#[derive(Deserialize, ToSchema)]
pub struct FolderMediaFilesPathInfo {
pub folder_token: FolderToken,
}
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListFolderMediaFilesQueryParams {
pub cursor: Option<String>,
pub limit: Option<u32>,
}
// ── GET /v1/folders/media_files_without_folder ──
//
// NB: `ListMediaFilesWithoutFolderSuccessResponse` and its list item live in
// `storyteller_web`'s handler because the wire shape embeds
// `MediaFileCoverImageDetails` and `MediaLinks` constructors that depend
// on the request's `MediaDomain` + `ServerEnvironment`.
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListMediaFilesWithoutFolderQueryParams {
pub cursor: Option<String>,
pub limit: Option<u32>,
/// Optional filter on the coarse media class.
///
/// Usage:
/// - `?filter_media_class=image`
/// - `?filter_media_class=video`
/// - `?filter_media_class=mesh`
/// - `?filter_media_class=splat`
pub filter_media_class: Option<MediaFileClass>,
}
// ── PUT /v1/folders/media_files/{folder_token}/bulk_add ──
#[derive(Deserialize, ToSchema)]
pub struct BulkAddFolderMediaFilesRequest {
/// Media files to add to the folder. Tokens that don't exist or are
/// soft-deleted are silently skipped. Already-added rows are no-ops
/// (idempotent via INSERT IGNORE on the composite primary key).
pub media_file_tokens: Vec<MediaFileToken>,
}
#[derive(Serialize, ToSchema)]
pub struct BulkAddFolderMediaFilesSuccessResponse {
pub success: bool,
/// Tokens that pre-existed (existed + not deleted). Already-added rows
/// are included since the operation is idempotent.
pub accepted_media_file_tokens: Vec<MediaFileToken>,
}
// ── PUT /v1/folders/media_files/{folder_token}/bulk_remove ──
#[derive(Deserialize, ToSchema)]
pub struct BulkRemoveFolderMediaFilesRequest {
pub media_file_tokens: Vec<MediaFileToken>,
}
#[derive(Serialize, ToSchema)]
pub struct BulkRemoveFolderMediaFilesSuccessResponse {
pub success: bool,
/// How many membership rows were actually hard-deleted.
pub removed_count: u64,
}
// ── POST /v1/folders/media_files/{folder_token}/bulk_move ──
/// Atomically move the listed media files from `source_folder` to the
/// URL `folder_token` (destination). Idempotent on both sides: tokens
/// that aren't currently in the source are silently skipped, and tokens
/// that are already in the destination stay there.
#[derive(Deserialize, ToSchema)]
pub struct BulkMoveFolderMediaFilesRequest {
pub source_folder: FolderToken,
pub media_file_tokens: Vec<MediaFileToken>,
}
#[derive(Serialize, ToSchema)]
pub struct BulkMoveFolderMediaFilesSuccessResponse {
pub success: bool,
/// Number of membership rows actually deleted from the source folder.
pub removed_from_source_count: u64,
/// Number of membership rows actually inserted into the destination
/// folder. May be lower than the input length because (a) tokens that
/// were already present in the destination don't insert, and (b)
/// tokens whose media file doesn't exist / is soft-deleted are filtered
/// out before the insert.
pub added_to_destination_count: u64,
/// The media file tokens that ended up resident in the destination
/// folder after the move — i.e. the subset of the input that actually
/// referred to live media files. Includes both newly-inserted rows and
/// rows that were already there.
pub accepted_media_file_tokens: Vec<MediaFileToken>,
}
@@ -0,0 +1,4 @@
pub mod common;
pub mod folder;
pub mod media_files;
pub mod subfolder;
@@ -0,0 +1,61 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use tokens::tokens::folders::FolderToken;
use crate::folders::common::FolderInfo;
// ── GET /v1/folders/subfolders/{folder_token} ──
#[derive(Deserialize, ToSchema)]
pub struct SubfolderPathInfo {
pub folder_token: FolderToken,
}
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListSubfoldersQueryParams {
pub cursor: Option<String>,
pub limit: Option<u32>,
}
#[derive(Serialize, ToSchema)]
pub struct ListSubfoldersSuccessResponse {
pub success: bool,
pub subfolders: Vec<FolderInfo>,
pub maybe_cursor: Option<String>,
}
// ── PUT /v1/folders/subfolders/{folder_token}/bulk_add ──
#[derive(Deserialize, ToSchema)]
pub struct BulkAddSubfoldersRequest {
/// The folders to reparent under the URL `folder_token`. Tokens that
/// don't exist, aren't owned by the caller, are soft-deleted, or are
/// the parent itself are silently skipped (idempotent).
pub subfolder_tokens: Vec<FolderToken>,
}
#[derive(Serialize, ToSchema)]
pub struct BulkAddSubfoldersSuccessResponse {
pub success: bool,
/// Tokens that were actually accepted (existed + owned + not deleted +
/// not the parent itself). Already-parented tokens are included here
/// since the operation is idempotent.
pub accepted_subfolder_tokens: Vec<FolderToken>,
}
// ── PUT /v1/folders/subfolders/{folder_token}/bulk_remove ──
#[derive(Deserialize, ToSchema)]
pub struct BulkRemoveSubfoldersRequest {
/// Folders to unparent. Only rows currently parented to the URL
/// `folder_token` are affected; others are silently skipped.
pub subfolder_tokens: Vec<FolderToken>,
}
#[derive(Serialize, ToSchema)]
pub struct BulkRemoveSubfoldersSuccessResponse {
pub success: bool,
/// How many rows were actually unparented.
pub removed_count: u64,
}
@@ -0,0 +1,122 @@
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
use enums::common::generation::common_image_model::CommonImageModel;
use enums::common::generation::common_quality::CommonQuality;
use enums::common::generation::common_resolution::CommonResolution;
use enums::common::generation_provider::GenerationProvider;
pub const ESTIMATE_IMAGE_COST_PATH: &str = "/v1/generate/cost_estimate/image";
/// Request body for the image cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct EstimateImageCostRequest {
/// The image model to estimate costs for.
pub model: CommonImageModel,
/// The provider to route the generation through.
pub provider: GenerationProvider,
/// The type of generation (determines whether input images are involved).
/// This is a tagged enum, so it looks like:
/// "generation_mode": {"type": "text_to_image"}
/// "generation_mode": {"type": "image_edit", "count": 2}
pub generation_mode: GenerationMode,
/// Optional aspect ratio.
pub aspect_ratio: Option<CommonAspectRatio>,
/// Optional resolution.
pub resolution: Option<CommonResolution>,
// Optional quality.
pub quality: Option<CommonQuality>,
/// Number of images to generate in parallel.
pub image_batch_count: Option<u16>,
}
/// Describes the type of image generation being requested.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum GenerationMode {
/// No input images — generate from prompt only.
TextToImage,
/// One or more input images are provided for editing/compositing.
ImageEdit { count: u32 },
}
/// Response body for the image cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct EstimateImageCostResponse {
pub success: bool,
/// Estimated cost in credits.
pub cost_in_credits: Option<u64>,
/// Estimated cost in USD cents.
pub cost_in_usd_cents: Option<u64>,
/// Whether the generation is free for this user/plan.
pub is_free: bool,
/// Whether the user has unlimited generations.
pub is_unlimited: bool,
/// Whether the user is rate limited.
pub is_rate_limited: bool,
/// Whether the output will have a watermark.
pub has_watermark: bool,
}
/// Error response for the image cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct EstimateImageCostError {
pub success: bool,
pub error_type: EstimateImageCostErrorType,
pub error_message: String,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum EstimateImageCostErrorType {
InvalidProviderForModel,
InvalidInput,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serialization_text_to_image() {
let request = EstimateImageCostRequest {
model: CommonImageModel::NanoBananaPro,
provider: GenerationProvider::Artcraft,
generation_mode: GenerationMode::TextToImage,
aspect_ratio: None,
resolution: None,
quality: None,
image_batch_count: None,
};
let serialized = serde_json::to_string(&request).unwrap();
assert!(serialized.contains("\"generation_mode\":{\"type\":\"text_to_image\"}"));
}
#[test]
fn test_serialization_image_edit() {
let request = EstimateImageCostRequest {
model: CommonImageModel::NanoBananaPro,
provider: GenerationProvider::Artcraft,
generation_mode: GenerationMode::ImageEdit { count: 2 },
aspect_ratio: None,
resolution: None,
quality: None,
image_batch_count: None,
};
let serialized = serde_json::to_string(&request).unwrap();
assert!(serialized.contains("\"generation_mode\":{\"type\":\"image_edit\",\"count\":2}"));
}
}
@@ -0,0 +1,59 @@
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use enums::common::generation::common_splat_model::CommonSplatModel;
use enums::common::generation_provider::GenerationProvider;
pub const ESTIMATE_SPLAT_COST_PATH: &str = "/v1/generate/cost_estimate/splat";
/// Request body for the splat cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct EstimateSplatCostRequest {
/// The splat model to estimate costs for.
pub model: CommonSplatModel,
/// The provider to route the generation through.
pub provider: GenerationProvider,
/// Whether the request includes a reference image.
pub has_reference_image: Option<bool>,
}
/// Response body for the splat cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct EstimateSplatCostResponse {
pub success: bool,
/// Estimated cost in credits.
pub cost_in_credits: Option<u64>,
/// Estimated cost in USD cents.
pub cost_in_usd_cents: Option<u64>,
/// Whether the generation is free for this user/plan.
pub is_free: bool,
/// Whether the user has unlimited generations.
pub is_unlimited: bool,
/// Whether the user is rate limited.
pub is_rate_limited: bool,
/// Whether the output will have a watermark.
pub has_watermark: bool,
}
/// Error response for the splat cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct EstimateSplatCostError {
pub success: bool,
pub error_type: EstimateSplatCostErrorType,
pub error_message: String,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum EstimateSplatCostErrorType {
InvalidProviderForModel,
InvalidInput,
}
@@ -0,0 +1,130 @@
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
use enums::common::generation::common_video_model::CommonVideoModel;
use enums::common::generation::common_resolution::CommonResolution;
use enums::common::generation_provider::GenerationProvider;
pub const ESTIMATE_VIDEO_COST_PATH: &str = "/v1/generate/cost_estimate/video";
/// Request body for the video cost estimate endpoint.
///
/// Every model cares about its own set of parameters and not all
/// parameters may be relevant for every model.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct EstimateVideoCostRequest {
/// The video model to estimate costs for.
pub model: CommonVideoModel,
/// The provider to route the generation through.
pub provider: GenerationProvider,
/// The type of generation (determines how many input images are involved).
/// This is a tagged enum, so it looks like:
/// "generation_mode": {"type": "text_to_video"}
/// "generation_mode": {"type": "reference_image_to_video", "count": 1}
pub generation_mode: GenerationMode,
/// Optional aspect ratio.
pub aspect_ratio: Option<CommonAspectRatio>,
/// Optional resolution.
pub resolution: Option<CommonResolution>,
/// Duration in seconds.
pub duration_seconds: Option<u16>,
/// Number of videos to generate in parallel.
pub video_batch_count: Option<u16>,
/// Whether to generate audio for the video.
pub generate_audio: Option<bool>,
}
/// Describes the type of video generation being requested.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum GenerationMode {
TextToVideo,
StartFrameToVideo,
StartAndEndFrameToVideo,
ReferenceImageToVideo { count: u32 },
}
/// Response body for the video cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct EstimateVideoCostResponse {
pub success: bool,
/// Estimated cost in credits.
pub cost_in_credits: Option<u64>,
/// Estimated cost in USD cents.
pub cost_in_usd_cents: Option<u64>,
/// Whether the generation is free for this user/plan.
pub is_free: bool,
/// Whether the user has unlimited generations.
pub is_unlimited: bool,
/// Whether the user is rate limited.
pub is_rate_limited: bool,
/// Whether the output will have a watermark.
pub has_watermark: bool,
}
/// Error response for the video cost estimate endpoint.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct EstimateVideoCostError {
pub success: bool,
pub error_type: EstimateVideoCostErrorType,
pub error_message: String,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum EstimateVideoCostErrorType {
InvalidProviderForModel,
InvalidInput,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serialization_tagging1() {
let request = EstimateVideoCostRequest {
model: CommonVideoModel::GrokVideo,
provider: GenerationProvider::Artcraft,
generation_mode: GenerationMode::TextToVideo,
aspect_ratio: None,
resolution: None,
duration_seconds: None,
video_batch_count: None,
generate_audio: None,
};
let serialized = serde_json::to_string(&request).unwrap();
assert!(serialized.contains("\"generation_mode\":{\"type\":\"text_to_video\"}"));
//assert_eq!(serialized, "{}");
}
#[test]
fn test_serialization_tagging2() {
let request = EstimateVideoCostRequest {
model: CommonVideoModel::GrokVideo,
provider: GenerationProvider::Artcraft,
generation_mode: GenerationMode::ReferenceImageToVideo { count: 1 },
aspect_ratio: None,
resolution: None,
duration_seconds: None,
video_batch_count: None,
generate_audio: None,
};
let serialized = serde_json::to_string(&request).unwrap();
assert!(serialized.contains("\"generation_mode\":{\"type\":\"reference_image_to_video\",\"count\":1}"));
}
}
@@ -0,0 +1,3 @@
pub mod estimate_image_cost;
pub mod estimate_splat_cost;
pub mod estimate_video_cost;
@@ -0,0 +1,56 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const FLUX_2_LORA_EDIT_IMAGE_ANGLE_PATH: &str = "/v1/generate/image/angle/flux_2_lora";
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct Flux2LoraEditImageAngleRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// The image to edit with angle adjustment.
pub image_media_token: MediaFileToken,
/// Horizontal rotation angle in degrees.
pub horizontal_angle: Option<f64>,
/// Vertical rotation angle in degrees.
pub vertical_angle: Option<f64>,
/// Zoom level.
pub zoom: Option<f64>,
/// Number of images to generate. Default is one.
pub num_images: Option<Flux2LoraEditImageAngleNumImages>,
/// Output image size. Default is square_hd.
pub image_size: Option<Flux2LoraEditImageAngleImageSize>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Flux2LoraEditImageAngleNumImages {
One,
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Flux2LoraEditImageAngleImageSize {
Square,
SquareHd,
PortraitFourThree,
PortraitSixteenNine,
LandscapeFourThree,
LandscapeSixteenNine,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Flux2LoraEditImageAngleResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,2 @@
pub mod flux_2_lora_edit_image_angle;
pub mod qwen_edit_2511_edit_image_angle;
@@ -0,0 +1,59 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const QWEN_EDIT_2511_EDIT_IMAGE_ANGLE_PATH: &str = "/v1/generate/image/angle/qwen_edit_2511";
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct QwenEdit2511EditImageAngleRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// The image to edit with angle adjustment.
pub image_media_token: MediaFileToken,
/// Horizontal rotation angle in degrees.
pub horizontal_angle: Option<f64>,
/// Vertical rotation angle in degrees.
pub vertical_angle: Option<f64>,
/// Zoom level.
pub zoom: Option<f64>,
/// Additional text prompt to guide the generation.
pub additional_prompt: Option<String>,
/// Number of images to generate. Default is one.
pub num_images: Option<QwenEdit2511EditImageAngleNumImages>,
/// Output image size. Default is square_hd.
pub image_size: Option<QwenEdit2511EditImageAngleImageSize>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum QwenEdit2511EditImageAngleNumImages {
One,
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum QwenEdit2511EditImageAngleImageSize {
Square,
SquareHd,
PortraitFourThree,
PortraitSixteenNine,
LandscapeFourThree,
LandscapeSixteenNine,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct QwenEdit2511EditImageAngleResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1 @@
pub mod remove_image_background;
@@ -0,0 +1,22 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const REMOVE_IMAGE_BACKGROUND_PATH: &str = "/v1/generate/image/remove_background";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct RemoveImageBackgroundRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the file to remove the background from.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct RemoveImageBackgroundResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,36 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const FLUX_PRO_KONTEXT_MAX_EDIT_IMAGE_PATH: &str = "/v1/generate/image/edit/flux_pro_kontext_max";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct FluxProKontextMaxEditImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// The image we're editing.
pub image_media_token: MediaFileToken,
/// Number of images to generate. Default is one.
pub num_images: Option<FluxProKontextMaxEditImageNumImages>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum FluxProKontextMaxEditImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct FluxProKontextMaxEditImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,50 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GEMINI_25_FLASH_EDIT_IMAGE_PATH: &str = "/v1/generate/image/edit/gemini_25_flash";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Gemini25FlashEditImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
// TODO: OneOf for image_urls or image_media_tokens
/// Image media tokens to include in the editing context.
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<Gemini25FlashEditImageNumImages>,
/// Quality of the image to generate. Default is High.
pub image_quality: Option<Gemini25FlashEditImageImageQuality>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Gemini25FlashEditImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Gemini25FlashEditImageImageQuality {
Auto,
Low,
Medium,
High, // Default
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Gemini25FlashEditImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,62 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GPT_IMAGE_1_EDIT_IMAGE_PATH: &str = "/v1/generate/image/edit/gpt_image_1";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GptImage1EditImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
// TODO: OneOf for image_urls or image_media_tokens
/// Image media tokens to include in the editing context.
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Size of the image to generate. Default is Square.
pub image_size: Option<GptImage1EditImageImageSize>,
/// Number of images to generate. Default is one.
pub num_images: Option<GptImage1EditImageNumImages>,
/// Quality of the image to generate. Default is High.
pub image_quality: Option<GptImage1EditImageImageQuality>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1EditImageImageSize {
Square, // 1:1, Default
Horizontal,
Vertical,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1EditImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1EditImageImageQuality {
Auto,
Low,
Medium,
High, // Default
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GptImage1EditImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,6 @@
pub mod flux_pro_kontext_max_edit_image;
pub mod gemini_25_flash_edit_image;
pub mod gpt_image_1_edit_image;
pub mod qwen_edit_image;
pub mod seededit_3_edit_image;
@@ -0,0 +1,51 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const QWEN_EDIT_IMAGE_PATH: &str = "/v1/generate/image/edit/qwen";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct QwenEditImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// The image we're editing.
pub image_media_token: MediaFileToken,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Text prompt to generate the image from.
pub negative_prompt: Option<String>,
/// Acceleration level for image generation.
/// Options: 'none', 'regular'. Higher acceleration increases speed.
/// 'regular' balances speed and quality. Default value: "none"
pub acceleration: Option<QwenEditImageAcceleration>,
/// Number of images to generate. Default is one.
pub num_images: Option<QwenEditImageNumImages>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub enum QwenEditImageAcceleration {
None,
Regular,
High,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum QwenEditImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct QwenEditImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,24 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const SEEDEDIT_3_EDIT_IMAGE_PATH: &str = "/v1/generate/image/edit/seededit_3";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct SeedEdit3EditImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// The image we're editing.
pub image_media_token: MediaFileToken,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct SeedEdit3EditImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,39 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const FLUX_DEV_JUGGERNAUT_INPAINT_PATH: &str = "/v1/generate/image/inpaint/flux_dev_juggernaut";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct FluxDevJuggernautInpaintImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// The image we're editing.
pub image_media_token: MediaFileToken,
/// The mask to use against the image.
pub mask_media_token: MediaFileToken,
/// Number of images to generate. Default is one.
pub num_images: Option<FluxDevJuggernautInpaintImageNumImages>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum FluxDevJuggernautInpaintImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct FluxDevJuggernautInpaintImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,39 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const FLUX_PRO_1_INPAINT_PATH: &str = "/v1/generate/image/inpaint/flux_pro_1";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct FluxPro1InpaintImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// The image we're editing.
pub image_media_token: MediaFileToken,
/// The mask to use against the image.
pub mask_media_token: MediaFileToken,
/// Number of images to generate. Default is one.
pub num_images: Option<FluxPro1InpaintImageNumImages>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum FluxPro1InpaintImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct FluxPro1InpaintImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,2 @@
pub mod flux_dev_juggernaut_inpaint_image;
pub mod flux_pro_1_inpaint_image;
@@ -0,0 +1,6 @@
pub mod angle;
pub mod bg_removal;
pub mod edit;
pub mod inpaint;
pub mod multi_function;
pub mod text;
@@ -0,0 +1,68 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const BYTEDANCE_SEEDREAM_5_LITE_MULTI_FUNCTION_IMAGE_GEN_PATH: &str = "/v1/generate/image/multi_function/bytedance_seedream_5_lite";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct BytedanceSeedream5LiteMultiFunctionImageGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Image media tokens to include in the editing context.
/// If present, we're doing image editing (image-to-image / image-editing)
/// If absent, we're doing image generation (text-to-image)
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<BytedanceSeedream5LiteMultiFunctionImageGenNumImages>,
pub max_images: Option<BytedanceSeedream5LiteMultiFunctionImageGenMaxImages>,
pub image_size: Option<BytedanceSeedream5LiteMultiFunctionImageGenImageSize>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedream5LiteMultiFunctionImageGenNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedream5LiteMultiFunctionImageGenMaxImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedream5LiteMultiFunctionImageGenImageSize {
// Square
Square,
SquareHd,
// Tall
PortraitFourThree,
PortraitSixteenNine,
// Wide
LandscapeFourThree,
LandscapeSixteenNine,
// Auto (NB: 5 Lite max is auto_3K, not auto_4K like V4.5)
Auto2k,
Auto3k,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct BytedanceSeedream5LiteMultiFunctionImageGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,69 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const BYTEDANCE_SEEDREAM_V4_MULTI_FUNCTION_IMAGE_GEN_PATH: &str = "/v1/generate/image/multi_function/bytedance_seedream_4";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct BytedanceSeedreamV4MultiFunctionImageGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Image media tokens to include in the editing context.
/// If present, we're doing image editing (image-to-image / image-editing)
/// If absent, we're doing image generation (text-to-image)
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<BytedanceSeedreamV4MultiFunctionImageGenNumImages>,
pub max_images: Option<BytedanceSeedreamV4MultiFunctionImageGenMaxImages>,
pub image_size: Option<BytedanceSeedreamV4MultiFunctionImageGenImageSize>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedreamV4MultiFunctionImageGenNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedreamV4MultiFunctionImageGenMaxImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedreamV4MultiFunctionImageGenImageSize {
// Square
Square,
SquareHd,
// Tall
PortraitFourThree,
PortraitSixteenNine,
// Wide
LandscapeFourThree,
LandscapeSixteenNine,
// Auto
Auto,
Auto2k,
Auto4k,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct BytedanceSeedreamV4MultiFunctionImageGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,68 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const BYTEDANCE_SEEDREAM_V4P5_MULTI_FUNCTION_IMAGE_GEN_PATH: &str = "/v1/generate/image/multi_function/bytedance_seedream_4p5";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct BytedanceSeedreamV4p5MultiFunctionImageGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Image media tokens to include in the editing context.
/// If present, we're doing image editing (image-to-image / image-editing)
/// If absent, we're doing image generation (text-to-image)
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<BytedanceSeedreamV4p5MultiFunctionImageGenNumImages>,
pub max_images: Option<BytedanceSeedreamV4p5MultiFunctionImageGenMaxImages>,
pub image_size: Option<BytedanceSeedreamV4p5MultiFunctionImageGenImageSize>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedreamV4p5MultiFunctionImageGenNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedreamV4p5MultiFunctionImageGenMaxImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum BytedanceSeedreamV4p5MultiFunctionImageGenImageSize {
// Square
Square,
SquareHd,
// Tall
PortraitFourThree,
PortraitSixteenNine,
// Wide
LandscapeFourThree,
LandscapeSixteenNine,
// Auto
Auto2k,
Auto4k,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct BytedanceSeedreamV4p5MultiFunctionImageGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,95 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GPT_IMAGE_1P5_MULTI_FUNCTION_IMAGE_GEN_PATH: &str = "/v1/generate/image/multi_function/gpt_image_1p5";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GptImage1p5MultiFunctionImageGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Image media tokens to include in the editing context (**OR INPAINTING CONTEXT!**).
/// If present, we're doing image editing (image-to-image / image-editing / image-inpainting)
/// If absent, we're doing image generation (text-to-image)
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Only for image editing, which turns this into an inpainting task.
/// Text to image should not set this.
pub mask_image_token: Option<MediaFileToken>,
/// Number of images to generate. Default is one.
pub num_images: Option<GptImage1p5MultiFunctionImageGenNumImages>,
pub image_size: Option<GptImage1p5MultiFunctionImageGenSize>,
pub background: Option<GptImage1p5MultiFunctionImageGenBackground>,
pub quality: Option<GptImage1p5MultiFunctionImageGenQuality>,
/// Only for image editing.
pub input_fidelity: Option<GptImage1p5MultiFunctionImageGenInputFidelity>,
pub output_format: Option<GptImage1p5MultiFunctionImageGenOutputFormat>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1p5MultiFunctionImageGenNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1p5MultiFunctionImageGenSize {
/// 1024x1024
Square,
/// 1536x1024
Wide,
/// 1024x1536
Tall,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1p5MultiFunctionImageGenBackground {
Auto,
Transparent,
Opaque,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1p5MultiFunctionImageGenQuality {
Low,
Medium,
High,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1p5MultiFunctionImageGenInputFidelity {
Low,
High,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GptImage1p5MultiFunctionImageGenOutputFormat {
Jpeg,
Png,
Webp,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GptImage1p5MultiFunctionImageGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,7 @@
pub mod bytedance_seedream_v4_multi_function_image_gen;
pub mod bytedance_seedream_v4p5_multi_function_image_gen;
pub mod bytedance_seedream_5_lite_multi_function_image_gen;
pub mod gpt_image_1p5_multi_function_image_gen;
pub mod nano_banana_2_multi_function_image_gen;
pub mod nano_banana_multi_function_image_gen;
pub mod nano_banana_pro_multi_function_image_gen;
@@ -0,0 +1,74 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const NANO_BANANA_2_MULTI_FUNCTION_IMAGE_GEN_PATH: &str = "/v1/generate/image/multi_function/nano_banana_2";
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct NanaBanana2MultiFunctionImageGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Image media tokens to include in the editing context.
/// If present, we're doing image editing (image-to-image / image-editing)
/// If absent, we're doing image generation (text-to-image)
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<NanaBanana2MultiFunctionImageGenNumImages>,
/// Resolution of the image to generate. Default is OneK (1K).
pub resolution: Option<NanaBanana2MultiFunctionImageGenImageResolution>,
/// Aspect ratio of the images to generate. Default is "1:1"
pub aspect_ratio: Option<NanaBanana2MultiFunctionImageGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanaBanana2MultiFunctionImageGenNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanaBanana2MultiFunctionImageGenImageResolution {
HalfK,
OneK,
TwoK,
FourK,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanaBanana2MultiFunctionImageGenAspectRatio {
// Auto (only for image editing)
Auto, // Default for image editing.
// Square
OneByOne, // Default for text-to-image
// Wide
FiveByFour,
FourByThree,
ThreeByTwo,
SixteenByNine,
TwentyOneByNine,
// Tall
FourByFive,
ThreeByFour,
TwoByThree,
NineBySixteen,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct NanaBanana2MultiFunctionImageGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,62 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const NANO_BANANA_MULTI_FUNCTION_IMAGE_GEN_PATH: &str = "/v1/generate/image/multi_function/nano_banana";
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct NanoBananaMultiFunctionImageGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Image media tokens to include in the editing context.
/// If present, we're doing image editing (image-to-image / image-editing)
/// If absent, we're doing image generation (text-to-image)
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<NanoBananaMultiFunctionImageGenNumImages>,
/// Aspect ratio of the images to generate. Default is "1:1"
pub aspect_ratio: Option<NanoBananaMultiFunctionImageGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanoBananaMultiFunctionImageGenNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanoBananaMultiFunctionImageGenAspectRatio {
// Auto (only for image editing)
Auto, // Default for image editing.
// Square
OneByOne, // Default for text-to-image
// Wide
FiveByFour,
FourByThree,
ThreeByTwo,
SixteenByNine,
TwentyOneByNine,
// Tall
FourByFive,
ThreeByFour,
TwoByThree,
NineBySixteen, // NB: No NineByTwentyOne ?
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct NanoBananaMultiFunctionImageGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,73 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const NANO_BANANA_PRO_MULTI_FUNCTION_IMAGE_GEN_PATH: &str = "/v1/generate/image/multi_function/nano_banana_pro";
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct NanoBananaProMultiFunctionImageGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Image media tokens to include in the editing context.
/// If present, we're doing image editing (image-to-image / image-editing)
/// If absent, we're doing image generation (text-to-image)
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<NanoBananaProMultiFunctionImageGenNumImages>,
/// Resolution of the image to generate. Default is OneK (1K).
pub resolution: Option<NanoBananaProMultiFunctionImageGenImageResolution>,
/// Aspect ratio of the images to generate. Default is "1:1"
pub aspect_ratio: Option<NanoBananaProMultiFunctionImageGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanoBananaProMultiFunctionImageGenNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanoBananaProMultiFunctionImageGenImageResolution {
OneK,
TwoK,
FourK,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NanoBananaProMultiFunctionImageGenAspectRatio {
// Auto (only for image editing)
Auto, // Default for image editing.
// Square
OneByOne, // Default for text-to-image
// Wide
FiveByFour,
FourByThree,
ThreeByTwo,
SixteenByNine,
TwentyOneByNine,
// Tall
FourByFive,
ThreeByFour,
TwoByThree,
NineBySixteen, // NB: No NineByTwentyOne ?
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct NanoBananaProMultiFunctionImageGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,50 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GEMINI_25_FLASH_EDIT_IMAGE_PATH: &str = "/v1/generate/image/gemini_25_flash";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Gemini25FlashTextToImageImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
// TODO: OneOf for image_urls or image_media_tokens
/// Image media tokens to include in the editing context.
pub image_media_tokens: Option<Vec<MediaFileToken>>,
/// Number of images to generate. Default is one.
pub num_images: Option<Gemini25FlashTextToImageImageNumImages>,
/// Quality of the image to generate. Default is High.
pub image_quality: Option<Gemini25FlashTextToImageImageImageQuality>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Gemini25FlashTextToImageImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Gemini25FlashTextToImageImageImageQuality {
Auto,
Low,
Medium,
High, // Default
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Gemini25FlashTextToImageImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,49 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use utoipa::ToSchema;
pub const GENERATE_FLUX_1_DEV_TEXT_TO_IMAGE_PATH: &str = "/v1/generate/image/flux_1_dev_text_to_image";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFlux1DevTextToImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Aspect ratio of the output images.
pub aspect_ratio: Option<GenerateFlux1DevTextToImageAspectRatio>,
/// Number of images to generate. Default is one.
pub num_images: Option<GenerateFlux1DevTextToImageNumImages>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFlux1DevTextToImageAspectRatio {
Square, // 1:1
SquareHd, // 1:1
LandscapeFourByThree, // 4:3
LandscapeSixteenByNine, // 16:9
PortraitThreeByFour, // 3:4
PortraitNineBySixteen, // 9:16
//Custom { width: u32, height: u32 }, // TODO
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFlux1DevTextToImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFlux1DevTextToImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,49 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use utoipa::ToSchema;
pub const GENERATE_FLUX_1_SCHNELL_TEXT_TO_IMAGE_PATH: &str = "/v1/generate/image/flux_1_schnell_text_to_image";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFlux1SchnellTextToImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Aspect ratio of the output images.
pub aspect_ratio: Option<GenerateFlux1SchnellTextToImageAspectRatio>,
/// Number of images to generate. Default is one.
pub num_images: Option<GenerateFlux1SchnellTextToImageNumImages>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFlux1SchnellTextToImageAspectRatio {
Square, // 1:1
SquareHd, // 1:1
LandscapeFourByThree, // 4:3
LandscapeSixteenByNine, // 16:9
PortraitThreeByFour, // 3:4
PortraitNineBySixteen, // 9:16
//Custom { width: u32, height: u32 }, // TODO
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFlux1SchnellTextToImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFlux1SchnellTextToImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,47 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use utoipa::ToSchema;
pub const GENERATE_FLUX_PRO_11_TEXT_TO_IMAGE_PATH: &str = "/v1/generate/image/flux_pro_1.1_text_to_image";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFluxPro11TextToImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Aspect ratio of the output images.
pub aspect_ratio: Option<GenerateFluxPro11TextToImageAspectRatio>,
/// Number of images to generate. Default is one.
pub num_images: Option<GenerateFluxPro11TextToImageNumImages>,
}
// TODO(btw,2026-01-01): Fal.ai and Fal.rs client libraries seem to disagree about the options.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFluxPro11TextToImageAspectRatio {
Square, // 1:1
LandscapeFourByThree, // 4:3
LandscapeSixteenByNine, // 16:9
PortraitThreeByFour, // 3:4
PortraitNineBySixteen, // 9:16
//Custom { width: u32, height: u32 }, // TODO
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFluxPro11TextToImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFluxPro11TextToImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,50 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use utoipa::ToSchema;
pub const GENERATE_FLUX_PRO_11_ULTRA_TEXT_TO_IMAGE_PATH: &str = "/v1/generate/image/flux_pro_1.1_ultra_text_to_image";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFluxPro11UltraTextToImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Aspect ratio of the output images.
pub aspect_ratio: Option<GenerateFluxPro11UltraTextToImageAspectRatio>,
/// Number of images to generate. Default is one.
pub num_images: Option<GenerateFluxPro11UltraTextToImageNumImages>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFluxPro11UltraTextToImageAspectRatio {
Square, // 1:1
LandscapeThreeByTwo, // 3:2
LandscapeFourByThree, // 4:3
LandscapeSixteenByNine, // 16:9
LandscapeTwentyOneByNine, // 21:9
PortraitTwoByThree, // 2:3
PortraitThreeByFour, // 3:4
PortraitNineBySixteen, // 9:16
PortraitNineByTwentyOne, // 9:21
//Custom { width: u32, height: u32 }, // TODO
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateFluxPro11UltraTextToImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateFluxPro11UltraTextToImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,58 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GPT_IMAGE_1_TEXT_TO_IMAGE_PATH: &str = "/v1/generate/image/gpt_image_1_text_to_image";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateGptImage1TextToImageRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt to generate the image from.
pub prompt: Option<String>,
/// Size of the image to generate. Default is Square.
pub image_size: Option<GenerateGptImage1TextToImageImageSize>,
/// Number of images to generate. Default is one.
pub num_images: Option<GenerateGptImage1TextToImageNumImages>,
/// Quality of the image to generate. Default is High.
pub image_quality: Option<GenerateGptImage1TextToImageImageQuality>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateGptImage1TextToImageImageSize {
Square, // 1:1, Default
Horizontal,
Vertical,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateGptImage1TextToImageNumImages {
One, // Default
Two,
Three,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateGptImage1TextToImageImageQuality {
Auto,
Low,
Medium,
High, // Default
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateGptImage1TextToImageResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,6 @@
pub mod gemini_25_flash_text_to_image;
pub mod generate_flux_1_dev_text_to_image;
pub mod generate_flux_1_schnell_text_to_image;
pub mod generate_flux_pro_11_text_to_image;
pub mod generate_flux_pro_11_ultra_text_to_image;
pub mod generate_gpt_image_1_text_to_image;
@@ -0,0 +1,5 @@
pub mod cost_estimate;
pub mod image;
pub mod object;
pub mod splat;
pub mod video;
@@ -0,0 +1,22 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_HUNYUAN_2_0_IMAGE_TO_3D_URL_PATH: &str = "/v1/generate/object/hunyuan_2.0_image_to_3d";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateHunyuan20ImageTo3dRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the file to convert to 3D
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateHunyuan20ImageTo3dResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,22 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_HUNYUAN_2_1_IMAGE_TO_3D_URL_PATH: &str = "/v1/generate/object/hunyuan_2.1_image_to_3d";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateHunyuan21ImageTo3dRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the file to convert to 3D
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateHunyuan21ImageTo3dResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,3 @@
pub mod generate_hunyuan_2_0_image_to_3d;
pub mod generate_hunyuan_2_1_image_to_3d;
pub mod multi_function;
@@ -0,0 +1,84 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const HUNYUAN3D_V3_MULTI_FUNCTION_OBJECT_GEN_PATH: &str = "/v1/generate/object/multi_function/hunyuan3d_v3";
/// Hunyuan 3D v3 Multi-Function Request
///
/// This endpoint combines three modes:
/// - Text-to-3D: Provide only a prompt (no image_media_token)
/// - Image-to-3D: Provide an image_media_token (no prompt or empty prompt)
/// - Sketch-to-3D: Provide both a prompt AND an image_media_token
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct Hunyuan3dV3MultiFunctionObjectGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt for generation.
/// - Required for text-to-3d mode
/// - Required for sketch-to-3d mode
/// - Ignored for image-to-3d mode
pub prompt: Option<String>,
/// Primary image media token.
/// - Required for image-to-3d mode
/// - Required for sketch-to-3d mode
/// - Not used for text-to-3d mode
pub image_media_token: Option<MediaFileToken>,
/// Back view image for multi-view image-to-3d mode.
/// Only applicable when image_media_token is provided without a prompt.
pub back_image_media_token: Option<MediaFileToken>,
/// Left view image for multi-view image-to-3d mode.
/// Only applicable when image_media_token is provided without a prompt.
pub left_image_media_token: Option<MediaFileToken>,
/// Right view image for multi-view image-to-3d mode.
/// Only applicable when image_media_token is provided without a prompt.
pub right_image_media_token: Option<MediaFileToken>,
/// Target face count for the generated mesh.
/// Optional - if not provided, the model will use its default.
pub face_count: Option<u32>,
/// Type of generation to perform.
/// Default is Normal.
pub generate_type: Option<Hunyuan3dV3GenerateType>,
/// Type of polygon to use in the generated mesh.
/// Default is Triangle.
pub polygon_type: Option<Hunyuan3dV3PolygonType>,
/// Whether to enable PBR (Physically Based Rendering) materials.
/// Default is false.
pub enable_pbr: Option<bool>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Hunyuan3dV3GenerateType {
/// Standard generation quality (default)
Normal,
/// Low polygon count for game assets
LowPoly,
/// Geometry only, no textures
Geometry,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Hunyuan3dV3PolygonType {
/// Triangle polygons (default)
Triangle,
/// Quadrilateral polygons
Quadrilateral,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Hunyuan3dV3MultiFunctionObjectGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1 @@
pub mod hunyuan3d_v3_multi_function_object_gen;
@@ -0,0 +1,25 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_WORLDLABS_MARBLE_0P1_MINI_SPLAT_URL_PATH: &str = "/v1/generate/splat/worldlabs_marble_0p1_mini";
/// World Labs Marble 0.1-mini Splat Generation
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateWorldlabsMarble0p1MiniSplatRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Optional image to use as input for world generation.
pub image_media_file_token: Option<MediaFileToken>,
/// Optional text prompt for world generation.
pub prompt: Option<String>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateWorldlabsMarble0p1MiniSplatResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,25 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_WORLDLABS_MARBLE_0P1_PLUS_SPLAT_URL_PATH: &str = "/v1/generate/splat/worldlabs_marble_0p1_plus";
/// World Labs Marble 0.1-plus Splat Generation
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateWorldlabsMarble0p1PlusSplatRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Optional image to use as input for world generation.
pub image_media_file_token: Option<MediaFileToken>,
/// Optional text prompt for world generation.
pub prompt: Option<String>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateWorldlabsMarble0p1PlusSplatResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,2 @@
pub mod generate_worldlabs_marble_0p1_mini_splat;
pub mod generate_worldlabs_marble_0p1_plus_splat;
@@ -0,0 +1,20 @@
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const BEEBLE_SWITCHX_EDIT_VIDEO_PATH: &str = "/v1/generate/video/edit/beeble_switchx";
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct BeebleSwitchXEditVideoRequest {
pub uuid_idempotency_token: String,
pub source_video_media_token: Option<MediaFileToken>,
pub reference_image_media_token: Option<MediaFileToken>,
pub prompt: Option<String>,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct BeebleSwitchXEditVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1 @@
pub mod beeble_switchx_edit_video;
@@ -0,0 +1,53 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_KLING_1_6_PRO_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/kling_1.6_pro_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateKling16ProImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional.
/// Image media file; the image to remove the background from.
pub end_frame_image_media_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// Optional: aspect ratio of the generated video.
pub aspect_ratio: Option<GenerateKling16ProAspectRatio>,
/// Optional: aspect ratio of the generated video.
pub duration: Option<GenerateKling16ProDuration>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling16ProAspectRatio {
/// 16:9 aspect ratio
WideSixteenNine,
/// 9:16 aspect ratio
TallNineSixteen,
/// 1:1 aspect ratio
Square,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling16ProDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateKling16ProImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,49 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_KLING_2_1_MASTER_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/kling_2.1_master_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateKling21MasterImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// Optional: aspect ratio of the generated video.
pub aspect_ratio: Option<GenerateKling21MasterAspectRatio>,
/// Optional: aspect ratio of the generated video.
pub duration: Option<GenerateKling21MasterDuration>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21MasterAspectRatio {
/// 16:9 aspect ratio
WideSixteenNine,
/// 9:16 aspect ratio
TallNineSixteen,
/// 1:1 aspect ratio
Square,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21MasterDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateKling21MasterImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,53 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_KLING_2_1_PRO_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/kling_2.1_pro_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateKling21ProImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional.
/// Image media file; the image to remove the background from.
pub end_frame_image_media_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// Optional: aspect ratio of the generated video.
pub aspect_ratio: Option<GenerateKling21ProAspectRatio>,
/// Optional: aspect ratio of the generated video.
pub duration: Option<GenerateKling21ProDuration>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21ProAspectRatio {
/// 16:9 aspect ratio
WideSixteenNine,
/// 9:16 aspect ratio
TallNineSixteen,
/// 1:1 aspect ratio
Square,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21ProDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateKling21ProImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,65 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_SEEDANCE_1_0_LITE_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/seedance_1.0_lite_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateSeedance10LiteImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional.
/// Image media file; the image to remove the background from.
pub end_frame_image_media_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// Optional: resolution of the generated video.
pub resolution: Option<GenerateSeedance10LiteResolution>,
/// Optional: duration of the generated video.
pub duration: Option<GenerateSeedance10LiteDuration>,
/// Optional: aspect ratio of the generated video.
pub aspect_ratio: Option<GenerateSeedance10LiteAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateSeedance10LiteResolution {
FourEightyP,
SevenTwentyP,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateSeedance10LiteDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateSeedance10LiteAspectRatio {
Auto,
TwentyOneByNine,
SixteenByNine,
FourByThree,
Square,
ThreeByFour,
NineBySixteen,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateSeedance10LiteImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,54 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_SEEDANCE_1_0_PRO_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/seedance_1.0_pro_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateSeedance10ProImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// Optional: aspect ratio of the generated video.
pub resolution: Option<GenerateSeedance10ProResolution>,
/// Optional: aspect ratio of the generated video.
pub duration: Option<GenerateSeedance10ProDuration>,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateSeedance10ProResolution {
FourEightyP,
SevenTwentyP,
TenEightyP,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateSeedance10ProDuration {
ThreeSeconds,
FourSeconds,
FiveSeconds,
SixSeconds,
SevenSeconds,
EightSeconds,
NineSeconds,
TenSeconds,
ElevenSeconds,
TwelveSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateSeedance10ProImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,50 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_VEO_2_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/veo_2_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateVeo2ImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// **NB(bt): ASPECT RATIO IS ACTUALLY NOT USED IN VEO 2 IMAGE-TO-VIDEO**
/// Optional: aspect ratio of the generated video.
pub aspect_ratio: Option<GenerateVeo2AspectRatio>,
/// Optional: aspect ratio of the generated video.
pub duration: Option<GenerateVeo2Duration>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo2AspectRatio {
Auto,
AutoPreferPortrait,
WideSixteenNine, // 16:9
TallNineSixteen, // 9:16
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo2Duration {
FiveSeconds,
SixSeconds,
SevenSeconds,
EightSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateVeo2ImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,58 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_VEO_3_FAST_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/veo_3_fast_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateVeo3FastImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// Optional: resolution of the generated video.
pub resolution: Option<GenerateVeo3FastResolution>,
/// Optional: aspect ratio of the generated video.
pub aspect_ratio: Option<GenerateVeo3FastAspectRatio>,
/// Optional: duration of the generated video.
pub duration: Option<GenerateVeo3FastDuration>,
/// Optional: Generate an audio track along with the video
pub generate_audio: Option<bool>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo3FastResolution {
SevenTwentyP, // 720p
TenEightyP, // 1080p
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo3FastAspectRatio {
Auto,
SixteenByNine,
NineBySixteen,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo3FastDuration {
EightSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateVeo3FastImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,69 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const GENERATE_VEO_3_IMAGE_TO_VIDEO_URL_PATH: &str = "/v1/generate/video/veo_3_image_to_video";
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateVeo3ImageToVideoRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Source of the image file to convert to video.
/// It must be an image.
pub media_file_token: Option<MediaFileToken>,
/// Optional text prompt.
pub prompt: Option<String>,
/// Optional: aspect ratio of the generated video.
pub aspect_ratio: Option<GenerateVeo3AspectRatio>,
/// Optional: resolution of the generated video.
pub resolution: Option<GenerateVeo3Resolution>,
/// Optional: aspect ratio of the generated video.
pub duration: Option<GenerateVeo3Duration>,
/// Optional: Generate an audio track along with the video
pub generate_audio: Option<bool>,
// /// Optional.
// pub enhance_prompt: Option<bool>,
// /// Optional. Whether to automatically attempt to fix prompts that fail
// /// content policy or other validation checks by rewriting them
// /// Default value: true
// pub auto_fix: Option<bool>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo3AspectRatio {
WideSixteenNine, // 16:9
TallNineSixteen, // 9:16
/// NB: DO NOT REMOVE. This is an unsupported resolution for Veo 3, but we can't
/// impact existing callers by removing it. The handler will convert this to a
/// supported resolution or 400 the request instead.
Square, // 1:1
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo3Resolution {
SevenTwentyP, // 720p
TenEightyP, // 1080p
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateVeo3Duration {
EightSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct GenerateVeo3ImageToVideoResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,10 @@
pub mod edit;
pub mod generate_kling_1_6_pro_image_to_video;
pub mod generate_kling_2_1_master_image_to_video;
pub mod generate_kling_2_1_pro_image_to_video;
pub mod generate_seedance_1_0_lite_image_to_video;
pub mod generate_seedance_1_0_pro_image_to_video;
pub mod generate_veo_2_image_to_video;
pub mod generate_veo_3_fast_image_to_video;
pub mod generate_veo_3_image_to_video;
pub mod multi_function;
@@ -0,0 +1,64 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const KLING_2P5_TURBO_PRO_MULTI_FUNCTION_VIDEO_VIDEO_PATH: &str = "/v1/generate/video/multi_function/kling_2p5_turbo_pro";
/// Both text-to-video and image-to-video in one request.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling2p5TurboProMultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// "Required".
/// Required downstream, but we'll coerce null to empty string.
/// Text prompt.
pub prompt: Option<String>,
/// Optional.
/// Only for text-to-video.
pub negative_prompt: Option<String>,
/// Optional.
/// Only for image-to-video
/// Source of the starting frame
/// If present, we're doing image-to-video
/// If absent, we're doing text-to-video
pub start_frame_image_media_token: Option<MediaFileToken>,
/// Optional.
/// Only for image-to-video
/// Source of the ending frame (if desired)
pub end_frame_image_media_token: Option<MediaFileToken>,
/// Optional
/// Duration of the video
pub duration: Option<Kling2p5TurboProMultiFunctionVideoGenDuration>,
/// Optional.
/// Only for text-to-video
pub aspect_ratio: Option<Kling2p5TurboProMultiFunctionVideoGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p5TurboProMultiFunctionVideoGenDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p5TurboProMultiFunctionVideoGenAspectRatio {
Square,
SixteenByNine,
NineBySixteen,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling2p5TurboProMultiFunctionVideoGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,68 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const KLING_2P6_PRO_MULTI_FUNCTION_VIDEO_VIDEO_PATH: &str = "/v1/generate/video/multi_function/kling_2p6_pro";
/// Both text-to-video and image-to-video in one request.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling2p6ProMultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// "Required".
/// Required downstream, but we'll coerce null to empty string.
/// Text prompt.
pub prompt: Option<String>,
/// Optional.
/// Only for text-to-video.
pub negative_prompt: Option<String>,
/// Optional.
/// Only for image-to-video
/// Source of the starting frame
/// If present, we're doing image-to-video
/// If absent, we're doing text-to-video
pub start_frame_image_media_token: Option<MediaFileToken>,
// /// Optional.
// /// Only for image-to-video
// /// Source of the ending frame (if desired)
// pub end_frame_image_media_token: Option<MediaFileToken>,
/// Optional
/// Duration of the video
pub duration: Option<Kling2p6ProMultiFunctionVideoGenDuration>,
/// Optional
/// Whether to generate audio.
pub generate_audio: Option<bool>,
/// Optional.
/// Only for text-to-video
pub aspect_ratio: Option<Kling2p6ProMultiFunctionVideoGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p6ProMultiFunctionVideoGenDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p6ProMultiFunctionVideoGenAspectRatio {
Square,
SixteenByNine,
NineBySixteen,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling2p6ProMultiFunctionVideoGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,66 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const KLING_3P0_PRO_MULTI_FUNCTION_VIDEO_PATH: &str = "/v1/generate/video/multi_function/kling_3p0_pro";
/// Both text-to-video and image-to-video in one request.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling3p0ProMultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt.
pub prompt: Option<String>,
/// Optional negative prompt.
pub negative_prompt: Option<String>,
/// If present, we're doing image-to-video. If absent, text-to-video.
pub image_media_token: Option<MediaFileToken>,
/// Optional end frame image.
pub end_image_media_token: Option<MediaFileToken>,
/// Duration of the video (3-15 seconds).
pub duration: Option<Kling3p0ProMultiFunctionVideoGenDuration>,
/// Whether to generate audio.
pub generate_audio: Option<bool>,
/// Aspect ratio (only for text-to-video).
pub aspect_ratio: Option<Kling3p0ProMultiFunctionVideoGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling3p0ProMultiFunctionVideoGenDuration {
ThreeSeconds,
FourSeconds,
FiveSeconds,
SixSeconds,
SevenSeconds,
EightSeconds,
NineSeconds,
TenSeconds,
ElevenSeconds,
TwelveSeconds,
ThirteenSeconds,
FourteenSeconds,
FifteenSeconds,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling3p0ProMultiFunctionVideoGenAspectRatio {
Square,
SixteenByNine,
NineBySixteen,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling3p0ProMultiFunctionVideoGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,66 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const KLING_3P0_STANDARD_MULTI_FUNCTION_VIDEO_PATH: &str = "/v1/generate/video/multi_function/kling_3p0_standard";
/// Both text-to-video and image-to-video in one request.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling3p0StandardMultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt.
pub prompt: Option<String>,
/// Optional negative prompt.
pub negative_prompt: Option<String>,
/// If present, we're doing image-to-video. If absent, text-to-video.
pub image_media_token: Option<MediaFileToken>,
/// Optional end frame image.
pub end_image_media_token: Option<MediaFileToken>,
/// Duration of the video (3-15 seconds).
pub duration: Option<Kling3p0StandardMultiFunctionVideoGenDuration>,
/// Whether to generate audio.
pub generate_audio: Option<bool>,
/// Aspect ratio (only for text-to-video).
pub aspect_ratio: Option<Kling3p0StandardMultiFunctionVideoGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling3p0StandardMultiFunctionVideoGenDuration {
ThreeSeconds,
FourSeconds,
FiveSeconds,
SixSeconds,
SevenSeconds,
EightSeconds,
NineSeconds,
TenSeconds,
ElevenSeconds,
TwelveSeconds,
ThirteenSeconds,
FourteenSeconds,
FifteenSeconds,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling3p0StandardMultiFunctionVideoGenAspectRatio {
Square,
SixteenByNine,
NineBySixteen,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Kling3p0StandardMultiFunctionVideoGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,10 @@
pub mod kling_2_5_turbo_multi_function_video_gen;
pub mod kling_2_6_multi_function_video_gen;
pub mod kling_3p0_pro_multi_function_video_gen;
pub mod kling_3p0_standard_multi_function_video_gen;
pub mod seedance_1p5_pro_multi_function_video_gen;
pub mod seedance_2p0_multi_function_video_gen;
pub mod sora_2_multi_function_video_gen;
pub mod sora_2_pro_multi_function_video_gen;
pub mod veo_3p1_fast_multi_function_video_gen;
pub mod veo_3p1_multi_function_video_gen;
@@ -0,0 +1,85 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const SEEDANCE_1P5_PRO_MULTI_FUNCTION_VIDEO_GEN_PATH: &str = "/v1/generate/video/multi_function/seedance_1p5_pro";
/// Both text-to-video and image-to-video in one request.
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct Seedance1p5ProMultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// "Required".
/// Required downstream, but we'll coerce null to empty string.
/// Text prompt.
pub prompt: Option<String>,
/// Optional.
/// Only for image-to-video.
/// Source of the starting frame.
/// If present, we're doing image-to-video.
/// If absent, we're doing text-to-video.
pub start_frame_image_media_token: Option<MediaFileToken>,
/// Optional.
/// Only for image-to-video.
/// Source of the ending frame.
pub end_frame_image_media_token: Option<MediaFileToken>,
/// Optional.
pub resolution: Option<Seedance1p5ProMultiFunctionVideoGenResolution>,
/// Optional.
/// Duration of the video.
/// (this is uniform against all modes)
pub duration: Option<Seedance1p5ProMultiFunctionVideoGenDuration>,
/// Optional.
pub aspect_ratio: Option<Seedance1p5ProMultiFunctionVideoGenAspectRatio>,
/// Whether to generate audio.
pub generate_audio: Option<bool>,
}
#[derive(Serialize, Deserialize, ToSchema, Copy, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Seedance1p5ProMultiFunctionVideoGenResolution {
FourEightyP,
SevenTwentyP,
TenEightyP,
}
#[derive(Serialize, Deserialize, ToSchema, Copy, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Seedance1p5ProMultiFunctionVideoGenDuration {
FourSeconds,
FiveSeconds,
SixSeconds,
SevenSeconds,
EightSeconds,
NineSeconds,
TenSeconds,
ElevenSeconds,
TwelveSeconds,
}
#[derive(Serialize, Deserialize, ToSchema, Copy, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Seedance1p5ProMultiFunctionVideoGenAspectRatio {
TwentyOneByNine,
SixteenByNine,
FourByThree,
Square,
ThreeByFour,
NineBySixteen,
Auto,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Seedance1p5ProMultiFunctionVideoGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,110 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::characters::CharacterToken;
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const SEEDANCE_2P0_MULTI_FUNCTION_VIDEO_GEN_PATH: &str = "/v1/generate/video/multi_function/seedance_2p0";
/// Seedance 2.0 multi-function video generation (text-to-video, image-to-video, and reference-based).
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct Seedance2p0MultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// Text prompt.
pub prompt: Option<String>,
/// Optional start frame image.
pub start_frame_media_token: Option<MediaFileToken>,
/// Optional end frame image.
pub end_frame_media_token: Option<MediaFileToken>,
/// Optional reference images (reference mode). When present, takes priority over start/end frames.
pub reference_image_media_tokens: Option<Vec<MediaFileToken>>,
/// Optional reference videos.
pub reference_video_media_tokens: Option<Vec<MediaFileToken>>,
/// Optional reference audio files.
pub reference_audio_media_tokens: Option<Vec<MediaFileToken>>,
/// Optional character tokens to reference in the prompt.
/// Characters are referenced in prompts as @CharacterName.
pub reference_character_tokens: Option<Vec<CharacterToken>>,
/// Video aspect ratio / resolution.
pub aspect_ratio: Option<Seedance2p0AspectRatio>,
/// Output resolution quality tier (480p, 720p, 1080p).
pub output_resolution: Option<Seedance2p0OutputResolution>,
/// Duration in seconds (4–15).
pub duration_seconds: Option<u8>,
/// Number of videos to generate.
pub batch_count: Option<Seedance2p0BatchCount>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Seedance2p0AspectRatio {
/// 16:9 landscape (1280x720)
Landscape16x9,
/// 9:16 portrait (720x1280)
Portrait9x16,
/// 1:1 square (720x720)
Square1x1,
/// 4:3 standard (960x720)
Standard4x3,
/// 3:4 portrait (720x960)
Portrait3x4,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Seedance2p0BatchCount {
One,
Two,
Four,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Seedance2p0OutputResolution {
/// 480p
FourEightyP,
/// 720p (default)
SevenTwentyP,
/// 1080p
TenEightyP,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Seedance2p0MultiFunctionVideoGenResponse {
pub success: bool,
/// The first inference job token (always present).
pub inference_job_token: InferenceJobToken,
/// All inference job tokens for the batch (includes `inference_job_token` as the first entry).
pub all_inference_job_tokens: Vec<InferenceJobToken>,
}
#[cfg(test)]
mod tests {
use super::*;
fn aspect_to_string(input: Seedance2p0AspectRatio) -> anyhow::Result<String> {
let val = serde_json::to_string(&input)?;
Ok(val.replace("\"", ""))
}
#[test]
fn just_testing_snake_case() -> anyhow::Result<()> {
// Ugh, not sure what these are...
assert_eq!(aspect_to_string(Seedance2p0AspectRatio::Landscape16x9)?, "landscape16x9");
Ok(())
}
}
@@ -0,0 +1,66 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const SORA_2_MULTI_FUNCTION_VIDEO_VIDEO_PATH: &str = "/v1/generate/video/multi_function/sora_2";
/// Both text-to-video and image-to-video in one request.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Sora2MultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// "Required".
/// Required downstream, but we'll coerce null to empty string.
/// Text prompt.
pub prompt: Option<String>,
/// Optional.
/// Only for image-to-video
/// Source of the starting frame
/// If present, we're doing image-to-video
/// If absent, we're doing text-to-video
pub image_media_token: Option<MediaFileToken>,
/// Optional.
pub resolution: Option<Sora2MultiFunctionVideoGenResolution>,
/// Optional
/// Duration of the video
/// (this is uniform against all modes)
pub duration: Option<Sora2MultiFunctionVideoGenDuration>,
/// Optional.
pub aspect_ratio: Option<Sora2MultiFunctionVideoGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Sora2MultiFunctionVideoGenResolution {
Auto,
SevenTwentyP,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Sora2MultiFunctionVideoGenDuration {
FourSeconds,
EightSeconds,
TwelveSeconds,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Sora2MultiFunctionVideoGenAspectRatio {
Auto,
NineBySixteen,
SixteenByNine,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Sora2MultiFunctionVideoGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}
@@ -0,0 +1,67 @@
use serde::{Deserialize, Serialize};
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use utoipa::ToSchema;
pub const SORA_2_PRO_MULTI_FUNCTION_VIDEO_VIDEO_PATH: &str = "/v1/generate/video/multi_function/sora_2_pro";
/// Both text-to-video and image-to-video in one request.
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Sora2ProMultiFunctionVideoGenRequest {
/// Idempotency token to prevent duplicate requests.
pub uuid_idempotency_token: String,
/// "Required".
/// Required downstream, but we'll coerce null to empty string.
/// Text prompt.
pub prompt: Option<String>,
/// Optional.
/// Only for image-to-video
/// Source of the starting frame
/// If present, we're doing image-to-video
/// If absent, we're doing text-to-video
pub image_media_token: Option<MediaFileToken>,
/// Optional.
pub resolution: Option<Sora2ProMultiFunctionVideoGenResolution>,
/// Optional
/// Duration of the video
/// (this is uniform against all modes)
pub duration: Option<Sora2ProMultiFunctionVideoGenDuration>,
/// Optional.
pub aspect_ratio: Option<Sora2ProMultiFunctionVideoGenAspectRatio>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Sora2ProMultiFunctionVideoGenResolution {
Auto,
SevenTwentyP,
TenEightyP,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Sora2ProMultiFunctionVideoGenDuration {
FourSeconds,
EightSeconds,
TwelveSeconds,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Sora2ProMultiFunctionVideoGenAspectRatio {
Auto,
NineBySixteen,
SixteenByNine,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct Sora2ProMultiFunctionVideoGenResponse {
pub success: bool,
pub inference_job_token: InferenceJobToken,
}

Some files were not shown because too many files have changed in this diff Show More