@weirdfingers/baseboards 0.9.6 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +560 -469
- package/dist/index.js.map +1 -1
- package/package.json +2 -5
- package/templates/README.md +0 -122
- package/templates/api/.env.example +0 -65
- package/templates/api/ARTIFACT_RESOLUTION_GUIDE.md +0 -148
- package/templates/api/Dockerfile +0 -32
- package/templates/api/README.md +0 -264
- package/templates/api/alembic/env.py +0 -114
- package/templates/api/alembic/script.py.mako +0 -28
- package/templates/api/alembic/versions/20250101_000000_initial_schema.py +0 -506
- package/templates/api/alembic/versions/20251022_174729_remove_provider_name_from_generations.py +0 -75
- package/templates/api/alembic/versions/20251023_165852_switch_to_declarative_base_and_mapping.py +0 -467
- package/templates/api/alembic/versions/20251202_000000_add_artifact_lineage.py +0 -134
- package/templates/api/alembic/versions/2025925_62735_add_seed_data_for_default_tenant.py +0 -88
- package/templates/api/alembic.ini +0 -36
- package/templates/api/config/generators.yaml +0 -237
- package/templates/api/config/storage_config.yaml +0 -26
- package/templates/api/docs/ADDING_GENERATORS.md +0 -409
- package/templates/api/docs/GENERATORS_API.md +0 -502
- package/templates/api/docs/MIGRATIONS.md +0 -472
- package/templates/api/docs/TESTING_LIVE_APIS.md +0 -417
- package/templates/api/docs/storage_providers.md +0 -337
- package/templates/api/pyproject.toml +0 -205
- package/templates/api/src/boards/__init__.py +0 -10
- package/templates/api/src/boards/api/app.py +0 -172
- package/templates/api/src/boards/api/auth.py +0 -75
- package/templates/api/src/boards/api/endpoints/__init__.py +0 -3
- package/templates/api/src/boards/api/endpoints/jobs.py +0 -76
- package/templates/api/src/boards/api/endpoints/setup.py +0 -505
- package/templates/api/src/boards/api/endpoints/sse.py +0 -129
- package/templates/api/src/boards/api/endpoints/storage.py +0 -155
- package/templates/api/src/boards/api/endpoints/tenant_registration.py +0 -296
- package/templates/api/src/boards/api/endpoints/uploads.py +0 -149
- package/templates/api/src/boards/api/endpoints/webhooks.py +0 -13
- package/templates/api/src/boards/auth/__init__.py +0 -15
- package/templates/api/src/boards/auth/adapters/__init__.py +0 -27
- package/templates/api/src/boards/auth/adapters/auth0.py +0 -220
- package/templates/api/src/boards/auth/adapters/base.py +0 -73
- package/templates/api/src/boards/auth/adapters/clerk.py +0 -172
- package/templates/api/src/boards/auth/adapters/jwt.py +0 -122
- package/templates/api/src/boards/auth/adapters/none.py +0 -102
- package/templates/api/src/boards/auth/adapters/oidc.py +0 -284
- package/templates/api/src/boards/auth/adapters/supabase.py +0 -110
- package/templates/api/src/boards/auth/context.py +0 -35
- package/templates/api/src/boards/auth/factory.py +0 -129
- package/templates/api/src/boards/auth/middleware.py +0 -221
- package/templates/api/src/boards/auth/provisioning.py +0 -129
- package/templates/api/src/boards/auth/tenant_extraction.py +0 -278
- package/templates/api/src/boards/cli.py +0 -354
- package/templates/api/src/boards/config.py +0 -131
- package/templates/api/src/boards/database/__init__.py +0 -7
- package/templates/api/src/boards/database/cli.py +0 -110
- package/templates/api/src/boards/database/connection.py +0 -292
- package/templates/api/src/boards/database/models.py +0 -19
- package/templates/api/src/boards/database/seed_data.py +0 -182
- package/templates/api/src/boards/dbmodels/__init__.py +0 -441
- package/templates/api/src/boards/generators/__init__.py +0 -57
- package/templates/api/src/boards/generators/artifact_resolution.py +0 -405
- package/templates/api/src/boards/generators/artifacts.py +0 -53
- package/templates/api/src/boards/generators/base.py +0 -144
- package/templates/api/src/boards/generators/implementations/__init__.py +0 -14
- package/templates/api/src/boards/generators/implementations/fal/__init__.py +0 -25
- package/templates/api/src/boards/generators/implementations/fal/audio/__init__.py +0 -23
- package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_music_generation.py +0 -171
- package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_sound_effect_generation.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_text_to_speech.py +0 -176
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_tts_turbo.py +0 -195
- package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_sound_effects_v2.py +0 -194
- package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_tts_eleven_v3.py +0 -209
- package/templates/api/src/boards/generators/implementations/fal/audio/fal_elevenlabs_tts_turbo_v2_5.py +0 -206
- package/templates/api/src/boards/generators/implementations/fal/audio/fal_minimax_speech_26_hd.py +0 -237
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_music_v2.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_speech_2_6_turbo.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/image/__init__.py +0 -63
- package/templates/api/src/boards/generators/implementations/fal/image/bytedance_seedream_v45_edit.py +0 -219
- package/templates/api/src/boards/generators/implementations/fal/image/clarity_upscaler.py +0 -220
- package/templates/api/src/boards/generators/implementations/fal/image/crystal_upscaler.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/image/fal_ideogram_character.py +0 -227
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2.py +0 -203
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_edit.py +0 -230
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro.py +0 -204
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro_edit.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_kontext.py +0 -216
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_ultra.py +0 -197
- package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image.py +0 -177
- package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image_edit.py +0 -208
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_15_edit.py +0 -216
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_5.py +0 -177
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_edit_image.py +0 -182
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_mini.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/image/ideogram_character_edit.py +0 -299
- package/templates/api/src/boards/generators/implementations/fal/image/ideogram_v2.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview.py +0 -191
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview_fast.py +0 -179
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana.py +0 -183
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_edit.py +0 -212
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro.py +0 -179
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro_edit.py +0 -226
- package/templates/api/src/boards/generators/implementations/fal/image/qwen_image.py +0 -249
- package/templates/api/src/boards/generators/implementations/fal/image/qwen_image_edit.py +0 -244
- package/templates/api/src/boards/generators/implementations/fal/image/reve_edit.py +0 -178
- package/templates/api/src/boards/generators/implementations/fal/image/reve_text_to_image.py +0 -155
- package/templates/api/src/boards/generators/implementations/fal/image/seedream_v45_text_to_image.py +0 -180
- package/templates/api/src/boards/generators/implementations/fal/utils.py +0 -61
- package/templates/api/src/boards/generators/implementations/fal/video/__init__.py +0 -77
- package/templates/api/src/boards/generators/implementations/fal/video/bytedance_seedance_v1_pro_text_to_video.py +0 -209
- package/templates/api/src/boards/generators/implementations/fal/video/creatify_lipsync.py +0 -161
- package/templates/api/src/boards/generators/implementations/fal/video/fal_bytedance_seedance_v1_pro_image_to_video.py +0 -222
- package/templates/api/src/boards/generators/implementations/fal/video/fal_minimax_hailuo_02_standard_text_to_video.py +0 -152
- package/templates/api/src/boards/generators/implementations/fal/video/fal_pixverse_lipsync.py +0 -197
- package/templates/api/src/boards/generators/implementations/fal/video/fal_sora_2_text_to_video.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/video/infinitalk.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_pro.py +0 -168
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_standard.py +0 -159
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_image_to_video.py +0 -175
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_text_to_video.py +0 -168
- package/templates/api/src/boards/generators/implementations/fal/video/minimax_hailuo_2_3_pro_image_to_video.py +0 -153
- package/templates/api/src/boards/generators/implementations/fal/video/sora2_image_to_video.py +0 -172
- package/templates/api/src/boards/generators/implementations/fal/video/sora_2_image_to_video_pro.py +0 -175
- package/templates/api/src/boards/generators/implementations/fal/video/sora_2_text_to_video_pro.py +0 -163
- package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2_pro.py +0 -155
- package/templates/api/src/boards/generators/implementations/fal/video/veed_fabric_1_0.py +0 -180
- package/templates/api/src/boards/generators/implementations/fal/video/veed_lipsync.py +0 -174
- package/templates/api/src/boards/generators/implementations/fal/video/veo3.py +0 -194
- package/templates/api/src/boards/generators/implementations/fal/video/veo31.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast_image_to_video.py +0 -191
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_first_last_frame_to_video.py +0 -187
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_image_to_video.py +0 -183
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_reference_to_video.py +0 -172
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_image_to_video.py +0 -212
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_text_to_video.py +0 -208
- package/templates/api/src/boards/generators/implementations/fal/video/wan_pro_image_to_video.py +0 -158
- package/templates/api/src/boards/generators/implementations/kie/__init__.py +0 -11
- package/templates/api/src/boards/generators/implementations/kie/base.py +0 -316
- package/templates/api/src/boards/generators/implementations/kie/image/__init__.py +0 -3
- package/templates/api/src/boards/generators/implementations/kie/image/nano_banana_edit.py +0 -190
- package/templates/api/src/boards/generators/implementations/kie/utils.py +0 -98
- package/templates/api/src/boards/generators/implementations/kie/video/__init__.py +0 -8
- package/templates/api/src/boards/generators/implementations/kie/video/veo3.py +0 -161
- package/templates/api/src/boards/generators/implementations/openai/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/audio/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/audio/whisper.py +0 -69
- package/templates/api/src/boards/generators/implementations/openai/image/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/image/dalle3.py +0 -96
- package/templates/api/src/boards/generators/implementations/replicate/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/image/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/image/flux_pro.py +0 -88
- package/templates/api/src/boards/generators/implementations/replicate/video/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/video/lipsync.py +0 -73
- package/templates/api/src/boards/generators/loader.py +0 -253
- package/templates/api/src/boards/generators/registry.py +0 -114
- package/templates/api/src/boards/generators/resolution.py +0 -632
- package/templates/api/src/boards/generators/testmods/class_gen.py +0 -34
- package/templates/api/src/boards/generators/testmods/import_side_effect.py +0 -35
- package/templates/api/src/boards/graphql/__init__.py +0 -7
- package/templates/api/src/boards/graphql/access_control.py +0 -136
- package/templates/api/src/boards/graphql/mutations/root.py +0 -148
- package/templates/api/src/boards/graphql/queries/root.py +0 -116
- package/templates/api/src/boards/graphql/resolvers/__init__.py +0 -8
- package/templates/api/src/boards/graphql/resolvers/auth.py +0 -12
- package/templates/api/src/boards/graphql/resolvers/board.py +0 -1053
- package/templates/api/src/boards/graphql/resolvers/generation.py +0 -666
- package/templates/api/src/boards/graphql/resolvers/generator.py +0 -50
- package/templates/api/src/boards/graphql/resolvers/lineage.py +0 -381
- package/templates/api/src/boards/graphql/resolvers/upload.py +0 -463
- package/templates/api/src/boards/graphql/resolvers/user.py +0 -25
- package/templates/api/src/boards/graphql/schema.py +0 -81
- package/templates/api/src/boards/graphql/types/board.py +0 -102
- package/templates/api/src/boards/graphql/types/generation.py +0 -166
- package/templates/api/src/boards/graphql/types/generator.py +0 -17
- package/templates/api/src/boards/graphql/types/user.py +0 -47
- package/templates/api/src/boards/jobs/repository.py +0 -153
- package/templates/api/src/boards/logging.py +0 -195
- package/templates/api/src/boards/middleware.py +0 -339
- package/templates/api/src/boards/progress/__init__.py +0 -4
- package/templates/api/src/boards/progress/models.py +0 -25
- package/templates/api/src/boards/progress/publisher.py +0 -64
- package/templates/api/src/boards/py.typed +0 -0
- package/templates/api/src/boards/redis_pool.py +0 -118
- package/templates/api/src/boards/storage/__init__.py +0 -52
- package/templates/api/src/boards/storage/base.py +0 -363
- package/templates/api/src/boards/storage/config.py +0 -187
- package/templates/api/src/boards/storage/factory.py +0 -288
- package/templates/api/src/boards/storage/implementations/__init__.py +0 -27
- package/templates/api/src/boards/storage/implementations/gcs.py +0 -340
- package/templates/api/src/boards/storage/implementations/local.py +0 -201
- package/templates/api/src/boards/storage/implementations/s3.py +0 -294
- package/templates/api/src/boards/storage/implementations/supabase.py +0 -218
- package/templates/api/src/boards/tenant_isolation.py +0 -446
- package/templates/api/src/boards/validation.py +0 -262
- package/templates/api/src/boards/workers/__init__.py +0 -1
- package/templates/api/src/boards/workers/actors.py +0 -274
- package/templates/api/src/boards/workers/cli.py +0 -125
- package/templates/api/src/boards/workers/context.py +0 -348
- package/templates/api/src/boards/workers/middleware.py +0 -58
- package/templates/api/src/py.typed +0 -0
- package/templates/compose.web.yaml +0 -35
- package/templates/compose.yaml +0 -116
- package/templates/docker/env.example +0 -23
- package/templates/web/.env.example +0 -28
- package/templates/web/Dockerfile +0 -51
- package/templates/web/components.json +0 -22
- package/templates/web/imageLoader.js +0 -18
- package/templates/web/next-env.d.ts +0 -5
- package/templates/web/next.config.js +0 -36
- package/templates/web/package.json +0 -41
- package/templates/web/postcss.config.mjs +0 -7
- package/templates/web/public/favicon.ico +0 -0
- package/templates/web/src/app/boards/[boardId]/page.tsx +0 -353
- package/templates/web/src/app/globals.css +0 -123
- package/templates/web/src/app/layout.tsx +0 -31
- package/templates/web/src/app/lineage/[generationId]/page.tsx +0 -235
- package/templates/web/src/app/page.tsx +0 -35
- package/templates/web/src/app/providers.tsx +0 -18
- package/templates/web/src/components/boards/ArtifactInputSlots.tsx +0 -206
- package/templates/web/src/components/boards/ArtifactPreview.tsx +0 -466
- package/templates/web/src/components/boards/GenerationGrid.tsx +0 -282
- package/templates/web/src/components/boards/GenerationInput.tsx +0 -370
- package/templates/web/src/components/boards/GeneratorSelector.tsx +0 -272
- package/templates/web/src/components/boards/UploadArtifact.tsx +0 -563
- package/templates/web/src/components/header.tsx +0 -32
- package/templates/web/src/components/theme-provider.tsx +0 -10
- package/templates/web/src/components/theme-toggle.tsx +0 -75
- package/templates/web/src/components/ui/alert-dialog.tsx +0 -157
- package/templates/web/src/components/ui/button.tsx +0 -58
- package/templates/web/src/components/ui/card.tsx +0 -92
- package/templates/web/src/components/ui/dropdown-menu.tsx +0 -200
- package/templates/web/src/components/ui/navigation-menu.tsx +0 -168
- package/templates/web/src/components/ui/toast.tsx +0 -128
- package/templates/web/src/components/ui/toaster.tsx +0 -35
- package/templates/web/src/components/ui/use-toast.ts +0 -187
- package/templates/web/src/hooks/useGeneratorMRU.ts +0 -57
- package/templates/web/src/lib/utils.ts +0 -6
- package/templates/web/tsconfig.json +0 -41
package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image.py
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Google Gemini 2.5 Flash Image text-to-image generator.
|
|
3
|
-
|
|
4
|
-
Google's state-of-the-art image generation and editing model available through fal.ai.
|
|
5
|
-
Supports multiple aspect ratios and output formats with batch generation up to 4 images.
|
|
6
|
-
|
|
7
|
-
Based on Fal AI's fal-ai/gemini-25-flash-image model.
|
|
8
|
-
See: https://fal.ai/models/fal-ai/gemini-25-flash-image
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import os
|
|
12
|
-
from typing import Literal
|
|
13
|
-
|
|
14
|
-
from pydantic import BaseModel, Field
|
|
15
|
-
|
|
16
|
-
from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class Gemini25FlashImageInput(BaseModel):
|
|
20
|
-
"""Input schema for Gemini 2.5 Flash Image generation."""
|
|
21
|
-
|
|
22
|
-
prompt: str = Field(
|
|
23
|
-
description="Text prompt for image generation",
|
|
24
|
-
min_length=3,
|
|
25
|
-
max_length=5000,
|
|
26
|
-
)
|
|
27
|
-
num_images: int = Field(
|
|
28
|
-
default=1,
|
|
29
|
-
ge=1,
|
|
30
|
-
le=4,
|
|
31
|
-
description="Number of images to generate (max 4)",
|
|
32
|
-
)
|
|
33
|
-
aspect_ratio: Literal[
|
|
34
|
-
"21:9",
|
|
35
|
-
"16:9",
|
|
36
|
-
"3:2",
|
|
37
|
-
"4:3",
|
|
38
|
-
"5:4",
|
|
39
|
-
"1:1",
|
|
40
|
-
"4:5",
|
|
41
|
-
"3:4",
|
|
42
|
-
"2:3",
|
|
43
|
-
"9:16",
|
|
44
|
-
] = Field(
|
|
45
|
-
default="1:1",
|
|
46
|
-
description="Image aspect ratio",
|
|
47
|
-
)
|
|
48
|
-
output_format: Literal["jpeg", "png", "webp"] = Field(
|
|
49
|
-
default="png",
|
|
50
|
-
description="Output image format",
|
|
51
|
-
)
|
|
52
|
-
sync_mode: bool = Field(
|
|
53
|
-
default=False,
|
|
54
|
-
description="Return media as data URI without request history storage",
|
|
55
|
-
)
|
|
56
|
-
limit_generations: bool = Field(
|
|
57
|
-
default=False,
|
|
58
|
-
description="Restrict to single generation per round (experimental)",
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
class FalGemini25FlashImageGenerator(BaseGenerator):
|
|
63
|
-
"""Google Gemini 2.5 Flash Image generator using fal.ai."""
|
|
64
|
-
|
|
65
|
-
name = "fal-gemini-25-flash-image"
|
|
66
|
-
artifact_type = "image"
|
|
67
|
-
description = "Fal: Gemini 2.5 Flash Image - Google's state-of-the-art text-to-image generation"
|
|
68
|
-
|
|
69
|
-
def get_input_schema(self) -> type[Gemini25FlashImageInput]:
|
|
70
|
-
return Gemini25FlashImageInput
|
|
71
|
-
|
|
72
|
-
async def generate(
|
|
73
|
-
self, inputs: Gemini25FlashImageInput, context: GeneratorExecutionContext
|
|
74
|
-
) -> GeneratorResult:
|
|
75
|
-
"""Generate images using Google Gemini 2.5 Flash Image via fal.ai."""
|
|
76
|
-
# Check for API key (fal-client uses FAL_KEY environment variable)
|
|
77
|
-
if not os.getenv("FAL_KEY"):
|
|
78
|
-
raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
|
|
79
|
-
|
|
80
|
-
# Import fal_client
|
|
81
|
-
try:
|
|
82
|
-
import fal_client
|
|
83
|
-
except ImportError as e:
|
|
84
|
-
raise ImportError(
|
|
85
|
-
"fal.ai SDK is required for FalGemini25FlashImageGenerator. "
|
|
86
|
-
"Install with: pip install weirdfingers-boards[generators-fal]"
|
|
87
|
-
) from e
|
|
88
|
-
|
|
89
|
-
# Prepare arguments for fal.ai API
|
|
90
|
-
arguments = {
|
|
91
|
-
"prompt": inputs.prompt,
|
|
92
|
-
"num_images": inputs.num_images,
|
|
93
|
-
"aspect_ratio": inputs.aspect_ratio,
|
|
94
|
-
"output_format": inputs.output_format,
|
|
95
|
-
"sync_mode": inputs.sync_mode,
|
|
96
|
-
"limit_generations": inputs.limit_generations,
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
# Submit async job and get handler
|
|
100
|
-
handler = await fal_client.submit_async(
|
|
101
|
-
"fal-ai/gemini-25-flash-image",
|
|
102
|
-
arguments=arguments,
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
# Store the external job ID for tracking
|
|
106
|
-
await context.set_external_job_id(handler.request_id)
|
|
107
|
-
|
|
108
|
-
# Stream progress updates (sample every 3rd event to avoid spam)
|
|
109
|
-
from .....progress.models import ProgressUpdate
|
|
110
|
-
|
|
111
|
-
event_count = 0
|
|
112
|
-
async for event in handler.iter_events(with_logs=True):
|
|
113
|
-
event_count += 1
|
|
114
|
-
|
|
115
|
-
# Process every 3rd event to provide feedback without overwhelming
|
|
116
|
-
if event_count % 3 == 0:
|
|
117
|
-
# Extract logs if available
|
|
118
|
-
logs = getattr(event, "logs", None)
|
|
119
|
-
if logs:
|
|
120
|
-
# Join log entries into a single message
|
|
121
|
-
if isinstance(logs, list):
|
|
122
|
-
message = " | ".join(str(log) for log in logs if log)
|
|
123
|
-
else:
|
|
124
|
-
message = str(logs)
|
|
125
|
-
|
|
126
|
-
if message:
|
|
127
|
-
await context.publish_progress(
|
|
128
|
-
ProgressUpdate(
|
|
129
|
-
job_id=handler.request_id,
|
|
130
|
-
status="processing",
|
|
131
|
-
progress=50.0, # Approximate mid-point progress
|
|
132
|
-
phase="processing",
|
|
133
|
-
message=message,
|
|
134
|
-
)
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
# Get final result
|
|
138
|
-
result = await handler.get()
|
|
139
|
-
|
|
140
|
-
# Extract image URLs from result
|
|
141
|
-
# fal.ai returns: {"images": [{"url": "...", "width": ..., "height": ..., ...}, ...]}
|
|
142
|
-
images = result.get("images", [])
|
|
143
|
-
if not images:
|
|
144
|
-
raise ValueError("No images returned from fal.ai API")
|
|
145
|
-
|
|
146
|
-
# Store each image using output_index
|
|
147
|
-
artifacts = []
|
|
148
|
-
for idx, image_data in enumerate(images):
|
|
149
|
-
image_url = image_data.get("url")
|
|
150
|
-
# Use 'or' to handle explicit None values from API
|
|
151
|
-
width = image_data.get("width") or 1024
|
|
152
|
-
height = image_data.get("height") or 1024
|
|
153
|
-
|
|
154
|
-
if not image_url:
|
|
155
|
-
raise ValueError(f"Image {idx} missing URL in fal.ai response")
|
|
156
|
-
|
|
157
|
-
# Store with appropriate output_index
|
|
158
|
-
artifact = await context.store_image_result(
|
|
159
|
-
storage_url=image_url,
|
|
160
|
-
format=inputs.output_format,
|
|
161
|
-
width=width,
|
|
162
|
-
height=height,
|
|
163
|
-
output_index=idx,
|
|
164
|
-
)
|
|
165
|
-
artifacts.append(artifact)
|
|
166
|
-
|
|
167
|
-
return GeneratorResult(outputs=artifacts)
|
|
168
|
-
|
|
169
|
-
async def estimate_cost(self, inputs: Gemini25FlashImageInput) -> float:
|
|
170
|
-
"""Estimate cost for Gemini 2.5 Flash Image generation.
|
|
171
|
-
|
|
172
|
-
TODO: Pricing information not available in fal.ai documentation.
|
|
173
|
-
This is a placeholder estimate that should be updated when pricing is known.
|
|
174
|
-
"""
|
|
175
|
-
# Placeholder cost estimate per image (to be updated with actual pricing)
|
|
176
|
-
cost_per_image = 0.00 # Unknown pricing
|
|
177
|
-
return cost_per_image * inputs.num_images
|
package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image_edit.py
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Google Gemini 2.5 Flash Image edit image-to-image generator.
|
|
3
|
-
|
|
4
|
-
Google's state-of-the-art image generation and editing model available through fal.ai.
|
|
5
|
-
Performs image-to-image transformations and edits based on text prompts.
|
|
6
|
-
Supports multiple aspect ratios and output formats with batch generation up to 4 images.
|
|
7
|
-
|
|
8
|
-
Based on Fal AI's fal-ai/gemini-25-flash-image/edit model.
|
|
9
|
-
See: https://fal.ai/models/fal-ai/gemini-25-flash-image/edit
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import os
|
|
13
|
-
from typing import Literal
|
|
14
|
-
|
|
15
|
-
from pydantic import BaseModel, Field
|
|
16
|
-
|
|
17
|
-
from ....artifacts import ImageArtifact
|
|
18
|
-
from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class Gemini25FlashImageEditInput(BaseModel):
|
|
22
|
-
"""Input schema for Gemini 2.5 Flash Image edit generation.
|
|
23
|
-
|
|
24
|
-
Artifact fields (like image_sources) are automatically detected via type
|
|
25
|
-
introspection and resolved from generation IDs to ImageArtifact objects.
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
prompt: str = Field(
|
|
29
|
-
description="The editing instruction for image transformation",
|
|
30
|
-
min_length=3,
|
|
31
|
-
max_length=5000,
|
|
32
|
-
)
|
|
33
|
-
image_sources: list[ImageArtifact] = Field(
|
|
34
|
-
description="List of input images for editing (from previous generations)",
|
|
35
|
-
min_length=1,
|
|
36
|
-
)
|
|
37
|
-
num_images: int = Field(
|
|
38
|
-
default=1,
|
|
39
|
-
ge=1,
|
|
40
|
-
le=4,
|
|
41
|
-
description="Number of images to generate (max 4)",
|
|
42
|
-
)
|
|
43
|
-
aspect_ratio: (
|
|
44
|
-
Literal[
|
|
45
|
-
"auto",
|
|
46
|
-
"21:9",
|
|
47
|
-
"16:9",
|
|
48
|
-
"3:2",
|
|
49
|
-
"4:3",
|
|
50
|
-
"5:4",
|
|
51
|
-
"1:1",
|
|
52
|
-
"4:5",
|
|
53
|
-
"3:4",
|
|
54
|
-
"2:3",
|
|
55
|
-
"9:16",
|
|
56
|
-
]
|
|
57
|
-
| None
|
|
58
|
-
) = Field(
|
|
59
|
-
default="auto",
|
|
60
|
-
description="Image aspect ratio. Default 'auto' uses input image's aspect ratio.",
|
|
61
|
-
)
|
|
62
|
-
output_format: Literal["jpeg", "png", "webp"] = Field(
|
|
63
|
-
default="png",
|
|
64
|
-
description="Output image format",
|
|
65
|
-
)
|
|
66
|
-
sync_mode: bool = Field(
|
|
67
|
-
default=False,
|
|
68
|
-
description="Return media as data URI without request history storage",
|
|
69
|
-
)
|
|
70
|
-
limit_generations: bool = Field(
|
|
71
|
-
default=False,
|
|
72
|
-
description="Restrict to single generation per round (experimental)",
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
class FalGemini25FlashImageEditGenerator(BaseGenerator):
|
|
77
|
-
"""Google Gemini 2.5 Flash Image edit generator using fal.ai."""
|
|
78
|
-
|
|
79
|
-
name = "fal-gemini-25-flash-image-edit"
|
|
80
|
-
artifact_type = "image"
|
|
81
|
-
description = "Fal: Gemini 2.5 Flash Image Edit - AI-powered image editing with Gemini"
|
|
82
|
-
|
|
83
|
-
def get_input_schema(self) -> type[Gemini25FlashImageEditInput]:
|
|
84
|
-
return Gemini25FlashImageEditInput
|
|
85
|
-
|
|
86
|
-
async def generate(
|
|
87
|
-
self, inputs: Gemini25FlashImageEditInput, context: GeneratorExecutionContext
|
|
88
|
-
) -> GeneratorResult:
|
|
89
|
-
"""Edit images using Google Gemini 2.5 Flash Image via fal.ai."""
|
|
90
|
-
# Check for API key (fal-client uses FAL_KEY environment variable)
|
|
91
|
-
if not os.getenv("FAL_KEY"):
|
|
92
|
-
raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
|
|
93
|
-
|
|
94
|
-
# Import fal_client
|
|
95
|
-
try:
|
|
96
|
-
import fal_client
|
|
97
|
-
except ImportError as e:
|
|
98
|
-
raise ImportError(
|
|
99
|
-
"fal.ai SDK is required for FalGemini25FlashImageEditGenerator. "
|
|
100
|
-
"Install with: pip install weirdfingers-boards[generators-fal]"
|
|
101
|
-
) from e
|
|
102
|
-
|
|
103
|
-
# Upload image artifacts to Fal's public storage
|
|
104
|
-
# Fal API requires publicly accessible URLs, but our storage_url might be:
|
|
105
|
-
# - Localhost URLs (not publicly accessible)
|
|
106
|
-
# - Private S3 buckets (not publicly accessible)
|
|
107
|
-
# So we upload to Fal's temporary storage first
|
|
108
|
-
from ..utils import upload_artifacts_to_fal
|
|
109
|
-
|
|
110
|
-
image_urls = await upload_artifacts_to_fal(inputs.image_sources, context)
|
|
111
|
-
|
|
112
|
-
# Prepare arguments for fal.ai API
|
|
113
|
-
arguments = {
|
|
114
|
-
"prompt": inputs.prompt,
|
|
115
|
-
"image_urls": image_urls,
|
|
116
|
-
"num_images": inputs.num_images,
|
|
117
|
-
"output_format": inputs.output_format,
|
|
118
|
-
"sync_mode": inputs.sync_mode,
|
|
119
|
-
"limit_generations": inputs.limit_generations,
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
# Add aspect_ratio if provided
|
|
123
|
-
if inputs.aspect_ratio is not None:
|
|
124
|
-
arguments["aspect_ratio"] = inputs.aspect_ratio
|
|
125
|
-
|
|
126
|
-
# Submit async job and get handler
|
|
127
|
-
handler = await fal_client.submit_async(
|
|
128
|
-
"fal-ai/gemini-25-flash-image/edit",
|
|
129
|
-
arguments=arguments,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
# Store the external job ID for tracking
|
|
133
|
-
await context.set_external_job_id(handler.request_id)
|
|
134
|
-
|
|
135
|
-
# Stream progress updates (sample every 3rd event to avoid spam)
|
|
136
|
-
from .....progress.models import ProgressUpdate
|
|
137
|
-
|
|
138
|
-
event_count = 0
|
|
139
|
-
async for event in handler.iter_events(with_logs=True):
|
|
140
|
-
event_count += 1
|
|
141
|
-
|
|
142
|
-
# Process every 3rd event to provide feedback without overwhelming
|
|
143
|
-
if event_count % 3 == 0:
|
|
144
|
-
# Extract logs if available
|
|
145
|
-
logs = getattr(event, "logs", None)
|
|
146
|
-
if logs:
|
|
147
|
-
# Join log entries into a single message
|
|
148
|
-
if isinstance(logs, list):
|
|
149
|
-
message = " | ".join(str(log) for log in logs if log)
|
|
150
|
-
else:
|
|
151
|
-
message = str(logs)
|
|
152
|
-
|
|
153
|
-
if message:
|
|
154
|
-
await context.publish_progress(
|
|
155
|
-
ProgressUpdate(
|
|
156
|
-
job_id=handler.request_id,
|
|
157
|
-
status="processing",
|
|
158
|
-
progress=50.0, # Approximate mid-point progress
|
|
159
|
-
phase="processing",
|
|
160
|
-
message=message,
|
|
161
|
-
)
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
# Get final result
|
|
165
|
-
result = await handler.get()
|
|
166
|
-
|
|
167
|
-
# Extract image URLs and description from result
|
|
168
|
-
# fal.ai returns: {
|
|
169
|
-
# "images": [{"url": "...", "width": ..., "height": ..., ...}, ...],
|
|
170
|
-
# "description": "Text description from Gemini"
|
|
171
|
-
# }
|
|
172
|
-
images = result.get("images", [])
|
|
173
|
-
|
|
174
|
-
if not images:
|
|
175
|
-
raise ValueError("No images returned from fal.ai API")
|
|
176
|
-
|
|
177
|
-
# Store each image using output_index
|
|
178
|
-
artifacts = []
|
|
179
|
-
for idx, image_data in enumerate(images):
|
|
180
|
-
image_url = image_data.get("url")
|
|
181
|
-
# Use 'or' to handle explicit None values from API
|
|
182
|
-
width = image_data.get("width") or 1024
|
|
183
|
-
height = image_data.get("height") or 1024
|
|
184
|
-
|
|
185
|
-
if not image_url:
|
|
186
|
-
raise ValueError(f"Image {idx} missing URL in fal.ai response")
|
|
187
|
-
|
|
188
|
-
# Store with appropriate output_index
|
|
189
|
-
artifact = await context.store_image_result(
|
|
190
|
-
storage_url=image_url,
|
|
191
|
-
format=inputs.output_format,
|
|
192
|
-
width=width,
|
|
193
|
-
height=height,
|
|
194
|
-
output_index=idx,
|
|
195
|
-
)
|
|
196
|
-
artifacts.append(artifact)
|
|
197
|
-
|
|
198
|
-
return GeneratorResult(outputs=artifacts)
|
|
199
|
-
|
|
200
|
-
async def estimate_cost(self, inputs: Gemini25FlashImageEditInput) -> float:
|
|
201
|
-
"""Estimate cost for Gemini 2.5 Flash Image edit generation.
|
|
202
|
-
|
|
203
|
-
Note: Pricing information not available in fal.ai documentation.
|
|
204
|
-
Using placeholder estimate similar to other Gemini-based models.
|
|
205
|
-
"""
|
|
206
|
-
# Placeholder cost estimate per image (similar to nano-banana which also uses Gemini)
|
|
207
|
-
per_image_cost = 0.039
|
|
208
|
-
return per_image_cost * inputs.num_images
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
fal.ai GPT-Image-1.5 image editing generator.
|
|
3
|
-
|
|
4
|
-
Edit images using OpenAI's GPT-Image-1.5 model via fal.ai.
|
|
5
|
-
Based on Fal AI's fal-ai/gpt-image-1.5/edit model.
|
|
6
|
-
See: https://fal.ai/models/fal-ai/gpt-image-1.5/edit
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import os
|
|
10
|
-
from typing import Literal
|
|
11
|
-
|
|
12
|
-
from pydantic import BaseModel, Field
|
|
13
|
-
|
|
14
|
-
from ....artifacts import ImageArtifact
|
|
15
|
-
from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class GptImage15EditInput(BaseModel):
|
|
19
|
-
"""Input schema for GPT-Image-1.5 image editing.
|
|
20
|
-
|
|
21
|
-
Artifact fields are automatically detected via type introspection
|
|
22
|
-
and resolved from generation IDs to artifact objects.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
prompt: str = Field(
|
|
26
|
-
description="Edit instruction for transforming the input images",
|
|
27
|
-
min_length=2,
|
|
28
|
-
max_length=32000,
|
|
29
|
-
)
|
|
30
|
-
image_urls: list[ImageArtifact] = Field(
|
|
31
|
-
description="URLs of images to use as reference for editing",
|
|
32
|
-
min_length=1,
|
|
33
|
-
)
|
|
34
|
-
mask_image_url: ImageArtifact | None = Field(
|
|
35
|
-
default=None,
|
|
36
|
-
description="Optional mask image to specify the area to edit",
|
|
37
|
-
)
|
|
38
|
-
num_images: int = Field(
|
|
39
|
-
default=1,
|
|
40
|
-
ge=1,
|
|
41
|
-
le=4,
|
|
42
|
-
description="Number of edited images to generate (1-4)",
|
|
43
|
-
)
|
|
44
|
-
image_size: Literal["auto", "1024x1024", "1536x1024", "1024x1536"] = Field(
|
|
45
|
-
default="auto",
|
|
46
|
-
description="Size of the output images",
|
|
47
|
-
)
|
|
48
|
-
quality: Literal["low", "medium", "high"] = Field(
|
|
49
|
-
default="high",
|
|
50
|
-
description="Quality level of the output images",
|
|
51
|
-
)
|
|
52
|
-
input_fidelity: Literal["low", "high"] = Field(
|
|
53
|
-
default="high",
|
|
54
|
-
description="How closely to follow the input image",
|
|
55
|
-
)
|
|
56
|
-
output_format: Literal["jpeg", "png", "webp"] = Field(
|
|
57
|
-
default="png",
|
|
58
|
-
description="Output image format",
|
|
59
|
-
)
|
|
60
|
-
background: Literal["auto", "transparent", "opaque"] = Field(
|
|
61
|
-
default="auto",
|
|
62
|
-
description="Background handling for the output images",
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class FalGptImage15EditGenerator(BaseGenerator):
|
|
67
|
-
"""Generator for OpenAI's GPT-Image-1.5 image editing via fal.ai."""
|
|
68
|
-
|
|
69
|
-
name = "fal-gpt-image-15-edit"
|
|
70
|
-
description = "Fal: GPT-Image-1.5 Edit - OpenAI's latest image editing model"
|
|
71
|
-
artifact_type = "image"
|
|
72
|
-
|
|
73
|
-
def get_input_schema(self) -> type[GptImage15EditInput]:
|
|
74
|
-
"""Return the input schema for this generator."""
|
|
75
|
-
return GptImage15EditInput
|
|
76
|
-
|
|
77
|
-
async def generate(
|
|
78
|
-
self, inputs: GptImage15EditInput, context: GeneratorExecutionContext
|
|
79
|
-
) -> GeneratorResult:
|
|
80
|
-
"""Generate edited images using fal.ai GPT-Image-1.5."""
|
|
81
|
-
# Check for API key
|
|
82
|
-
if not os.getenv("FAL_KEY"):
|
|
83
|
-
raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
|
|
84
|
-
|
|
85
|
-
# Import fal_client
|
|
86
|
-
try:
|
|
87
|
-
import fal_client
|
|
88
|
-
except ImportError as e:
|
|
89
|
-
raise ImportError(
|
|
90
|
-
"fal.ai SDK is required for FalGptImage15EditGenerator. "
|
|
91
|
-
"Install with: pip install weirdfingers-boards[generators-fal]"
|
|
92
|
-
) from e
|
|
93
|
-
|
|
94
|
-
# Upload image artifacts to Fal's public storage
|
|
95
|
-
# Fal API requires publicly accessible URLs
|
|
96
|
-
from ..utils import upload_artifacts_to_fal
|
|
97
|
-
|
|
98
|
-
image_urls = await upload_artifacts_to_fal(inputs.image_urls, context)
|
|
99
|
-
|
|
100
|
-
# Upload mask image if provided
|
|
101
|
-
mask_image_url = None
|
|
102
|
-
if inputs.mask_image_url is not None:
|
|
103
|
-
mask_urls = await upload_artifacts_to_fal([inputs.mask_image_url], context)
|
|
104
|
-
mask_image_url = mask_urls[0] if mask_urls else None
|
|
105
|
-
|
|
106
|
-
# Prepare arguments for fal.ai API
|
|
107
|
-
arguments: dict = {
|
|
108
|
-
"prompt": inputs.prompt,
|
|
109
|
-
"image_urls": image_urls,
|
|
110
|
-
"num_images": inputs.num_images,
|
|
111
|
-
"image_size": inputs.image_size,
|
|
112
|
-
"quality": inputs.quality,
|
|
113
|
-
"input_fidelity": inputs.input_fidelity,
|
|
114
|
-
"output_format": inputs.output_format,
|
|
115
|
-
"background": inputs.background,
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
# Add mask image if provided
|
|
119
|
-
if mask_image_url is not None:
|
|
120
|
-
arguments["mask_image_url"] = mask_image_url
|
|
121
|
-
|
|
122
|
-
# Submit async job
|
|
123
|
-
handler = await fal_client.submit_async(
|
|
124
|
-
"fal-ai/gpt-image-1.5/edit",
|
|
125
|
-
arguments=arguments,
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
# Store external job ID
|
|
129
|
-
await context.set_external_job_id(handler.request_id)
|
|
130
|
-
|
|
131
|
-
# Stream progress updates
|
|
132
|
-
from .....progress.models import ProgressUpdate
|
|
133
|
-
|
|
134
|
-
event_count = 0
|
|
135
|
-
async for event in handler.iter_events(with_logs=True):
|
|
136
|
-
event_count += 1
|
|
137
|
-
# Sample every 3rd event to avoid spam
|
|
138
|
-
if event_count % 3 == 0:
|
|
139
|
-
logs = getattr(event, "logs", None)
|
|
140
|
-
if logs:
|
|
141
|
-
# Join log entries into a single message
|
|
142
|
-
if isinstance(logs, list):
|
|
143
|
-
message = " | ".join(str(log) for log in logs if log)
|
|
144
|
-
else:
|
|
145
|
-
message = str(logs)
|
|
146
|
-
|
|
147
|
-
if message:
|
|
148
|
-
await context.publish_progress(
|
|
149
|
-
ProgressUpdate(
|
|
150
|
-
job_id=handler.request_id,
|
|
151
|
-
status="processing",
|
|
152
|
-
progress=50.0,
|
|
153
|
-
phase="processing",
|
|
154
|
-
message=message,
|
|
155
|
-
)
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
# Get final result
|
|
159
|
-
result = await handler.get()
|
|
160
|
-
|
|
161
|
-
# Extract images from result
|
|
162
|
-
# Response structure: {"images": [{"url": "...", "width": 1024, "height": 1024, ...}, ...]}
|
|
163
|
-
images = result.get("images", [])
|
|
164
|
-
|
|
165
|
-
if not images:
|
|
166
|
-
raise ValueError("No images returned from fal.ai API")
|
|
167
|
-
|
|
168
|
-
# Store each image using output_index
|
|
169
|
-
artifacts = []
|
|
170
|
-
for idx, image_data in enumerate(images):
|
|
171
|
-
image_url = image_data.get("url")
|
|
172
|
-
width = image_data.get("width", 1024)
|
|
173
|
-
height = image_data.get("height", 1024)
|
|
174
|
-
|
|
175
|
-
if not image_url:
|
|
176
|
-
raise ValueError(f"Image {idx} missing URL in fal.ai response")
|
|
177
|
-
|
|
178
|
-
# Determine format from content_type if available, otherwise use input format
|
|
179
|
-
format = inputs.output_format
|
|
180
|
-
if "content_type" in image_data:
|
|
181
|
-
content_type = image_data["content_type"]
|
|
182
|
-
if "jpeg" in content_type:
|
|
183
|
-
format = "jpeg"
|
|
184
|
-
elif "webp" in content_type:
|
|
185
|
-
format = "webp"
|
|
186
|
-
elif "png" in content_type:
|
|
187
|
-
format = "png"
|
|
188
|
-
|
|
189
|
-
artifact = await context.store_image_result(
|
|
190
|
-
storage_url=image_url,
|
|
191
|
-
format=format,
|
|
192
|
-
width=width,
|
|
193
|
-
height=height,
|
|
194
|
-
output_index=idx,
|
|
195
|
-
)
|
|
196
|
-
artifacts.append(artifact)
|
|
197
|
-
|
|
198
|
-
return GeneratorResult(outputs=artifacts)
|
|
199
|
-
|
|
200
|
-
async def estimate_cost(self, inputs: GptImage15EditInput) -> float:
|
|
201
|
-
"""Estimate cost for GPT-Image-1.5 edit generation.
|
|
202
|
-
|
|
203
|
-
Pricing varies by quality and image size:
|
|
204
|
-
- Low Quality: $0.009-$0.013 per image
|
|
205
|
-
- Medium Quality: $0.034-$0.051 per image
|
|
206
|
-
- High Quality: $0.133-$0.200 per image
|
|
207
|
-
"""
|
|
208
|
-
# Base costs by quality (using 1024x1024 as reference)
|
|
209
|
-
quality_costs = {
|
|
210
|
-
"low": 0.011, # Average of $0.009-$0.013
|
|
211
|
-
"medium": 0.045, # Average of $0.034-$0.051
|
|
212
|
-
"high": 0.177, # Average of $0.133-$0.200
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
per_image_cost = quality_costs.get(inputs.quality, 0.177)
|
|
216
|
-
return per_image_cost * inputs.num_images
|