@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,409 +0,0 @@
|
|
|
1
|
-
# Adding Generators to Boards
|
|
2
|
-
|
|
3
|
-
This guide explains how to create and add new generators to the Boards system. Generators are components that integrate AI generation services and define their input/output schemas using Pydantic models.
|
|
4
|
-
|
|
5
|
-
## Quick Start
|
|
6
|
-
|
|
7
|
-
Creating a new generator involves just 3 steps:
|
|
8
|
-
|
|
9
|
-
1. **Define input/output schemas** using Pydantic models
|
|
10
|
-
2. **Implement the generator class** with generation logic
|
|
11
|
-
3. **Register the generator** with the system
|
|
12
|
-
|
|
13
|
-
## Example: Creating a Text-to-Speech Generator
|
|
14
|
-
|
|
15
|
-
Let's create a generator that converts text to speech using ElevenLabs API:
|
|
16
|
-
|
|
17
|
-
### Step 1: Define Pydantic Schemas
|
|
18
|
-
|
|
19
|
-
```python
|
|
20
|
-
from typing import Type, Optional
|
|
21
|
-
from pydantic import BaseModel, Field
|
|
22
|
-
from boards.generators.base import BaseGenerator
|
|
23
|
-
from boards.generators.artifacts import TextArtifact, AudioArtifact
|
|
24
|
-
|
|
25
|
-
class TTSInput(BaseModel):
|
|
26
|
-
"""Input schema for text-to-speech generation."""
|
|
27
|
-
text_source: TextArtifact = Field(description="Text to convert to speech")
|
|
28
|
-
voice_id: str = Field(description="Voice ID to use for generation")
|
|
29
|
-
stability: float = Field(default=0.75, ge=0.0, le=1.0, description="Voice stability")
|
|
30
|
-
clarity: float = Field(default=0.75, ge=0.0, le=1.0, description="Voice clarity")
|
|
31
|
-
|
|
32
|
-
class TTSOutput(BaseModel):
|
|
33
|
-
"""Output schema for text-to-speech generation."""
|
|
34
|
-
audio: AudioArtifact
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Step 2: Implement Generator Class
|
|
38
|
-
|
|
39
|
-
```python
|
|
40
|
-
import os
|
|
41
|
-
from boards.generators.resolution import store_audio_result
|
|
42
|
-
|
|
43
|
-
class ElevenLabsTTSGenerator(BaseGenerator):
|
|
44
|
-
"""Text-to-speech generator using ElevenLabs API."""
|
|
45
|
-
|
|
46
|
-
name = "elevenlabs-tts"
|
|
47
|
-
artifact_type = "audio"
|
|
48
|
-
description = "ElevenLabs text-to-speech generation"
|
|
49
|
-
|
|
50
|
-
def get_input_schema(self) -> Type[TTSInput]:
|
|
51
|
-
return TTSInput
|
|
52
|
-
|
|
53
|
-
def get_output_schema(self) -> Type[TTSOutput]:
|
|
54
|
-
return TTSOutput
|
|
55
|
-
|
|
56
|
-
async def generate(self, inputs: TTSInput) -> TTSOutput:
|
|
57
|
-
"""Generate speech from text using ElevenLabs."""
|
|
58
|
-
# Check for API key
|
|
59
|
-
if not os.getenv("ELEVENLABS_API_KEY"):
|
|
60
|
-
raise ValueError("ELEVENLABS_API_KEY environment variable is required")
|
|
61
|
-
|
|
62
|
-
# Import SDK directly - no wrapper layer
|
|
63
|
-
import elevenlabs
|
|
64
|
-
|
|
65
|
-
# Get text content from the text artifact
|
|
66
|
-
text_content = inputs.text_source.content
|
|
67
|
-
|
|
68
|
-
# Use ElevenLabs SDK directly
|
|
69
|
-
audio_bytes = elevenlabs.generate(
|
|
70
|
-
text=text_content,
|
|
71
|
-
voice=inputs.voice_id,
|
|
72
|
-
model="eleven_monolingual_v1",
|
|
73
|
-
voice_settings=elevenlabs.VoiceSettings(
|
|
74
|
-
stability=inputs.stability,
|
|
75
|
-
similarity_boost=inputs.clarity
|
|
76
|
-
)
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
# TODO: In real implementation, upload to storage and get URL
|
|
80
|
-
storage_url = "https://storage.example.com/generated_audio.mp3"
|
|
81
|
-
|
|
82
|
-
# Create audio artifact
|
|
83
|
-
audio_artifact = await store_audio_result(
|
|
84
|
-
storage_url=storage_url,
|
|
85
|
-
format="mp3",
|
|
86
|
-
generation_id="temp_gen_id", # TODO: Get from generation context
|
|
87
|
-
duration=None, # Could estimate from text length
|
|
88
|
-
sample_rate=22050,
|
|
89
|
-
channels=1
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
return TTSOutput(audio=audio_artifact)
|
|
93
|
-
|
|
94
|
-
async def estimate_cost(self, inputs: TTSInput) -> float:
|
|
95
|
-
"""Estimate cost based on text length."""
|
|
96
|
-
text_length = len(inputs.text_source.content)
|
|
97
|
-
# ElevenLabs charges per character, roughly $0.0001 per character
|
|
98
|
-
return text_length * 0.0001
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Step 3: Register the Generator
|
|
102
|
-
|
|
103
|
-
```python
|
|
104
|
-
from boards.generators.registry import registry
|
|
105
|
-
|
|
106
|
-
# Register the generator so it's available to the system
|
|
107
|
-
registry.register(ElevenLabsTTSGenerator())
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Key Concepts
|
|
111
|
-
|
|
112
|
-
### Artifact Types
|
|
113
|
-
|
|
114
|
-
Artifacts represent generated content and can be used as inputs to other generators:
|
|
115
|
-
|
|
116
|
-
- **`ImageArtifact`**: Images (PNG, JPG, WebP, etc.)
|
|
117
|
-
- **`VideoArtifact`**: Videos (MP4, WebM, etc.)
|
|
118
|
-
- **`AudioArtifact`**: Audio files (MP3, WAV, etc.)
|
|
119
|
-
- **`TextArtifact`**: Text content (plain, markdown, HTML, etc.)
|
|
120
|
-
- **`LoRArtifact`**: LoRA models (SafeTensors, etc.)
|
|
121
|
-
|
|
122
|
-
### Artifact Resolution
|
|
123
|
-
|
|
124
|
-
The system automatically resolves artifact references to file paths:
|
|
125
|
-
|
|
126
|
-
```python
|
|
127
|
-
# If input has an artifact, resolve it to a usable file path
|
|
128
|
-
audio_file_path = await resolve_artifact(inputs.audio_source)
|
|
129
|
-
|
|
130
|
-
# Now you can pass the file path to any provider SDK
|
|
131
|
-
result = await some_api.process_audio(audio_file_path)
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
For `TextArtifact`, use the `.content` property directly:
|
|
135
|
-
|
|
136
|
-
```python
|
|
137
|
-
# Text artifacts contain content directly
|
|
138
|
-
text_content = inputs.text_source.content
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Environment Variables
|
|
142
|
-
|
|
143
|
-
Generators should use environment variables for API keys and configuration:
|
|
144
|
-
|
|
145
|
-
```python
|
|
146
|
-
import os
|
|
147
|
-
|
|
148
|
-
# Check for required environment variables
|
|
149
|
-
if not os.getenv("PROVIDER_API_KEY"):
|
|
150
|
-
raise ValueError("PROVIDER_API_KEY environment variable is required")
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Advanced Examples
|
|
154
|
-
|
|
155
|
-
### Multiple Input Artifacts
|
|
156
|
-
|
|
157
|
-
Some generators need multiple artifacts as input:
|
|
158
|
-
|
|
159
|
-
```python
|
|
160
|
-
class VideoWithMusicInput(BaseModel):
|
|
161
|
-
"""Add background music to a video."""
|
|
162
|
-
video_source: VideoArtifact = Field(description="Video to add music to")
|
|
163
|
-
audio_source: AudioArtifact = Field(description="Background music")
|
|
164
|
-
music_volume: float = Field(default=0.3, ge=0.0, le=1.0, description="Music volume")
|
|
165
|
-
|
|
166
|
-
async def generate(self, inputs: VideoWithMusicInput) -> VideoWithMusicOutput:
|
|
167
|
-
# Resolve both artifacts
|
|
168
|
-
video_path = await resolve_artifact(inputs.video_source)
|
|
169
|
-
audio_path = await resolve_artifact(inputs.audio_source)
|
|
170
|
-
|
|
171
|
-
# Use both files with your provider SDK
|
|
172
|
-
result = await provider.add_background_music(
|
|
173
|
-
video=video_path,
|
|
174
|
-
audio=audio_path,
|
|
175
|
-
volume=inputs.music_volume
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
return VideoWithMusicOutput(video=result_artifact)
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### Custom Validation
|
|
182
|
-
|
|
183
|
-
Use Pydantic validators for complex input validation:
|
|
184
|
-
|
|
185
|
-
```python
|
|
186
|
-
from pydantic import field_validator
|
|
187
|
-
|
|
188
|
-
class CustomInput(BaseModel):
|
|
189
|
-
prompt: str
|
|
190
|
-
style: str
|
|
191
|
-
|
|
192
|
-
@field_validator('style')
|
|
193
|
-
@classmethod
|
|
194
|
-
def validate_style(cls, v):
|
|
195
|
-
allowed_styles = ['realistic', 'artistic', 'cartoon']
|
|
196
|
-
if v not in allowed_styles:
|
|
197
|
-
raise ValueError(f'Style must be one of {allowed_styles}')
|
|
198
|
-
return v
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Conditional Fields
|
|
202
|
-
|
|
203
|
-
Some inputs might be conditional on other fields:
|
|
204
|
-
|
|
205
|
-
```python
|
|
206
|
-
from typing import Union
|
|
207
|
-
from pydantic import Field
|
|
208
|
-
|
|
209
|
-
class ConditionalInput(BaseModel):
|
|
210
|
-
input_type: str = Field(description="Type of input", pattern="^(text|image)$")
|
|
211
|
-
text_input: Optional[str] = Field(None, description="Text input (if input_type=text)")
|
|
212
|
-
image_input: Optional[ImageArtifact] = Field(None, description="Image input (if input_type=image)")
|
|
213
|
-
|
|
214
|
-
def model_validate(cls, values):
|
|
215
|
-
input_type = values.get('input_type')
|
|
216
|
-
if input_type == 'text' and not values.get('text_input'):
|
|
217
|
-
raise ValueError('text_input is required when input_type=text')
|
|
218
|
-
elif input_type == 'image' and not values.get('image_input'):
|
|
219
|
-
raise ValueError('image_input is required when input_type=image')
|
|
220
|
-
return values
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
## Testing Your Generator
|
|
224
|
-
|
|
225
|
-
Create comprehensive tests for your generator:
|
|
226
|
-
|
|
227
|
-
```python
|
|
228
|
-
import pytest
|
|
229
|
-
from unittest.mock import patch, AsyncMock
|
|
230
|
-
|
|
231
|
-
class TestElevenLabsTTSGenerator:
|
|
232
|
-
def setup_method(self):
|
|
233
|
-
self.generator = ElevenLabsTTSGenerator()
|
|
234
|
-
|
|
235
|
-
def test_generator_metadata(self):
|
|
236
|
-
assert self.generator.name == "elevenlabs-tts"
|
|
237
|
-
assert self.generator.artifact_type == "audio"
|
|
238
|
-
|
|
239
|
-
@pytest.mark.asyncio
|
|
240
|
-
async def test_generate_success(self):
|
|
241
|
-
input_data = TTSInput(
|
|
242
|
-
text_source=TextArtifact(
|
|
243
|
-
generation_id="test",
|
|
244
|
-
content="Hello world"
|
|
245
|
-
),
|
|
246
|
-
voice_id="voice_123"
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
with patch.dict(os.environ, {"ELEVENLABS_API_KEY": "fake-key"}):
|
|
250
|
-
with patch('elevenlabs.generate') as mock_generate:
|
|
251
|
-
mock_generate.return_value = b"fake audio bytes"
|
|
252
|
-
|
|
253
|
-
result = await self.generator.generate(input_data)
|
|
254
|
-
|
|
255
|
-
assert isinstance(result, TTSOutput)
|
|
256
|
-
assert isinstance(result.audio, AudioArtifact)
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
## Best Practices
|
|
260
|
-
|
|
261
|
-
### 1. Use Provider SDKs Directly
|
|
262
|
-
|
|
263
|
-
Don't create wrapper layers - import and use provider SDKs directly:
|
|
264
|
-
|
|
265
|
-
```python
|
|
266
|
-
# Good: Use SDK directly
|
|
267
|
-
import replicate
|
|
268
|
-
result = await replicate.async_run("model", input=data)
|
|
269
|
-
|
|
270
|
-
# Avoid: Creating unnecessary wrappers
|
|
271
|
-
class ReplicateWrapper:
|
|
272
|
-
def __init__(self): ...
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### 2. Handle Errors Gracefully
|
|
276
|
-
|
|
277
|
-
Provide clear error messages for common issues:
|
|
278
|
-
|
|
279
|
-
```python
|
|
280
|
-
async def generate(self, inputs):
|
|
281
|
-
if not os.getenv("API_KEY"):
|
|
282
|
-
raise ValueError(
|
|
283
|
-
"API_KEY environment variable is required. "
|
|
284
|
-
"Get your key from https://provider.com/api-keys"
|
|
285
|
-
)
|
|
286
|
-
|
|
287
|
-
try:
|
|
288
|
-
result = await provider_api.generate(inputs)
|
|
289
|
-
except provider_api.AuthError:
|
|
290
|
-
raise ValueError("Invalid API key - check your API_KEY environment variable")
|
|
291
|
-
except provider_api.RateLimitError:
|
|
292
|
-
raise ValueError("Rate limit exceeded - please try again later")
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### 3. Accurate Cost Estimation
|
|
296
|
-
|
|
297
|
-
Implement realistic cost estimation:
|
|
298
|
-
|
|
299
|
-
```python
|
|
300
|
-
async def estimate_cost(self, inputs: MyInput) -> float:
|
|
301
|
-
# Base cost
|
|
302
|
-
base_cost = 0.01
|
|
303
|
-
|
|
304
|
-
# Variable costs based on input complexity
|
|
305
|
-
if inputs.high_quality:
|
|
306
|
-
base_cost *= 2
|
|
307
|
-
|
|
308
|
-
# Consider input size
|
|
309
|
-
if hasattr(inputs, 'image_input'):
|
|
310
|
-
# Larger images might cost more
|
|
311
|
-
pixels = inputs.image_input.width * inputs.image_input.height
|
|
312
|
-
base_cost += (pixels / 1000000) * 0.005 # $0.005 per megapixel
|
|
313
|
-
|
|
314
|
-
return base_cost
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### 4. Comprehensive Input Validation
|
|
318
|
-
|
|
319
|
-
Use Pydantic's full validation capabilities:
|
|
320
|
-
|
|
321
|
-
```python
|
|
322
|
-
class WellValidatedInput(BaseModel):
|
|
323
|
-
prompt: str = Field(min_length=1, max_length=1000, description="Generation prompt")
|
|
324
|
-
strength: float = Field(ge=0.0, le=1.0, description="Generation strength")
|
|
325
|
-
seed: Optional[int] = Field(None, ge=0, description="Random seed for reproducibility")
|
|
326
|
-
|
|
327
|
-
@field_validator('prompt')
|
|
328
|
-
@classmethod
|
|
329
|
-
def validate_prompt(cls, v):
|
|
330
|
-
if len(v.strip()) == 0:
|
|
331
|
-
raise ValueError('Prompt cannot be empty or only whitespace')
|
|
332
|
-
return v.strip()
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
## Deployment and Registration
|
|
336
|
-
|
|
337
|
-
### Auto-Registration
|
|
338
|
-
|
|
339
|
-
Generators can register themselves when their module is imported:
|
|
340
|
-
|
|
341
|
-
```python
|
|
342
|
-
# At the bottom of your generator file
|
|
343
|
-
from boards.generators.registry import registry
|
|
344
|
-
registry.register(MyGenerator())
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### Manual Registration
|
|
348
|
-
|
|
349
|
-
For more control, register generators manually:
|
|
350
|
-
|
|
351
|
-
```python
|
|
352
|
-
from boards.generators.registry import registry
|
|
353
|
-
from my_generators import MyGenerator
|
|
354
|
-
|
|
355
|
-
def setup_generators():
|
|
356
|
-
registry.register(MyGenerator())
|
|
357
|
-
# Register other generators...
|
|
358
|
-
|
|
359
|
-
# Call during application startup
|
|
360
|
-
setup_generators()
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
## Frontend Integration
|
|
364
|
-
|
|
365
|
-
Once your generator is registered, the frontend automatically gets:
|
|
366
|
-
|
|
367
|
-
1. **TypeScript types** generated from your Pydantic schemas
|
|
368
|
-
2. **Form UI** with appropriate input fields
|
|
369
|
-
3. **Drag/drop zones** for artifact inputs
|
|
370
|
-
4. **Validation** based on your schema constraints
|
|
371
|
-
|
|
372
|
-
The frontend will automatically create:
|
|
373
|
-
- Text inputs for `str` fields
|
|
374
|
-
- Number inputs for `int`/`float` fields
|
|
375
|
-
- Dropdowns for fields with `enum` constraints
|
|
376
|
-
- Drag/drop zones for `*Artifact` fields
|
|
377
|
-
- Sliders for fields with `ge`/`le` constraints
|
|
378
|
-
|
|
379
|
-
## Example Integration
|
|
380
|
-
|
|
381
|
-
Here's how your generator would be used from the frontend:
|
|
382
|
-
|
|
383
|
-
```typescript
|
|
384
|
-
// TypeScript types auto-generated from Pydantic
|
|
385
|
-
interface TTSInput {
|
|
386
|
-
text_source: TextArtifact;
|
|
387
|
-
voice_id: string;
|
|
388
|
-
stability: number;
|
|
389
|
-
clarity: number;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// UI automatically generated
|
|
393
|
-
<GeneratorForm
|
|
394
|
-
generatorName="elevenlabs-tts"
|
|
395
|
-
onSubmit={handleGeneration}
|
|
396
|
-
/>
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
This creates a form with:
|
|
400
|
-
- A drag/drop zone for `text_source` (accepts text artifacts only)
|
|
401
|
-
- A text input for `voice_id`
|
|
402
|
-
- Sliders for `stability` and `clarity` (constrained 0.0-1.0)
|
|
403
|
-
|
|
404
|
-
## Need Help?
|
|
405
|
-
|
|
406
|
-
- Check existing generators in `boards/generators/implementations/` for examples
|
|
407
|
-
- All generators follow the same simple pattern
|
|
408
|
-
- The system handles artifact resolution, storage, and UI generation automatically
|
|
409
|
-
- Focus on your generation logic - the framework handles the rest!
|