@weirdfingers/baseboards 0.9.5 → 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 +561 -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,50 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Generator resolvers for GraphQL API
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import strawberry
|
|
6
|
-
|
|
7
|
-
from ...generators.registry import registry
|
|
8
|
-
from ..types.generation import ArtifactType
|
|
9
|
-
from ..types.generator import GeneratorInfo
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
async def resolve_generators(
|
|
13
|
-
info: strawberry.Info,
|
|
14
|
-
artifact_type: str | None = None,
|
|
15
|
-
) -> list[GeneratorInfo]:
|
|
16
|
-
"""Get all available generators, optionally filtered by artifact type.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
info: GraphQL info context
|
|
20
|
-
artifact_type: Optional filter by artifact type (image, video, audio, text)
|
|
21
|
-
|
|
22
|
-
Returns:
|
|
23
|
-
List of generator information
|
|
24
|
-
"""
|
|
25
|
-
_ = info # Unused but required by GraphQL interface
|
|
26
|
-
|
|
27
|
-
# Get generators from registry
|
|
28
|
-
if artifact_type:
|
|
29
|
-
generators = registry.list_by_artifact_type(artifact_type)
|
|
30
|
-
else:
|
|
31
|
-
generators = registry.list_all()
|
|
32
|
-
|
|
33
|
-
# Convert to GraphQL types
|
|
34
|
-
result = []
|
|
35
|
-
for gen in generators:
|
|
36
|
-
input_schema_class = gen.get_input_schema()
|
|
37
|
-
|
|
38
|
-
# Convert string artifact_type to enum
|
|
39
|
-
artifact_type_enum = ArtifactType(gen.artifact_type)
|
|
40
|
-
|
|
41
|
-
result.append(
|
|
42
|
-
GeneratorInfo(
|
|
43
|
-
name=gen.name,
|
|
44
|
-
description=gen.description,
|
|
45
|
-
artifact_type=artifact_type_enum,
|
|
46
|
-
input_schema=input_schema_class.model_json_schema(),
|
|
47
|
-
)
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
return result
|
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Lineage resolvers for ancestry and descendants tracking
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from uuid import UUID
|
|
6
|
-
|
|
7
|
-
import strawberry
|
|
8
|
-
from sqlalchemy import select, text
|
|
9
|
-
|
|
10
|
-
from ...database.connection import get_async_session
|
|
11
|
-
from ...dbmodels import Boards, Generations
|
|
12
|
-
from ...logging import get_logger
|
|
13
|
-
from ..access_control import can_access_board, get_auth_context_from_info
|
|
14
|
-
from ..types.generation import (
|
|
15
|
-
AncestryNode,
|
|
16
|
-
ArtifactLineage,
|
|
17
|
-
ArtifactType,
|
|
18
|
-
DescendantNode,
|
|
19
|
-
Generation,
|
|
20
|
-
GenerationStatus,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
logger = get_logger(__name__)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def convert_db_to_graphql_generation(gen: Generations) -> Generation:
|
|
27
|
-
"""Convert a database Generation model to GraphQL Generation type."""
|
|
28
|
-
return Generation(
|
|
29
|
-
id=gen.id,
|
|
30
|
-
tenant_id=gen.tenant_id,
|
|
31
|
-
board_id=gen.board_id,
|
|
32
|
-
user_id=gen.user_id,
|
|
33
|
-
generator_name=gen.generator_name,
|
|
34
|
-
artifact_type=ArtifactType(gen.artifact_type),
|
|
35
|
-
storage_url=gen.storage_url,
|
|
36
|
-
thumbnail_url=gen.thumbnail_url,
|
|
37
|
-
additional_files=gen.additional_files or [],
|
|
38
|
-
input_params=gen.input_params or {},
|
|
39
|
-
output_metadata=gen.output_metadata or {},
|
|
40
|
-
external_job_id=gen.external_job_id,
|
|
41
|
-
status=GenerationStatus(gen.status),
|
|
42
|
-
progress=float(gen.progress or 0.0),
|
|
43
|
-
error_message=gen.error_message,
|
|
44
|
-
started_at=gen.started_at,
|
|
45
|
-
completed_at=gen.completed_at,
|
|
46
|
-
created_at=gen.created_at,
|
|
47
|
-
updated_at=gen.updated_at,
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
async def resolve_input_artifacts(
|
|
52
|
-
generation: Generation, info: strawberry.Info
|
|
53
|
-
) -> list[ArtifactLineage]:
|
|
54
|
-
"""Resolve input artifacts with role metadata."""
|
|
55
|
-
async with get_async_session() as session:
|
|
56
|
-
# Query the generation to get input_artifacts
|
|
57
|
-
stmt = select(Generations).where(Generations.id == generation.id)
|
|
58
|
-
result = await session.execute(stmt)
|
|
59
|
-
gen = result.scalar_one_or_none()
|
|
60
|
-
|
|
61
|
-
if not gen or not gen.input_artifacts:
|
|
62
|
-
return []
|
|
63
|
-
|
|
64
|
-
# Build ArtifactLineage objects
|
|
65
|
-
lineages = []
|
|
66
|
-
for artifact_data in gen.input_artifacts:
|
|
67
|
-
lineages.append(
|
|
68
|
-
ArtifactLineage(
|
|
69
|
-
generation_id=UUID(artifact_data["generation_id"]),
|
|
70
|
-
role=artifact_data["role"],
|
|
71
|
-
artifact_type=ArtifactType(artifact_data["artifact_type"]),
|
|
72
|
-
)
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
return lineages
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
async def resolve_generation_by_id(info: strawberry.Info, generation_id: UUID) -> Generation | None:
|
|
79
|
-
"""Helper to resolve a generation by ID with access control."""
|
|
80
|
-
auth_context = await get_auth_context_from_info(info)
|
|
81
|
-
if auth_context is None:
|
|
82
|
-
return None
|
|
83
|
-
|
|
84
|
-
async with get_async_session() as session:
|
|
85
|
-
# Query generation
|
|
86
|
-
stmt = select(Generations).where(Generations.id == generation_id)
|
|
87
|
-
result = await session.execute(stmt)
|
|
88
|
-
gen = result.scalar_one_or_none()
|
|
89
|
-
|
|
90
|
-
if not gen:
|
|
91
|
-
return None
|
|
92
|
-
|
|
93
|
-
# Check board access
|
|
94
|
-
board_stmt = select(Boards).where(Boards.id == gen.board_id)
|
|
95
|
-
board_result = await session.execute(board_stmt)
|
|
96
|
-
board = board_result.scalar_one_or_none()
|
|
97
|
-
|
|
98
|
-
if not board or not can_access_board(board, auth_context):
|
|
99
|
-
return None
|
|
100
|
-
|
|
101
|
-
return convert_db_to_graphql_generation(gen)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
async def resolve_ancestry(
|
|
105
|
-
generation: Generation, info: strawberry.Info, max_depth: int = 25
|
|
106
|
-
) -> AncestryNode:
|
|
107
|
-
"""Build recursive ancestry tree using recursive CTE."""
|
|
108
|
-
auth_context = await get_auth_context_from_info(info)
|
|
109
|
-
|
|
110
|
-
if not auth_context:
|
|
111
|
-
# Return empty tree if not authenticated
|
|
112
|
-
return AncestryNode(generation=generation, depth=0, role=None, parents=[])
|
|
113
|
-
|
|
114
|
-
async with get_async_session() as session:
|
|
115
|
-
# Use recursive CTE to fetch entire ancestry tree in one query
|
|
116
|
-
cte_query = text("""
|
|
117
|
-
WITH RECURSIVE ancestry_tree AS (
|
|
118
|
-
-- Base case: starting generation
|
|
119
|
-
SELECT
|
|
120
|
-
id,
|
|
121
|
-
tenant_id,
|
|
122
|
-
board_id,
|
|
123
|
-
user_id,
|
|
124
|
-
generator_name,
|
|
125
|
-
artifact_type,
|
|
126
|
-
storage_url,
|
|
127
|
-
thumbnail_url,
|
|
128
|
-
additional_files,
|
|
129
|
-
input_params,
|
|
130
|
-
output_metadata,
|
|
131
|
-
external_job_id,
|
|
132
|
-
status,
|
|
133
|
-
progress,
|
|
134
|
-
error_message,
|
|
135
|
-
started_at,
|
|
136
|
-
completed_at,
|
|
137
|
-
created_at,
|
|
138
|
-
updated_at,
|
|
139
|
-
input_artifacts,
|
|
140
|
-
0 as depth,
|
|
141
|
-
NULL::text as role,
|
|
142
|
-
ARRAY[id] as path -- cycle detection
|
|
143
|
-
FROM boards.generations
|
|
144
|
-
WHERE id = :gen_id AND tenant_id = :tenant_id
|
|
145
|
-
|
|
146
|
-
UNION ALL
|
|
147
|
-
|
|
148
|
-
-- Recursive case: parent generations
|
|
149
|
-
SELECT
|
|
150
|
-
g.id,
|
|
151
|
-
g.tenant_id,
|
|
152
|
-
g.board_id,
|
|
153
|
-
g.user_id,
|
|
154
|
-
g.generator_name,
|
|
155
|
-
g.artifact_type,
|
|
156
|
-
g.storage_url,
|
|
157
|
-
g.thumbnail_url,
|
|
158
|
-
g.additional_files,
|
|
159
|
-
g.input_params,
|
|
160
|
-
g.output_metadata,
|
|
161
|
-
g.external_job_id,
|
|
162
|
-
g.status,
|
|
163
|
-
g.progress,
|
|
164
|
-
g.error_message,
|
|
165
|
-
g.started_at,
|
|
166
|
-
g.completed_at,
|
|
167
|
-
g.created_at,
|
|
168
|
-
g.updated_at,
|
|
169
|
-
g.input_artifacts,
|
|
170
|
-
at.depth + 1,
|
|
171
|
-
artifact->>'role' as role,
|
|
172
|
-
at.path || g.id
|
|
173
|
-
FROM ancestry_tree at
|
|
174
|
-
CROSS JOIN LATERAL jsonb_array_elements(at.input_artifacts) AS artifact
|
|
175
|
-
JOIN boards.generations g ON
|
|
176
|
-
g.id = (artifact->>'generation_id')::uuid
|
|
177
|
-
AND NOT (g.id = ANY(at.path)) -- prevent cycles
|
|
178
|
-
AND at.depth < :max_depth
|
|
179
|
-
WHERE g.tenant_id = :tenant_id
|
|
180
|
-
)
|
|
181
|
-
SELECT * FROM ancestry_tree ORDER BY depth, id
|
|
182
|
-
""")
|
|
183
|
-
|
|
184
|
-
result = await session.execute(
|
|
185
|
-
cte_query,
|
|
186
|
-
{
|
|
187
|
-
"gen_id": generation.id,
|
|
188
|
-
"tenant_id": auth_context.tenant_id,
|
|
189
|
-
"max_depth": max_depth,
|
|
190
|
-
},
|
|
191
|
-
)
|
|
192
|
-
rows = result.fetchall()
|
|
193
|
-
|
|
194
|
-
if not rows:
|
|
195
|
-
# Return root node with no parents
|
|
196
|
-
return AncestryNode(generation=generation, depth=0, role=None, parents=[])
|
|
197
|
-
|
|
198
|
-
# Build tree from flat results
|
|
199
|
-
nodes_by_id: dict[UUID, tuple[Generations, int, str | None]] = {}
|
|
200
|
-
for row in rows:
|
|
201
|
-
gen_obj = Generations()
|
|
202
|
-
gen_obj.id = row.id
|
|
203
|
-
gen_obj.tenant_id = row.tenant_id
|
|
204
|
-
gen_obj.board_id = row.board_id
|
|
205
|
-
gen_obj.user_id = row.user_id
|
|
206
|
-
gen_obj.generator_name = row.generator_name
|
|
207
|
-
gen_obj.artifact_type = row.artifact_type
|
|
208
|
-
gen_obj.storage_url = row.storage_url
|
|
209
|
-
gen_obj.thumbnail_url = row.thumbnail_url
|
|
210
|
-
gen_obj.additional_files = row.additional_files
|
|
211
|
-
gen_obj.input_params = row.input_params
|
|
212
|
-
gen_obj.output_metadata = row.output_metadata
|
|
213
|
-
gen_obj.external_job_id = row.external_job_id
|
|
214
|
-
gen_obj.status = row.status
|
|
215
|
-
gen_obj.progress = row.progress
|
|
216
|
-
gen_obj.error_message = row.error_message
|
|
217
|
-
gen_obj.started_at = row.started_at
|
|
218
|
-
gen_obj.completed_at = row.completed_at
|
|
219
|
-
gen_obj.created_at = row.created_at
|
|
220
|
-
gen_obj.updated_at = row.updated_at
|
|
221
|
-
gen_obj.input_artifacts = row.input_artifacts
|
|
222
|
-
nodes_by_id[row.id] = (gen_obj, row.depth, row.role)
|
|
223
|
-
|
|
224
|
-
# Build tree structure recursively
|
|
225
|
-
def build_node(gen_id: UUID) -> AncestryNode:
|
|
226
|
-
gen_obj, depth, role = nodes_by_id[gen_id]
|
|
227
|
-
gen_graphql = convert_db_to_graphql_generation(gen_obj)
|
|
228
|
-
|
|
229
|
-
# Find parent nodes
|
|
230
|
-
parent_nodes = []
|
|
231
|
-
if gen_obj.input_artifacts:
|
|
232
|
-
for artifact_data in gen_obj.input_artifacts:
|
|
233
|
-
parent_id = UUID(artifact_data["generation_id"])
|
|
234
|
-
if parent_id in nodes_by_id:
|
|
235
|
-
parent_nodes.append(build_node(parent_id))
|
|
236
|
-
|
|
237
|
-
return AncestryNode(
|
|
238
|
-
generation=gen_graphql, depth=depth, role=role, parents=parent_nodes
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
return build_node(generation.id)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
async def resolve_descendants(
|
|
245
|
-
generation: Generation, info: strawberry.Info, max_depth: int = 25
|
|
246
|
-
) -> DescendantNode:
|
|
247
|
-
"""Build recursive descendants tree using recursive CTE."""
|
|
248
|
-
auth_context = await get_auth_context_from_info(info)
|
|
249
|
-
|
|
250
|
-
if not auth_context:
|
|
251
|
-
# Return empty tree if not authenticated
|
|
252
|
-
return DescendantNode(generation=generation, depth=0, role=None, children=[])
|
|
253
|
-
|
|
254
|
-
async with get_async_session() as session:
|
|
255
|
-
# Use recursive CTE to fetch entire descendants tree in one query
|
|
256
|
-
cte_query = text("""
|
|
257
|
-
WITH RECURSIVE descendants_tree AS (
|
|
258
|
-
-- Base case: starting generation
|
|
259
|
-
SELECT
|
|
260
|
-
id,
|
|
261
|
-
tenant_id,
|
|
262
|
-
board_id,
|
|
263
|
-
user_id,
|
|
264
|
-
generator_name,
|
|
265
|
-
artifact_type,
|
|
266
|
-
storage_url,
|
|
267
|
-
thumbnail_url,
|
|
268
|
-
additional_files,
|
|
269
|
-
input_params,
|
|
270
|
-
output_metadata,
|
|
271
|
-
external_job_id,
|
|
272
|
-
status,
|
|
273
|
-
progress,
|
|
274
|
-
error_message,
|
|
275
|
-
started_at,
|
|
276
|
-
completed_at,
|
|
277
|
-
created_at,
|
|
278
|
-
updated_at,
|
|
279
|
-
input_artifacts,
|
|
280
|
-
0 as depth,
|
|
281
|
-
NULL::text as role,
|
|
282
|
-
NULL::uuid as parent_id,
|
|
283
|
-
ARRAY[id] as path -- cycle detection
|
|
284
|
-
FROM boards.generations
|
|
285
|
-
WHERE id = :gen_id AND tenant_id = :tenant_id
|
|
286
|
-
|
|
287
|
-
UNION ALL
|
|
288
|
-
|
|
289
|
-
-- Recursive case: child generations
|
|
290
|
-
SELECT
|
|
291
|
-
g.id,
|
|
292
|
-
g.tenant_id,
|
|
293
|
-
g.board_id,
|
|
294
|
-
g.user_id,
|
|
295
|
-
g.generator_name,
|
|
296
|
-
g.artifact_type,
|
|
297
|
-
g.storage_url,
|
|
298
|
-
g.thumbnail_url,
|
|
299
|
-
g.additional_files,
|
|
300
|
-
g.input_params,
|
|
301
|
-
g.output_metadata,
|
|
302
|
-
g.external_job_id,
|
|
303
|
-
g.status,
|
|
304
|
-
g.progress,
|
|
305
|
-
g.error_message,
|
|
306
|
-
g.started_at,
|
|
307
|
-
g.completed_at,
|
|
308
|
-
g.created_at,
|
|
309
|
-
g.updated_at,
|
|
310
|
-
g.input_artifacts,
|
|
311
|
-
dt.depth + 1,
|
|
312
|
-
artifact->>'role' as role,
|
|
313
|
-
dt.id as parent_id,
|
|
314
|
-
dt.path || g.id
|
|
315
|
-
FROM boards.generations g
|
|
316
|
-
CROSS JOIN LATERAL jsonb_array_elements(g.input_artifacts) AS artifact
|
|
317
|
-
JOIN descendants_tree dt ON
|
|
318
|
-
dt.id = (artifact->>'generation_id')::uuid
|
|
319
|
-
AND NOT (g.id = ANY(dt.path)) -- prevent cycles
|
|
320
|
-
AND dt.depth < :max_depth
|
|
321
|
-
WHERE g.tenant_id = :tenant_id
|
|
322
|
-
)
|
|
323
|
-
SELECT * FROM descendants_tree ORDER BY depth, id
|
|
324
|
-
""")
|
|
325
|
-
|
|
326
|
-
result = await session.execute(
|
|
327
|
-
cte_query,
|
|
328
|
-
{
|
|
329
|
-
"gen_id": generation.id,
|
|
330
|
-
"tenant_id": auth_context.tenant_id,
|
|
331
|
-
"max_depth": max_depth,
|
|
332
|
-
},
|
|
333
|
-
)
|
|
334
|
-
rows = result.fetchall()
|
|
335
|
-
|
|
336
|
-
if not rows:
|
|
337
|
-
# Return root node with no children
|
|
338
|
-
return DescendantNode(generation=generation, depth=0, role=None, children=[])
|
|
339
|
-
|
|
340
|
-
# Build tree from flat results
|
|
341
|
-
nodes_by_id: dict[UUID, tuple[Generations, int, str | None, UUID | None]] = {}
|
|
342
|
-
for row in rows:
|
|
343
|
-
gen_obj = Generations()
|
|
344
|
-
gen_obj.id = row.id
|
|
345
|
-
gen_obj.tenant_id = row.tenant_id
|
|
346
|
-
gen_obj.board_id = row.board_id
|
|
347
|
-
gen_obj.user_id = row.user_id
|
|
348
|
-
gen_obj.generator_name = row.generator_name
|
|
349
|
-
gen_obj.artifact_type = row.artifact_type
|
|
350
|
-
gen_obj.storage_url = row.storage_url
|
|
351
|
-
gen_obj.thumbnail_url = row.thumbnail_url
|
|
352
|
-
gen_obj.additional_files = row.additional_files
|
|
353
|
-
gen_obj.input_params = row.input_params
|
|
354
|
-
gen_obj.output_metadata = row.output_metadata
|
|
355
|
-
gen_obj.external_job_id = row.external_job_id
|
|
356
|
-
gen_obj.status = row.status
|
|
357
|
-
gen_obj.progress = row.progress
|
|
358
|
-
gen_obj.error_message = row.error_message
|
|
359
|
-
gen_obj.started_at = row.started_at
|
|
360
|
-
gen_obj.completed_at = row.completed_at
|
|
361
|
-
gen_obj.created_at = row.created_at
|
|
362
|
-
gen_obj.updated_at = row.updated_at
|
|
363
|
-
gen_obj.input_artifacts = row.input_artifacts
|
|
364
|
-
nodes_by_id[row.id] = (gen_obj, row.depth, row.role, row.parent_id)
|
|
365
|
-
|
|
366
|
-
# Build tree structure recursively
|
|
367
|
-
def build_node(gen_id: UUID) -> DescendantNode:
|
|
368
|
-
gen_obj, depth, role, _ = nodes_by_id[gen_id]
|
|
369
|
-
gen_graphql = convert_db_to_graphql_generation(gen_obj)
|
|
370
|
-
|
|
371
|
-
# Find child nodes (nodes that have this as parent_id)
|
|
372
|
-
child_nodes = []
|
|
373
|
-
for child_id, (_, _, _, parent_id) in nodes_by_id.items():
|
|
374
|
-
if parent_id == gen_id:
|
|
375
|
-
child_nodes.append(build_node(child_id))
|
|
376
|
-
|
|
377
|
-
return DescendantNode(
|
|
378
|
-
generation=gen_graphql, depth=depth, role=role, children=child_nodes
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
return build_node(generation.id)
|