@happyvertical/smrt-video 0.37.2 → 0.37.4
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/chunks/owned-asset-utils-Da0Tlhhl.js +101 -0
- package/dist/chunks/owned-asset-utils-Da0Tlhhl.js.map +1 -0
- package/dist/chunks/performer-DlDaK50F.js +144 -0
- package/dist/chunks/performer-DlDaK50F.js.map +1 -0
- package/dist/chunks/scene-CCQdUj6S.js +172 -0
- package/dist/chunks/scene-CCQdUj6S.js.map +1 -0
- package/dist/index.js +1087 -1827
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/smrt-knowledge.json +8 -8
- package/package.json +16 -16
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { withSystemContext } from "@happyvertical/smrt-tenancy";
|
|
2
|
+
import { AssetCollection } from "@happyvertical/smrt-assets";
|
|
3
|
+
//#region src/owned-asset-utils.ts
|
|
4
|
+
var VIDEO_ASSET_ROLE_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;
|
|
5
|
+
var VIDEO_ASSET_OWNER_COLUMNS = [
|
|
6
|
+
"character_id",
|
|
7
|
+
"performer_id",
|
|
8
|
+
"scene_id",
|
|
9
|
+
"video_shot_id",
|
|
10
|
+
"video_sequence_id",
|
|
11
|
+
"video_composition_id"
|
|
12
|
+
];
|
|
13
|
+
function getQueryRows(result) {
|
|
14
|
+
if (Array.isArray(result)) return result;
|
|
15
|
+
if (typeof result === "object" && result !== null && "rows" in result && Array.isArray(result.rows)) return result.rows;
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
function isMissingSchemaError(error, target) {
|
|
19
|
+
const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
20
|
+
if (!(message.includes("no such table") || message.includes("no such column") || message.includes("does not exist") || message.includes("unknown column"))) return false;
|
|
21
|
+
return !target || message.includes(target.toLowerCase());
|
|
22
|
+
}
|
|
23
|
+
function buildPlaceholders(count) {
|
|
24
|
+
return Array.from({ length: count }, () => "?").join(", ");
|
|
25
|
+
}
|
|
26
|
+
function uniqueAssetIds(assetIds) {
|
|
27
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28
|
+
const result = [];
|
|
29
|
+
for (const assetId of assetIds) {
|
|
30
|
+
if (!assetId || seen.has(assetId)) continue;
|
|
31
|
+
seen.add(assetId);
|
|
32
|
+
result.push(assetId);
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
function mergeOwnedAssetIds(...groups) {
|
|
37
|
+
const seen = /* @__PURE__ */ new Set();
|
|
38
|
+
const merged = [];
|
|
39
|
+
for (const group of groups) for (const assetId of group) {
|
|
40
|
+
if (!assetId || seen.has(assetId)) continue;
|
|
41
|
+
seen.add(assetId);
|
|
42
|
+
merged.push(assetId);
|
|
43
|
+
}
|
|
44
|
+
return merged;
|
|
45
|
+
}
|
|
46
|
+
function assertValidVideoAssetRole(role) {
|
|
47
|
+
if (!VIDEO_ASSET_ROLE_PATTERN.test(role)) throw new Error(`Invalid asset role "${role}"; must start with a letter or underscore and contain only letters, digits, underscores, and hyphens`);
|
|
48
|
+
}
|
|
49
|
+
function assertValidVideoAssetSortOrder(sortOrder) {
|
|
50
|
+
if (!Number.isInteger(sortOrder) || sortOrder < 0 || sortOrder > 2147483647) throw new Error(`Invalid sortOrder "${sortOrder}"; must be a non-negative integer`);
|
|
51
|
+
}
|
|
52
|
+
async function resolveOwnedAssets(db, tenantId, assetIds) {
|
|
53
|
+
const orderedIds = uniqueAssetIds(assetIds);
|
|
54
|
+
if (orderedIds.length === 0) return [];
|
|
55
|
+
const assets = await AssetCollection.create({ db });
|
|
56
|
+
let resolved;
|
|
57
|
+
try {
|
|
58
|
+
resolved = tenantId ? await withSystemContext(async () => assets.listByIds(orderedIds)) : await assets.listByIds(orderedIds);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (isMissingSchemaError(error, "assets")) return [];
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
const visibleAssets = tenantId ? resolved.filter((asset) => asset.tenantId === tenantId || asset.tenantId === null) : resolved;
|
|
64
|
+
const assetsById = new Map(visibleAssets.filter((asset) => asset.id).map((asset) => [asset.id, asset]));
|
|
65
|
+
return orderedIds.map((assetId) => assetsById.get(assetId)).filter(Boolean);
|
|
66
|
+
}
|
|
67
|
+
async function listCanonicalOwnedAssetIds(options) {
|
|
68
|
+
try {
|
|
69
|
+
return uniqueAssetIds((await options.loadLinks()).map((link) => link.assetId));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (isMissingSchemaError(error, options.tableName)) return [];
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function listLegacyOwnedAssetIds(options) {
|
|
76
|
+
const { db, ownerColumn, ownerId, role, metaTypes } = options;
|
|
77
|
+
if (!ownerId || metaTypes.length === 0) return [];
|
|
78
|
+
if (!VIDEO_ASSET_OWNER_COLUMNS.includes(ownerColumn)) throw new Error(`Unsupported video asset owner column "${ownerColumn}"`);
|
|
79
|
+
const params = [ownerId, ...metaTypes];
|
|
80
|
+
const clauses = [`${ownerColumn} = ?`, `_meta_type IN (${buildPlaceholders(metaTypes.length)})`];
|
|
81
|
+
if (role) {
|
|
82
|
+
clauses.push("role = ?");
|
|
83
|
+
params.push(role);
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
return uniqueAssetIds(getQueryRows(await db.query(`SELECT id
|
|
87
|
+
FROM assets
|
|
88
|
+
WHERE ${clauses.join(" AND ")}
|
|
89
|
+
ORDER BY created_at ASC, id ASC`, ...params)).map((row) => String(row?.id || "")));
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (isMissingSchemaError(error)) return [];
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function legacyVideoAssetMetaTypes(className) {
|
|
96
|
+
return [className, `@happyvertical/smrt-video:${className}`];
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { listLegacyOwnedAssetIds as a, listCanonicalOwnedAssetIds as i, assertValidVideoAssetSortOrder as n, mergeOwnedAssetIds as o, legacyVideoAssetMetaTypes as r, resolveOwnedAssets as s, assertValidVideoAssetRole as t };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=owned-asset-utils-Da0Tlhhl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned-asset-utils-Da0Tlhhl.js","names":[],"sources":["../../src/owned-asset-utils.ts"],"sourcesContent":["import { type Asset, AssetCollection } from '@happyvertical/smrt-assets';\nimport { withSystemContext } from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\n\n// Video roles intentionally allow hyphens for legacy compatibility\n// (`seed-image`, `base-motion`, `env-map`, etc.).\nconst VIDEO_ASSET_ROLE_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;\nconst VIDEO_ASSET_OWNER_COLUMNS = [\n 'character_id',\n 'performer_id',\n 'scene_id',\n 'video_shot_id',\n 'video_sequence_id',\n 'video_composition_id',\n] as const;\n\nexport type VideoAssetOwnerColumn = (typeof VIDEO_ASSET_OWNER_COLUMNS)[number];\n\nfunction getQueryRows(result: unknown): Record<string, unknown>[] {\n if (Array.isArray(result)) {\n return result as Record<string, unknown>[];\n }\n\n if (\n typeof result === 'object' &&\n result !== null &&\n 'rows' in result &&\n Array.isArray((result as { rows: unknown }).rows)\n ) {\n return (result as { rows: Record<string, unknown>[] }).rows;\n }\n\n return [];\n}\n\nfunction isMissingSchemaError(error: unknown, target?: string): boolean {\n const message =\n error instanceof Error\n ? error.message.toLowerCase()\n : String(error).toLowerCase();\n\n const isMissing =\n message.includes('no such table') ||\n message.includes('no such column') ||\n message.includes('does not exist') ||\n message.includes('unknown column');\n\n if (!isMissing) {\n return false;\n }\n\n return !target || message.includes(target.toLowerCase());\n}\n\nfunction buildPlaceholders(count: number): string {\n return Array.from({ length: count }, () => '?').join(', ');\n}\n\nfunction uniqueAssetIds(\n assetIds: Iterable<string | null | undefined>,\n): string[] {\n const seen = new Set<string>();\n const result: string[] = [];\n\n for (const assetId of assetIds) {\n if (!assetId || seen.has(assetId)) {\n continue;\n }\n\n seen.add(assetId);\n result.push(assetId);\n }\n\n return result;\n}\n\nexport function mergeOwnedAssetIds(\n ...groups: Array<Iterable<string | null | undefined>>\n): string[] {\n const seen = new Set<string>();\n const merged: string[] = [];\n\n for (const group of groups) {\n for (const assetId of group) {\n if (!assetId || seen.has(assetId)) {\n continue;\n }\n\n seen.add(assetId);\n merged.push(assetId);\n }\n }\n\n return merged;\n}\n\nexport function assertValidVideoAssetRole(role: string): void {\n if (!VIDEO_ASSET_ROLE_PATTERN.test(role)) {\n throw new Error(\n `Invalid asset role \"${role}\"; must start with a letter or underscore and contain only letters, digits, underscores, and hyphens`,\n );\n }\n}\n\nexport function assertValidVideoAssetSortOrder(sortOrder: number): void {\n if (!Number.isInteger(sortOrder) || sortOrder < 0 || sortOrder > 2147483647) {\n throw new Error(\n `Invalid sortOrder \"${sortOrder}\"; must be a non-negative integer`,\n );\n }\n}\n\nexport async function resolveOwnedAssets(\n db: DatabaseInterface,\n tenantId: string | null | undefined,\n assetIds: Iterable<string | null | undefined>,\n): Promise<Asset[]> {\n const orderedIds = uniqueAssetIds(assetIds);\n if (orderedIds.length === 0) {\n return [];\n }\n\n const assets = await AssetCollection.create({ db });\n let resolved: Asset[];\n try {\n resolved = tenantId\n ? await withSystemContext(async () => assets.listByIds(orderedIds))\n : await assets.listByIds(orderedIds);\n } catch (error) {\n if (isMissingSchemaError(error, 'assets')) {\n return [];\n }\n\n throw error;\n }\n\n const visibleAssets = tenantId\n ? resolved.filter(\n (asset) => asset.tenantId === tenantId || asset.tenantId === null,\n )\n : resolved;\n const assetsById = new Map(\n visibleAssets\n .filter((asset) => asset.id)\n .map((asset) => [asset.id as string, asset]),\n );\n\n return orderedIds\n .map((assetId) => assetsById.get(assetId))\n .filter(Boolean) as Asset[];\n}\n\nexport async function listCanonicalOwnedAssetIds<\n T extends { assetId: string },\n>(options: {\n tableName: string;\n loadLinks: () => Promise<T[]>;\n}): Promise<string[]> {\n try {\n return uniqueAssetIds(\n (await options.loadLinks()).map((link) => link.assetId),\n );\n } catch (error) {\n if (isMissingSchemaError(error, options.tableName)) {\n return [];\n }\n\n throw error;\n }\n}\n\nexport async function listLegacyOwnedAssetIds(options: {\n db: DatabaseInterface;\n ownerColumn: VideoAssetOwnerColumn;\n ownerId: string;\n role?: string;\n metaTypes: string[];\n}): Promise<string[]> {\n const { db, ownerColumn, ownerId, role, metaTypes } = options;\n if (!ownerId || metaTypes.length === 0) {\n return [];\n }\n\n if (!VIDEO_ASSET_OWNER_COLUMNS.includes(ownerColumn)) {\n throw new Error(`Unsupported video asset owner column \"${ownerColumn}\"`);\n }\n\n const params: unknown[] = [ownerId, ...metaTypes];\n const clauses = [\n `${ownerColumn} = ?`,\n `_meta_type IN (${buildPlaceholders(metaTypes.length)})`,\n ];\n\n if (role) {\n clauses.push('role = ?');\n params.push(role);\n }\n\n try {\n const result = await db.query(\n `SELECT id\n FROM assets\n WHERE ${clauses.join(' AND ')}\n ORDER BY created_at ASC, id ASC`,\n ...params,\n );\n\n return uniqueAssetIds(\n getQueryRows(result).map((row) => String(row?.id || '')),\n );\n } catch (error) {\n if (isMissingSchemaError(error)) {\n return [];\n }\n\n throw error;\n }\n}\n\nexport function legacyVideoAssetMetaTypes(className: string): string[] {\n return [className, `@happyvertical/smrt-video:${className}`];\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { a as listLegacyOwnedAssetIds, i as listCanonicalOwnedAssetIds, n as assertValidVideoAssetSortOrder, o as mergeOwnedAssetIds, r as legacyVideoAssetMetaTypes, s as resolveOwnedAssets, t as assertValidVideoAssetRole } from "./owned-asset-utils-Da0Tlhhl.js";
|
|
2
|
+
import { SmrtObject, crossPackageRef, smrt } from "@happyvertical/smrt-core";
|
|
3
|
+
import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
|
|
4
|
+
//#region src/performer.ts
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
8
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
9
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
10
|
+
if (kind && result) __defProp(target, key, result);
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
var Performer = class extends SmrtObject {
|
|
14
|
+
tenantId = null;
|
|
15
|
+
/** Human-readable name */
|
|
16
|
+
name = "";
|
|
17
|
+
/** Description */
|
|
18
|
+
description = null;
|
|
19
|
+
/** Performer DNA for consistent face generation */
|
|
20
|
+
dna = {
|
|
21
|
+
gender: "neutral",
|
|
22
|
+
ageRange: "adult",
|
|
23
|
+
ipAdapterWeight: .7
|
|
24
|
+
};
|
|
25
|
+
/** Reference images for IP-Adapter (multiple angles/expressions) */
|
|
26
|
+
referenceAssetIds = [];
|
|
27
|
+
seedImageAssetId = null;
|
|
28
|
+
voiceProfileId = null;
|
|
29
|
+
/** Performer status */
|
|
30
|
+
status = "pending";
|
|
31
|
+
profileId = null;
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
super(options);
|
|
34
|
+
if (options.name !== void 0) this.name = options.name;
|
|
35
|
+
if (options.description !== void 0) this.description = options.description;
|
|
36
|
+
if (options.dna !== void 0) this.dna = options.dna;
|
|
37
|
+
if (options.referenceAssetIds !== void 0) this.referenceAssetIds = options.referenceAssetIds;
|
|
38
|
+
if (options.seedImageAssetId !== void 0) this.seedImageAssetId = options.seedImageAssetId;
|
|
39
|
+
if (options.voiceProfileId !== void 0) this.voiceProfileId = options.voiceProfileId;
|
|
40
|
+
if (options.status !== void 0) this.status = options.status;
|
|
41
|
+
if (options.profileId !== void 0) this.profileId = options.profileId;
|
|
42
|
+
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
43
|
+
}
|
|
44
|
+
async getPerformerAssetCollection() {
|
|
45
|
+
const { PerformerOwnedAssetCollection } = await import("../index.js").then((n) => n.n);
|
|
46
|
+
return PerformerOwnedAssetCollection.create({ db: this.db });
|
|
47
|
+
}
|
|
48
|
+
getLegacyFieldAssetIds(role) {
|
|
49
|
+
if (role === "reference") return this.referenceAssetIds;
|
|
50
|
+
if (role === "seed") return this.seedImageAssetId ? [this.seedImageAssetId] : [];
|
|
51
|
+
return [...this.referenceAssetIds, this.seedImageAssetId].filter((assetId) => Boolean(assetId));
|
|
52
|
+
}
|
|
53
|
+
setLegacyFieldAssetId(role, assetId) {
|
|
54
|
+
if (role === "seed") {
|
|
55
|
+
if (this.seedImageAssetId === assetId) return false;
|
|
56
|
+
this.seedImageAssetId = assetId;
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (this.referenceAssetIds.includes(assetId)) return false;
|
|
60
|
+
this.referenceAssetIds = [...this.referenceAssetIds, assetId];
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
clearLegacyFieldAssetId(assetId, role) {
|
|
64
|
+
let changed = false;
|
|
65
|
+
if ((!role || role === "seed") && this.seedImageAssetId === assetId) {
|
|
66
|
+
this.seedImageAssetId = null;
|
|
67
|
+
changed = true;
|
|
68
|
+
}
|
|
69
|
+
if (!role || role === "reference") {
|
|
70
|
+
const remaining = this.referenceAssetIds.filter((referenceAssetId) => referenceAssetId !== assetId);
|
|
71
|
+
if (remaining.length !== this.referenceAssetIds.length) {
|
|
72
|
+
this.referenceAssetIds = remaining;
|
|
73
|
+
changed = true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return changed;
|
|
77
|
+
}
|
|
78
|
+
async getAssets(role) {
|
|
79
|
+
const canonicalAssetIds = this.id ? await listCanonicalOwnedAssetIds({
|
|
80
|
+
tableName: "performer_assets",
|
|
81
|
+
loadLinks: async () => (await this.getPerformerAssetCollection()).byLeft(this.id, role ? { role } : {})
|
|
82
|
+
}) : [];
|
|
83
|
+
const legacyFieldAssetIds = this.getLegacyFieldAssetIds(role);
|
|
84
|
+
const legacyOwnedAssetIds = this.id ? await listLegacyOwnedAssetIds({
|
|
85
|
+
db: this.db,
|
|
86
|
+
ownerColumn: "performer_id",
|
|
87
|
+
ownerId: this.id,
|
|
88
|
+
role,
|
|
89
|
+
metaTypes: legacyVideoAssetMetaTypes("PerformerAsset")
|
|
90
|
+
}) : [];
|
|
91
|
+
return resolveOwnedAssets(this.db, this.tenantId, mergeOwnedAssetIds(canonicalAssetIds, legacyFieldAssetIds, legacyOwnedAssetIds));
|
|
92
|
+
}
|
|
93
|
+
async getAssetByRole(role) {
|
|
94
|
+
return (await this.getAssets(role))[0] || null;
|
|
95
|
+
}
|
|
96
|
+
async addAsset(asset, role = "reference", sortOrder = 0) {
|
|
97
|
+
if (!this.id || !asset.id) throw new Error("Cannot associate unsaved performer or asset");
|
|
98
|
+
assertValidVideoAssetRole(role);
|
|
99
|
+
assertValidVideoAssetSortOrder(sortOrder);
|
|
100
|
+
await (await this.getPerformerAssetCollection()).attach(this.id, asset.id, {
|
|
101
|
+
role,
|
|
102
|
+
sortOrder,
|
|
103
|
+
tenantId: this.tenantId
|
|
104
|
+
});
|
|
105
|
+
if (this.setLegacyFieldAssetId(role, asset.id)) await this.save();
|
|
106
|
+
}
|
|
107
|
+
async removeAsset(assetId, role) {
|
|
108
|
+
if (!this.id) return;
|
|
109
|
+
await (await this.getPerformerAssetCollection()).detach(this.id, assetId, role ? { role } : {});
|
|
110
|
+
if (this.clearLegacyFieldAssetId(assetId, role)) await this.save();
|
|
111
|
+
}
|
|
112
|
+
/** Check if the performer has reference images */
|
|
113
|
+
get hasReferences() {
|
|
114
|
+
return this.referenceAssetIds.length > 0;
|
|
115
|
+
}
|
|
116
|
+
/** Check if the performer has a face embedding */
|
|
117
|
+
get hasFaceEmbedding() {
|
|
118
|
+
return Array.isArray(this.dna.faceEmbedding) && this.dna.faceEmbedding.length > 0;
|
|
119
|
+
}
|
|
120
|
+
/** Check if the performer is ready for generation */
|
|
121
|
+
get isReady() {
|
|
122
|
+
return this.status === "ready" && this.hasReferences;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
__decorateClass([tenantId({ nullable: true })], Performer.prototype, "tenantId", 2);
|
|
126
|
+
__decorateClass([crossPackageRef("@happyvertical/smrt-assets:Asset")], Performer.prototype, "seedImageAssetId", 2);
|
|
127
|
+
__decorateClass([crossPackageRef("@happyvertical/smrt-voice:VoiceProfile")], Performer.prototype, "voiceProfileId", 2);
|
|
128
|
+
__decorateClass([crossPackageRef("@happyvertical/smrt-profiles:Profile")], Performer.prototype, "profileId", 2);
|
|
129
|
+
Performer = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
|
|
130
|
+
tableStrategy: "sti",
|
|
131
|
+
api: { include: [
|
|
132
|
+
"list",
|
|
133
|
+
"get",
|
|
134
|
+
"create",
|
|
135
|
+
"update",
|
|
136
|
+
"delete"
|
|
137
|
+
] },
|
|
138
|
+
mcp: { include: ["list", "get"] },
|
|
139
|
+
cli: true
|
|
140
|
+
})], Performer);
|
|
141
|
+
//#endregion
|
|
142
|
+
export { Performer as t };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=performer-DlDaK50F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performer-DlDaK50F.js","names":[],"sources":["../../src/performer.ts"],"sourcesContent":["/**\n * Performer Model\n *\n * Represents the physical likeness/face DNA for consistent face generation.\n * A Performer can play multiple Characters (PersonalityProfiles).\n * Ensures face consistency via IP-Adapter FaceID.\n */\n\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport { crossPackageRef, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n assertValidVideoAssetRole,\n assertValidVideoAssetSortOrder,\n legacyVideoAssetMetaTypes,\n listCanonicalOwnedAssetIds,\n listLegacyOwnedAssetIds,\n mergeOwnedAssetIds,\n resolveOwnedAssets,\n} from './owned-asset-utils.js';\nimport type { PerformerAssetRole } from './performer-asset.js';\n\n/**\n * Performer DNA for IP-Adapter FaceID consistency\n */\nexport interface PerformerDNA {\n /** Gender */\n gender: 'male' | 'female' | 'neutral';\n\n /** Age range */\n ageRange:\n | 'child'\n | 'teen'\n | 'young_adult'\n | 'adult'\n | 'middle_aged'\n | 'senior';\n\n /** Face embedding for IP-Adapter FaceID (512-dim vector) */\n faceEmbedding?: number[];\n\n /** Default clothing style (can be overridden per Character) */\n defaultClothing?: {\n style: 'business' | 'casual' | 'formal' | 'outdoor';\n colors?: string[];\n description?: string;\n };\n\n /** IP-Adapter weight for consistency (0.5-1.0) */\n ipAdapterWeight: number;\n\n /** FaceID weight for face consistency */\n faceIdWeight?: number;\n}\n\n/**\n * Performer status\n */\nexport type PerformerStatus = 'pending' | 'ready';\n\n/**\n * Performer creation options\n */\nexport interface PerformerOptions extends SmrtObjectOptions {\n /** Human-readable name */\n name?: string;\n\n /** Description */\n description?: string | null;\n\n /** Performer DNA for consistent face generation */\n dna?: PerformerDNA;\n\n /** Reference images for IP-Adapter (multiple angles/expressions) */\n referenceAssetIds?: string[];\n\n /** Generated seed image asset ID */\n seedImageAssetId?: string | null;\n\n /** Default voice profile for this performer */\n voiceProfileId?: string | null;\n\n /** Performer status */\n status?: PerformerStatus;\n\n /** 1-1 profile record for this performer */\n profileId?: string | null;\n\n /** Tenant ID for multi-tenant isolation */\n tenantId?: string | null;\n}\n\n/**\n * Performer - The physical likeness/face DNA\n *\n * A Performer represents a person's visual identity for consistent\n * face generation across multiple Characters. One Performer can play\n * many Characters (e.g., same face as \"Evening Anchor\" and \"Weekend Host\").\n *\n * @example\n * ```typescript\n * import { Performer } from '@happyvertical/smrt-video';\n *\n * const performer = new Performer({\n * name: 'Alex Bentley',\n * dna: {\n * gender: 'male',\n * ageRange: 'adult',\n * ipAdapterWeight: 0.75,\n * },\n * referenceAssetIds: ['ref-img-1', 'ref-img-2'],\n * });\n * await performer.save();\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: {\n include: ['list', 'get', 'create', 'update', 'delete'],\n },\n mcp: {\n include: ['list', 'get'],\n },\n cli: true,\n})\nexport class Performer extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Human-readable name */\n name: string = '';\n\n /** Description */\n description: string | null = null;\n\n /** Performer DNA for consistent face generation */\n dna: PerformerDNA = {\n gender: 'neutral',\n ageRange: 'adult',\n ipAdapterWeight: 0.7,\n };\n\n /** Reference images for IP-Adapter (multiple angles/expressions) */\n referenceAssetIds: string[] = [];\n\n /** Generated seed image asset ID */\n @crossPackageRef('@happyvertical/smrt-assets:Asset')\n seedImageAssetId: string | null = null;\n\n /** Default voice profile for this performer */\n @crossPackageRef('@happyvertical/smrt-voice:VoiceProfile')\n voiceProfileId: string | null = null;\n\n /** Performer status */\n status: PerformerStatus = 'pending';\n\n /** 1-1 profile record for this performer */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n profileId: string | null = null;\n\n constructor(options: PerformerOptions = {}) {\n super(options);\n\n if (options.name !== undefined) this.name = options.name;\n if (options.description !== undefined)\n this.description = options.description;\n if (options.dna !== undefined) this.dna = options.dna;\n if (options.referenceAssetIds !== undefined)\n this.referenceAssetIds = options.referenceAssetIds;\n if (options.seedImageAssetId !== undefined)\n this.seedImageAssetId = options.seedImageAssetId;\n if (options.voiceProfileId !== undefined)\n this.voiceProfileId = options.voiceProfileId;\n if (options.status !== undefined) this.status = options.status;\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n\n private async getPerformerAssetCollection() {\n const { PerformerOwnedAssetCollection } = await import(\n './performer-assets.js'\n );\n return PerformerOwnedAssetCollection.create({ db: this.db });\n }\n\n private getLegacyFieldAssetIds(role?: PerformerAssetRole): string[] {\n if (role === 'reference') {\n return this.referenceAssetIds;\n }\n\n if (role === 'seed') {\n return this.seedImageAssetId ? [this.seedImageAssetId] : [];\n }\n\n return [...this.referenceAssetIds, this.seedImageAssetId].filter(\n (assetId): assetId is string => Boolean(assetId),\n );\n }\n\n private setLegacyFieldAssetId(\n role: PerformerAssetRole,\n assetId: string,\n ): boolean {\n if (role === 'seed') {\n if (this.seedImageAssetId === assetId) {\n return false;\n }\n\n this.seedImageAssetId = assetId;\n return true;\n }\n\n if (this.referenceAssetIds.includes(assetId)) {\n return false;\n }\n\n this.referenceAssetIds = [...this.referenceAssetIds, assetId];\n return true;\n }\n\n private clearLegacyFieldAssetId(\n assetId: string,\n role?: PerformerAssetRole,\n ): boolean {\n let changed = false;\n\n if ((!role || role === 'seed') && this.seedImageAssetId === assetId) {\n this.seedImageAssetId = null;\n changed = true;\n }\n\n if (!role || role === 'reference') {\n const remaining = this.referenceAssetIds.filter(\n (referenceAssetId) => referenceAssetId !== assetId,\n );\n\n if (remaining.length !== this.referenceAssetIds.length) {\n this.referenceAssetIds = remaining;\n changed = true;\n }\n }\n\n return changed;\n }\n\n async getAssets(role?: PerformerAssetRole): Promise<Asset[]> {\n const canonicalAssetIds = this.id\n ? await listCanonicalOwnedAssetIds({\n tableName: 'performer_assets',\n loadLinks: async () =>\n (await this.getPerformerAssetCollection()).byLeft(\n this.id as string,\n role ? { role } : {},\n ),\n })\n : [];\n const legacyFieldAssetIds = this.getLegacyFieldAssetIds(role);\n const legacyOwnedAssetIds = this.id\n ? await listLegacyOwnedAssetIds({\n db: this.db,\n ownerColumn: 'performer_id',\n ownerId: this.id,\n role,\n metaTypes: legacyVideoAssetMetaTypes('PerformerAsset'),\n })\n : [];\n\n return resolveOwnedAssets(\n this.db,\n this.tenantId,\n mergeOwnedAssetIds(\n canonicalAssetIds,\n legacyFieldAssetIds,\n legacyOwnedAssetIds,\n ),\n );\n }\n\n async getAssetByRole(role: PerformerAssetRole): Promise<Asset | null> {\n const assets = await this.getAssets(role);\n return assets[0] || null;\n }\n\n async addAsset(\n asset: Asset,\n role: PerformerAssetRole = 'reference',\n sortOrder = 0,\n ): Promise<void> {\n if (!this.id || !asset.id) {\n throw new Error('Cannot associate unsaved performer or asset');\n }\n\n assertValidVideoAssetRole(role);\n assertValidVideoAssetSortOrder(sortOrder);\n\n const performerAssets = await this.getPerformerAssetCollection();\n await performerAssets.attach(this.id, asset.id, {\n role,\n sortOrder,\n tenantId: this.tenantId,\n });\n\n if (this.setLegacyFieldAssetId(role, asset.id)) {\n await this.save();\n }\n }\n\n async removeAsset(assetId: string, role?: PerformerAssetRole): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const performerAssets = await this.getPerformerAssetCollection();\n await performerAssets.detach(this.id, assetId, role ? { role } : {});\n\n if (this.clearLegacyFieldAssetId(assetId, role)) {\n await this.save();\n }\n }\n\n /** Check if the performer has reference images */\n get hasReferences(): boolean {\n return this.referenceAssetIds.length > 0;\n }\n\n /** Check if the performer has a face embedding */\n get hasFaceEmbedding(): boolean {\n return (\n Array.isArray(this.dna.faceEmbedding) && this.dna.faceEmbedding.length > 0\n );\n }\n\n /** Check if the performer is ready for generation */\n get isReady(): boolean {\n return this.status === 'ready' && this.hasReferences;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { a as listLegacyOwnedAssetIds, i as listCanonicalOwnedAssetIds, n as assertValidVideoAssetSortOrder, o as mergeOwnedAssetIds, r as legacyVideoAssetMetaTypes, s as resolveOwnedAssets, t as assertValidVideoAssetRole } from "./owned-asset-utils-Da0Tlhhl.js";
|
|
2
|
+
import { SmrtObject, crossPackageRef, smrt } from "@happyvertical/smrt-core";
|
|
3
|
+
import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
|
|
4
|
+
//#region src/scene.ts
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
8
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
9
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
10
|
+
if (kind && result) __defProp(target, key, result);
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
var Scene = class extends SmrtObject {
|
|
14
|
+
tenantId = null;
|
|
15
|
+
/** Human-readable name */
|
|
16
|
+
name = "";
|
|
17
|
+
/** Description */
|
|
18
|
+
description = null;
|
|
19
|
+
sourceAssetId = null;
|
|
20
|
+
/** Type of source media */
|
|
21
|
+
sourceType = "image";
|
|
22
|
+
/** Projection type for panoramas */
|
|
23
|
+
projection = null;
|
|
24
|
+
/** Extracted camera angles from 360° panoramas */
|
|
25
|
+
viewpoints = [];
|
|
26
|
+
/** Lighting analysis for IC-Light matching */
|
|
27
|
+
lightingProfile = null;
|
|
28
|
+
/** Location metadata */
|
|
29
|
+
location = null;
|
|
30
|
+
/** Anchor points for character placement */
|
|
31
|
+
anchorPoints = [];
|
|
32
|
+
/** Scene status */
|
|
33
|
+
status = "pending";
|
|
34
|
+
constructor(options = {}) {
|
|
35
|
+
super(options);
|
|
36
|
+
if (options.name !== void 0) this.name = options.name;
|
|
37
|
+
if (options.description !== void 0) this.description = options.description;
|
|
38
|
+
if (options.sourceAssetId !== void 0) this.sourceAssetId = options.sourceAssetId;
|
|
39
|
+
if (options.sourceType !== void 0) this.sourceType = options.sourceType;
|
|
40
|
+
if (options.projection !== void 0) this.projection = options.projection;
|
|
41
|
+
if (options.viewpoints !== void 0) this.viewpoints = options.viewpoints;
|
|
42
|
+
if (options.lightingProfile !== void 0) this.lightingProfile = options.lightingProfile;
|
|
43
|
+
if (options.location !== void 0) this.location = options.location;
|
|
44
|
+
if (options.anchorPoints !== void 0) this.anchorPoints = options.anchorPoints;
|
|
45
|
+
if (options.status !== void 0) this.status = options.status;
|
|
46
|
+
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
47
|
+
}
|
|
48
|
+
async getSceneAssetCollection() {
|
|
49
|
+
const { SceneOwnedAssetCollection } = await import("../index.js").then((n) => n.t);
|
|
50
|
+
return SceneOwnedAssetCollection.create({ db: this.db });
|
|
51
|
+
}
|
|
52
|
+
getLegacyFieldAssetIds(role) {
|
|
53
|
+
if (role === "source") return this.sourceAssetId ? [this.sourceAssetId] : [];
|
|
54
|
+
if (role === "env-map") return this.lightingProfile?.envMapAssetId ? [this.lightingProfile.envMapAssetId] : [];
|
|
55
|
+
if (role === "viewpoint-extract") return this.viewpoints.map((viewpoint) => viewpoint.extractedAssetId || null).filter((assetId) => Boolean(assetId));
|
|
56
|
+
return [
|
|
57
|
+
this.sourceAssetId,
|
|
58
|
+
this.lightingProfile?.envMapAssetId || null,
|
|
59
|
+
...this.viewpoints.map((viewpoint) => viewpoint.extractedAssetId || null)
|
|
60
|
+
].filter((assetId) => Boolean(assetId));
|
|
61
|
+
}
|
|
62
|
+
setLegacyFieldAssetId(role, assetId) {
|
|
63
|
+
if (role === "source") {
|
|
64
|
+
if (this.sourceAssetId === assetId) return false;
|
|
65
|
+
this.sourceAssetId = assetId;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (role === "env-map") {
|
|
69
|
+
if ((this.lightingProfile?.envMapAssetId || null) === assetId) return false;
|
|
70
|
+
this.lightingProfile = {
|
|
71
|
+
...this.lightingProfile || {},
|
|
72
|
+
envMapAssetId: assetId
|
|
73
|
+
};
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
clearLegacyFieldAssetId(assetId, role) {
|
|
79
|
+
let changed = false;
|
|
80
|
+
if ((!role || role === "source") && this.sourceAssetId === assetId) {
|
|
81
|
+
this.sourceAssetId = null;
|
|
82
|
+
changed = true;
|
|
83
|
+
}
|
|
84
|
+
if ((!role || role === "env-map") && this.lightingProfile?.envMapAssetId === assetId) {
|
|
85
|
+
this.lightingProfile = {
|
|
86
|
+
...this.lightingProfile || {},
|
|
87
|
+
envMapAssetId: void 0
|
|
88
|
+
};
|
|
89
|
+
changed = true;
|
|
90
|
+
}
|
|
91
|
+
if (!role || role === "viewpoint-extract") {
|
|
92
|
+
let viewpointChanged = false;
|
|
93
|
+
const nextViewpoints = this.viewpoints.map((viewpoint) => {
|
|
94
|
+
if (viewpoint.extractedAssetId !== assetId) return viewpoint;
|
|
95
|
+
viewpointChanged = true;
|
|
96
|
+
return {
|
|
97
|
+
...viewpoint,
|
|
98
|
+
extractedAssetId: void 0
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
if (viewpointChanged) {
|
|
102
|
+
this.viewpoints = nextViewpoints;
|
|
103
|
+
changed = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return changed;
|
|
107
|
+
}
|
|
108
|
+
async getAssets(role) {
|
|
109
|
+
const canonicalAssetIds = this.id ? await listCanonicalOwnedAssetIds({
|
|
110
|
+
tableName: "scene_assets",
|
|
111
|
+
loadLinks: async () => (await this.getSceneAssetCollection()).byLeft(this.id, role ? { role } : {})
|
|
112
|
+
}) : [];
|
|
113
|
+
const legacyFieldAssetIds = this.getLegacyFieldAssetIds(role);
|
|
114
|
+
const legacyOwnedAssetIds = this.id ? await listLegacyOwnedAssetIds({
|
|
115
|
+
db: this.db,
|
|
116
|
+
ownerColumn: "scene_id",
|
|
117
|
+
ownerId: this.id,
|
|
118
|
+
role,
|
|
119
|
+
metaTypes: legacyVideoAssetMetaTypes("SceneAsset")
|
|
120
|
+
}) : [];
|
|
121
|
+
return resolveOwnedAssets(this.db, this.tenantId, mergeOwnedAssetIds(canonicalAssetIds, legacyFieldAssetIds, legacyOwnedAssetIds));
|
|
122
|
+
}
|
|
123
|
+
async getAssetByRole(role) {
|
|
124
|
+
return (await this.getAssets(role))[0] || null;
|
|
125
|
+
}
|
|
126
|
+
async addAsset(asset, role = "source", sortOrder = 0) {
|
|
127
|
+
if (!this.id || !asset.id) throw new Error("Cannot associate unsaved scene or asset");
|
|
128
|
+
assertValidVideoAssetRole(role);
|
|
129
|
+
assertValidVideoAssetSortOrder(sortOrder);
|
|
130
|
+
await (await this.getSceneAssetCollection()).attach(this.id, asset.id, {
|
|
131
|
+
role,
|
|
132
|
+
sortOrder,
|
|
133
|
+
tenantId: this.tenantId
|
|
134
|
+
});
|
|
135
|
+
if (this.setLegacyFieldAssetId(role, asset.id)) await this.save();
|
|
136
|
+
}
|
|
137
|
+
async removeAsset(assetId, role) {
|
|
138
|
+
if (!this.id) return;
|
|
139
|
+
await (await this.getSceneAssetCollection()).detach(this.id, assetId, role ? { role } : {});
|
|
140
|
+
if (this.clearLegacyFieldAssetId(assetId, role)) await this.save();
|
|
141
|
+
}
|
|
142
|
+
/** Check if this is a 360° panorama */
|
|
143
|
+
get isPanorama() {
|
|
144
|
+
return this.sourceType === "panorama_360" || this.sourceType === "panorama_180";
|
|
145
|
+
}
|
|
146
|
+
/** Check if the scene has viewpoints extracted */
|
|
147
|
+
get hasViewpoints() {
|
|
148
|
+
return this.viewpoints.length > 0;
|
|
149
|
+
}
|
|
150
|
+
/** Check if the scene is ready for compositing */
|
|
151
|
+
get isReady() {
|
|
152
|
+
return this.status === "ready" && this.sourceAssetId !== null;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
__decorateClass([tenantId({ nullable: true })], Scene.prototype, "tenantId", 2);
|
|
156
|
+
__decorateClass([crossPackageRef("@happyvertical/smrt-assets:Asset")], Scene.prototype, "sourceAssetId", 2);
|
|
157
|
+
Scene = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
|
|
158
|
+
tableStrategy: "sti",
|
|
159
|
+
api: { include: [
|
|
160
|
+
"list",
|
|
161
|
+
"get",
|
|
162
|
+
"create",
|
|
163
|
+
"update",
|
|
164
|
+
"delete"
|
|
165
|
+
] },
|
|
166
|
+
mcp: { include: ["list", "get"] },
|
|
167
|
+
cli: true
|
|
168
|
+
})], Scene);
|
|
169
|
+
//#endregion
|
|
170
|
+
export { Scene as t };
|
|
171
|
+
|
|
172
|
+
//# sourceMappingURL=scene-CCQdUj6S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene-CCQdUj6S.js","names":[],"sources":["../../src/scene.ts"],"sourcesContent":["/**\n * Scene Model\n *\n * Represents a virtual production scene (background environment).\n * Supports 360° panoramas, standard images, and video backgrounds.\n */\n\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport { crossPackageRef, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n assertValidVideoAssetRole,\n assertValidVideoAssetSortOrder,\n legacyVideoAssetMetaTypes,\n listCanonicalOwnedAssetIds,\n listLegacyOwnedAssetIds,\n mergeOwnedAssetIds,\n resolveOwnedAssets,\n} from './owned-asset-utils.js';\nimport type { SceneAssetRole } from './scene-asset.js';\n\n/**\n * Viewpoint extracted from 360° scene\n */\nexport interface SceneViewpoint {\n /** Viewpoint identifier */\n id: string;\n\n /** Human-readable name */\n name: string;\n\n /** Horizontal rotation (-180 to 180°) */\n pan: number;\n\n /** Vertical rotation (-90 to 90°) */\n tilt: number;\n\n /** Field of view (60-120°) */\n fov: number;\n\n /** Generated rectilinear image asset ID */\n extractedAssetId?: string;\n\n /** Viewpoint-specific lighting profile */\n lightingProfile?: LightingProfile;\n}\n\n/**\n * Lighting profile for IC-Light matching\n */\nexport interface LightingProfile {\n /** Dominant light direction (normalized vector) */\n direction?: { x: number; y: number; z: number };\n\n /** Light color temperature (Kelvin) */\n colorTemperature?: number;\n\n /** Ambient light intensity (0-1) */\n ambientIntensity?: number;\n\n /** Key light intensity (0-1) */\n keyLightIntensity?: number;\n\n /** Shadow softness (0-1) */\n shadowSoftness?: number;\n\n /** Environment map asset ID for reflections */\n envMapAssetId?: string;\n}\n\n/**\n * Anchor point for character placement in scene\n */\nexport interface AnchorPoint {\n /** Anchor point identifier */\n id: string;\n\n /** Human-readable name */\n name: string;\n\n /** Position as normalized coordinates (0-1) */\n position: { x: number; y: number };\n\n /** Suggested character scale at this point */\n suggestedScale: number;\n\n /** Ground plane Y coordinate for perspective */\n groundY: number;\n\n /** Optional viewpoint this anchor belongs to */\n viewpointId?: string;\n}\n\n/**\n * Scene source type\n */\nexport type SceneSourceType =\n | 'image'\n | 'video'\n | 'panorama_360'\n | 'panorama_180';\n\n/**\n * Scene projection type\n */\nexport type SceneProjection = 'equirectangular' | 'cubemap';\n\n/**\n * Scene status\n */\nexport type SceneStatus = 'pending' | 'processing' | 'ready' | 'failed';\n\n/**\n * Scene creation options\n */\nexport interface SceneOptions extends SmrtObjectOptions {\n /** Human-readable name */\n name?: string;\n\n /** Description */\n description?: string | null;\n\n /** Source media asset ID */\n sourceAssetId?: string | null;\n\n /** Type of source media */\n sourceType?: SceneSourceType;\n\n /** Projection type for panoramas */\n projection?: SceneProjection | null;\n\n /** Extracted camera angles from 360° panoramas */\n viewpoints?: SceneViewpoint[];\n\n /** Lighting analysis for IC-Light matching */\n lightingProfile?: LightingProfile | null;\n\n /** Location metadata */\n location?: {\n name: string;\n coordinates?: { lat: number; lng: number };\n } | null;\n\n /** Anchor points for character placement */\n anchorPoints?: AnchorPoint[];\n\n /** Scene status */\n status?: SceneStatus;\n\n /** Tenant ID for multi-tenant isolation */\n tenantId?: string | null;\n}\n\n/**\n * Scene for virtual production compositing\n *\n * Supports 360° panoramas, standard images, and video backgrounds\n * with viewpoint extraction, lighting analysis, and character placement.\n *\n * @example\n * ```typescript\n * import { Scene } from '@happyvertical/smrt-video';\n *\n * const scene = new Scene({\n * name: 'Town Hall Exterior',\n * sourceAssetId: 'asset-townhall-pano',\n * sourceType: 'panorama_360',\n * projection: 'equirectangular',\n * });\n * await scene.save();\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: {\n include: ['list', 'get', 'create', 'update', 'delete'],\n },\n mcp: {\n include: ['list', 'get'],\n },\n cli: true,\n})\nexport class Scene extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Human-readable name */\n name: string = '';\n\n /** Description */\n description: string | null = null;\n\n /** Source media asset ID */\n @crossPackageRef('@happyvertical/smrt-assets:Asset')\n sourceAssetId: string | null = null;\n\n /** Type of source media */\n sourceType: SceneSourceType = 'image';\n\n /** Projection type for panoramas */\n projection: SceneProjection | null = null;\n\n /** Extracted camera angles from 360° panoramas */\n viewpoints: SceneViewpoint[] = [];\n\n /** Lighting analysis for IC-Light matching */\n lightingProfile: LightingProfile | null = null;\n\n /** Location metadata */\n location: {\n name: string;\n coordinates?: { lat: number; lng: number };\n } | null = null;\n\n /** Anchor points for character placement */\n anchorPoints: AnchorPoint[] = [];\n\n /** Scene status */\n status: SceneStatus = 'pending';\n\n constructor(options: SceneOptions = {}) {\n super(options);\n\n if (options.name !== undefined) this.name = options.name;\n if (options.description !== undefined)\n this.description = options.description;\n if (options.sourceAssetId !== undefined)\n this.sourceAssetId = options.sourceAssetId;\n if (options.sourceType !== undefined) this.sourceType = options.sourceType;\n if (options.projection !== undefined) this.projection = options.projection;\n if (options.viewpoints !== undefined) this.viewpoints = options.viewpoints;\n if (options.lightingProfile !== undefined)\n this.lightingProfile = options.lightingProfile;\n if (options.location !== undefined) this.location = options.location;\n if (options.anchorPoints !== undefined)\n this.anchorPoints = options.anchorPoints;\n if (options.status !== undefined) this.status = options.status;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n\n private async getSceneAssetCollection() {\n const { SceneOwnedAssetCollection } = await import('./scene-assets.js');\n return SceneOwnedAssetCollection.create({ db: this.db });\n }\n\n private getLegacyFieldAssetIds(role?: SceneAssetRole): string[] {\n if (role === 'source') {\n return this.sourceAssetId ? [this.sourceAssetId] : [];\n }\n\n if (role === 'env-map') {\n return this.lightingProfile?.envMapAssetId\n ? [this.lightingProfile.envMapAssetId]\n : [];\n }\n\n if (role === 'viewpoint-extract') {\n return this.viewpoints\n .map((viewpoint) => viewpoint.extractedAssetId || null)\n .filter((assetId): assetId is string => Boolean(assetId));\n }\n\n return [\n this.sourceAssetId,\n this.lightingProfile?.envMapAssetId || null,\n ...this.viewpoints.map((viewpoint) => viewpoint.extractedAssetId || null),\n ].filter((assetId): assetId is string => Boolean(assetId));\n }\n\n private setLegacyFieldAssetId(\n role: SceneAssetRole,\n assetId: string,\n ): boolean {\n if (role === 'source') {\n if (this.sourceAssetId === assetId) {\n return false;\n }\n\n this.sourceAssetId = assetId;\n return true;\n }\n\n if (role === 'env-map') {\n if ((this.lightingProfile?.envMapAssetId || null) === assetId) {\n return false;\n }\n\n this.lightingProfile = {\n ...(this.lightingProfile || {}),\n envMapAssetId: assetId,\n };\n return true;\n }\n\n return false;\n }\n\n private clearLegacyFieldAssetId(\n assetId: string,\n role?: SceneAssetRole,\n ): boolean {\n let changed = false;\n\n if ((!role || role === 'source') && this.sourceAssetId === assetId) {\n this.sourceAssetId = null;\n changed = true;\n }\n\n if (\n (!role || role === 'env-map') &&\n this.lightingProfile?.envMapAssetId === assetId\n ) {\n this.lightingProfile = {\n ...(this.lightingProfile || {}),\n envMapAssetId: undefined,\n };\n changed = true;\n }\n\n if (!role || role === 'viewpoint-extract') {\n let viewpointChanged = false;\n const nextViewpoints = this.viewpoints.map((viewpoint) => {\n if (viewpoint.extractedAssetId !== assetId) {\n return viewpoint;\n }\n\n viewpointChanged = true;\n return {\n ...viewpoint,\n extractedAssetId: undefined,\n };\n });\n\n if (viewpointChanged) {\n this.viewpoints = nextViewpoints;\n changed = true;\n }\n }\n\n return changed;\n }\n\n async getAssets(role?: SceneAssetRole): Promise<Asset[]> {\n const canonicalAssetIds = this.id\n ? await listCanonicalOwnedAssetIds({\n tableName: 'scene_assets',\n loadLinks: async () =>\n (await this.getSceneAssetCollection()).byLeft(\n this.id as string,\n role ? { role } : {},\n ),\n })\n : [];\n const legacyFieldAssetIds = this.getLegacyFieldAssetIds(role);\n const legacyOwnedAssetIds = this.id\n ? await listLegacyOwnedAssetIds({\n db: this.db,\n ownerColumn: 'scene_id',\n ownerId: this.id,\n role,\n metaTypes: legacyVideoAssetMetaTypes('SceneAsset'),\n })\n : [];\n\n return resolveOwnedAssets(\n this.db,\n this.tenantId,\n mergeOwnedAssetIds(\n canonicalAssetIds,\n legacyFieldAssetIds,\n legacyOwnedAssetIds,\n ),\n );\n }\n\n async getAssetByRole(role: SceneAssetRole): Promise<Asset | null> {\n const assets = await this.getAssets(role);\n return assets[0] || null;\n }\n\n async addAsset(\n asset: Asset,\n role: SceneAssetRole = 'source',\n sortOrder = 0,\n ): Promise<void> {\n if (!this.id || !asset.id) {\n throw new Error('Cannot associate unsaved scene or asset');\n }\n\n assertValidVideoAssetRole(role);\n assertValidVideoAssetSortOrder(sortOrder);\n\n const sceneAssets = await this.getSceneAssetCollection();\n await sceneAssets.attach(this.id, asset.id, {\n role,\n sortOrder,\n tenantId: this.tenantId,\n });\n\n if (this.setLegacyFieldAssetId(role, asset.id)) {\n await this.save();\n }\n }\n\n async removeAsset(assetId: string, role?: SceneAssetRole): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const sceneAssets = await this.getSceneAssetCollection();\n await sceneAssets.detach(this.id, assetId, role ? { role } : {});\n\n if (this.clearLegacyFieldAssetId(assetId, role)) {\n await this.save();\n }\n }\n\n /** Check if this is a 360° panorama */\n get isPanorama(): boolean {\n return (\n this.sourceType === 'panorama_360' || this.sourceType === 'panorama_180'\n );\n }\n\n /** Check if the scene has viewpoints extracted */\n get hasViewpoints(): boolean {\n return this.viewpoints.length > 0;\n }\n\n /** Check if the scene is ready for compositing */\n get isReady(): boolean {\n return this.status === 'ready' && this.sourceAssetId !== null;\n }\n}\n"],"mappings":"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"}
|