@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.
Files changed (237) hide show
  1. package/dist/index.js +560 -469
  2. package/dist/index.js.map +1 -1
  3. package/package.json +2 -5
  4. package/templates/README.md +0 -122
  5. package/templates/api/.env.example +0 -65
  6. package/templates/api/ARTIFACT_RESOLUTION_GUIDE.md +0 -148
  7. package/templates/api/Dockerfile +0 -32
  8. package/templates/api/README.md +0 -264
  9. package/templates/api/alembic/env.py +0 -114
  10. package/templates/api/alembic/script.py.mako +0 -28
  11. package/templates/api/alembic/versions/20250101_000000_initial_schema.py +0 -506
  12. package/templates/api/alembic/versions/20251022_174729_remove_provider_name_from_generations.py +0 -75
  13. package/templates/api/alembic/versions/20251023_165852_switch_to_declarative_base_and_mapping.py +0 -467
  14. package/templates/api/alembic/versions/20251202_000000_add_artifact_lineage.py +0 -134
  15. package/templates/api/alembic/versions/2025925_62735_add_seed_data_for_default_tenant.py +0 -88
  16. package/templates/api/alembic.ini +0 -36
  17. package/templates/api/config/generators.yaml +0 -237
  18. package/templates/api/config/storage_config.yaml +0 -26
  19. package/templates/api/docs/ADDING_GENERATORS.md +0 -409
  20. package/templates/api/docs/GENERATORS_API.md +0 -502
  21. package/templates/api/docs/MIGRATIONS.md +0 -472
  22. package/templates/api/docs/TESTING_LIVE_APIS.md +0 -417
  23. package/templates/api/docs/storage_providers.md +0 -337
  24. package/templates/api/pyproject.toml +0 -205
  25. package/templates/api/src/boards/__init__.py +0 -10
  26. package/templates/api/src/boards/api/app.py +0 -172
  27. package/templates/api/src/boards/api/auth.py +0 -75
  28. package/templates/api/src/boards/api/endpoints/__init__.py +0 -3
  29. package/templates/api/src/boards/api/endpoints/jobs.py +0 -76
  30. package/templates/api/src/boards/api/endpoints/setup.py +0 -505
  31. package/templates/api/src/boards/api/endpoints/sse.py +0 -129
  32. package/templates/api/src/boards/api/endpoints/storage.py +0 -155
  33. package/templates/api/src/boards/api/endpoints/tenant_registration.py +0 -296
  34. package/templates/api/src/boards/api/endpoints/uploads.py +0 -149
  35. package/templates/api/src/boards/api/endpoints/webhooks.py +0 -13
  36. package/templates/api/src/boards/auth/__init__.py +0 -15
  37. package/templates/api/src/boards/auth/adapters/__init__.py +0 -27
  38. package/templates/api/src/boards/auth/adapters/auth0.py +0 -220
  39. package/templates/api/src/boards/auth/adapters/base.py +0 -73
  40. package/templates/api/src/boards/auth/adapters/clerk.py +0 -172
  41. package/templates/api/src/boards/auth/adapters/jwt.py +0 -122
  42. package/templates/api/src/boards/auth/adapters/none.py +0 -102
  43. package/templates/api/src/boards/auth/adapters/oidc.py +0 -284
  44. package/templates/api/src/boards/auth/adapters/supabase.py +0 -110
  45. package/templates/api/src/boards/auth/context.py +0 -35
  46. package/templates/api/src/boards/auth/factory.py +0 -129
  47. package/templates/api/src/boards/auth/middleware.py +0 -221
  48. package/templates/api/src/boards/auth/provisioning.py +0 -129
  49. package/templates/api/src/boards/auth/tenant_extraction.py +0 -278
  50. package/templates/api/src/boards/cli.py +0 -354
  51. package/templates/api/src/boards/config.py +0 -131
  52. package/templates/api/src/boards/database/__init__.py +0 -7
  53. package/templates/api/src/boards/database/cli.py +0 -110
  54. package/templates/api/src/boards/database/connection.py +0 -292
  55. package/templates/api/src/boards/database/models.py +0 -19
  56. package/templates/api/src/boards/database/seed_data.py +0 -182
  57. package/templates/api/src/boards/dbmodels/__init__.py +0 -441
  58. package/templates/api/src/boards/generators/__init__.py +0 -57
  59. package/templates/api/src/boards/generators/artifact_resolution.py +0 -405
  60. package/templates/api/src/boards/generators/artifacts.py +0 -53
  61. package/templates/api/src/boards/generators/base.py +0 -144
  62. package/templates/api/src/boards/generators/implementations/__init__.py +0 -14
  63. package/templates/api/src/boards/generators/implementations/fal/__init__.py +0 -25
  64. package/templates/api/src/boards/generators/implementations/fal/audio/__init__.py +0 -23
  65. package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_music_generation.py +0 -171
  66. package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_sound_effect_generation.py +0 -167
  67. package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_text_to_speech.py +0 -176
  68. package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_tts_turbo.py +0 -195
  69. package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_sound_effects_v2.py +0 -194
  70. package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_tts_eleven_v3.py +0 -209
  71. package/templates/api/src/boards/generators/implementations/fal/audio/fal_elevenlabs_tts_turbo_v2_5.py +0 -206
  72. package/templates/api/src/boards/generators/implementations/fal/audio/fal_minimax_speech_26_hd.py +0 -237
  73. package/templates/api/src/boards/generators/implementations/fal/audio/minimax_music_v2.py +0 -173
  74. package/templates/api/src/boards/generators/implementations/fal/audio/minimax_speech_2_6_turbo.py +0 -221
  75. package/templates/api/src/boards/generators/implementations/fal/image/__init__.py +0 -63
  76. package/templates/api/src/boards/generators/implementations/fal/image/bytedance_seedream_v45_edit.py +0 -219
  77. package/templates/api/src/boards/generators/implementations/fal/image/clarity_upscaler.py +0 -220
  78. package/templates/api/src/boards/generators/implementations/fal/image/crystal_upscaler.py +0 -173
  79. package/templates/api/src/boards/generators/implementations/fal/image/fal_ideogram_character.py +0 -227
  80. package/templates/api/src/boards/generators/implementations/fal/image/flux_2.py +0 -203
  81. package/templates/api/src/boards/generators/implementations/fal/image/flux_2_edit.py +0 -230
  82. package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro.py +0 -204
  83. package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro_edit.py +0 -221
  84. package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_kontext.py +0 -216
  85. package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_ultra.py +0 -197
  86. package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image.py +0 -177
  87. package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image_edit.py +0 -208
  88. package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_15_edit.py +0 -216
  89. package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_5.py +0 -177
  90. package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_edit_image.py +0 -182
  91. package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_mini.py +0 -167
  92. package/templates/api/src/boards/generators/implementations/fal/image/ideogram_character_edit.py +0 -299
  93. package/templates/api/src/boards/generators/implementations/fal/image/ideogram_v2.py +0 -190
  94. package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview.py +0 -191
  95. package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview_fast.py +0 -179
  96. package/templates/api/src/boards/generators/implementations/fal/image/nano_banana.py +0 -183
  97. package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_edit.py +0 -212
  98. package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro.py +0 -179
  99. package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro_edit.py +0 -226
  100. package/templates/api/src/boards/generators/implementations/fal/image/qwen_image.py +0 -249
  101. package/templates/api/src/boards/generators/implementations/fal/image/qwen_image_edit.py +0 -244
  102. package/templates/api/src/boards/generators/implementations/fal/image/reve_edit.py +0 -178
  103. package/templates/api/src/boards/generators/implementations/fal/image/reve_text_to_image.py +0 -155
  104. package/templates/api/src/boards/generators/implementations/fal/image/seedream_v45_text_to_image.py +0 -180
  105. package/templates/api/src/boards/generators/implementations/fal/utils.py +0 -61
  106. package/templates/api/src/boards/generators/implementations/fal/video/__init__.py +0 -77
  107. package/templates/api/src/boards/generators/implementations/fal/video/bytedance_seedance_v1_pro_text_to_video.py +0 -209
  108. package/templates/api/src/boards/generators/implementations/fal/video/creatify_lipsync.py +0 -161
  109. package/templates/api/src/boards/generators/implementations/fal/video/fal_bytedance_seedance_v1_pro_image_to_video.py +0 -222
  110. package/templates/api/src/boards/generators/implementations/fal/video/fal_minimax_hailuo_02_standard_text_to_video.py +0 -152
  111. package/templates/api/src/boards/generators/implementations/fal/video/fal_pixverse_lipsync.py +0 -197
  112. package/templates/api/src/boards/generators/implementations/fal/video/fal_sora_2_text_to_video.py +0 -173
  113. package/templates/api/src/boards/generators/implementations/fal/video/infinitalk.py +0 -221
  114. package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_pro.py +0 -168
  115. package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_standard.py +0 -159
  116. package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_image_to_video.py +0 -175
  117. package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_text_to_video.py +0 -168
  118. package/templates/api/src/boards/generators/implementations/fal/video/minimax_hailuo_2_3_pro_image_to_video.py +0 -153
  119. package/templates/api/src/boards/generators/implementations/fal/video/sora2_image_to_video.py +0 -172
  120. package/templates/api/src/boards/generators/implementations/fal/video/sora_2_image_to_video_pro.py +0 -175
  121. package/templates/api/src/boards/generators/implementations/fal/video/sora_2_text_to_video_pro.py +0 -163
  122. package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2.py +0 -167
  123. package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2_pro.py +0 -155
  124. package/templates/api/src/boards/generators/implementations/fal/video/veed_fabric_1_0.py +0 -180
  125. package/templates/api/src/boards/generators/implementations/fal/video/veed_lipsync.py +0 -174
  126. package/templates/api/src/boards/generators/implementations/fal/video/veo3.py +0 -194
  127. package/templates/api/src/boards/generators/implementations/fal/video/veo31.py +0 -190
  128. package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast.py +0 -190
  129. package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast_image_to_video.py +0 -191
  130. package/templates/api/src/boards/generators/implementations/fal/video/veo31_first_last_frame_to_video.py +0 -187
  131. package/templates/api/src/boards/generators/implementations/fal/video/veo31_image_to_video.py +0 -183
  132. package/templates/api/src/boards/generators/implementations/fal/video/veo31_reference_to_video.py +0 -172
  133. package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_image_to_video.py +0 -212
  134. package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_text_to_video.py +0 -208
  135. package/templates/api/src/boards/generators/implementations/fal/video/wan_pro_image_to_video.py +0 -158
  136. package/templates/api/src/boards/generators/implementations/kie/__init__.py +0 -11
  137. package/templates/api/src/boards/generators/implementations/kie/base.py +0 -316
  138. package/templates/api/src/boards/generators/implementations/kie/image/__init__.py +0 -3
  139. package/templates/api/src/boards/generators/implementations/kie/image/nano_banana_edit.py +0 -190
  140. package/templates/api/src/boards/generators/implementations/kie/utils.py +0 -98
  141. package/templates/api/src/boards/generators/implementations/kie/video/__init__.py +0 -8
  142. package/templates/api/src/boards/generators/implementations/kie/video/veo3.py +0 -161
  143. package/templates/api/src/boards/generators/implementations/openai/__init__.py +0 -1
  144. package/templates/api/src/boards/generators/implementations/openai/audio/__init__.py +0 -1
  145. package/templates/api/src/boards/generators/implementations/openai/audio/whisper.py +0 -69
  146. package/templates/api/src/boards/generators/implementations/openai/image/__init__.py +0 -1
  147. package/templates/api/src/boards/generators/implementations/openai/image/dalle3.py +0 -96
  148. package/templates/api/src/boards/generators/implementations/replicate/__init__.py +0 -1
  149. package/templates/api/src/boards/generators/implementations/replicate/image/__init__.py +0 -1
  150. package/templates/api/src/boards/generators/implementations/replicate/image/flux_pro.py +0 -88
  151. package/templates/api/src/boards/generators/implementations/replicate/video/__init__.py +0 -1
  152. package/templates/api/src/boards/generators/implementations/replicate/video/lipsync.py +0 -73
  153. package/templates/api/src/boards/generators/loader.py +0 -253
  154. package/templates/api/src/boards/generators/registry.py +0 -114
  155. package/templates/api/src/boards/generators/resolution.py +0 -632
  156. package/templates/api/src/boards/generators/testmods/class_gen.py +0 -34
  157. package/templates/api/src/boards/generators/testmods/import_side_effect.py +0 -35
  158. package/templates/api/src/boards/graphql/__init__.py +0 -7
  159. package/templates/api/src/boards/graphql/access_control.py +0 -136
  160. package/templates/api/src/boards/graphql/mutations/root.py +0 -148
  161. package/templates/api/src/boards/graphql/queries/root.py +0 -116
  162. package/templates/api/src/boards/graphql/resolvers/__init__.py +0 -8
  163. package/templates/api/src/boards/graphql/resolvers/auth.py +0 -12
  164. package/templates/api/src/boards/graphql/resolvers/board.py +0 -1053
  165. package/templates/api/src/boards/graphql/resolvers/generation.py +0 -666
  166. package/templates/api/src/boards/graphql/resolvers/generator.py +0 -50
  167. package/templates/api/src/boards/graphql/resolvers/lineage.py +0 -381
  168. package/templates/api/src/boards/graphql/resolvers/upload.py +0 -463
  169. package/templates/api/src/boards/graphql/resolvers/user.py +0 -25
  170. package/templates/api/src/boards/graphql/schema.py +0 -81
  171. package/templates/api/src/boards/graphql/types/board.py +0 -102
  172. package/templates/api/src/boards/graphql/types/generation.py +0 -166
  173. package/templates/api/src/boards/graphql/types/generator.py +0 -17
  174. package/templates/api/src/boards/graphql/types/user.py +0 -47
  175. package/templates/api/src/boards/jobs/repository.py +0 -153
  176. package/templates/api/src/boards/logging.py +0 -195
  177. package/templates/api/src/boards/middleware.py +0 -339
  178. package/templates/api/src/boards/progress/__init__.py +0 -4
  179. package/templates/api/src/boards/progress/models.py +0 -25
  180. package/templates/api/src/boards/progress/publisher.py +0 -64
  181. package/templates/api/src/boards/py.typed +0 -0
  182. package/templates/api/src/boards/redis_pool.py +0 -118
  183. package/templates/api/src/boards/storage/__init__.py +0 -52
  184. package/templates/api/src/boards/storage/base.py +0 -363
  185. package/templates/api/src/boards/storage/config.py +0 -187
  186. package/templates/api/src/boards/storage/factory.py +0 -288
  187. package/templates/api/src/boards/storage/implementations/__init__.py +0 -27
  188. package/templates/api/src/boards/storage/implementations/gcs.py +0 -340
  189. package/templates/api/src/boards/storage/implementations/local.py +0 -201
  190. package/templates/api/src/boards/storage/implementations/s3.py +0 -294
  191. package/templates/api/src/boards/storage/implementations/supabase.py +0 -218
  192. package/templates/api/src/boards/tenant_isolation.py +0 -446
  193. package/templates/api/src/boards/validation.py +0 -262
  194. package/templates/api/src/boards/workers/__init__.py +0 -1
  195. package/templates/api/src/boards/workers/actors.py +0 -274
  196. package/templates/api/src/boards/workers/cli.py +0 -125
  197. package/templates/api/src/boards/workers/context.py +0 -348
  198. package/templates/api/src/boards/workers/middleware.py +0 -58
  199. package/templates/api/src/py.typed +0 -0
  200. package/templates/compose.web.yaml +0 -35
  201. package/templates/compose.yaml +0 -116
  202. package/templates/docker/env.example +0 -23
  203. package/templates/web/.env.example +0 -28
  204. package/templates/web/Dockerfile +0 -51
  205. package/templates/web/components.json +0 -22
  206. package/templates/web/imageLoader.js +0 -18
  207. package/templates/web/next-env.d.ts +0 -5
  208. package/templates/web/next.config.js +0 -36
  209. package/templates/web/package.json +0 -41
  210. package/templates/web/postcss.config.mjs +0 -7
  211. package/templates/web/public/favicon.ico +0 -0
  212. package/templates/web/src/app/boards/[boardId]/page.tsx +0 -353
  213. package/templates/web/src/app/globals.css +0 -123
  214. package/templates/web/src/app/layout.tsx +0 -31
  215. package/templates/web/src/app/lineage/[generationId]/page.tsx +0 -235
  216. package/templates/web/src/app/page.tsx +0 -35
  217. package/templates/web/src/app/providers.tsx +0 -18
  218. package/templates/web/src/components/boards/ArtifactInputSlots.tsx +0 -206
  219. package/templates/web/src/components/boards/ArtifactPreview.tsx +0 -466
  220. package/templates/web/src/components/boards/GenerationGrid.tsx +0 -282
  221. package/templates/web/src/components/boards/GenerationInput.tsx +0 -370
  222. package/templates/web/src/components/boards/GeneratorSelector.tsx +0 -272
  223. package/templates/web/src/components/boards/UploadArtifact.tsx +0 -563
  224. package/templates/web/src/components/header.tsx +0 -32
  225. package/templates/web/src/components/theme-provider.tsx +0 -10
  226. package/templates/web/src/components/theme-toggle.tsx +0 -75
  227. package/templates/web/src/components/ui/alert-dialog.tsx +0 -157
  228. package/templates/web/src/components/ui/button.tsx +0 -58
  229. package/templates/web/src/components/ui/card.tsx +0 -92
  230. package/templates/web/src/components/ui/dropdown-menu.tsx +0 -200
  231. package/templates/web/src/components/ui/navigation-menu.tsx +0 -168
  232. package/templates/web/src/components/ui/toast.tsx +0 -128
  233. package/templates/web/src/components/ui/toaster.tsx +0 -35
  234. package/templates/web/src/components/ui/use-toast.ts +0 -187
  235. package/templates/web/src/hooks/useGeneratorMRU.ts +0 -57
  236. package/templates/web/src/lib/utils.ts +0 -6
  237. package/templates/web/tsconfig.json +0 -41
