@weirdfingers/baseboards 0.2.1 → 0.4.0
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/README.md +14 -4
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/api/ARTIFACT_RESOLUTION_GUIDE.md +148 -0
- package/templates/api/Dockerfile +2 -2
- package/templates/api/README.md +138 -6
- package/templates/api/config/generators.yaml +41 -7
- package/templates/api/docs/TESTING_LIVE_APIS.md +417 -0
- package/templates/api/pyproject.toml +49 -9
- package/templates/api/src/boards/__init__.py +1 -1
- package/templates/api/src/boards/auth/adapters/__init__.py +9 -2
- package/templates/api/src/boards/auth/factory.py +16 -2
- package/templates/api/src/boards/generators/__init__.py +2 -2
- package/templates/api/src/boards/generators/artifact_resolution.py +372 -0
- package/templates/api/src/boards/generators/artifacts.py +4 -4
- package/templates/api/src/boards/generators/base.py +8 -4
- package/templates/api/src/boards/generators/implementations/__init__.py +4 -2
- package/templates/api/src/boards/generators/implementations/fal/__init__.py +25 -0
- package/templates/api/src/boards/generators/implementations/fal/audio/__init__.py +4 -0
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_music_v2.py +173 -0
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_speech_2_6_turbo.py +221 -0
- package/templates/api/src/boards/generators/implementations/fal/image/__init__.py +17 -0
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_kontext.py +216 -0
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_ultra.py +197 -0
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview.py +191 -0
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview_fast.py +179 -0
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana.py +183 -0
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_edit.py +212 -0
- package/templates/api/src/boards/generators/implementations/fal/utils.py +61 -0
- package/templates/api/src/boards/generators/implementations/fal/video/__init__.py +13 -0
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_text_to_video.py +168 -0
- package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2.py +167 -0
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_first_last_frame_to_video.py +180 -0
- package/templates/api/src/boards/generators/implementations/openai/__init__.py +1 -0
- package/templates/api/src/boards/generators/implementations/openai/audio/__init__.py +1 -0
- package/templates/api/src/boards/generators/implementations/{audio → openai/audio}/whisper.py +9 -6
- package/templates/api/src/boards/generators/implementations/openai/image/__init__.py +1 -0
- package/templates/api/src/boards/generators/implementations/{image → openai/image}/dalle3.py +8 -5
- package/templates/api/src/boards/generators/implementations/replicate/__init__.py +1 -0
- package/templates/api/src/boards/generators/implementations/replicate/image/__init__.py +1 -0
- package/templates/api/src/boards/generators/implementations/{image → replicate/image}/flux_pro.py +8 -5
- package/templates/api/src/boards/generators/implementations/replicate/video/__init__.py +1 -0
- package/templates/api/src/boards/generators/implementations/{video → replicate/video}/lipsync.py +9 -6
- package/templates/api/src/boards/generators/resolution.py +80 -20
- package/templates/api/src/boards/jobs/repository.py +49 -0
- package/templates/api/src/boards/storage/factory.py +16 -6
- package/templates/api/src/boards/workers/actors.py +69 -5
- package/templates/api/src/boards/workers/context.py +177 -21
- package/templates/web/package.json +2 -1
- package/templates/web/src/components/boards/GenerationInput.tsx +154 -52
- package/templates/web/src/components/boards/GeneratorSelector.tsx +57 -59
- package/templates/web/src/components/ui/dropdown-menu.tsx +200 -0
- package/templates/api/src/boards/generators/implementations/audio/__init__.py +0 -3
- package/templates/api/src/boards/generators/implementations/image/__init__.py +0 -3
- package/templates/api/src/boards/generators/implementations/video/__init__.py +0 -3
package/templates/api/README.md
CHANGED
|
@@ -15,21 +15,72 @@ Backend for the Boards open-source creative toolkit for AI-generated content.
|
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
|
+
### Minimal Install
|
|
19
|
+
|
|
20
|
+
The minimal installation includes core functionality with local filesystem storage only:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install weirdfingers-boards
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Install with Specific Generators
|
|
27
|
+
|
|
28
|
+
Install only the generator providers you need:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# OpenAI generators (DALL-E 3, Whisper)
|
|
32
|
+
pip install weirdfingers-boards[generators-openai]
|
|
33
|
+
|
|
34
|
+
# Replicate generators (Flux Pro, Lipsync)
|
|
35
|
+
pip install weirdfingers-boards[generators-replicate]
|
|
36
|
+
|
|
37
|
+
# fal.ai generators (nano-banana)
|
|
38
|
+
pip install weirdfingers-boards[generators-fal]
|
|
39
|
+
|
|
40
|
+
# Multiple generators
|
|
41
|
+
pip install weirdfingers-boards[generators-openai,generators-replicate]
|
|
42
|
+
|
|
43
|
+
# All generators
|
|
44
|
+
pip install weirdfingers-boards[generators-all]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Install with Storage Backends
|
|
48
|
+
|
|
49
|
+
Add cloud storage providers as needed:
|
|
50
|
+
|
|
18
51
|
```bash
|
|
19
|
-
#
|
|
20
|
-
pip install boards-
|
|
52
|
+
# S3 storage (AWS, MinIO, DigitalOcean Spaces)
|
|
53
|
+
pip install weirdfingers-boards[storage-s3]
|
|
54
|
+
|
|
55
|
+
# Supabase storage
|
|
56
|
+
pip install weirdfingers-boards[storage-supabase]
|
|
21
57
|
|
|
22
|
-
#
|
|
23
|
-
pip install boards
|
|
58
|
+
# Google Cloud Storage
|
|
59
|
+
pip install weirdfingers-boards[storage-gcs]
|
|
60
|
+
|
|
61
|
+
# All storage backends
|
|
62
|
+
pip install weirdfingers-boards[storage-all]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Full Installation
|
|
66
|
+
|
|
67
|
+
Install everything (all generators and storage backends):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install weirdfingers-boards[all]
|
|
24
71
|
```
|
|
25
72
|
|
|
26
73
|
### Development Installation
|
|
27
74
|
|
|
75
|
+
For local development with all providers for type checking and testing:
|
|
76
|
+
|
|
28
77
|
```bash
|
|
29
|
-
# Clone the repository
|
|
78
|
+
# Clone the repository
|
|
30
79
|
git clone https://github.com/weirdfingers/boards.git
|
|
31
80
|
cd boards/packages/backend
|
|
32
|
-
|
|
81
|
+
|
|
82
|
+
# Install with dev dependencies (includes all providers)
|
|
83
|
+
uv sync
|
|
33
84
|
```
|
|
34
85
|
|
|
35
86
|
## Configuration
|
|
@@ -127,6 +178,87 @@ packages/backend/
|
|
|
127
178
|
└── tests/
|
|
128
179
|
```
|
|
129
180
|
|
|
181
|
+
## Community & Social
|
|
182
|
+
|
|
183
|
+
Join the Weirdfingers community:
|
|
184
|
+
|
|
185
|
+
- **TikTok**: [https://www.tiktok.com/@weirdfingers](https://www.tiktok.com/@weirdfingers)
|
|
186
|
+
- **X (Twitter)**: [https://x.com/_Weirdfingers_](https://x.com/_Weirdfingers_)
|
|
187
|
+
- **YouTube**: [https://www.youtube.com/@Weirdfingers](https://www.youtube.com/@Weirdfingers)
|
|
188
|
+
- **Discord**: [https://discord.gg/rvVuHyuPEx](https://discord.gg/rvVuHyuPEx)
|
|
189
|
+
- **Instagram**: [https://www.instagram.com/_weirdfingers_/](https://www.instagram.com/_weirdfingers_/)
|
|
190
|
+
## Testing
|
|
191
|
+
|
|
192
|
+
Boards uses pytest for testing with both unit tests (mocked) and optional live API tests.
|
|
193
|
+
|
|
194
|
+
### Running Tests
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Run all unit tests (excludes live API tests)
|
|
198
|
+
make test-backend
|
|
199
|
+
|
|
200
|
+
# Or using pytest directly
|
|
201
|
+
cd packages/backend
|
|
202
|
+
uv run pytest tests/
|
|
203
|
+
|
|
204
|
+
# Run with coverage
|
|
205
|
+
uv run pytest tests/ --cov=src/boards --cov-report=html
|
|
206
|
+
|
|
207
|
+
# Run specific test file
|
|
208
|
+
uv run pytest tests/generators/implementations/test_flux_pro.py -v
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Unit Tests vs Live API Tests
|
|
212
|
+
|
|
213
|
+
**Unit tests** (default):
|
|
214
|
+
- Use mocked provider SDKs
|
|
215
|
+
- Fast and free
|
|
216
|
+
- Run automatically in CI/CD
|
|
217
|
+
- Located: `tests/**/test_*.py`
|
|
218
|
+
|
|
219
|
+
**Live API tests** (opt-in only):
|
|
220
|
+
- Make real API calls to providers
|
|
221
|
+
- Consume API credits
|
|
222
|
+
- **Never run by default**
|
|
223
|
+
- Located: `tests/**/test_*_live.py`
|
|
224
|
+
|
|
225
|
+
### Running Live API Tests
|
|
226
|
+
|
|
227
|
+
Live tests verify real connectivity with provider APIs but cost money. They are **excluded from default test runs**.
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Set up API key
|
|
231
|
+
export BOARDS_GENERATOR_API_KEYS='{"REPLICATE_API_TOKEN": "r8_..."}'
|
|
232
|
+
|
|
233
|
+
# Run a specific generator's live test
|
|
234
|
+
uv run pytest tests/generators/implementations/test_flux_pro_live.py -v -m live_api
|
|
235
|
+
|
|
236
|
+
# Run all live tests for one provider
|
|
237
|
+
uv run pytest -m live_replicate -v
|
|
238
|
+
|
|
239
|
+
# Run all live tests (not recommended - expensive!)
|
|
240
|
+
uv run pytest -m live_api -v
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
For detailed information on live API testing, see:
|
|
244
|
+
- [Live API Testing Guide](docs/TESTING_LIVE_APIS.md)
|
|
245
|
+
- [Generator Testing Documentation](../../apps/docs/docs/generators/testing.md)
|
|
246
|
+
|
|
247
|
+
### Test Organization
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
tests/
|
|
251
|
+
├── conftest.py # Shared fixtures (database, etc.)
|
|
252
|
+
├── generators/
|
|
253
|
+
│ └── implementations/
|
|
254
|
+
│ ├── conftest.py # Generator-specific fixtures
|
|
255
|
+
│ ├── test_flux_pro.py # Unit tests (mocked)
|
|
256
|
+
│ ├── test_flux_pro_live.py # Live API tests (opt-in)
|
|
257
|
+
│ └── ...
|
|
258
|
+
├── graphql/ # GraphQL API tests
|
|
259
|
+
└── storage/ # Storage backend tests
|
|
260
|
+
```
|
|
261
|
+
|
|
130
262
|
## License
|
|
131
263
|
|
|
132
264
|
MIT
|
|
@@ -8,18 +8,52 @@
|
|
|
8
8
|
strict_mode: true
|
|
9
9
|
allow_unlisted: false
|
|
10
10
|
|
|
11
|
+
# NOTE: Please keep generators in alphabetical order by class name for easier maintenance
|
|
11
12
|
generators:
|
|
12
|
-
#
|
|
13
|
-
- class: "boards.generators.implementations.image.
|
|
13
|
+
# Fal.ai generators
|
|
14
|
+
- class: "boards.generators.implementations.fal.image.flux_pro_kontext.FalFluxProKontextGenerator"
|
|
14
15
|
enabled: true
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
- class: "boards.generators.implementations.audio.whisper.WhisperGenerator"
|
|
17
|
+
- class: "boards.generators.implementations.fal.image.flux_pro_ultra.FalFluxProUltraGenerator"
|
|
18
18
|
enabled: true
|
|
19
19
|
|
|
20
|
-
- class: "boards.generators.implementations.image.
|
|
20
|
+
- class: "boards.generators.implementations.fal.image.imagen4_preview_fast.FalImagen4PreviewFastGenerator"
|
|
21
21
|
enabled: true
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
- class: "boards.generators.implementations.fal.image.imagen4_preview.FalImagen4PreviewGenerator"
|
|
24
|
+
enabled: true
|
|
25
|
+
|
|
26
|
+
- class: "boards.generators.implementations.fal.video.kling_video_v2_5_turbo_pro_text_to_video.FalKlingVideoV25TurboProTextToVideoGenerator"
|
|
27
|
+
enabled: true
|
|
28
|
+
|
|
29
|
+
- class: "boards.generators.implementations.fal.audio.minimax_music_v2.FalMinimaxMusicV2Generator"
|
|
30
|
+
enabled: true
|
|
31
|
+
|
|
32
|
+
- class: "boards.generators.implementations.fal.audio.minimax_speech_2_6_turbo.FalMinimaxSpeech26TurboGenerator"
|
|
33
|
+
enabled: true
|
|
34
|
+
|
|
35
|
+
- class: "boards.generators.implementations.fal.image.nano_banana_edit.FalNanoBananaEditGenerator"
|
|
36
|
+
enabled: true
|
|
37
|
+
|
|
38
|
+
- class: "boards.generators.implementations.fal.image.nano_banana.FalNanoBananaGenerator"
|
|
39
|
+
enabled: true
|
|
40
|
+
|
|
41
|
+
- class: "boards.generators.implementations.fal.video.sync_lipsync_v2.FalSyncLipsyncV2Generator"
|
|
42
|
+
enabled: true
|
|
43
|
+
|
|
44
|
+
- class: "boards.generators.implementations.fal.video.veo31_first_last_frame_to_video.FalVeo31FirstLastFrameToVideoGenerator"
|
|
45
|
+
enabled: true
|
|
46
|
+
|
|
47
|
+
# OpenAI generators
|
|
48
|
+
- class: "boards.generators.implementations.openai.image.dalle3.OpenAIDallE3Generator"
|
|
49
|
+
enabled: true
|
|
50
|
+
|
|
51
|
+
- class: "boards.generators.implementations.openai.audio.whisper.OpenAIWhisperGenerator"
|
|
52
|
+
enabled: true
|
|
53
|
+
|
|
54
|
+
# Replicate generators
|
|
55
|
+
- class: "boards.generators.implementations.replicate.image.flux_pro.ReplicateFluxProGenerator"
|
|
56
|
+
enabled: true
|
|
57
|
+
|
|
58
|
+
- class: "boards.generators.implementations.replicate.video.lipsync.ReplicateLipsyncGenerator"
|
|
25
59
|
enabled: true
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# Live API Testing Guide for Generators
|
|
2
|
+
|
|
3
|
+
This guide explains how to test generators with real provider APIs (Replicate, Fal.ai, OpenAI, etc.) rather than mocked responses.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Boards includes two types of generator tests:
|
|
8
|
+
|
|
9
|
+
1. **Unit tests** (`test_<generator>.py`) - Use mocks, run by default, fast and free
|
|
10
|
+
2. **Live API tests** (`test_<generator>_live.py`) - Call real APIs, opt-in only, consume credits
|
|
11
|
+
|
|
12
|
+
Live API tests are **never run by default**. They must be explicitly invoked and require valid API keys.
|
|
13
|
+
|
|
14
|
+
## When to Run Live API Tests
|
|
15
|
+
|
|
16
|
+
Run live API tests when:
|
|
17
|
+
|
|
18
|
+
- ✅ You've modified a generator implementation
|
|
19
|
+
- ✅ You've updated a provider SDK dependency
|
|
20
|
+
- ✅ You want to verify real API connectivity
|
|
21
|
+
- ✅ You're debugging unexpected behavior in production
|
|
22
|
+
- ✅ Before releasing a new generator to production
|
|
23
|
+
|
|
24
|
+
**Don't run live tests:**
|
|
25
|
+
|
|
26
|
+
- ❌ During regular development (use unit tests instead)
|
|
27
|
+
- ❌ In pre-commit hooks
|
|
28
|
+
- ❌ As part of `make test` or `make test-backend`
|
|
29
|
+
- ❌ In CI/CD pipelines (unless explicitly configured)
|
|
30
|
+
|
|
31
|
+
## Setting Up API Keys
|
|
32
|
+
|
|
33
|
+
Live tests require provider API keys. There are two ways to configure them:
|
|
34
|
+
|
|
35
|
+
### Option 1: Via Environment Variables (Direct)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Replicate
|
|
39
|
+
export REPLICATE_API_TOKEN="r8_..."
|
|
40
|
+
|
|
41
|
+
# Fal.ai
|
|
42
|
+
export FAL_KEY="..."
|
|
43
|
+
|
|
44
|
+
# OpenAI
|
|
45
|
+
export OPENAI_API_KEY="sk-..."
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Option 2: Via Boards Configuration (Recommended)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Single key
|
|
52
|
+
export BOARDS_GENERATOR_API_KEYS='{"REPLICATE_API_TOKEN": "r8_..."}'
|
|
53
|
+
|
|
54
|
+
# Multiple keys (JSON format)
|
|
55
|
+
export BOARDS_GENERATOR_API_KEYS='{
|
|
56
|
+
"REPLICATE_API_TOKEN": "r8_...",
|
|
57
|
+
"FAL_KEY": "...",
|
|
58
|
+
"OPENAI_API_KEY": "sk-..."
|
|
59
|
+
}'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Or add to your `.env` file:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
BOARDS_GENERATOR_API_KEYS={"REPLICATE_API_TOKEN": "r8_..."}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The Boards config system will automatically sync these keys to `os.environ` for third-party SDKs.
|
|
69
|
+
|
|
70
|
+
## Running Live API Tests
|
|
71
|
+
|
|
72
|
+
### Run a Single Generator's Live Test
|
|
73
|
+
|
|
74
|
+
This is the **most common workflow** when developing generators:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# After modifying flux_pro.py
|
|
78
|
+
export REPLICATE_API_TOKEN="r8_..."
|
|
79
|
+
pytest tests/generators/implementations/test_flux_pro_live.py -v -m live_api
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Example output:
|
|
83
|
+
```
|
|
84
|
+
tests/generators/implementations/test_flux_pro_live.py::TestFluxProGeneratorLive::test_generate_basic PASSED
|
|
85
|
+
tests/generators/implementations/test_flux_pro_live.py::TestFluxProGeneratorLive::test_generate_with_aspect_ratio PASSED
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If the API key is missing, tests will be skipped:
|
|
89
|
+
```
|
|
90
|
+
tests/generators/implementations/test_flux_pro_live.py::TestFluxProGeneratorLive::test_generate_basic SKIPPED (REPLICATE_API_TOKEN not set)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Run All Live Tests for One Provider
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# All Replicate generators
|
|
97
|
+
export REPLICATE_API_TOKEN="r8_..."
|
|
98
|
+
pytest -m live_replicate -v
|
|
99
|
+
|
|
100
|
+
# All Fal generators
|
|
101
|
+
export FAL_KEY="..."
|
|
102
|
+
pytest -m live_fal -v
|
|
103
|
+
|
|
104
|
+
# All OpenAI generators
|
|
105
|
+
export OPENAI_API_KEY="sk-..."
|
|
106
|
+
pytest -m live_openai -v
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Run All Live API Tests (Rarely Used)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Requires ALL provider API keys to be set
|
|
113
|
+
export REPLICATE_API_TOKEN="r8_..."
|
|
114
|
+
export FAL_KEY="..."
|
|
115
|
+
export OPENAI_API_KEY="sk-..."
|
|
116
|
+
|
|
117
|
+
pytest -m live_api -v
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
⚠️ **Warning:** This will consume credits across all providers!
|
|
121
|
+
|
|
122
|
+
### Run With Extra Verbosity
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Show detailed output including print statements and logs
|
|
126
|
+
pytest tests/generators/implementations/test_flux_pro_live.py -v -s -m live_api
|
|
127
|
+
|
|
128
|
+
# Show full error tracebacks
|
|
129
|
+
pytest tests/generators/implementations/test_flux_pro_live.py -v --tb=long -m live_api
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Cost Management
|
|
133
|
+
|
|
134
|
+
Live API tests consume real provider credits. Follow these practices:
|
|
135
|
+
|
|
136
|
+
### 1. Cost Logging
|
|
137
|
+
|
|
138
|
+
All live tests log estimated costs before running:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
@pytest.mark.asyncio
|
|
142
|
+
async def test_generate_basic(self, cost_logger):
|
|
143
|
+
cost_logger("replicate-flux-pro", 0.055)
|
|
144
|
+
# Test implementation...
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Look for log output like:
|
|
148
|
+
```
|
|
149
|
+
WARNING live_api_test_cost generator=replicate-flux-pro estimated_cost_usd=0.055
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 2. Minimal Inputs
|
|
153
|
+
|
|
154
|
+
Tests use minimal/cheap parameters:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# ✅ Good - Simple prompt, small size
|
|
158
|
+
inputs = FluxProInput(
|
|
159
|
+
prompt="A simple red circle",
|
|
160
|
+
aspect_ratio="1:1",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# ❌ Bad - Complex prompt, large size, multiple images
|
|
164
|
+
inputs = FluxProInput(
|
|
165
|
+
prompt="Ultra detailed 8K photorealistic...",
|
|
166
|
+
aspect_ratio="21:9",
|
|
167
|
+
num_images=10,
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 3. Approximate Costs (as of 2024)
|
|
172
|
+
|
|
173
|
+
| Provider | Generator | Estimated Cost |
|
|
174
|
+
|----------|-----------|----------------|
|
|
175
|
+
| Replicate | flux-pro | $0.055/image |
|
|
176
|
+
| Fal.ai | nano-banana | $0.05/image |
|
|
177
|
+
| Fal.ai | nano-banana-edit | $0.05/image |
|
|
178
|
+
| OpenAI | dalle3 | $0.04-$0.08/image |
|
|
179
|
+
| OpenAI | whisper | $0.006/minute |
|
|
180
|
+
|
|
181
|
+
Running a full test suite for one generator typically costs **$0.10 - $0.30**.
|
|
182
|
+
|
|
183
|
+
## Verifying Tests Are Excluded
|
|
184
|
+
|
|
185
|
+
Live tests are **automatically excluded by default** thanks to `pytest.ini` configuration:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# All of these commands exclude live tests by default:
|
|
189
|
+
make test-backend
|
|
190
|
+
cd packages/backend && uv run pytest
|
|
191
|
+
cd packages/backend && uv run pytest tests/
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
You should see output like:
|
|
195
|
+
```
|
|
196
|
+
337/350 tests collected (13 deselected)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The 13 deselected tests are the live API tests.
|
|
200
|
+
|
|
201
|
+
Check pytest markers to see which tests would run:
|
|
202
|
+
```bash
|
|
203
|
+
# List all live API tests (without running them)
|
|
204
|
+
pytest --collect-only -m live_api
|
|
205
|
+
|
|
206
|
+
# Verify default behavior excludes live tests
|
|
207
|
+
pytest --collect-only -q | tail -1
|
|
208
|
+
# Should show: "337/350 tests collected (13 deselected)"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Troubleshooting
|
|
212
|
+
|
|
213
|
+
### Tests Are Skipped
|
|
214
|
+
|
|
215
|
+
**Problem:** All tests show `SKIPPED` status
|
|
216
|
+
|
|
217
|
+
**Cause:** API key not found
|
|
218
|
+
|
|
219
|
+
**Solution:**
|
|
220
|
+
```bash
|
|
221
|
+
# Verify API key is set
|
|
222
|
+
echo $REPLICATE_API_TOKEN
|
|
223
|
+
|
|
224
|
+
# If empty, export it
|
|
225
|
+
export REPLICATE_API_TOKEN="r8_..."
|
|
226
|
+
|
|
227
|
+
# Or check Boards config
|
|
228
|
+
python -c "from boards.config import settings; print(settings.generator_api_keys)"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### API Errors
|
|
232
|
+
|
|
233
|
+
**Problem:** Test fails with authentication error
|
|
234
|
+
|
|
235
|
+
**Solutions:**
|
|
236
|
+
1. Verify API key is valid (not expired/revoked)
|
|
237
|
+
2. Check API key has correct permissions
|
|
238
|
+
3. Verify provider account has sufficient credits
|
|
239
|
+
|
|
240
|
+
**Example error:**
|
|
241
|
+
```
|
|
242
|
+
ValueError: API configuration invalid. Missing REPLICATE_API_TOKEN
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Unexpected Costs
|
|
246
|
+
|
|
247
|
+
**Problem:** Tests consumed more credits than expected
|
|
248
|
+
|
|
249
|
+
**Prevention:**
|
|
250
|
+
1. Always read the test file first to understand what it does
|
|
251
|
+
2. Check cost logger output before tests run
|
|
252
|
+
3. Use single generator tests, not `pytest -m live_api`
|
|
253
|
+
4. Start with one test function: `pytest test_flux_pro_live.py::TestFluxProGeneratorLive::test_estimate_cost`
|
|
254
|
+
|
|
255
|
+
## Adding Live Tests for New Generators
|
|
256
|
+
|
|
257
|
+
When creating a new generator, follow these steps:
|
|
258
|
+
|
|
259
|
+
### 1. Create the Live Test File
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Template: test_<generator>_live.py
|
|
263
|
+
touch tests/generators/implementations/test_my_generator_live.py
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### 2. Use This Template
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
"""
|
|
270
|
+
Live API tests for MyGenerator.
|
|
271
|
+
|
|
272
|
+
To run: pytest tests/generators/implementations/test_my_generator_live.py -v -m live_api
|
|
273
|
+
"""
|
|
274
|
+
import pytest
|
|
275
|
+
from boards.config import initialize_generator_api_keys
|
|
276
|
+
from boards.generators.implementations.provider.type.my_generator import (
|
|
277
|
+
MyGeneratorInput,
|
|
278
|
+
MyGenerator,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
pytestmark = [pytest.mark.live_api, pytest.mark.live_<provider>]
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class TestMyGeneratorLive:
|
|
285
|
+
"""Live API tests for MyGenerator."""
|
|
286
|
+
|
|
287
|
+
def setup_method(self):
|
|
288
|
+
"""Set up generator and sync API keys."""
|
|
289
|
+
self.generator = MyGenerator()
|
|
290
|
+
initialize_generator_api_keys()
|
|
291
|
+
|
|
292
|
+
@pytest.mark.asyncio
|
|
293
|
+
async def test_generate_basic(
|
|
294
|
+
self, skip_if_no_<provider>_key, dummy_context, cost_logger
|
|
295
|
+
):
|
|
296
|
+
"""Test basic generation with minimal parameters."""
|
|
297
|
+
# Log cost
|
|
298
|
+
estimated_cost = await self.generator.estimate_cost(
|
|
299
|
+
MyGeneratorInput(prompt="test")
|
|
300
|
+
)
|
|
301
|
+
cost_logger(self.generator.name, estimated_cost)
|
|
302
|
+
|
|
303
|
+
# Minimal input to reduce cost
|
|
304
|
+
inputs = MyGeneratorInput(prompt="Simple test")
|
|
305
|
+
|
|
306
|
+
# Execute
|
|
307
|
+
result = await self.generator.generate(inputs, dummy_context)
|
|
308
|
+
|
|
309
|
+
# Verify
|
|
310
|
+
assert result.outputs is not None
|
|
311
|
+
assert len(result.outputs) > 0
|
|
312
|
+
assert result.outputs[0].storage_url is not None
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 3. Add Provider-Specific Skip Fixture (If New Provider)
|
|
316
|
+
|
|
317
|
+
If adding a new provider (not Replicate/Fal/OpenAI), add to `conftest.py`:
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
@pytest.fixture
|
|
321
|
+
def skip_if_no_my_provider_key():
|
|
322
|
+
"""Skip test if MY_PROVIDER_API_KEY is not available."""
|
|
323
|
+
if not check_api_key("MY_PROVIDER_API_KEY"):
|
|
324
|
+
pytest.skip("MY_PROVIDER_API_KEY not set, skipping live API test")
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 4. Add Pytest Marker (If New Provider)
|
|
328
|
+
|
|
329
|
+
Update `pytest.ini`:
|
|
330
|
+
|
|
331
|
+
```ini
|
|
332
|
+
markers =
|
|
333
|
+
...
|
|
334
|
+
live_my_provider: marks tests that call MyProvider API (subset of live_api)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 5. Test Your Live Test
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# Without API key - should skip
|
|
341
|
+
pytest tests/generators/implementations/test_my_generator_live.py -v -m live_api
|
|
342
|
+
|
|
343
|
+
# With API key - should run
|
|
344
|
+
export MY_PROVIDER_API_KEY="..."
|
|
345
|
+
pytest tests/generators/implementations/test_my_generator_live.py -v -m live_api
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Best Practices
|
|
349
|
+
|
|
350
|
+
### DO:
|
|
351
|
+
- ✅ Run live tests individually after modifying a generator
|
|
352
|
+
- ✅ Use minimal inputs to reduce costs
|
|
353
|
+
- ✅ Log estimated costs before running tests
|
|
354
|
+
- ✅ Keep live tests simple and focused
|
|
355
|
+
- ✅ Verify tests are skipped when API keys are missing
|
|
356
|
+
- ✅ Document expected costs in test docstrings
|
|
357
|
+
|
|
358
|
+
### DON'T:
|
|
359
|
+
- ❌ Run `pytest -m live_api` unless you mean it
|
|
360
|
+
- ❌ Add live tests to CI without explicit approval
|
|
361
|
+
- ❌ Use live tests for load/performance testing
|
|
362
|
+
- ❌ Test with expensive parameters (high quality, large sizes, etc.)
|
|
363
|
+
- ❌ Create hundreds of test cases for one generator
|
|
364
|
+
- ❌ Commit API keys to the repository
|
|
365
|
+
|
|
366
|
+
## Continuous Integration (Optional)
|
|
367
|
+
|
|
368
|
+
If you want to run live tests in CI (not recommended for most projects):
|
|
369
|
+
|
|
370
|
+
### GitHub Actions Example
|
|
371
|
+
|
|
372
|
+
```yaml
|
|
373
|
+
name: Live API Tests (Manual)
|
|
374
|
+
|
|
375
|
+
on:
|
|
376
|
+
workflow_dispatch: # Manual trigger only
|
|
377
|
+
|
|
378
|
+
jobs:
|
|
379
|
+
live-tests:
|
|
380
|
+
runs-on: ubuntu-latest
|
|
381
|
+
steps:
|
|
382
|
+
- uses: actions/checkout@v3
|
|
383
|
+
- name: Set up Python
|
|
384
|
+
uses: actions/setup-python@v4
|
|
385
|
+
with:
|
|
386
|
+
python-version: '3.12'
|
|
387
|
+
- name: Install dependencies
|
|
388
|
+
run: |
|
|
389
|
+
cd packages/backend
|
|
390
|
+
pip install uv
|
|
391
|
+
uv sync
|
|
392
|
+
- name: Run Replicate live tests
|
|
393
|
+
env:
|
|
394
|
+
REPLICATE_API_TOKEN: ${{ secrets.REPLICATE_API_TOKEN }}
|
|
395
|
+
run: |
|
|
396
|
+
cd packages/backend
|
|
397
|
+
uv run pytest -m live_replicate --tb=short
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Important:** Only run on:
|
|
401
|
+
- Manual workflow dispatch
|
|
402
|
+
- Scheduled (e.g., nightly) runs
|
|
403
|
+
- Release branches
|
|
404
|
+
|
|
405
|
+
**Never** run live tests on every PR or commit.
|
|
406
|
+
|
|
407
|
+
## Summary
|
|
408
|
+
|
|
409
|
+
- Live API tests verify real connectivity to provider APIs
|
|
410
|
+
- They are **opt-in only** and never run by default
|
|
411
|
+
- Set up API keys via environment variables or Boards config
|
|
412
|
+
- Run individual tests after modifying generators: `pytest test_flux_pro_live.py -v -m live_api`
|
|
413
|
+
- Monitor costs using cost logger output
|
|
414
|
+
- Use minimal inputs to reduce expenses
|
|
415
|
+
- Follow the template when adding tests for new generators
|
|
416
|
+
|
|
417
|
+
For questions or issues, see the main [generator testing documentation](../../../apps/docs/docs/generators/testing.md).
|