feat: add AirShelf core implementation

This commit is contained in:
zyc
2026-06-05 10:21:40 +08:00
parent 2ba1058329
commit cfdcd84a30
252 changed files with 70828 additions and 0 deletions
@@ -0,0 +1,721 @@
# Generated by Django 5.1.15 on 2026-05-29 03:59
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("accounts", "0001_initial"),
("ai", "0001_initial"),
("assets", "0001_initial"),
("products", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Project",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("name", models.CharField(max_length=255)),
(
"status",
models.CharField(
choices=[
("draft", "Draft"),
("scripting", "Scripting"),
("asseting", "Asseting"),
("storyboarding", "Storyboarding"),
("videoing", "Videoing"),
("exporting", "Exporting"),
("completed", "Completed"),
("failed", "Failed"),
],
default="draft",
max_length=32,
),
),
("current_stage", models.CharField(default="script", max_length=32)),
(
"budget_limit",
models.DecimalField(
blank=True, decimal_places=2, max_digits=12, null=True
),
),
("failure_reason", models.TextField(blank=True)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"created_by",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="created_%(class)s_set",
to=settings.AUTH_USER_MODEL,
),
),
(
"product",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="projects",
to="products.product",
),
),
(
"team",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="%(class)s_set",
to="accounts.team",
),
),
],
),
migrations.CreateModel(
name="BaseAssetGroup",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"kind",
models.CharField(
choices=[
("product", "Product"),
("person", "Person"),
("scene", "Scene"),
],
max_length=32,
),
),
("prompt", models.TextField(blank=True)),
("version", models.PositiveIntegerField(default=1)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"adopted_asset",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="adopted_base_groups",
to="assets.asset",
),
),
(
"candidate_assets",
models.ManyToManyField(
blank=True,
related_name="candidate_base_groups",
to="assets.asset",
),
),
(
"task",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="base_asset_groups",
to="ai.aitask",
),
),
(
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="base_asset_groups",
to="projects.project",
),
),
],
),
migrations.CreateModel(
name="ProjectStage",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"stage",
models.CharField(
choices=[
("script", "Script"),
("base_assets", "Base Assets"),
("storyboard", "Storyboard"),
("video", "Video"),
("export", "Export"),
],
max_length=32,
),
),
(
"status",
models.CharField(
choices=[
("not_started", "Not Started"),
("draft", "Draft"),
("queued", "Queued"),
("running", "Running"),
("succeeded", "Succeeded"),
("failed", "Failed"),
("skipped", "Skipped"),
("needs_review", "Needs Review"),
],
default="not_started",
max_length=32,
),
),
("started_at", models.DateTimeField(blank=True, null=True)),
("completed_at", models.DateTimeField(blank=True, null=True)),
("error_message", models.TextField(blank=True)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="stages",
to="projects.project",
),
),
],
options={
"ordering": ["created_at"],
},
),
migrations.CreateModel(
name="ScriptVersion",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("title", models.CharField(blank=True, max_length=128)),
("content", models.TextField()),
("source", models.CharField(default="ai", max_length=32)),
("is_adopted", models.BooleanField(default=False)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="script_versions",
to="projects.project",
),
),
(
"task",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="script_versions",
to="ai.aitask",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="ScriptSegment",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("sort_order", models.PositiveIntegerField(default=0)),
("duration_seconds", models.PositiveIntegerField(default=15)),
("narration", models.TextField(blank=True)),
("visual_prompt", models.TextField(blank=True)),
("product_points", models.JSONField(blank=True, default=list)),
(
"script_version",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="segments",
to="projects.scriptversion",
),
),
],
options={
"ordering": ["sort_order", "created_at"],
},
),
migrations.CreateModel(
name="StoryboardVersion",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("prompt", models.TextField(blank=True)),
("is_adopted", models.BooleanField(default=False)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="storyboard_versions",
to="projects.project",
),
),
(
"task",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="storyboard_versions",
to="ai.aitask",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="StoryboardFrame",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("sort_order", models.PositiveIntegerField(default=0)),
("prompt", models.TextField(blank=True)),
(
"asset",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="storyboard_frames",
to="assets.asset",
),
),
(
"script_segment",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="storyboard_frames",
to="projects.scriptsegment",
),
),
(
"storyboard",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="frames",
to="projects.storyboardversion",
),
),
],
options={
"ordering": ["sort_order", "created_at"],
},
),
migrations.CreateModel(
name="Timeline",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("name", models.CharField(blank=True, max_length=255)),
("aspect_ratio", models.CharField(default="9:16", max_length=16)),
("resolution", models.CharField(default="1080x1920", max_length=32)),
("duration_seconds", models.PositiveIntegerField(default=60)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"project",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="timeline",
to="projects.project",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="SubtitleTrack",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("content", models.JSONField(blank=True, default=list)),
("style", models.JSONField(blank=True, default=dict)),
("enabled", models.BooleanField(default=True)),
(
"timeline",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="subtitle_tracks",
to="projects.timeline",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="ExportJob",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"status",
models.CharField(
choices=[
("draft", "Draft"),
("queued", "Queued"),
("running", "Running"),
("succeeded", "Succeeded"),
("failed", "Failed"),
],
default="draft",
max_length=32,
),
),
("progress", models.PositiveIntegerField(default=0)),
("error_message", models.TextField(blank=True)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"output_asset",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="export_jobs",
to="assets.asset",
),
),
(
"task",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="export_jobs",
to="ai.aitask",
),
),
(
"timeline",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="export_jobs",
to="projects.timeline",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="BgmTrack",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("volume", models.PositiveIntegerField(default=60)),
("start_ms", models.PositiveIntegerField(default=0)),
(
"asset",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="bgm_tracks",
to="assets.asset",
),
),
(
"timeline",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="bgm_tracks",
to="projects.timeline",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="TimelineClip",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("sort_order", models.PositiveIntegerField(default=0)),
("start_ms", models.PositiveIntegerField(default=0)),
("duration_ms", models.PositiveIntegerField(default=15000)),
("trim_start_ms", models.PositiveIntegerField(default=0)),
("trim_end_ms", models.PositiveIntegerField(blank=True, null=True)),
(
"asset",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="timeline_clips",
to="assets.asset",
),
),
(
"timeline",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="clips",
to="projects.timeline",
),
),
],
options={
"ordering": ["sort_order", "created_at"],
},
),
migrations.CreateModel(
name="VideoSegment",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("sort_order", models.PositiveIntegerField(default=0)),
("target_duration_seconds", models.PositiveIntegerField(default=15)),
(
"status",
models.CharField(
choices=[
("not_started", "Not Started"),
("queued", "Queued"),
("running", "Running"),
("succeeded", "Succeeded"),
("failed", "Failed"),
],
default="not_started",
max_length=32,
),
),
("error_message", models.TextField(blank=True)),
(
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="video_segments",
to="projects.project",
),
),
(
"script_segment",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="video_segments",
to="projects.scriptsegment",
),
),
],
options={
"ordering": ["sort_order", "created_at"],
},
),
migrations.CreateModel(
name="VideoSegmentVersion",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("prompt", models.TextField(blank=True)),
("is_adopted", models.BooleanField(default=False)),
("metadata", models.JSONField(blank=True, default=dict)),
(
"asset",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="video_segment_versions",
to="assets.asset",
),
),
(
"task",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="video_versions",
to="ai.aitask",
),
),
(
"video_segment",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="versions",
to="projects.videosegment",
),
),
],
options={
"abstract": False,
},
),
migrations.AddField(
model_name="videosegment",
name="adopted_version",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="adopted_by_segments",
to="projects.videosegmentversion",
),
),
migrations.AddIndex(
model_name="project",
index=models.Index(
fields=["team", "status"], name="projects_pr_team_id_4a0091_idx"
),
),
migrations.AddIndex(
model_name="project",
index=models.Index(
fields=["team", "current_stage"], name="projects_pr_team_id_a3c9ff_idx"
),
),
migrations.AddIndex(
model_name="baseassetgroup",
index=models.Index(
fields=["project", "kind"], name="projects_ba_project_8fb70a_idx"
),
),
migrations.AlterUniqueTogether(
name="projectstage",
unique_together={("project", "stage")},
),
migrations.AlterUniqueTogether(
name="videosegment",
unique_together={("project", "sort_order")},
),
]
@@ -0,0 +1 @@