@@ -1,98 +0,0 @@
1
- """
2
- Shared utilities for Kie.ai generators.
3
-
4
- Provides helper functions for common operations across Kie generators.
5
- """
6
-
7
- import asyncio
8
- import os
9
-
10
- import httpx
11
-
12
- from ...artifacts import AudioArtifact, DigitalArtifact, ImageArtifact, VideoArtifact
13
- from ...base import GeneratorExecutionContext
14
-
15
-
16
- async def upload_artifacts_to_kie[T: DigitalArtifact](
17
- artifacts: list[ImageArtifact] | list[VideoArtifact] | list[AudioArtifact] | list[T],
18
- context: GeneratorExecutionContext,
19
- ) -> list[str]:
20
- """
21
- Upload artifacts to Kie.ai's temporary storage for use in API requests.
22
-
23
- Kie.ai API endpoints require publicly accessible URLs for file inputs. Since our
24
- storage URLs might be local or private (localhost, private S3 buckets, etc.),
25
- we need to:
26
- 1. Resolve each artifact to a local file path
27
- 2. Upload to Kie.ai's public temporary storage
28
- 3. Get back publicly accessible URLs
29
-
30
- Note: Files uploaded to Kie.ai storage expire after 3 days.
31
-
32
- Args:
33
- artifacts: List of artifacts (image, video, or audio) to upload
34
- context: Generator execution context for artifact resolution
35
-
36
- Returns:
37
- List of publicly accessible URLs from Kie.ai storage
38
-
39
- Raises:
40
- ValueError: If KIE_API_KEY is not set
41
- Any exceptions from file resolution or upload are propagated
42
- """
43
- api_key = os.getenv("KIE_API_KEY")
44
- if not api_key:
45
- raise ValueError("KIE_API_KEY environment variable is required for file uploads")
46
-
47
- async def upload_single_artifact(artifact: DigitalArtifact) -> str:
48
- """Upload a single artifact and return its public URL."""
49
- # Resolve artifact to local file path (downloads if needed)
50
- file_path_str = await context.resolve_artifact(artifact)
51
-
52
- # Upload to Kie.ai's temporary storage
53
- # Using file stream upload API
54
- async with httpx.AsyncClient() as client:
55
- with open(file_path_str, "rb") as f:
56
- files = {"file": f}
57
- # uploadPath is required by Kie.ai API - specifies the storage path
58
- data = {"uploadPath": "boards/temp"}
59
- response = await client.post(
60
- "https://kieai.redpandaai.co/api/file-stream-upload",
61
- files=files,
62
- data=data,
63
- headers={"Authorization": f"Bearer {api_key}"},
64
- timeout=120.0, # 2 minute timeout for uploads
65
- )
66
-
67
- if response.status_code != 200:
68
- raise ValueError(f"File upload failed: {response.status_code} {response.text}")
69
-
70
- result = response.json()
71
-
72
- if not result.get("success"):
73
- raise ValueError(f"File upload failed: {result.get('msg')}")
74
-
75
- # Extract the public URL from response data
76
- data = result.get("data", {})
77
-
78
- # The actual field name is 'downloadUrl' based on API response
79
- file_url = data.get("downloadUrl")
80
-
81
- if not file_url:
82
- # Fallback to other possible field names
83
- file_url = data.get("fileUrl") or data.get("file_url") or data.get("url")
84
-
85
- if not file_url:
86
- # If we still can't find the URL, provide detailed error message
87
- raise ValueError(
88
- f"File upload succeeded but couldn't find URL in response. "
89
- f"Response data keys: {list(data.keys())}, "
90
- f"Full response: {result}"
91
- )
92
-
93
- return file_url
94
-
95
- # Upload all artifacts in parallel for performance
96
- urls = await asyncio.gather(*[upload_single_artifact(artifact) for artifact in artifacts])
97
-
98
- return list(urls)
@@ -1,8 +0,0 @@
1
- """Kie.ai video generators."""
2
-
3
- from .veo3 import KieVeo3Generator, KieVeo3Input
4
-
5
- __all__ = [
6
- "KieVeo3Generator",
7
- "KieVeo3Input",
8
- ]
@@ -1,161 +0,0 @@
1
- """
2
- Kie.ai Veo 3.1 text-to-video and image-to-video generator.
3
-
4
- Generate high-quality videos from text prompts with optional image inputs
5
- using Kie.ai's Google Veo 3.1 model (Dedicated API).
6
-
7
- Based on Kie.ai's Veo 3.1 API.
8
- See: https://docs.kie.ai/veo3-api/generate-veo-3-video
9
- """
10
-
11
- from typing import Any, Literal
12
-
13
- from pydantic import BaseModel, Field
14
-
15
- from ....artifacts import ImageArtifact
16
- from ....base import GeneratorExecutionContext, GeneratorResult
17
- from ..base import KieDedicatedAPIGenerator
18
-
19
-
20
- class KieVeo3Input(BaseModel):
21
- """Input schema for Kie.ai Veo 3.1 video generation.
22
-
23
- Supports both text-to-video and image-to-video modes.
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 text prompt describing the video you want to generate",
30
- max_length=5000,
31
- )
32
- image_sources: list[ImageArtifact] | None = Field(
33
- default=None,
34
- description="Optional list of 1-2 input images for image-to-video generation",
35
- min_length=1,
36
- max_length=2,
37
- )
38
- aspect_ratio: Literal["16:9", "9:16", "Auto"] = Field(
39
- default="16:9",
40
- description="Aspect ratio of the generated video",
41
- )
42
- model: Literal["veo3", "veo3_fast"] = Field(
43
- default="veo3",
44
- description="Model variant to use (veo3 for quality, veo3_fast for speed)",
45
- )
46
-
47
-
48
- class KieVeo3Generator(KieDedicatedAPIGenerator):
49
- """Veo 3.1 video generator using Kie.ai Dedicated API."""
50
-
51
- name = "kie-veo3"
52
- artifact_type = "video"
53
- description = "Kie.ai: Google Veo 3.1 - High-quality AI video generation"
54
-
55
- # Dedicated API configuration
56
- model_id = "veo3"
57
-
58
- def get_input_schema(self) -> type[KieVeo3Input]:
59
- return KieVeo3Input
60
-
61
- def _get_status_url(self, task_id: str) -> str:
62
- """Get the Veo3-specific status check URL."""
63
- return f"https://api.kie.ai/api/v1/veo/record-info?taskId={task_id}"
64
-
65
- async def generate(
66
- self, inputs: KieVeo3Input, context: GeneratorExecutionContext
67
- ) -> GeneratorResult:
68
- """Generate video using Kie.ai Veo 3.1 model."""
69
- # Get API key using base class method
70
- api_key = self._get_api_key()
71
-
72
- # Prepare request body for Dedicated API
73
- body: dict[str, Any] = {
74
- "prompt": inputs.prompt,
75
- "aspectRatio": inputs.aspect_ratio,
76
- "model": inputs.model,
77
- }
78
-
79
- # Upload image artifacts if provided (for image-to-video mode)
80
- if inputs.image_sources:
81
- from ..utils import upload_artifacts_to_kie
82
-
83
- image_urls = await upload_artifacts_to_kie(inputs.image_sources, context)
84
- body["imageUrls"] = image_urls
85
-
86
- # Submit task to Dedicated API endpoint using base class method
87
- submit_url = "https://api.kie.ai/api/v1/veo/generate"
88
- result = await self._make_request(submit_url, "POST", api_key, json=body)
89
-
90
- # Extract task ID from Dedicated API response
91
- # Try direct taskId first, then nested under 'data'
92
- task_id = result.get("taskId")
93
- if not task_id:
94
- data = result.get("data", {})
95
- task_id = data.get("taskId")
96
-
97
- if not task_id:
98
- raise ValueError(f"No taskId returned from Kie.ai API. Response: {result}")
99
-
100
- # Store external job ID
101
- await context.set_external_job_id(task_id)
102
-
103
- # Poll for completion using base class method
104
- result_data = await self._poll_for_completion(task_id, api_key, context)
105
-
106
- # Extract video URLs from response.resultUrls field
107
- # Dedicated API nests the results inside a 'response' object
108
- response_data = result_data.get("response")
109
- if not response_data:
110
- raise ValueError(f"No response field in result. Response: {result_data}")
111
-
112
- result_urls = response_data.get("resultUrls")
113
- if not result_urls or not isinstance(result_urls, list):
114
- raise ValueError(f"No resultUrls in response. Response: {result_data}")
115
-
116
- # Determine video dimensions based on aspect ratio
117
- # Default to 1080p quality
118
- if inputs.aspect_ratio == "16:9":
119
- width, height = 1920, 1080
120
- elif inputs.aspect_ratio == "9:16":
121
- width, height = 1080, 1920
122
- else: # Auto
123
- # Default to 16:9 for Auto
124
- width, height = 1920, 1080
125
-
126
- # Veo 3 generates ~8 second videos by default
127
- duration = 8.0
128
-
129
- # Store each video using output_index
130
- artifacts = []
131
- for idx, video_url in enumerate(result_urls):
132
- if not video_url:
133
- raise ValueError(f"Video {idx} missing URL in Kie.ai response")
134
-
135
- artifact = await context.store_video_result(
136
- storage_url=video_url,
137
- format="mp4",
138
- width=width,
139
- height=height,
140
- duration=duration,
141
- output_index=idx,
142
- )
143
- artifacts.append(artifact)
144
-
145
- return GeneratorResult(outputs=artifacts)
146
-
147
- async def estimate_cost(self, inputs: KieVeo3Input) -> float:
148
- """Estimate cost for Veo 3.1 video generation.
149
-
150
- Veo 3.1 pricing is estimated based on typical video generation costs.
151
- Actual pricing should be verified at https://kie.ai/pricing
152
-
153
- Base cost estimates:
154
- - veo3: $0.08 per video (standard quality)
155
- - veo3_fast: $0.04 per video (faster generation)
156
- """
157
- # Cost varies by model
158
- if inputs.model == "veo3_fast":
159
- return 0.04
160
- else: # veo3
161
- return 0.08
@@ -1 +0,0 @@
1
- """OpenAI provider generators."""
@@ -1 +0,0 @@
1
- """OpenAI audio generators."""
@@ -1,69 +0,0 @@
1
- """
2
- Whisper audio transcription using OpenAI API.
3
-
4
- Demonstrates audio processing generator that outputs text.
5
- """
6
-
7
- from pydantic import BaseModel, Field
8
-
9
- from ....artifacts import AudioArtifact
10
- from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
11
-
12
-
13
- class WhisperInput(BaseModel):
14
- """Input schema for Whisper transcription."""
15
-
16
- audio_source: AudioArtifact = Field(description="Audio file to transcribe")
17
- language: str = Field(default="en", description="Language code (e.g., 'en', 'es', 'fr')")
18
- prompt: str = Field(default="", description="Optional prompt to guide transcription")
19
-
20
-
21
- class OpenAIWhisperGenerator(BaseGenerator):
22
- """Whisper speech-to-text transcription using OpenAI API."""
23
-
24
- name = "openai-whisper"
25
- artifact_type = "text"
26
- description = "OpenAI: Whisper - speech-to-text transcription"
27
-
28
- def get_input_schema(self) -> type[WhisperInput]:
29
- return WhisperInput
30
-
31
- async def generate(
32
- self, inputs: WhisperInput, context: GeneratorExecutionContext
33
- ) -> GeneratorResult:
34
- """Transcribe audio using OpenAI Whisper."""
35
- try:
36
- from openai import AsyncOpenAI
37
- except ImportError as e:
38
- raise ImportError(
39
- "OpenAI SDK is required for WhisperGenerator. "
40
- "Install with: pip install weirdfingers-boards[generators-openai]"
41
- ) from e
42
-
43
- client = AsyncOpenAI()
44
-
45
- # Resolve audio artifact to file path via context
46
- audio_file_path = await context.resolve_artifact(inputs.audio_source)
47
-
48
- # Use OpenAI SDK for transcription
49
- with open(audio_file_path, "rb") as audio_file:
50
- transcript = await client.audio.transcriptions.create(
51
- model="whisper-1",
52
- file=audio_file,
53
- language=inputs.language,
54
- prompt=inputs.prompt,
55
- )
56
-
57
- # Create text artifact
58
- text_artifact = await context.store_text_result(
59
- content=transcript.text,
60
- format="plain",
61
- )
62
-
63
- return GeneratorResult(outputs=[text_artifact])
64
-
65
- async def estimate_cost(self, inputs: WhisperInput) -> float:
66
- """Estimate cost for Whisper transcription."""
67
- # Whisper pricing is $0.006 per minute
68
- duration_minutes = (inputs.audio_source.duration or 60) / 60
69
- return duration_minutes * 0.006
@@ -1 +0,0 @@
1
- """OpenAI image generators."""
@@ -1,96 +0,0 @@
1
- """
2
- DALL-E 3 generator using OpenAI API.
3
-
4
- Demonstrates integration with OpenAI's SDK for image generation.
5
- """
6
-
7
- import os
8
-
9
- from pydantic import BaseModel, Field
10
-
11
- from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
12
-
13
-
14
- class DallE3Input(BaseModel):
15
- """Input schema for DALL-E 3 image generation."""
16
-
17
- prompt: str = Field(description="Text prompt for image generation")
18
- size: str = Field(
19
- default="1024x1024",
20
- description="Image size",
21
- pattern="^(1024x1024|1024x1792|1792x1024)$",
22
- )
23
- quality: str = Field(default="standard", description="Image quality", pattern="^(standard|hd)$")
24
- style: str = Field(default="vivid", description="Image style", pattern="^(vivid|natural)$")
25
-
26
-
27
- class OpenAIDallE3Generator(BaseGenerator):
28
- """DALL-E 3 image generator using OpenAI API."""
29
-
30
- name = "openai-dall-e-3"
31
- artifact_type = "image"
32
- description = "OpenAI: DALL-E 3 - advanced text-to-image generation"
33
-
34
- def get_input_schema(self) -> type[DallE3Input]:
35
- return DallE3Input
36
-
37
- async def generate(
38
- self, inputs: DallE3Input, context: GeneratorExecutionContext
39
- ) -> GeneratorResult:
40
- """Generate image using OpenAI DALL-E 3."""
41
- # Check for API key
42
- if not os.getenv("OPENAI_API_KEY"):
43
- raise ValueError("API configuration invalid")
44
-
45
- # Import SDK directly
46
- try:
47
- from openai import AsyncOpenAI
48
- except ImportError as e:
49
- raise ImportError(
50
- "OpenAI SDK is required for DallE3Generator. "
51
- "Install with: pip install weirdfingers-boards[generators-openai]"
52
- ) from e
53
-
54
- client = AsyncOpenAI()
55
-
56
- # Use OpenAI SDK directly
57
- response = await client.images.generate(
58
- model="dall-e-3",
59
- prompt=inputs.prompt,
60
- size=inputs.size, # pyright: ignore[reportArgumentType]
61
- quality=inputs.quality, # pyright: ignore[reportArgumentType]
62
- style=inputs.style, # pyright: ignore[reportArgumentType]
63
- n=1,
64
- )
65
-
66
- # Get the generated image URL
67
- if not response.data or not response.data[0].url:
68
- raise ValueError("No image generated")
69
- image_url = response.data[0].url
70
-
71
- # Parse dimensions from size
72
- width, height = map(int, inputs.size.split("x"))
73
-
74
- # Store via context (downloads from OpenAI and uploads to our storage)
75
- image_artifact = await context.store_image_result(
76
- storage_url=image_url,
77
- format="png", # DALL-E 3 outputs PNG
78
- width=width,
79
- height=height,
80
- )
81
-
82
- return GeneratorResult(outputs=[image_artifact])
83
-
84
- async def estimate_cost(self, inputs: DallE3Input) -> float:
85
- """Estimate cost for DALL-E 3 generation."""
86
- # DALL-E 3 pricing varies by quality and size
87
- if inputs.quality == "hd":
88
- if inputs.size in ["1024x1792", "1792x1024"]:
89
- return 0.080 # HD, non-square
90
- else:
91
- return 0.080 # HD, square
92
- else: # standard quality
93
- if inputs.size in ["1024x1792", "1792x1024"]:
94
- return 0.040 # Standard, non-square
95
- else:
96
- return 0.040 # Standard, square
@@ -1 +0,0 @@
1
- """Replicate provider generators."""
@@ -1 +0,0 @@
1
- """Replicate image generators."""
@@ -1,88 +0,0 @@
1
- """
2
- FLUX.1.1 Pro generator using Replicate API.
3
-
4
- This demonstrates the simple pattern for creating generators:
5
- 1. Define Pydantic input/output models
6
- 2. Implement generation logic using provider SDK directly
7
- 3. Register with the global registry
8
- """
9
-
10
- import os
11
- from collections.abc import AsyncIterator
12
-
13
- from pydantic import BaseModel, Field
14
-
15
- from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
16
-
17
-
18
- class FluxProInput(BaseModel):
19
- """Input schema for FLUX.1.1 Pro image generation."""
20
-
21
- prompt: str = Field(description="Text prompt for image generation")
22
- aspect_ratio: str = Field(
23
- default="1:1",
24
- description="Image aspect ratio",
25
- pattern="^(1:1|16:9|21:9|2:3|3:2|4:5|5:4|9:16|9:21)$",
26
- )
27
- safety_tolerance: int = Field(default=2, ge=1, le=5, description="Safety tolerance level (1-5)")
28
-
29
-
30
- class ReplicateFluxProGenerator(BaseGenerator):
31
- """FLUX.1.1 Pro image generator using Replicate."""
32
-
33
- name = "replicate-flux-pro"
34
- artifact_type = "image"
35
- description = "Replicate: FLUX.1.1 [pro] by Black Forest Labs - high-quality image generation"
36
-
37
- def get_input_schema(self) -> type[FluxProInput]:
38
- return FluxProInput
39
-
40
- async def generate(
41
- self, inputs: FluxProInput, context: GeneratorExecutionContext
42
- ) -> GeneratorResult:
43
- """Generate image using Replicate FLUX.1.1 Pro model."""
44
- # Check for API key
45
- if not os.getenv("REPLICATE_API_TOKEN"):
46
- raise ValueError("API configuration invalid. Missing REPLICATE_API_TOKEN")
47
-
48
- # Import SDK directly
49
- try:
50
- import replicate
51
- from replicate.helpers import FileOutput
52
- except ImportError as e:
53
- raise ImportError(
54
- "Replicate SDK is required for FluxProGenerator. "
55
- "Install with: pip install weirdfingers-boards[generators-replicate]"
56
- ) from e
57
-
58
- # Use Replicate SDK directly
59
- prediction: FileOutput | AsyncIterator[FileOutput] = await replicate.async_run(
60
- "black-forest-labs/flux-1.1-pro",
61
- input={
62
- "prompt": inputs.prompt,
63
- "aspect_ratio": inputs.aspect_ratio,
64
- "safety_tolerance": inputs.safety_tolerance,
65
- },
66
- )
67
-
68
- # If prediction is an async iterator, get the first item; else, use as is.
69
- if isinstance(prediction, AsyncIterator):
70
- file_output = await anext(prediction)
71
- else:
72
- file_output = prediction
73
-
74
- output_url = file_output.url
75
-
76
- image_artifact = await context.store_image_result(
77
- storage_url=output_url,
78
- format="png",
79
- width=1024,
80
- height=1024,
81
- )
82
-
83
- return GeneratorResult(outputs=[image_artifact])
84
-
85
- async def estimate_cost(self, inputs: FluxProInput) -> float:
86
- """Estimate cost for FLUX.1.1 Pro generation."""
87
- # FLUX.1.1 Pro typically costs around $0.055 per generation
88
- return 0.055
@@ -1 +0,0 @@
1
- """Replicate video generators."""
@@ -1,73 +0,0 @@
1
- """
2
- Lipsync generator using Replicate API.
3
-
4
- This demonstrates how generators can use multiple artifact inputs
5
- with automatic artifact resolution.
6
- """
7
-
8
- from pydantic import BaseModel, Field
9
-
10
- from ....artifacts import AudioArtifact, VideoArtifact
11
- from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
12
-
13
-
14
- class LipsyncInput(BaseModel):
15
- """Input schema for lipsync generation."""
16
-
17
- audio_source: AudioArtifact = Field(description="Audio track for lip sync")
18
- video_source: VideoArtifact = Field(description="Video to sync lips in")
19
- prompt: str | None = Field(None, description="Optional prompt for generation")
20
-
21
-
22
- class ReplicateLipsyncGenerator(BaseGenerator):
23
- """Lipsync generator that syncs lips in video to audio."""
24
-
25
- name = "replicate-lipsync"
26
- artifact_type = "video"
27
- description = "Replicate: Sync lips in video to match audio track"
28
-
29
- def get_input_schema(self) -> type[LipsyncInput]:
30
- return LipsyncInput
31
-
32
- async def generate(
33
- self, inputs: LipsyncInput, context: GeneratorExecutionContext
34
- ) -> GeneratorResult:
35
- """Generate lip-synced video."""
36
- # Import SDK directly
37
- try:
38
- import replicate # type: ignore
39
- except ImportError as e:
40
- raise ImportError(
41
- "Replicate SDK is required for LipsyncGenerator. "
42
- "Install with: pip install weirdfingers-boards[generators-replicate]"
43
- ) from e
44
-
45
- # Resolve artifacts via context
46
- audio_file = await context.resolve_artifact(inputs.audio_source)
47
- video_file = await context.resolve_artifact(inputs.video_source)
48
-
49
- # Use Replicate SDK directly with proper file handling
50
- with open(audio_file, "rb") as audio_f, open(video_file, "rb") as video_f:
51
- result = await replicate.async_run(
52
- "cjwbw/wav2lip",
53
- input={
54
- "audio": audio_f,
55
- "video": video_f,
56
- },
57
- )
58
-
59
- # Store output and create artifact via context
60
- video_artifact = await context.store_video_result(
61
- storage_url=str(result),
62
- format="mp4",
63
- width=inputs.video_source.width,
64
- height=inputs.video_source.height,
65
- duration=inputs.audio_source.duration,
66
- )
67
-
68
- return GeneratorResult(outputs=[video_artifact])
69
-
70
- async def estimate_cost(self, inputs: LipsyncInput) -> float:
71
- """Estimate cost for lipsync generation."""
72
- # Wav2Lip is typically free on Replicate, but let's add a small cost
73
- return 0.01