@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
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
fal.ai clarity-upscaler image upscaling generator.
|
|
3
|
-
|
|
4
|
-
Upscale images with high fidelity using fal.ai's clarity-upscaler model.
|
|
5
|
-
Supports upscaling factors from 1x to 4x with configurable creativity and resemblance.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import os
|
|
9
|
-
|
|
10
|
-
from pydantic import BaseModel, Field
|
|
11
|
-
|
|
12
|
-
from ....artifacts import ImageArtifact
|
|
13
|
-
from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class ClarityUpscalerInput(BaseModel):
|
|
17
|
-
"""Input schema for clarity upscaler.
|
|
18
|
-
|
|
19
|
-
Artifact fields (like image_url) are automatically detected via type
|
|
20
|
-
introspection and resolved from generation IDs to ImageArtifact objects.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
image_url: ImageArtifact = Field(
|
|
24
|
-
description="The input image to upscale (from a previous generation)"
|
|
25
|
-
)
|
|
26
|
-
prompt: str = Field(
|
|
27
|
-
default="masterpiece, best quality, highres",
|
|
28
|
-
description="Descriptive text guiding the upscaling generation",
|
|
29
|
-
)
|
|
30
|
-
upscale_factor: float = Field(
|
|
31
|
-
default=2.0,
|
|
32
|
-
ge=1.0,
|
|
33
|
-
le=4.0,
|
|
34
|
-
description="Scaling multiplier for the upscaling (1-4x)",
|
|
35
|
-
)
|
|
36
|
-
negative_prompt: str = Field(
|
|
37
|
-
default="(worst quality, low quality, normal quality:2)",
|
|
38
|
-
description="Text describing unwanted details in the output",
|
|
39
|
-
)
|
|
40
|
-
creativity: float = Field(
|
|
41
|
-
default=0.35,
|
|
42
|
-
ge=0.0,
|
|
43
|
-
le=1.0,
|
|
44
|
-
description="Deviation from prompt strength (0-1)",
|
|
45
|
-
)
|
|
46
|
-
resemblance: float = Field(
|
|
47
|
-
default=0.6,
|
|
48
|
-
ge=0.0,
|
|
49
|
-
le=1.0,
|
|
50
|
-
description="The strength of the ControlNet for fidelity to original (0-1)",
|
|
51
|
-
)
|
|
52
|
-
guidance_scale: float = Field(
|
|
53
|
-
default=4.0,
|
|
54
|
-
ge=0.0,
|
|
55
|
-
le=20.0,
|
|
56
|
-
description="CFG scale for prompt adherence (0-20)",
|
|
57
|
-
)
|
|
58
|
-
num_inference_steps: int = Field(
|
|
59
|
-
default=18,
|
|
60
|
-
ge=4,
|
|
61
|
-
le=50,
|
|
62
|
-
description="Number of processing iterations (4-50)",
|
|
63
|
-
)
|
|
64
|
-
seed: int | None = Field(
|
|
65
|
-
default=None,
|
|
66
|
-
description="Random seed for reproducibility",
|
|
67
|
-
)
|
|
68
|
-
enable_safety_checker: bool = Field(
|
|
69
|
-
default=True,
|
|
70
|
-
description="Enable content filtering",
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class FalClarityUpscalerGenerator(BaseGenerator):
|
|
75
|
-
"""Clarity upscaler generator using fal.ai."""
|
|
76
|
-
|
|
77
|
-
name = "fal-clarity-upscaler"
|
|
78
|
-
artifact_type = "image"
|
|
79
|
-
description = "Fal: Clarity upscaler - High fidelity image upscaling (1-4x)"
|
|
80
|
-
|
|
81
|
-
def get_input_schema(self) -> type[ClarityUpscalerInput]:
|
|
82
|
-
return ClarityUpscalerInput
|
|
83
|
-
|
|
84
|
-
async def generate(
|
|
85
|
-
self, inputs: ClarityUpscalerInput, context: GeneratorExecutionContext
|
|
86
|
-
) -> GeneratorResult:
|
|
87
|
-
"""Upscale images using fal.ai clarity-upscaler model."""
|
|
88
|
-
# Check for API key (fal-client uses FAL_KEY environment variable)
|
|
89
|
-
if not os.getenv("FAL_KEY"):
|
|
90
|
-
raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
|
|
91
|
-
|
|
92
|
-
# Import fal_client
|
|
93
|
-
try:
|
|
94
|
-
import fal_client
|
|
95
|
-
except ImportError as e:
|
|
96
|
-
raise ImportError(
|
|
97
|
-
"fal.ai SDK is required for FalClarityUpscalerGenerator. "
|
|
98
|
-
"Install with: pip install weirdfingers-boards[generators-fal]"
|
|
99
|
-
) from e
|
|
100
|
-
|
|
101
|
-
# Upload image artifact to Fal's public storage
|
|
102
|
-
# Fal API requires publicly accessible URLs, but our storage_url might be:
|
|
103
|
-
# - Localhost URLs (not publicly accessible)
|
|
104
|
-
# - Private S3 buckets (not publicly accessible)
|
|
105
|
-
# So we upload to Fal's temporary storage first
|
|
106
|
-
from ..utils import upload_artifacts_to_fal
|
|
107
|
-
|
|
108
|
-
# upload_artifacts_to_fal expects a list, so wrap the single image
|
|
109
|
-
image_urls = await upload_artifacts_to_fal([inputs.image_url], context)
|
|
110
|
-
image_url = image_urls[0] # Extract the single URL
|
|
111
|
-
|
|
112
|
-
# Prepare arguments for fal.ai API
|
|
113
|
-
arguments = {
|
|
114
|
-
"image_url": image_url,
|
|
115
|
-
"prompt": inputs.prompt,
|
|
116
|
-
"upscale_factor": inputs.upscale_factor,
|
|
117
|
-
"negative_prompt": inputs.negative_prompt,
|
|
118
|
-
"creativity": inputs.creativity,
|
|
119
|
-
"resemblance": inputs.resemblance,
|
|
120
|
-
"guidance_scale": inputs.guidance_scale,
|
|
121
|
-
"num_inference_steps": inputs.num_inference_steps,
|
|
122
|
-
"enable_safety_checker": inputs.enable_safety_checker,
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
# Add seed if provided
|
|
126
|
-
if inputs.seed is not None:
|
|
127
|
-
arguments["seed"] = inputs.seed
|
|
128
|
-
|
|
129
|
-
# Submit async job and get handler
|
|
130
|
-
handler = await fal_client.submit_async(
|
|
131
|
-
"fal-ai/clarity-upscaler",
|
|
132
|
-
arguments=arguments,
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
# Store the external job ID for tracking
|
|
136
|
-
await context.set_external_job_id(handler.request_id)
|
|
137
|
-
|
|
138
|
-
# Stream progress updates (sample every 3rd event to avoid spam)
|
|
139
|
-
from .....progress.models import ProgressUpdate
|
|
140
|
-
|
|
141
|
-
event_count = 0
|
|
142
|
-
async for event in handler.iter_events(with_logs=True):
|
|
143
|
-
event_count += 1
|
|
144
|
-
|
|
145
|
-
# Process every 3rd event to provide feedback without overwhelming
|
|
146
|
-
if event_count % 3 == 0:
|
|
147
|
-
# Extract logs if available
|
|
148
|
-
logs = getattr(event, "logs", None)
|
|
149
|
-
if logs:
|
|
150
|
-
# Join log entries into a single message
|
|
151
|
-
if isinstance(logs, list):
|
|
152
|
-
message = " | ".join(str(log) for log in logs if log)
|
|
153
|
-
else:
|
|
154
|
-
message = str(logs)
|
|
155
|
-
|
|
156
|
-
if message:
|
|
157
|
-
await context.publish_progress(
|
|
158
|
-
ProgressUpdate(
|
|
159
|
-
job_id=handler.request_id,
|
|
160
|
-
status="processing",
|
|
161
|
-
progress=50.0, # Approximate mid-point progress
|
|
162
|
-
phase="processing",
|
|
163
|
-
message=message,
|
|
164
|
-
)
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
# Get final result
|
|
168
|
-
result = await handler.get()
|
|
169
|
-
|
|
170
|
-
# Extract image from result
|
|
171
|
-
# fal.ai returns: {
|
|
172
|
-
# "image": {"url": "...", "width": ..., "height": ...},
|
|
173
|
-
# "seed": 12345,
|
|
174
|
-
# "timings": {...}
|
|
175
|
-
# }
|
|
176
|
-
image_data = result.get("image")
|
|
177
|
-
|
|
178
|
-
if not image_data:
|
|
179
|
-
raise ValueError("No image returned from fal.ai API")
|
|
180
|
-
|
|
181
|
-
image_url = image_data.get("url")
|
|
182
|
-
if not image_url:
|
|
183
|
-
raise ValueError("Image missing URL in fal.ai response")
|
|
184
|
-
|
|
185
|
-
# Extract dimensions if available
|
|
186
|
-
width = image_data.get("width")
|
|
187
|
-
height = image_data.get("height")
|
|
188
|
-
|
|
189
|
-
# If dimensions are not in the response, calculate from upscale factor
|
|
190
|
-
if width is None or height is None:
|
|
191
|
-
# Use original image dimensions multiplied by upscale factor
|
|
192
|
-
original_width = inputs.image_url.width
|
|
193
|
-
original_height = inputs.image_url.height
|
|
194
|
-
if original_width and original_height:
|
|
195
|
-
width = int(original_width * inputs.upscale_factor)
|
|
196
|
-
height = int(original_height * inputs.upscale_factor)
|
|
197
|
-
else:
|
|
198
|
-
# Fallback to reasonable defaults
|
|
199
|
-
width = 2048
|
|
200
|
-
height = 2048
|
|
201
|
-
|
|
202
|
-
# Store the upscaled image
|
|
203
|
-
artifact = await context.store_image_result(
|
|
204
|
-
storage_url=image_url,
|
|
205
|
-
format="png", # Clarity upscaler outputs PNG
|
|
206
|
-
width=width,
|
|
207
|
-
height=height,
|
|
208
|
-
output_index=0,
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
return GeneratorResult(outputs=[artifact])
|
|
212
|
-
|
|
213
|
-
async def estimate_cost(self, inputs: ClarityUpscalerInput) -> float:
|
|
214
|
-
"""Estimate cost for clarity upscaler generation.
|
|
215
|
-
|
|
216
|
-
Based on typical Fal image upscaling model pricing.
|
|
217
|
-
"""
|
|
218
|
-
# Estimated cost per upscale operation
|
|
219
|
-
# Using a conservative estimate based on similar Fal upscaling models
|
|
220
|
-
return 0.05
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
fal.ai Crystal Upscaler - Advanced image enhancement for facial details and portraits.
|
|
3
|
-
|
|
4
|
-
Upscales images with specialized enhancement for facial details using Clarity AI's
|
|
5
|
-
upscaling technology. Supports scale factors from 1x to 200x.
|
|
6
|
-
|
|
7
|
-
Based on Fal AI's fal-ai/crystal-upscaler model.
|
|
8
|
-
See: https://fal.ai/models/fal-ai/crystal-upscaler
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import os
|
|
12
|
-
|
|
13
|
-
from pydantic import BaseModel, Field
|
|
14
|
-
|
|
15
|
-
from ....artifacts import ImageArtifact
|
|
16
|
-
from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class CrystalUpscalerInput(BaseModel):
|
|
20
|
-
"""Input schema for crystal-upscaler.
|
|
21
|
-
|
|
22
|
-
Artifact fields (like image_url) are automatically detected via type
|
|
23
|
-
introspection and resolved from generation IDs to ImageArtifact objects.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
image_url: ImageArtifact = Field(
|
|
27
|
-
description="Input image to upscale (from a previous generation)"
|
|
28
|
-
)
|
|
29
|
-
scale_factor: int = Field(
|
|
30
|
-
default=2,
|
|
31
|
-
ge=1,
|
|
32
|
-
le=200,
|
|
33
|
-
description="Scale factor for upscaling (1-200)",
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class FalCrystalUpscalerGenerator(BaseGenerator):
|
|
38
|
-
"""Crystal Upscaler generator using fal.ai."""
|
|
39
|
-
|
|
40
|
-
name = "fal-crystal-upscaler"
|
|
41
|
-
artifact_type = "image"
|
|
42
|
-
description = "Fal: Crystal Upscaler - Advanced image enhancement for facial details"
|
|
43
|
-
|
|
44
|
-
def get_input_schema(self) -> type[CrystalUpscalerInput]:
|
|
45
|
-
return CrystalUpscalerInput
|
|
46
|
-
|
|
47
|
-
async def generate(
|
|
48
|
-
self, inputs: CrystalUpscalerInput, context: GeneratorExecutionContext
|
|
49
|
-
) -> GeneratorResult:
|
|
50
|
-
"""Upscale image using fal.ai crystal-upscaler model."""
|
|
51
|
-
# Check for API key (fal-client uses FAL_KEY environment variable)
|
|
52
|
-
if not os.getenv("FAL_KEY"):
|
|
53
|
-
raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
|
|
54
|
-
|
|
55
|
-
# Import fal_client
|
|
56
|
-
try:
|
|
57
|
-
import fal_client
|
|
58
|
-
except ImportError as e:
|
|
59
|
-
raise ImportError(
|
|
60
|
-
"fal.ai SDK is required for FalCrystalUpscalerGenerator. "
|
|
61
|
-
"Install with: pip install weirdfingers-boards[generators-fal]"
|
|
62
|
-
) from e
|
|
63
|
-
|
|
64
|
-
# Upload image artifact to Fal's public storage
|
|
65
|
-
# Fal API requires publicly accessible URLs, but our storage_url might be:
|
|
66
|
-
# - Localhost URLs (not publicly accessible)
|
|
67
|
-
# - Private S3 buckets (not publicly accessible)
|
|
68
|
-
# So we upload to Fal's temporary storage first
|
|
69
|
-
from ..utils import upload_artifacts_to_fal
|
|
70
|
-
|
|
71
|
-
# upload_artifacts_to_fal expects a list, returns a list
|
|
72
|
-
image_urls = await upload_artifacts_to_fal([inputs.image_url], context)
|
|
73
|
-
image_url = image_urls[0]
|
|
74
|
-
|
|
75
|
-
# Prepare arguments for fal.ai API
|
|
76
|
-
arguments = {
|
|
77
|
-
"image_url": image_url,
|
|
78
|
-
"scale_factor": inputs.scale_factor,
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
# Submit async job and get handler
|
|
82
|
-
handler = await fal_client.submit_async(
|
|
83
|
-
"fal-ai/crystal-upscaler",
|
|
84
|
-
arguments=arguments,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
# Store the external job ID for tracking
|
|
88
|
-
await context.set_external_job_id(handler.request_id)
|
|
89
|
-
|
|
90
|
-
# Stream progress updates (sample every 3rd event to avoid spam)
|
|
91
|
-
from .....progress.models import ProgressUpdate
|
|
92
|
-
|
|
93
|
-
event_count = 0
|
|
94
|
-
async for event in handler.iter_events(with_logs=True):
|
|
95
|
-
event_count += 1
|
|
96
|
-
|
|
97
|
-
# Process every 3rd event to provide feedback without overwhelming
|
|
98
|
-
if event_count % 3 == 0:
|
|
99
|
-
# Extract logs if available
|
|
100
|
-
logs = getattr(event, "logs", None)
|
|
101
|
-
if logs:
|
|
102
|
-
# Join log entries into a single message
|
|
103
|
-
if isinstance(logs, list):
|
|
104
|
-
message = " | ".join(str(log) for log in logs if log)
|
|
105
|
-
else:
|
|
106
|
-
message = str(logs)
|
|
107
|
-
|
|
108
|
-
if message:
|
|
109
|
-
await context.publish_progress(
|
|
110
|
-
ProgressUpdate(
|
|
111
|
-
job_id=handler.request_id,
|
|
112
|
-
status="processing",
|
|
113
|
-
progress=50.0, # Approximate mid-point progress
|
|
114
|
-
phase="processing",
|
|
115
|
-
message=message,
|
|
116
|
-
)
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
# Get final result
|
|
120
|
-
result = await handler.get()
|
|
121
|
-
|
|
122
|
-
# Extract image URLs from result
|
|
123
|
-
# fal.ai returns: {
|
|
124
|
-
# "images": [{"url": "...", "width": ..., "height": ..., ...}]
|
|
125
|
-
# }
|
|
126
|
-
images = result.get("images", [])
|
|
127
|
-
|
|
128
|
-
if not images:
|
|
129
|
-
raise ValueError("No images returned from fal.ai API")
|
|
130
|
-
|
|
131
|
-
# Store each image using output_index
|
|
132
|
-
artifacts = []
|
|
133
|
-
for idx, image_data in enumerate(images):
|
|
134
|
-
image_url = image_data.get("url")
|
|
135
|
-
# Extract dimensions from response
|
|
136
|
-
width = image_data.get("width")
|
|
137
|
-
height = image_data.get("height")
|
|
138
|
-
|
|
139
|
-
if not image_url:
|
|
140
|
-
raise ValueError(f"Image {idx} missing URL in fal.ai response")
|
|
141
|
-
|
|
142
|
-
# Determine format from content_type or use png as default
|
|
143
|
-
content_type = image_data.get("content_type", "image/png")
|
|
144
|
-
format_map = {
|
|
145
|
-
"image/jpeg": "jpeg",
|
|
146
|
-
"image/jpg": "jpeg",
|
|
147
|
-
"image/png": "png",
|
|
148
|
-
"image/webp": "webp",
|
|
149
|
-
}
|
|
150
|
-
format = format_map.get(content_type, "png")
|
|
151
|
-
|
|
152
|
-
# Store with appropriate output_index
|
|
153
|
-
artifact = await context.store_image_result(
|
|
154
|
-
storage_url=image_url,
|
|
155
|
-
format=format,
|
|
156
|
-
width=width,
|
|
157
|
-
height=height,
|
|
158
|
-
output_index=idx,
|
|
159
|
-
)
|
|
160
|
-
artifacts.append(artifact)
|
|
161
|
-
|
|
162
|
-
return GeneratorResult(outputs=artifacts)
|
|
163
|
-
|
|
164
|
-
async def estimate_cost(self, inputs: CrystalUpscalerInput) -> float:
|
|
165
|
-
"""Estimate cost for crystal upscaler generation.
|
|
166
|
-
|
|
167
|
-
Using a conservative estimate for image upscaling operations.
|
|
168
|
-
Actual cost may vary based on image size and scale factor.
|
|
169
|
-
"""
|
|
170
|
-
# Base cost per upscale operation
|
|
171
|
-
# Higher scale factors may cost more, but using fixed cost for now
|
|
172
|
-
base_cost = 0.05
|
|
173
|
-
return base_cost
|
package/templates/api/src/boards/generators/implementations/fal/image/fal_ideogram_character.py
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Ideogram V3 Character generator - Generate consistent character appearances.
|
|
3
|
-
|
|
4
|
-
This generator creates images with consistent character appearances across multiple
|
|
5
|
-
generations, maintaining facial features, proportions, and distinctive traits for
|
|
6
|
-
cohesive storytelling and branding purposes.
|
|
7
|
-
|
|
8
|
-
Based on Fal AI's fal-ai/ideogram/character model.
|
|
9
|
-
See: https://fal.ai/models/fal-ai/ideogram/character
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import os
|
|
13
|
-
from typing import Literal
|
|
14
|
-
|
|
15
|
-
from pydantic import BaseModel, Field
|
|
16
|
-
|
|
17
|
-
from .....generators.artifacts import ImageArtifact
|
|
18
|
-
from .....generators.base import (
|
|
19
|
-
BaseGenerator,
|
|
20
|
-
GeneratorExecutionContext,
|
|
21
|
-
GeneratorResult,
|
|
22
|
-
)
|
|
23
|
-
from .....progress.models import ProgressUpdate
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class IdeogramCharacterInput(BaseModel):
|
|
27
|
-
"""Input schema for fal-ideogram-character.
|
|
28
|
-
|
|
29
|
-
Artifact fields are automatically detected via type introspection
|
|
30
|
-
and resolved from generation IDs to artifact objects.
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
prompt: str = Field(
|
|
34
|
-
description="The prompt to fill the masked part of the image. Describe the scene, "
|
|
35
|
-
"setting, and action for the character."
|
|
36
|
-
)
|
|
37
|
-
reference_image_urls: list[ImageArtifact] = Field(
|
|
38
|
-
description="A set of images to use as character references. Currently only 1 image "
|
|
39
|
-
"is supported, rest will be ignored. Maximum total size 10MB across all character "
|
|
40
|
-
"references. The images should be in JPEG, PNG or WebP format.",
|
|
41
|
-
min_length=1,
|
|
42
|
-
)
|
|
43
|
-
image_size: str | dict[str, int] = Field(
|
|
44
|
-
default="square_hd",
|
|
45
|
-
description="Size preset (square_hd, square, portrait_4_3, portrait_16_9, "
|
|
46
|
-
"landscape_4_3, landscape_16_9) or custom dimensions with width and height.",
|
|
47
|
-
)
|
|
48
|
-
style: Literal["AUTO", "REALISTIC", "FICTION"] = Field(
|
|
49
|
-
default="AUTO",
|
|
50
|
-
description="The style preset to use for generation.",
|
|
51
|
-
)
|
|
52
|
-
expand_prompt: bool = Field(
|
|
53
|
-
default=True,
|
|
54
|
-
description="Determine if MagicPrompt should be used in generating the request or not.",
|
|
55
|
-
)
|
|
56
|
-
rendering_speed: Literal["TURBO", "BALANCED", "QUALITY"] = Field(
|
|
57
|
-
default="BALANCED",
|
|
58
|
-
description="The speed/quality tradeoff for generation. TURBO is fastest but lower "
|
|
59
|
-
"quality, QUALITY is slowest but highest quality.",
|
|
60
|
-
)
|
|
61
|
-
num_images: int = Field(
|
|
62
|
-
default=1,
|
|
63
|
-
ge=1,
|
|
64
|
-
le=8,
|
|
65
|
-
description="Number of images to generate (1-8).",
|
|
66
|
-
)
|
|
67
|
-
negative_prompt: str | None = Field(
|
|
68
|
-
default=None,
|
|
69
|
-
description="Things to exclude from the generation.",
|
|
70
|
-
)
|
|
71
|
-
sync_mode: bool = Field(
|
|
72
|
-
default=False,
|
|
73
|
-
description="If true, returns data URI instead of URL.",
|
|
74
|
-
)
|
|
75
|
-
seed: int | None = Field(
|
|
76
|
-
default=None,
|
|
77
|
-
description="Random number generator seed for reproducible results.",
|
|
78
|
-
)
|
|
79
|
-
reference_mask_urls: list[ImageArtifact] | None = Field(
|
|
80
|
-
default=None,
|
|
81
|
-
description="Masking images to refine character editing. Maximum 10MB total size. "
|
|
82
|
-
"Currently only 1 mask is supported.",
|
|
83
|
-
)
|
|
84
|
-
image_urls: list[ImageArtifact] | None = Field(
|
|
85
|
-
default=None,
|
|
86
|
-
description="Style reference images. Maximum 10MB total size.",
|
|
87
|
-
)
|
|
88
|
-
style_codes: list[str] | None = Field(
|
|
89
|
-
default=None,
|
|
90
|
-
description="8-character hexadecimal style codes for custom styles.",
|
|
91
|
-
)
|
|
92
|
-
color_palette: dict[str, str | list[dict[str, int]]] | None = Field(
|
|
93
|
-
default=None,
|
|
94
|
-
description="Color palette preset (EMBER, FRESH, JUNGLE, MAGIC, MELON, MOSAIC, "
|
|
95
|
-
"PASTEL, ULTRAMARINE) or custom RGB members.",
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
class FalIdeogramCharacterGenerator(BaseGenerator):
|
|
100
|
-
"""Generator for consistent character appearance generation."""
|
|
101
|
-
|
|
102
|
-
name = "fal-ideogram-character"
|
|
103
|
-
description = (
|
|
104
|
-
"Generate consistent character appearances across multiple images. Maintains facial "
|
|
105
|
-
"features, proportions, and distinctive traits for cohesive storytelling and branding."
|
|
106
|
-
)
|
|
107
|
-
artifact_type = "image"
|
|
108
|
-
|
|
109
|
-
def get_input_schema(self) -> type[IdeogramCharacterInput]:
|
|
110
|
-
"""Return the input schema for this generator."""
|
|
111
|
-
return IdeogramCharacterInput
|
|
112
|
-
|
|
113
|
-
async def generate(
|
|
114
|
-
self, inputs: IdeogramCharacterInput, context: GeneratorExecutionContext
|
|
115
|
-
) -> GeneratorResult:
|
|
116
|
-
"""Generate images with consistent character appearance using fal.ai ideogram/character."""
|
|
117
|
-
# Check for API key
|
|
118
|
-
if not os.getenv("FAL_KEY"):
|
|
119
|
-
raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
|
|
120
|
-
|
|
121
|
-
# Import fal_client
|
|
122
|
-
try:
|
|
123
|
-
import fal_client
|
|
124
|
-
except ImportError as e:
|
|
125
|
-
raise ImportError(
|
|
126
|
-
"fal.ai SDK is required for FalIdeogramCharacterGenerator. "
|
|
127
|
-
"Install with: pip install weirdfingers-boards[generators-fal]"
|
|
128
|
-
) from e
|
|
129
|
-
|
|
130
|
-
# Upload artifact inputs to Fal's storage
|
|
131
|
-
from ..utils import upload_artifacts_to_fal
|
|
132
|
-
|
|
133
|
-
reference_image_urls = await upload_artifacts_to_fal(inputs.reference_image_urls, context)
|
|
134
|
-
|
|
135
|
-
# Prepare arguments for fal.ai API
|
|
136
|
-
arguments: dict = {
|
|
137
|
-
"prompt": inputs.prompt,
|
|
138
|
-
"reference_image_urls": reference_image_urls,
|
|
139
|
-
"image_size": inputs.image_size,
|
|
140
|
-
"style": inputs.style,
|
|
141
|
-
"expand_prompt": inputs.expand_prompt,
|
|
142
|
-
"rendering_speed": inputs.rendering_speed,
|
|
143
|
-
"num_images": inputs.num_images,
|
|
144
|
-
"sync_mode": inputs.sync_mode,
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
# Add optional parameters if provided
|
|
148
|
-
if inputs.negative_prompt is not None:
|
|
149
|
-
arguments["negative_prompt"] = inputs.negative_prompt
|
|
150
|
-
if inputs.seed is not None:
|
|
151
|
-
arguments["seed"] = inputs.seed
|
|
152
|
-
if inputs.reference_mask_urls is not None:
|
|
153
|
-
arguments["reference_mask_urls"] = await upload_artifacts_to_fal(
|
|
154
|
-
inputs.reference_mask_urls, context
|
|
155
|
-
)
|
|
156
|
-
if inputs.image_urls is not None:
|
|
157
|
-
arguments["image_urls"] = await upload_artifacts_to_fal(inputs.image_urls, context)
|
|
158
|
-
if inputs.style_codes is not None:
|
|
159
|
-
arguments["style_codes"] = inputs.style_codes
|
|
160
|
-
if inputs.color_palette is not None:
|
|
161
|
-
arguments["color_palette"] = inputs.color_palette
|
|
162
|
-
|
|
163
|
-
# Submit async job
|
|
164
|
-
handler = await fal_client.submit_async(
|
|
165
|
-
"fal-ai/ideogram/character",
|
|
166
|
-
arguments=arguments,
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
# Store external job ID
|
|
170
|
-
await context.set_external_job_id(handler.request_id)
|
|
171
|
-
|
|
172
|
-
# Stream progress updates
|
|
173
|
-
event_count = 0
|
|
174
|
-
async for _event in handler.iter_events(with_logs=True):
|
|
175
|
-
event_count += 1
|
|
176
|
-
# Sample every 3rd event to avoid spam
|
|
177
|
-
if event_count % 3 == 0:
|
|
178
|
-
await context.publish_progress(
|
|
179
|
-
ProgressUpdate(
|
|
180
|
-
job_id="", # Will be populated by context
|
|
181
|
-
status="processing",
|
|
182
|
-
progress=0.5,
|
|
183
|
-
phase="processing",
|
|
184
|
-
)
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
# Get final result
|
|
188
|
-
result = await handler.get()
|
|
189
|
-
|
|
190
|
-
# Extract outputs from result and store artifacts
|
|
191
|
-
artifacts = []
|
|
192
|
-
images = result.get("images", [])
|
|
193
|
-
|
|
194
|
-
for idx, image_data in enumerate(images):
|
|
195
|
-
# Determine image format from content_type or URL
|
|
196
|
-
content_type = image_data.get("content_type", "image/png")
|
|
197
|
-
image_format = content_type.split("/")[-1] if "/" in content_type else "png"
|
|
198
|
-
|
|
199
|
-
# Store image artifact
|
|
200
|
-
artifact = await context.store_image_result(
|
|
201
|
-
storage_url=image_data["url"],
|
|
202
|
-
format=image_format,
|
|
203
|
-
# Image dimensions are not provided in response, use defaults based on size
|
|
204
|
-
width=1024, # Will be updated when image is downloaded
|
|
205
|
-
height=1024,
|
|
206
|
-
output_index=idx,
|
|
207
|
-
)
|
|
208
|
-
artifacts.append(artifact)
|
|
209
|
-
|
|
210
|
-
return GeneratorResult(outputs=artifacts)
|
|
211
|
-
|
|
212
|
-
async def estimate_cost(self, inputs: IdeogramCharacterInput) -> float:
|
|
213
|
-
"""Estimate cost for this generation in USD.
|
|
214
|
-
|
|
215
|
-
Pricing based on rendering speed:
|
|
216
|
-
- TURBO: $0.10 per image
|
|
217
|
-
- BALANCED: $0.15 per image
|
|
218
|
-
- QUALITY: $0.20 per image
|
|
219
|
-
"""
|
|
220
|
-
cost_per_image = {
|
|
221
|
-
"TURBO": 0.10,
|
|
222
|
-
"BALANCED": 0.15,
|
|
223
|
-
"QUALITY": 0.20,
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
base_cost = cost_per_image.get(inputs.rendering_speed, 0.15)
|
|
227
|
-
return base_cost * inputs.num_images
|