@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,155 +0,0 @@
1
- """
2
- fal.ai sync-lipsync v2 pro video generator.
3
-
4
- Generate high-quality realistic lipsync animations from audio while preserving
5
- unique details like natural teeth and unique facial features.
6
-
7
- Based on Fal AI's fal-ai/sync-lipsync/v2/pro model.
8
- See: https://fal.ai/models/fal-ai/sync-lipsync/v2/pro
9
- """
10
-
11
- import os
12
- from typing import Literal
13
-
14
- from pydantic import BaseModel, Field
15
-
16
- from ....artifacts import AudioArtifact, VideoArtifact
17
- from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
18
-
19
-
20
- class SyncLipsyncV2ProInput(BaseModel):
21
- """Input schema for sync-lipsync v2 pro.
22
-
23
- Artifact fields are automatically detected via type introspection
24
- and resolved from generation IDs to artifact objects.
25
- """
26
-
27
- video: VideoArtifact = Field(description="Input video for lip-sync animation")
28
- audio: AudioArtifact = Field(description="Audio to synchronize with the video")
29
- sync_mode: Literal["cut_off", "loop", "bounce", "silence", "remap"] = Field(
30
- default="cut_off",
31
- description="Lipsync synchronization approach when media durations differ",
32
- )
33
-
34
-
35
- class FalSyncLipsyncV2ProGenerator(BaseGenerator):
36
- """Generator for high-quality realistic lip-synchronization animations."""
37
-
38
- name = "fal-sync-lipsync-v2-pro"
39
- description = "Fal: sync-lipsync v2 pro - High-quality lipsync preserving facial features"
40
- artifact_type = "video"
41
-
42
- def get_input_schema(self) -> type[SyncLipsyncV2ProInput]:
43
- """Return the input schema for this generator."""
44
- return SyncLipsyncV2ProInput
45
-
46
- async def generate(
47
- self, inputs: SyncLipsyncV2ProInput, context: GeneratorExecutionContext
48
- ) -> GeneratorResult:
49
- """Generate lip-synced video using fal.ai sync-lipsync/v2/pro."""
50
- # Check for API key
51
- if not os.getenv("FAL_KEY"):
52
- raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
53
-
54
- # Import fal_client
55
- try:
56
- import fal_client
57
- except ImportError as e:
58
- raise ImportError(
59
- "fal.ai SDK is required for FalSyncLipsyncV2ProGenerator. "
60
- "Install with: pip install weirdfingers-boards[generators-fal]"
61
- ) from e
62
-
63
- # Upload video and audio artifacts to Fal's public storage
64
- # Fal API requires publicly accessible URLs
65
- from ..utils import upload_artifacts_to_fal
66
-
67
- # Upload video and audio separately
68
- video_urls = await upload_artifacts_to_fal([inputs.video], context)
69
- audio_urls = await upload_artifacts_to_fal([inputs.audio], context)
70
-
71
- # Prepare arguments for fal.ai API
72
- arguments = {
73
- "video_url": video_urls[0],
74
- "audio_url": audio_urls[0],
75
- "sync_mode": inputs.sync_mode,
76
- }
77
-
78
- # Submit async job
79
- handler = await fal_client.submit_async(
80
- "fal-ai/sync-lipsync/v2/pro",
81
- arguments=arguments,
82
- )
83
-
84
- # Store external job ID
85
- await context.set_external_job_id(handler.request_id)
86
-
87
- # Stream progress updates
88
- from .....progress.models import ProgressUpdate
89
-
90
- event_count = 0
91
- async for event in handler.iter_events(with_logs=True):
92
- event_count += 1
93
- # Sample every 3rd event to avoid spam
94
- if event_count % 3 == 0:
95
- # Extract logs if available
96
- logs = getattr(event, "logs", None)
97
- if logs:
98
- # Join log entries into a single message
99
- if isinstance(logs, list):
100
- message = " | ".join(str(log) for log in logs if log)
101
- else:
102
- message = str(logs)
103
-
104
- if message:
105
- await context.publish_progress(
106
- ProgressUpdate(
107
- job_id=handler.request_id,
108
- status="processing",
109
- progress=50.0, # Approximate mid-point progress
110
- phase="processing",
111
- message=message,
112
- )
113
- )
114
-
115
- # Get final result
116
- result = await handler.get()
117
-
118
- # Extract video from result
119
- # fal.ai returns: {"video": {"url": "...", "content_type": "video/mp4", ...}}
120
- video_data = result.get("video")
121
-
122
- if not video_data:
123
- raise ValueError("No video returned from fal.ai API")
124
-
125
- video_url = video_data.get("url")
126
- if not video_url:
127
- raise ValueError("Video missing URL in fal.ai response")
128
-
129
- # Extract format from content_type (e.g., "video/mp4" -> "mp4")
130
- content_type = video_data.get("content_type", "video/mp4")
131
- video_format = content_type.split("/")[-1] if "/" in content_type else "mp4"
132
-
133
- # Store the video result
134
- # Note: The API doesn't return width/height/duration/fps, so we use input values
135
- # The actual dimensions will be the same as the input video
136
- artifact = await context.store_video_result(
137
- storage_url=video_url,
138
- format=video_format,
139
- width=inputs.video.width,
140
- height=inputs.video.height,
141
- duration=inputs.audio.duration,
142
- fps=inputs.video.fps,
143
- output_index=0,
144
- )
145
-
146
- return GeneratorResult(outputs=[artifact])
147
-
148
- async def estimate_cost(self, inputs: SyncLipsyncV2ProInput) -> float:
149
- """Estimate cost for sync-lipsync v2 pro generation in USD.
150
-
151
- Pricing not specified in documentation, using estimate based on
152
- typical video processing costs for pro models.
153
- """
154
- # Estimated cost per generation for pro model
155
- return 0.10
@@ -1,180 +0,0 @@
1
- """
2
- VEED Fabric 1.0 image-to-video generator.
3
-
4
- Generate talking videos from any image using VEED Fabric 1.0.
5
- This generator turns a static image into a talking video with synchronized
6
- lip movements based on provided audio.
7
-
8
- Based on Fal AI's veed/fabric-1.0 model.
9
- See: https://fal.ai/models/veed/fabric-1.0
10
- """
11
-
12
- import os
13
- from typing import Literal
14
-
15
- from pydantic import BaseModel, Field
16
-
17
- from ....artifacts import AudioArtifact, ImageArtifact
18
- from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
19
- from ..utils import upload_artifacts_to_fal
20
-
21
-
22
- class VeedFabric10Input(BaseModel):
23
- """Input schema for VEED Fabric 1.0.
24
-
25
- Artifact fields are automatically detected via type introspection
26
- and resolved from generation IDs to artifact objects.
27
- """
28
-
29
- image_url: ImageArtifact = Field(description="Image to turn into a talking video")
30
- audio_url: AudioArtifact = Field(description="Audio to synchronize with the image")
31
- resolution: Literal["720p", "480p"] = Field(
32
- default="720p", description="Output video resolution"
33
- )
34
-
35
-
36
- class FalVeedFabric10Generator(BaseGenerator):
37
- """Generator for turning images into talking videos using VEED Fabric 1.0."""
38
-
39
- name = "veed-fabric-1.0"
40
- description = "VEED: Fabric 1.0 - Turn any image into a talking video"
41
- artifact_type = "video"
42
-
43
- def get_input_schema(self) -> type[VeedFabric10Input]:
44
- """Return the input schema for this generator."""
45
- return VeedFabric10Input
46
-
47
- async def generate(
48
- self, inputs: VeedFabric10Input, context: GeneratorExecutionContext
49
- ) -> GeneratorResult:
50
- """Generate talking video using VEED Fabric 1.0."""
51
- # Check for API key
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 FalVeedFabric10Generator. "
61
- "Install with: pip install weirdfingers-boards[generators-fal]"
62
- ) from e
63
-
64
- # Upload image and audio artifacts to Fal's public storage
65
- # Fal API requires publicly accessible URLs
66
- image_urls = await upload_artifacts_to_fal([inputs.image_url], context)
67
- audio_urls = await upload_artifacts_to_fal([inputs.audio_url], context)
68
-
69
- # Prepare arguments for fal.ai API
70
- arguments = {
71
- "image_url": image_urls[0],
72
- "audio_url": audio_urls[0],
73
- "resolution": inputs.resolution,
74
- }
75
-
76
- # Submit async job
77
- handler = await fal_client.submit_async(
78
- "veed/fabric-1.0",
79
- arguments=arguments,
80
- )
81
-
82
- # Store external job ID
83
- await context.set_external_job_id(handler.request_id)
84
-
85
- # Stream progress updates
86
- from .....progress.models import ProgressUpdate
87
-
88
- event_count = 0
89
- async for event in handler.iter_events(with_logs=True):
90
- event_count += 1
91
- # Sample every 3rd event to avoid spamming progress updates
92
- if event_count % 3 == 0:
93
- logs = getattr(event, "logs", None)
94
- if logs:
95
- if isinstance(logs, list):
96
- message = " | ".join(str(log) for log in logs if log)
97
- else:
98
- message = str(logs)
99
-
100
- if message:
101
- await context.publish_progress(
102
- ProgressUpdate(
103
- job_id=handler.request_id,
104
- status="processing",
105
- progress=50.0,
106
- phase="processing",
107
- message=message,
108
- )
109
- )
110
-
111
- # Get final result
112
- result = await handler.get()
113
-
114
- # Extract video from result
115
- # Fabric 1.0 API returns: {"video": {"url": "...", "content_type": "video/mp4", ...}}
116
- video_data = result.get("video")
117
-
118
- if not video_data:
119
- raise ValueError(
120
- "No video returned from VEED Fabric 1.0 API. "
121
- f"Response structure: {list(result.keys())}"
122
- )
123
-
124
- video_url = video_data.get("url")
125
- if not video_url:
126
- raise ValueError(
127
- f"Video missing URL in VEED response. Video data keys: {list(video_data.keys())}"
128
- )
129
-
130
- # Determine video format with fallback strategy:
131
- # 1. Try to extract from URL extension
132
- # 2. Parse content_type only if it's a video/* MIME type
133
- # 3. Default to mp4
134
- video_format = "mp4" # Default
135
-
136
- if video_url:
137
- url_parts = video_url.split(".")
138
- if len(url_parts) > 1:
139
- ext = url_parts[-1].split("?")[0].lower()
140
- if ext in ["mp4", "webm", "mov", "avi"]:
141
- video_format = ext
142
-
143
- if video_format == "mp4":
144
- content_type = video_data.get("content_type", "")
145
- if content_type.startswith("video/"):
146
- video_format = content_type.split("/")[-1]
147
-
148
- # Determine output dimensions based on resolution
149
- # 720p = 1280x720, 480p = 854x480 (16:9 aspect ratio)
150
- if inputs.resolution == "720p":
151
- output_width = 1280
152
- output_height = 720
153
- else:
154
- output_width = 854
155
- output_height = 480
156
-
157
- # Store the video result
158
- artifact = await context.store_video_result(
159
- storage_url=video_url,
160
- format=video_format,
161
- width=output_width,
162
- height=output_height,
163
- duration=inputs.audio_url.duration,
164
- fps=30.0, # Standard frame rate for talking videos
165
- output_index=0,
166
- )
167
-
168
- return GeneratorResult(outputs=[artifact])
169
-
170
- async def estimate_cost(self, inputs: VeedFabric10Input) -> float:
171
- """Estimate cost for VEED Fabric 1.0 generation in USD.
172
-
173
- Pricing not specified in documentation, using estimate based on
174
- typical video lipsync processing costs.
175
- """
176
- # Fixed cost estimate of $0.08 per generation
177
- # Based on typical AI video processing costs
178
- # This is a conservative estimate and should be updated when official
179
- # pricing information becomes available
180
- return 0.08
@@ -1,174 +0,0 @@
1
- """
2
- VEED Lipsync video generator.
3
-
4
- Generate realistic lipsync from any audio using VEED's latest model.
5
- This generator synchronizes lip movements in video with provided audio.
6
-
7
- Based on Fal AI's veed/lipsync model.
8
- See: https://fal.ai/models/veed/lipsync
9
- """
10
-
11
- import os
12
-
13
- from pydantic import BaseModel, Field
14
-
15
- from ....artifacts import AudioArtifact, VideoArtifact
16
- from ....base import BaseGenerator, GeneratorExecutionContext, GeneratorResult
17
- from ..utils import upload_artifacts_to_fal
18
-
19
-
20
- class VeedLipsyncInput(BaseModel):
21
- """Input schema for VEED lipsync.
22
-
23
- Artifact fields are automatically detected via type introspection
24
- and resolved from generation IDs to artifact objects.
25
- """
26
-
27
- video_url: VideoArtifact = Field(description="Video to apply lip-sync animation to")
28
- audio_url: AudioArtifact = Field(description="Audio to synchronize with the video")
29
-
30
-
31
- class FalVeedLipsyncGenerator(BaseGenerator):
32
- """Generator for realistic lip-synchronization using VEED's model."""
33
-
34
- name = "veed-lipsync"
35
- description = "VEED: Lipsync - Generate realistic lipsync from any audio"
36
- artifact_type = "video"
37
-
38
- def get_input_schema(self) -> type[VeedLipsyncInput]:
39
- """Return the input schema for this generator."""
40
- return VeedLipsyncInput
41
-
42
- async def generate(
43
- self, inputs: VeedLipsyncInput, context: GeneratorExecutionContext
44
- ) -> GeneratorResult:
45
- """Generate lip-synced video using VEED lipsync."""
46
- # Check for API key
47
- if not os.getenv("FAL_KEY"):
48
- raise ValueError("API configuration invalid. Missing FAL_KEY environment variable")
49
-
50
- # Import fal_client
51
- try:
52
- import fal_client
53
- except ImportError as e:
54
- raise ImportError(
55
- "fal.ai SDK is required for FalVeedLipsyncGenerator. "
56
- "Install with: pip install weirdfingers-boards[generators-fal]"
57
- ) from e
58
-
59
- # Upload video and audio artifacts to Fal's public storage
60
- # Fal API requires publicly accessible URLs
61
- # Upload video and audio separately
62
- video_urls = await upload_artifacts_to_fal([inputs.video_url], context)
63
- audio_urls = await upload_artifacts_to_fal([inputs.audio_url], context)
64
-
65
- # Prepare arguments for fal.ai API
66
- arguments = {
67
- "video_url": video_urls[0],
68
- "audio_url": audio_urls[0],
69
- }
70
-
71
- # Submit async job
72
- handler = await fal_client.submit_async(
73
- "veed/lipsync",
74
- arguments=arguments,
75
- )
76
-
77
- # Store external job ID
78
- await context.set_external_job_id(handler.request_id)
79
-
80
- # Stream progress updates
81
- from .....progress.models import ProgressUpdate
82
-
83
- event_count = 0
84
- async for event in handler.iter_events(with_logs=True):
85
- event_count += 1
86
- # Sample every 3rd event to avoid spamming progress updates
87
- # This provides regular feedback without overwhelming the system
88
- if event_count % 3 == 0:
89
- # Extract logs if available
90
- logs = getattr(event, "logs", None)
91
- if logs:
92
- # Join log entries into a single message
93
- if isinstance(logs, list):
94
- message = " | ".join(str(log) for log in logs if log)
95
- else:
96
- message = str(logs)
97
-
98
- if message:
99
- await context.publish_progress(
100
- ProgressUpdate(
101
- job_id=handler.request_id,
102
- status="processing",
103
- # Using fixed 50% since API doesn't provide granular progress
104
- # This indicates processing is underway without false precision
105
- progress=50.0,
106
- phase="processing",
107
- message=message,
108
- )
109
- )
110
-
111
- # Get final result
112
- result = await handler.get()
113
-
114
- # Extract video from result
115
- # VEED API returns: {"video": {"url": "...", "content_type": "video/mp4", ...}}
116
- video_data = result.get("video")
117
-
118
- if not video_data:
119
- raise ValueError(
120
- f"No video returned from VEED API. Response structure: {list(result.keys())}"
121
- )
122
-
123
- video_url = video_data.get("url")
124
- if not video_url:
125
- raise ValueError(
126
- f"Video missing URL in VEED response. Video data keys: {list(video_data.keys())}"
127
- )
128
-
129
- # Determine video format with fallback strategy:
130
- # 1. Try to extract from URL extension (most reliable)
131
- # 2. Parse content_type only if it's a video/* MIME type
132
- # 3. Default to mp4 (most common format for this API)
133
- video_format = "mp4" # Default
134
-
135
- # Try extracting extension from URL
136
- if video_url:
137
- url_parts = video_url.split(".")
138
- if len(url_parts) > 1:
139
- ext = url_parts[-1].split("?")[0].lower() # Remove query params
140
- if ext in ["mp4", "webm", "mov", "avi"]: # Common video formats
141
- video_format = ext
142
-
143
- # If no valid extension found, try content_type (only if it's video/*)
144
- if video_format == "mp4": # Still using default
145
- content_type = video_data.get("content_type", "")
146
- if content_type.startswith("video/"):
147
- video_format = content_type.split("/")[-1]
148
-
149
- # Store the video result
150
- # Note: The API doesn't return width/height/duration/fps in documentation
151
- # Using input video dimensions and audio duration
152
- artifact = await context.store_video_result(
153
- storage_url=video_url,
154
- format=video_format,
155
- width=inputs.video_url.width,
156
- height=inputs.video_url.height,
157
- duration=inputs.audio_url.duration,
158
- fps=inputs.video_url.fps,
159
- output_index=0,
160
- )
161
-
162
- return GeneratorResult(outputs=[artifact])
163
-
164
- async def estimate_cost(self, inputs: VeedLipsyncInput) -> float:
165
- """Estimate cost for VEED lipsync generation in USD.
166
-
167
- Pricing not specified in documentation, using estimate based on
168
- typical video lipsync processing costs.
169
- """
170
- # Fixed cost estimate of $0.05 per generation
171
- # Based on typical AI video processing costs (~$0.03-0.07 per minute)
172
- # This is a conservative estimate and should be updated when official
173
- # pricing information becomes available from VEED/FAL
174
- return 0.05