vidspotai-shared 1.0.53 → 1.0.55

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.
Files changed (230) hide show
  1. package/lib/globals/aiModels/providers/alibaba.d.ts +4 -0
  2. package/lib/globals/aiModels/providers/alibaba.d.ts.map +1 -0
  3. package/lib/globals/aiModels/providers/alibaba.js +183 -0
  4. package/lib/globals/aiModels/providers/elevenlabs.d.ts +13 -0
  5. package/lib/globals/aiModels/providers/elevenlabs.d.ts.map +1 -0
  6. package/lib/globals/aiModels/providers/elevenlabs.js +25 -0
  7. package/lib/globals/aiModels/providers/pixverseTemplates.d.ts +36 -0
  8. package/lib/globals/aiModels/providers/pixverseTemplates.d.ts.map +1 -0
  9. package/lib/globals/aiModels/providers/pixverseTemplates.js +42 -0
  10. package/lib/globals/aiModels/tierHelpers.d.ts +27 -0
  11. package/lib/globals/aiModels/tierHelpers.d.ts.map +1 -0
  12. package/lib/globals/aiModels/tierHelpers.js +73 -0
  13. package/lib/globals/ttsModels/providers/minimax.d.ts +8 -0
  14. package/lib/globals/ttsModels/providers/minimax.d.ts.map +1 -0
  15. package/lib/globals/ttsModels/providers/minimax.js +18 -0
  16. package/lib/globals/ttsModels/providers/openai.d.ts +8 -0
  17. package/lib/globals/ttsModels/providers/openai.d.ts.map +1 -0
  18. package/lib/globals/ttsModels/providers/openai.js +18 -0
  19. package/lib/globals/types.d.ts +2 -1
  20. package/lib/globals/types.d.ts.map +1 -1
  21. package/lib/globals/types.js +1 -0
  22. package/lib/models/agent.model.d.ts +117 -0
  23. package/lib/models/agent.model.d.ts.map +1 -0
  24. package/lib/models/agent.model.js +13 -0
  25. package/lib/models/analytics.model.d.ts +4 -0
  26. package/lib/models/analytics.model.d.ts.map +1 -1
  27. package/lib/models/cachedAsset.model.d.ts +18 -0
  28. package/lib/models/cachedAsset.model.d.ts.map +1 -0
  29. package/lib/models/cachedAsset.model.js +2 -0
  30. package/lib/models/cachedRawAsset.model.d.ts +20 -0
  31. package/lib/models/cachedRawAsset.model.d.ts.map +1 -0
  32. package/lib/models/cachedRawAsset.model.js +2 -0
  33. package/lib/models/video.model.d.ts +1 -0
  34. package/lib/models/video.model.d.ts.map +1 -1
  35. package/lib/schemas/agentPersona.schema.d.ts +10 -0
  36. package/lib/schemas/agentPersona.schema.d.ts.map +1 -0
  37. package/lib/schemas/agentPersona.schema.js +11 -0
  38. package/lib/schemas/brandKit.schema.d.ts +101 -0
  39. package/lib/schemas/brandKit.schema.d.ts.map +1 -0
  40. package/lib/schemas/brandKit.schema.js +46 -0
  41. package/lib/schemas/brief.schema.d.ts +216 -0
  42. package/lib/schemas/brief.schema.d.ts.map +1 -0
  43. package/lib/schemas/brief.schema.js +118 -0
  44. package/lib/schemas/index.d.ts +6 -0
  45. package/lib/schemas/index.d.ts.map +1 -0
  46. package/lib/schemas/index.js +21 -0
  47. package/lib/schemas/project.schema.d.ts +1005 -0
  48. package/lib/schemas/project.schema.d.ts.map +1 -0
  49. package/lib/schemas/project.schema.js +238 -0
  50. package/lib/schemas/videoPlan.schema.d.ts +145 -0
  51. package/lib/schemas/videoPlan.schema.d.ts.map +1 -0
  52. package/lib/schemas/videoPlan.schema.js +109 -0
  53. package/lib/services/agent/beatSnap.d.ts +10 -0
  54. package/lib/services/agent/beatSnap.d.ts.map +1 -0
  55. package/lib/services/agent/beatSnap.js +128 -0
  56. package/lib/services/agent/costPreflight.d.ts +22 -0
  57. package/lib/services/agent/costPreflight.d.ts.map +1 -0
  58. package/lib/services/agent/costPreflight.js +75 -0
  59. package/lib/services/agent/critic.d.ts +103 -0
  60. package/lib/services/agent/critic.d.ts.map +1 -0
  61. package/lib/services/agent/critic.js +132 -0
  62. package/lib/services/agent/eval/index.d.ts +5 -0
  63. package/lib/services/agent/eval/index.d.ts.map +1 -0
  64. package/lib/services/agent/eval/index.js +20 -0
  65. package/lib/services/agent/eval/judge.d.ts +14 -0
  66. package/lib/services/agent/eval/judge.d.ts.map +1 -0
  67. package/lib/services/agent/eval/judge.js +95 -0
  68. package/lib/services/agent/eval/recorder.d.ts +17 -0
  69. package/lib/services/agent/eval/recorder.d.ts.map +1 -0
  70. package/lib/services/agent/eval/recorder.js +65 -0
  71. package/lib/services/agent/eval/seedBriefs.d.ts +16 -0
  72. package/lib/services/agent/eval/seedBriefs.d.ts.map +1 -0
  73. package/lib/services/agent/eval/seedBriefs.js +1188 -0
  74. package/lib/services/agent/eval/types.d.ts +196 -0
  75. package/lib/services/agent/eval/types.d.ts.map +1 -0
  76. package/lib/services/agent/eval/types.js +65 -0
  77. package/lib/services/agent/executor.d.ts +50 -0
  78. package/lib/services/agent/executor.d.ts.map +1 -0
  79. package/lib/services/agent/executor.js +188 -0
  80. package/lib/services/agent/index.d.ts +15 -0
  81. package/lib/services/agent/index.d.ts.map +1 -0
  82. package/lib/services/agent/index.js +30 -0
  83. package/lib/services/agent/llmCaller.d.ts +77 -0
  84. package/lib/services/agent/llmCaller.d.ts.map +1 -0
  85. package/lib/services/agent/llmCaller.js +16 -0
  86. package/lib/services/agent/llmCallerGateway.d.ts +39 -0
  87. package/lib/services/agent/llmCallerGateway.d.ts.map +1 -0
  88. package/lib/services/agent/llmCallerGateway.js +246 -0
  89. package/lib/services/agent/llmCallerRegistry.d.ts +4 -0
  90. package/lib/services/agent/llmCallerRegistry.d.ts.map +1 -0
  91. package/lib/services/agent/llmCallerRegistry.js +19 -0
  92. package/lib/services/agent/modelRouter.d.ts +41 -0
  93. package/lib/services/agent/modelRouter.d.ts.map +1 -0
  94. package/lib/services/agent/modelRouter.js +57 -0
  95. package/lib/services/agent/musicSelect.d.ts +23 -0
  96. package/lib/services/agent/musicSelect.d.ts.map +1 -0
  97. package/lib/services/agent/musicSelect.js +65 -0
  98. package/lib/services/agent/personas.d.ts +60 -0
  99. package/lib/services/agent/personas.d.ts.map +1 -0
  100. package/lib/services/agent/personas.js +156 -0
  101. package/lib/services/agent/planner.d.ts +56 -0
  102. package/lib/services/agent/planner.d.ts.map +1 -0
  103. package/lib/services/agent/planner.js +237 -0
  104. package/lib/services/agent/toolRegistry.d.ts +64 -0
  105. package/lib/services/agent/toolRegistry.d.ts.map +1 -0
  106. package/lib/services/agent/toolRegistry.js +78 -0
  107. package/lib/services/agent/tools/analyzeReference.tool.d.ts +36 -0
  108. package/lib/services/agent/tools/analyzeReference.tool.d.ts.map +1 -0
  109. package/lib/services/agent/tools/analyzeReference.tool.js +44 -0
  110. package/lib/services/agent/tools/animateImage.tool.d.ts +23 -0
  111. package/lib/services/agent/tools/animateImage.tool.d.ts.map +1 -0
  112. package/lib/services/agent/tools/animateImage.tool.js +58 -0
  113. package/lib/services/agent/tools/animateImageWithMotionBrush.tool.d.ts +30 -0
  114. package/lib/services/agent/tools/animateImageWithMotionBrush.tool.d.ts.map +1 -0
  115. package/lib/services/agent/tools/animateImageWithMotionBrush.tool.js +90 -0
  116. package/lib/services/agent/tools/composeScene.tool.d.ts +948 -0
  117. package/lib/services/agent/tools/composeScene.tool.d.ts.map +1 -0
  118. package/lib/services/agent/tools/composeScene.tool.js +90 -0
  119. package/lib/services/agent/tools/estimateCost.tool.d.ts +342 -0
  120. package/lib/services/agent/tools/estimateCost.tool.d.ts.map +1 -0
  121. package/lib/services/agent/tools/estimateCost.tool.js +62 -0
  122. package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts +32 -0
  123. package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts.map +1 -0
  124. package/lib/services/agent/tools/generateAvatarVideo.tool.js +112 -0
  125. package/lib/services/agent/tools/generateImage.tool.d.ts +28 -0
  126. package/lib/services/agent/tools/generateImage.tool.d.ts.map +1 -0
  127. package/lib/services/agent/tools/generateImage.tool.js +97 -0
  128. package/lib/services/agent/tools/generateVideo.tool.d.ts +30 -0
  129. package/lib/services/agent/tools/generateVideo.tool.d.ts.map +1 -0
  130. package/lib/services/agent/tools/generateVideo.tool.js +84 -0
  131. package/lib/services/agent/tools/generateVoiceover.tool.d.ts +18 -0
  132. package/lib/services/agent/tools/generateVoiceover.tool.d.ts.map +1 -0
  133. package/lib/services/agent/tools/generateVoiceover.tool.js +72 -0
  134. package/lib/services/agent/tools/index.d.ts +19 -0
  135. package/lib/services/agent/tools/index.d.ts.map +1 -0
  136. package/lib/services/agent/tools/index.js +34 -0
  137. package/lib/services/agent/tools/planVideo.tool.d.ts +191 -0
  138. package/lib/services/agent/tools/planVideo.tool.d.ts.map +1 -0
  139. package/lib/services/agent/tools/planVideo.tool.js +46 -0
  140. package/lib/services/agent/tools/render.tool.d.ts +357 -0
  141. package/lib/services/agent/tools/render.tool.d.ts.map +1 -0
  142. package/lib/services/agent/tools/render.tool.js +48 -0
  143. package/lib/services/agent/tools/searchMusic.tool.d.ts +49 -0
  144. package/lib/services/agent/tools/searchMusic.tool.d.ts.map +1 -0
  145. package/lib/services/agent/tools/searchMusic.tool.js +74 -0
  146. package/lib/services/agent/tools/searchStock.tool.d.ts +37 -0
  147. package/lib/services/agent/tools/searchStock.tool.d.ts.map +1 -0
  148. package/lib/services/agent/tools/searchStock.tool.js +101 -0
  149. package/lib/services/agent/tools/searchUserLibrary.tool.d.ts +59 -0
  150. package/lib/services/agent/tools/searchUserLibrary.tool.d.ts.map +1 -0
  151. package/lib/services/agent/tools/searchUserLibrary.tool.js +58 -0
  152. package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts +31 -0
  153. package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts.map +1 -0
  154. package/lib/services/aiGen/canonicalAdapters/cameraControl.types.js +2 -0
  155. package/lib/services/aiGen/canonicalAdapters/index.d.ts +3 -0
  156. package/lib/services/aiGen/canonicalAdapters/index.d.ts.map +1 -0
  157. package/lib/services/aiGen/canonicalAdapters/index.js +18 -0
  158. package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts +23 -0
  159. package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts.map +1 -0
  160. package/lib/services/aiGen/canonicalAdapters/multiShot.types.js +12 -0
  161. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.d.ts +18 -0
  162. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.d.ts.map +1 -0
  163. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.js +100 -0
  164. package/lib/services/aiGen/providers/fal/falImage.service.d.ts +9 -0
  165. package/lib/services/aiGen/providers/fal/falImage.service.d.ts.map +1 -0
  166. package/lib/services/aiGen/providers/fal/falImage.service.js +102 -0
  167. package/lib/services/aiGen/providers/fal/index.d.ts +2 -0
  168. package/lib/services/aiGen/providers/fal/index.d.ts.map +1 -0
  169. package/lib/services/aiGen/providers/fal/index.js +17 -0
  170. package/lib/services/aiGen/providers/kling/cameraAdapter.d.ts +4 -0
  171. package/lib/services/aiGen/providers/kling/cameraAdapter.d.ts.map +1 -0
  172. package/lib/services/aiGen/providers/kling/cameraAdapter.js +53 -0
  173. package/lib/services/aiGen/providers/pexels/index.d.ts +2 -0
  174. package/lib/services/aiGen/providers/pexels/index.d.ts.map +1 -0
  175. package/lib/services/aiGen/providers/pexels/index.js +17 -0
  176. package/lib/services/aiGen/providers/pexels/pexels.service.d.ts +11 -0
  177. package/lib/services/aiGen/providers/pexels/pexels.service.d.ts.map +1 -0
  178. package/lib/services/aiGen/providers/pexels/pexels.service.js +118 -0
  179. package/lib/services/aiGen/providers/runway/cameraAdapter.d.ts +3 -0
  180. package/lib/services/aiGen/providers/runway/cameraAdapter.d.ts.map +1 -0
  181. package/lib/services/aiGen/providers/runway/cameraAdapter.js +46 -0
  182. package/lib/services/analytics.service.d.ts +10 -0
  183. package/lib/services/analytics.service.d.ts.map +1 -1
  184. package/lib/services/analytics.service.js +27 -0
  185. package/lib/services/asr/assemblyai.service.d.ts +72 -0
  186. package/lib/services/asr/assemblyai.service.d.ts.map +1 -0
  187. package/lib/services/asr/assemblyai.service.js +89 -0
  188. package/lib/services/asr/index.d.ts +2 -0
  189. package/lib/services/asr/index.d.ts.map +1 -0
  190. package/lib/services/asr/index.js +17 -0
  191. package/lib/services/assetCache.service.d.ts +54 -0
  192. package/lib/services/assetCache.service.d.ts.map +1 -0
  193. package/lib/services/assetCache.service.js +96 -0
  194. package/lib/services/audioAnalysis/index.d.ts +2 -0
  195. package/lib/services/audioAnalysis/index.d.ts.map +1 -0
  196. package/lib/services/audioAnalysis/index.js +17 -0
  197. package/lib/services/audioAnalysis/onsetDetection.service.d.ts +50 -0
  198. package/lib/services/audioAnalysis/onsetDetection.service.d.ts.map +1 -0
  199. package/lib/services/audioAnalysis/onsetDetection.service.js +136 -0
  200. package/lib/services/editor/designToProject.d.ts +60 -0
  201. package/lib/services/editor/designToProject.d.ts.map +1 -0
  202. package/lib/services/editor/designToProject.js +194 -0
  203. package/lib/services/musicGen/index.d.ts +6 -0
  204. package/lib/services/musicGen/index.d.ts.map +1 -0
  205. package/lib/services/musicGen/index.js +26 -0
  206. package/lib/services/musicGen/musicSearchFactory.service.d.ts +14 -0
  207. package/lib/services/musicGen/musicSearchFactory.service.d.ts.map +1 -0
  208. package/lib/services/musicGen/musicSearchFactory.service.js +59 -0
  209. package/lib/services/musicGen/providers/curated.service.d.ts +22 -0
  210. package/lib/services/musicGen/providers/curated.service.d.ts.map +1 -0
  211. package/lib/services/musicGen/providers/curated.service.js +171 -0
  212. package/lib/services/musicGen/providers/jamendo.service.d.ts +8 -0
  213. package/lib/services/musicGen/providers/jamendo.service.d.ts.map +1 -0
  214. package/lib/services/musicGen/providers/jamendo.service.js +93 -0
  215. package/lib/services/musicGen/providers/mubert.service.d.ts +9 -0
  216. package/lib/services/musicGen/providers/mubert.service.d.ts.map +1 -0
  217. package/lib/services/musicGen/providers/mubert.service.js +113 -0
  218. package/lib/services/musicGen/types.d.ts +42 -0
  219. package/lib/services/musicGen/types.d.ts.map +1 -0
  220. package/lib/services/musicGen/types.js +10 -0
  221. package/lib/services/tts/providers/minimax.service.d.ts +14 -0
  222. package/lib/services/tts/providers/minimax.service.d.ts.map +1 -0
  223. package/lib/services/tts/providers/minimax.service.js +78 -0
  224. package/lib/services/tts/providers/openai.service.d.ts +14 -0
  225. package/lib/services/tts/providers/openai.service.d.ts.map +1 -0
  226. package/lib/services/tts/providers/openai.service.js +71 -0
  227. package/lib/utils/helpers.d.ts +1 -0
  228. package/lib/utils/helpers.d.ts.map +1 -1
  229. package/lib/utils/helpers.js +26 -12
  230. package/package.json +1 -1
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PexelsProviderService = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const baseAiGenProvider_service_1 = require("../baseAiGenProvider.service");
9
+ /**
10
+ * Pexels stock provider — T0 tier (free).
11
+ *
12
+ * Pexels' free API supports video + image search. We deliberately ignore the
13
+ * music API for now (it's photo-only on the free tier; music comes from a
14
+ * different stock provider in a later commit).
15
+ *
16
+ * Attribution: Pexels' license requires "Photos provided by Pexels" attribution
17
+ * when used in publication. Producer surfaces (storyboard, finished video page)
18
+ * must surface this — handled in the UI layer, not here.
19
+ */
20
+ const PEXELS_VIDEO_URL = "https://api.pexels.com/videos/search";
21
+ const PEXELS_IMAGE_URL = "https://api.pexels.com/v1/search";
22
+ class PexelsProviderService extends baseAiGenProvider_service_1.BaseAiGenProviderService {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.apiKey = process.env.PEXELS_API_KEY;
26
+ }
27
+ async searchStock(params) {
28
+ if (!this.apiKey) {
29
+ throw new Error("PEXELS_API_KEY not set — pexels provider cannot search");
30
+ }
31
+ if (params.kind === "music") {
32
+ throw new Error("Pexels does not provide stock music");
33
+ }
34
+ const headers = { Authorization: this.apiKey };
35
+ const perPage = Math.min(params.perPage ?? 15, 80);
36
+ if (params.kind === "video") {
37
+ const { data } = await axios_1.default.get(PEXELS_VIDEO_URL, {
38
+ headers,
39
+ timeout: 20000,
40
+ params: {
41
+ query: params.query,
42
+ per_page: perPage,
43
+ orientation: this.aspectToOrientation(params.aspectRatio),
44
+ },
45
+ });
46
+ const filtered = data.videos.filter((v) => {
47
+ if (params.minDurationSec && v.duration < params.minDurationSec)
48
+ return false;
49
+ if (params.maxDurationSec && v.duration > params.maxDurationSec)
50
+ return false;
51
+ return true;
52
+ });
53
+ return {
54
+ assets: filtered.map((v) => ({
55
+ id: String(v.id),
56
+ url: this.pickBestVideoFile(v.video_files),
57
+ thumbnailUrl: v.image,
58
+ width: v.width,
59
+ height: v.height,
60
+ durationSec: v.duration,
61
+ source: "pexels",
62
+ attribution: { name: v.user.name, url: v.user.url },
63
+ })),
64
+ totalAvailable: data.total_results,
65
+ };
66
+ }
67
+ // image
68
+ const { data } = await axios_1.default.get(PEXELS_IMAGE_URL, {
69
+ headers,
70
+ timeout: 20000,
71
+ params: {
72
+ query: params.query,
73
+ per_page: perPage,
74
+ orientation: this.aspectToOrientation(params.aspectRatio),
75
+ },
76
+ });
77
+ return {
78
+ assets: data.photos.map((p) => ({
79
+ id: String(p.id),
80
+ url: p.src.original,
81
+ thumbnailUrl: p.src.medium,
82
+ width: p.width,
83
+ height: p.height,
84
+ source: "pexels",
85
+ attribution: { name: p.photographer, url: p.photographer_url },
86
+ })),
87
+ totalAvailable: data.total_results,
88
+ };
89
+ }
90
+ /** Free assets — registers as 0 credits regardless of model. */
91
+ getCreditUsed(_params) {
92
+ return 0;
93
+ }
94
+ aspectToOrientation(aspect) {
95
+ if (!aspect)
96
+ return undefined;
97
+ if (aspect === "9:16" || aspect === "4:5")
98
+ return "portrait";
99
+ if (aspect === "1:1")
100
+ return "square";
101
+ return "landscape";
102
+ }
103
+ pickBestVideoFile(files) {
104
+ // Prefer .mp4 1080p, fall back to highest-resolution mp4.
105
+ const mp4 = files.filter((f) => f.file_type === "video/mp4");
106
+ if (mp4.length === 0) {
107
+ const first = files[0];
108
+ if (!first)
109
+ throw new Error("Pexels video has no files");
110
+ return first.link;
111
+ }
112
+ const hd = mp4.find((f) => f.height >= 1000 && f.height <= 1200);
113
+ if (hd)
114
+ return hd.link;
115
+ return mp4.sort((a, b) => b.height - a.height)[0].link;
116
+ }
117
+ }
118
+ exports.PexelsProviderService = PexelsProviderService;
@@ -0,0 +1,3 @@
1
+ import type { CameraControl } from "../../canonicalAdapters/cameraControl.types";
2
+ export declare function applyRunwayCameraControl(prompt: string | undefined, c: CameraControl): string;
3
+ //# sourceMappingURL=cameraAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cameraAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/runway/cameraAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAEd,MAAM,6CAA6C,CAAC;AAmCrD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,CAAC,EAAE,aAAa,GACf,MAAM,CAMR"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyRunwayCameraControl = applyRunwayCameraControl;
4
+ /**
5
+ * Runway gen4 doesn't expose a structured camera-control field — moves are
6
+ * inferred from prompt text. We translate the canonical preset/intensity into
7
+ * a short bracketed clause prepended to the prompt. Matches Runway's own
8
+ * cinematography vocabulary so the model parses it reliably.
9
+ */
10
+ const PRESET_TO_PHRASE = {
11
+ static: "static camera",
12
+ pan_left: "camera pans left",
13
+ pan_right: "camera pans right",
14
+ tilt_up: "camera tilts up",
15
+ tilt_down: "camera tilts down",
16
+ zoom_in: "camera zooms in",
17
+ zoom_out: "camera zooms out",
18
+ dolly_in: "camera dollies in",
19
+ dolly_out: "camera dollies out",
20
+ orbit_left: "camera orbits left around subject",
21
+ orbit_right: "camera orbits right around subject",
22
+ roll_left: "camera rolls counter-clockwise",
23
+ roll_right: "camera rolls clockwise",
24
+ tracking: "tracking shot following subject",
25
+ handheld: "handheld camera",
26
+ push_in: "slow push in",
27
+ pull_out: "slow pull out",
28
+ };
29
+ function intensityWord(i) {
30
+ if (i === undefined)
31
+ return "";
32
+ if (i <= 0.33)
33
+ return "subtle ";
34
+ if (i >= 0.67)
35
+ return "strong ";
36
+ return "";
37
+ }
38
+ function applyRunwayCameraControl(prompt, c) {
39
+ if (!c.preset)
40
+ return prompt ?? "";
41
+ const phrase = PRESET_TO_PHRASE[c.preset];
42
+ if (!phrase)
43
+ return prompt ?? "";
44
+ const clause = `[${intensityWord(c.intensity)}${phrase}]`;
45
+ return prompt ? `${clause} ${prompt}` : clause;
46
+ }
@@ -19,5 +19,15 @@ export interface RecordJobOutcomeParams {
19
19
  */
20
20
  export declare class AnalyticsService {
21
21
  static recordJobOutcome(p: RecordJobOutcomeParams): Promise<void>;
22
+ /**
23
+ * Records a "sample" video — i.e. the try-example short-circuit in the
24
+ * functions controller that returns a pre-generated video without actually
25
+ * invoking any provider. Tracked separately so dashboard "Jobs" remains a
26
+ * count of real provider-backed generations.
27
+ */
28
+ static recordSampleOutcome(p: {
29
+ modelKey: string;
30
+ finalizedAt?: Date;
31
+ }): Promise<void>;
22
32
  }
23
33
  //# sourceMappingURL=analytics.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.service.d.ts","sourceRoot":"","sources":["../../src/services/analytics.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAqB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAUpD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,eAAe,CAAC;IAC7B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;;;;;GAMG;AACH,qBAAa,gBAAgB;WACd,gBAAgB,CAAC,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;CAqDxE"}
1
+ {"version":3,"file":"analytics.service.d.ts","sourceRoot":"","sources":["../../src/services/analytics.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAqB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAUpD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,eAAe,CAAC;IAC7B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;;;;;GAMG;AACH,qBAAa,gBAAgB;WACd,gBAAgB,CAAC,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDvE;;;;;OAKG;WACU,mBAAmB,CAAC,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAqB7F"}
@@ -65,5 +65,32 @@ class AnalyticsService {
65
65
  batch.set(globalRef, globalPayload, { merge: true });
66
66
  await batch.commit();
67
67
  }
68
+ /**
69
+ * Records a "sample" video — i.e. the try-example short-circuit in the
70
+ * functions controller that returns a pre-generated video without actually
71
+ * invoking any provider. Tracked separately so dashboard "Jobs" remains a
72
+ * count of real provider-backed generations.
73
+ */
74
+ static async recordSampleOutcome(p) {
75
+ const date = dateKey(p.finalizedAt);
76
+ const inc = firestore_1.FieldValue.increment;
77
+ const perModelRef = firebase_1.firestore.collection(DAILY_COL).doc(`${date}_${p.modelKey}`);
78
+ const globalRef = firebase_1.firestore.collection(DAILY_GLOBAL_COL).doc(date);
79
+ const payload = {
80
+ date,
81
+ modelKey: p.modelKey,
82
+ samplesCompleted: inc(1),
83
+ updatedAt: firestore_1.FieldValue.serverTimestamp(),
84
+ };
85
+ const globalPayload = {
86
+ date,
87
+ samplesCompleted: inc(1),
88
+ updatedAt: firestore_1.FieldValue.serverTimestamp(),
89
+ };
90
+ const batch = firebase_1.firestore.batch();
91
+ batch.set(perModelRef, payload, { merge: true });
92
+ batch.set(globalRef, globalPayload, { merge: true });
93
+ await batch.commit();
94
+ }
68
95
  }
69
96
  exports.AnalyticsService = AnalyticsService;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * AssemblyAI ASR client. Supports submit + poll-to-completion (sync caller flow).
3
+ *
4
+ * Pricing: Universal-2 model is $0.15/hr (verified 2026-05-11 against
5
+ * https://www.assemblyai.com/pricing). Diarization (`speaker_labels`) adds
6
+ * ~$0.02/hr (≈ +13%). Long audio (>3 min) should go through the BullMQ async
7
+ * path; the inline poll here is bounded at 3 min to stay inside Firebase
8
+ * Functions HTTP timeout budgets.
9
+ */
10
+ export interface TranscribeParams {
11
+ audioUrl: string;
12
+ /** Hint to AssemblyAI for language autodetect short-circuit (e.g. "en", "es"). */
13
+ languageCode?: string;
14
+ /** Diarization (speaker labels). Adds ~30% latency. */
15
+ speakerLabels?: boolean;
16
+ /** Auto-redact PII (SSN, credit cards, etc.). */
17
+ redactPii?: boolean;
18
+ /** Word-level timestamps in result. */
19
+ wordTimestamps?: boolean;
20
+ }
21
+ export interface TranscribeResult {
22
+ id: string;
23
+ status: "completed" | "queued" | "processing" | "error";
24
+ text?: string;
25
+ /** Audio duration in seconds; populated on completion. */
26
+ audioDuration?: number;
27
+ /** Per-word timestamps (start/end ms). */
28
+ words?: Array<{
29
+ text: string;
30
+ start: number;
31
+ end: number;
32
+ confidence: number;
33
+ speaker?: string;
34
+ }>;
35
+ /** Per-utterance segments when speakerLabels=true. */
36
+ utterances?: Array<{
37
+ text: string;
38
+ start: number;
39
+ end: number;
40
+ speaker: string;
41
+ confidence: number;
42
+ }>;
43
+ errorMessage?: string;
44
+ }
45
+ export declare class AssemblyAIService {
46
+ private readonly baseUrl;
47
+ private readonly apiKey;
48
+ constructor();
49
+ private request;
50
+ /** Submit a transcription job. Returns the transcript id immediately. */
51
+ submit(params: TranscribeParams): Promise<{
52
+ id: string;
53
+ }>;
54
+ checkStatus(id: string): Promise<TranscribeResult>;
55
+ /**
56
+ * Submit and poll inline until completion. Use for short-to-medium audio.
57
+ * Bounded at `timeoutMs` (default 3 min) — caller should fall back to async
58
+ * BullMQ flow for longer audio.
59
+ */
60
+ transcribe(params: TranscribeParams, { timeoutMs, intervalMs }?: {
61
+ timeoutMs?: number;
62
+ intervalMs?: number;
63
+ }): Promise<TranscribeResult>;
64
+ /**
65
+ * Credit cost for transcription. Universal-2 = $0.15/hr; diarization
66
+ * (speakerLabels) adds $0.02/hr (≈ +13%). Routes through the same
67
+ * `getCreditsFromCost` helper as every other endpoint so the credit ↔ USD
68
+ * ratio (1 credit = $0.10) and the per-call floor stay consistent.
69
+ */
70
+ getCreditUsed(audioDurationSec: number, speakerLabels?: boolean): number;
71
+ }
72
+ //# sourceMappingURL=assemblyai.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemblyai.service.d.ts","sourceRoot":"","sources":["../../../src/services/asr/assemblyai.service.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uCAAuC;IACvC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClG,sDAAsD;IACtD,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;YASlB,OAAO;IAyBrB,yEAAyE;IACnE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAWzD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAaxD;;;;OAIG;IACG,UAAU,CACd,MAAM,EAAE,gBAAgB,EACxB,EAAE,SAAmB,EAAE,UAAiB,EAAE,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO,GAC3F,OAAO,CAAC,gBAAgB,CAAC;IAc5B;;;;;OAKG;IACH,aAAa,CAAC,gBAAgB,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,MAAM;CAMvE"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AssemblyAIService = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const logger_1 = require("../../utils/logger");
9
+ const helpers_1 = require("../../utils/helpers");
10
+ class AssemblyAIService {
11
+ constructor() {
12
+ this.baseUrl = "https://api.assemblyai.com/v2";
13
+ if (!process.env.ASSEMBLYAI_API_KEY) {
14
+ throw new Error("Missing ASSEMBLYAI_API_KEY in environment variables");
15
+ }
16
+ this.apiKey = process.env.ASSEMBLYAI_API_KEY;
17
+ }
18
+ async request(endpoint, method, body) {
19
+ const config = {
20
+ method,
21
+ url: `${this.baseUrl}${endpoint}`,
22
+ headers: {
23
+ Authorization: this.apiKey,
24
+ "Content-Type": "application/json",
25
+ },
26
+ data: body,
27
+ timeout: 60000,
28
+ validateStatus: () => true,
29
+ };
30
+ const resp = await axios_1.default.request(config);
31
+ if (resp.status < 200 || resp.status >= 300) {
32
+ throw new Error(`AssemblyAI API Error: ${resp.status} ${resp.statusText} — ${JSON.stringify(resp.data)}`);
33
+ }
34
+ return resp.data;
35
+ }
36
+ /** Submit a transcription job. Returns the transcript id immediately. */
37
+ async submit(params) {
38
+ const body = {
39
+ audio_url: params.audioUrl,
40
+ ...(params.languageCode ? { language_code: params.languageCode } : { language_detection: true }),
41
+ ...(params.speakerLabels ? { speaker_labels: true } : {}),
42
+ ...(params.redactPii ? { redact_pii: true, redact_pii_policies: ["us_social_security_number", "credit_card_number", "email_address", "phone_number"] } : {}),
43
+ };
44
+ const resp = await this.request("/transcript", "POST", body);
45
+ return { id: resp.id };
46
+ }
47
+ async checkStatus(id) {
48
+ const resp = await this.request(`/transcript/${id}`, "GET");
49
+ return {
50
+ id: resp.id,
51
+ status: resp.status,
52
+ text: resp.text,
53
+ audioDuration: resp.audio_duration,
54
+ words: resp.words,
55
+ utterances: resp.utterances,
56
+ errorMessage: resp.error,
57
+ };
58
+ }
59
+ /**
60
+ * Submit and poll inline until completion. Use for short-to-medium audio.
61
+ * Bounded at `timeoutMs` (default 3 min) — caller should fall back to async
62
+ * BullMQ flow for longer audio.
63
+ */
64
+ async transcribe(params, { timeoutMs = 180000, intervalMs = 3000 } = {}) {
65
+ const { id } = await this.submit(params);
66
+ const deadline = Date.now() + timeoutMs;
67
+ while (Date.now() < deadline) {
68
+ await new Promise((r) => setTimeout(r, intervalMs));
69
+ const status = await this.checkStatus(id);
70
+ if (status.status === "completed" || status.status === "error")
71
+ return status;
72
+ }
73
+ logger_1.logger.warn("AssemblyAI transcribe timed out — returning processing status", { id });
74
+ return { id, status: "processing", errorMessage: "Transcription exceeded inline poll budget; use checkStatus(id) to fetch later." };
75
+ }
76
+ /**
77
+ * Credit cost for transcription. Universal-2 = $0.15/hr; diarization
78
+ * (speakerLabels) adds $0.02/hr (≈ +13%). Routes through the same
79
+ * `getCreditsFromCost` helper as every other endpoint so the credit ↔ USD
80
+ * ratio (1 credit = $0.10) and the per-call floor stay consistent.
81
+ */
82
+ getCreditUsed(audioDurationSec, speakerLabels = false) {
83
+ const ratePerSecond = 0.15 / 3600;
84
+ const multiplier = speakerLabels ? 1.133 : 1.0;
85
+ const cost = ratePerSecond * audioDurationSec * multiplier;
86
+ return (0, helpers_1.getCreditsFromCost)(cost);
87
+ }
88
+ }
89
+ exports.AssemblyAIService = AssemblyAIService;
@@ -0,0 +1,2 @@
1
+ export * from "./assemblyai.service";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/asr/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./assemblyai.service"), exports);
@@ -0,0 +1,54 @@
1
+ import { ICachedAssetModel } from "../models/cachedAsset.model";
2
+ import { ICachedRawAssetModel } from "../models/cachedRawAsset.model";
3
+ /**
4
+ * Asset cache + dedupe.
5
+ *
6
+ * Many agent runs ask for similar things — same VO line, same stock query,
7
+ * similar image prompt. Caching by a content-hashed key turns the second
8
+ * request into an instant lookup, which is a massive cost lever for bulk runs
9
+ * (where the same template variant is generated 100×) and serial creators.
10
+ *
11
+ * The cache is content-addressed: hash(provider + normalized-input) → the
12
+ * resulting asset URL + metadata. Any input change produces a different hash,
13
+ * so stale results are impossible.
14
+ *
15
+ * Backed by Firestore for V1; can move to Redis / GCS metadata index later
16
+ * without changing the API.
17
+ */
18
+ export type CachedAsset = ICachedAssetModel;
19
+ export interface AssetCacheKeyParts {
20
+ provider: string;
21
+ /** Stable input identity — must capture every parameter that affects output. */
22
+ input: Record<string, unknown>;
23
+ }
24
+ export declare class AssetCacheService {
25
+ /**
26
+ * Compute a stable cache key. Same input → same key, regardless of object
27
+ * key order. Use externally to derive the idempotency key for the upstream
28
+ * provider call so retries dedupe naturally.
29
+ */
30
+ static hashKey(parts: AssetCacheKeyParts): string;
31
+ static lookup(parts: AssetCacheKeyParts): Promise<CachedAsset | null>;
32
+ static store(parts: AssetCacheKeyParts, asset: Omit<CachedAsset, "key" | "createdAt" | "lastAccessedAt" | "hitCount">): Promise<CachedAsset>;
33
+ }
34
+ /**
35
+ * Raw payload cache — sibling to the asset URL cache for things that aren't
36
+ * a single asset URL: stock-search responses (lists), VO bytes, etc.
37
+ *
38
+ * Same content-hash key strategy. TTL is optional — stock results expire
39
+ * after 30 min, VOs are immutable so they live until evicted.
40
+ *
41
+ * Firestore doc cap is 1MB. Callers that may exceed it (VO base64) are
42
+ * responsible for skipping the store call when payloads get big.
43
+ */
44
+ export interface RawCacheKeyParts extends AssetCacheKeyParts {
45
+ kind: ICachedRawAssetModel["kind"];
46
+ }
47
+ export declare class RawAssetCacheService {
48
+ static hashKey(parts: RawCacheKeyParts): string;
49
+ static lookup<T = unknown>(parts: RawCacheKeyParts): Promise<T | null>;
50
+ static store(parts: RawCacheKeyParts, payload: unknown, options?: {
51
+ ttlMs?: number;
52
+ }): Promise<void>;
53
+ }
54
+ //# sourceMappingURL=assetCache.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assetCache.service.d.ts","sourceRoot":"","sources":["../../src/services/assetCache.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAGtE;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAE5C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,qBAAa,iBAAiB;IAC5B;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM;WAQpC,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;WAoB9D,KAAK,CAChB,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,IAAI,CACT,WAAW,EACX,KAAK,GAAG,WAAW,GAAG,gBAAgB,GAAG,UAAU,CACpD,GACA,OAAO,CAAC,WAAW,CAAC;CAaxB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CACpC;AAED,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM;WAIlC,MAAM,CAAC,CAAC,GAAG,OAAO,EAC7B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;WAqBP,KAAK,CAChB,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/B,OAAO,CAAC,IAAI,CAAC;CAoBjB"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RawAssetCacheService = exports.AssetCacheService = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const firestore_service_1 = require("./firestore.service");
9
+ class AssetCacheService {
10
+ /**
11
+ * Compute a stable cache key. Same input → same key, regardless of object
12
+ * key order. Use externally to derive the idempotency key for the upstream
13
+ * provider call so retries dedupe naturally.
14
+ */
15
+ static hashKey(parts) {
16
+ const normalized = JSON.stringify({
17
+ p: parts.provider,
18
+ i: sortedClone(parts.input),
19
+ });
20
+ return crypto_1.default.createHash("sha256").update(normalized).digest("hex");
21
+ }
22
+ static async lookup(parts) {
23
+ const key = AssetCacheService.hashKey(parts);
24
+ const doc = await firestore_service_1.FirestoreService.getDataById(firestore_service_1.FirestoreService.assetCacheCol, key);
25
+ if (!doc)
26
+ return null;
27
+ // Best-effort hit-count update; don't block on it.
28
+ void firestore_service_1.FirestoreService.updateData(firestore_service_1.FirestoreService.assetCacheCol, key, {
29
+ lastAccessedAt: new Date().toISOString(),
30
+ hitCount: (doc.hitCount ?? 0) + 1,
31
+ }).catch(() => undefined);
32
+ const { id: _id, ...stripped } = doc;
33
+ return stripped;
34
+ }
35
+ static async store(parts, asset) {
36
+ const key = AssetCacheService.hashKey(parts);
37
+ const now = new Date().toISOString();
38
+ const entry = {
39
+ ...asset,
40
+ key,
41
+ createdAt: now,
42
+ lastAccessedAt: now,
43
+ hitCount: 0,
44
+ };
45
+ await firestore_service_1.FirestoreService.addData(firestore_service_1.FirestoreService.assetCacheCol, key, entry);
46
+ return entry;
47
+ }
48
+ }
49
+ exports.AssetCacheService = AssetCacheService;
50
+ class RawAssetCacheService {
51
+ static hashKey(parts) {
52
+ return AssetCacheService.hashKey(parts);
53
+ }
54
+ static async lookup(parts) {
55
+ const key = RawAssetCacheService.hashKey(parts);
56
+ const doc = await firestore_service_1.FirestoreService.getDataById(firestore_service_1.FirestoreService.assetCacheRawCol, key);
57
+ if (!doc)
58
+ return null;
59
+ if (doc.expiresAt && new Date(doc.expiresAt).getTime() < Date.now()) {
60
+ return null;
61
+ }
62
+ void firestore_service_1.FirestoreService.updateData(firestore_service_1.FirestoreService.assetCacheRawCol, key, {
63
+ lastAccessedAt: new Date().toISOString(),
64
+ hitCount: (doc.hitCount ?? 0) + 1,
65
+ }).catch(() => undefined);
66
+ return doc.payload;
67
+ }
68
+ static async store(parts, payload, options = {}) {
69
+ const key = RawAssetCacheService.hashKey(parts);
70
+ const now = new Date();
71
+ const entry = {
72
+ key,
73
+ kind: parts.kind,
74
+ payload,
75
+ createdAt: now.toISOString(),
76
+ lastAccessedAt: now.toISOString(),
77
+ hitCount: 0,
78
+ };
79
+ if (options.ttlMs) {
80
+ entry.expiresAt = new Date(now.getTime() + options.ttlMs).toISOString();
81
+ }
82
+ await firestore_service_1.FirestoreService.addData(firestore_service_1.FirestoreService.assetCacheRawCol, key, entry);
83
+ }
84
+ }
85
+ exports.RawAssetCacheService = RawAssetCacheService;
86
+ function sortedClone(value) {
87
+ if (value === null || typeof value !== "object")
88
+ return value;
89
+ if (Array.isArray(value))
90
+ return value.map(sortedClone);
91
+ const sorted = {};
92
+ for (const k of Object.keys(value).sort()) {
93
+ sorted[k] = sortedClone(value[k]);
94
+ }
95
+ return sorted;
96
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./onsetDetection.service";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/audioAnalysis/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./onsetDetection.service"), exports);
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Onset detection — finds the actual transient peaks in a music track so the
3
+ * agent can snap scene cuts to where a kick / snare / vocal entry actually
4
+ * lands, not just where a uniform BPM grid says they should.
5
+ *
6
+ * Backend: essentia.js (RhythmExtractor2013) — the same engine that powers
7
+ * Spotify's tempo estimation research. Industrial-strength for audio
8
+ * analysis.
9
+ *
10
+ * ╔═══════════════════════════════════════════════════════════════════════╗
11
+ * ║ LICENSING NOTE — essentia.js is AGPL-3 upstream. ║
12
+ * ║ ║
13
+ * ║ Until the MTG-UPF commercial license is signed, this module is ║
14
+ * ║ STRICTLY BACKEND-ONLY: ║
15
+ * ║ - never bundle into the frontend ║
16
+ * ║ - never include in any client-distributed artifact (Electron, ║
17
+ * ║ desktop, mobile, downloadable build) ║
18
+ * ║ - never expose the .wasm via a public URL ║
19
+ * ║ - never reference essentia by name in customer-facing copy, ║
20
+ * ║ marketing, blog posts, talks, job listings, or social posts ║
21
+ * ║ ║
22
+ * ║ Theory of operation: the SaaS commercial license — once signed — ║
23
+ * ║ covers VidSpot's use as the operator. Until then, do not amplify ║
24
+ * ║ visibility. See backend/docs/licensing-essentia.md for the full ║
25
+ * ║ constraint and contact (mtg-info@upf.edu). ║
26
+ * ║ ║
27
+ * ║ Operator switch: ENABLE_ONSET_DETECTION=true in env. Flip to false ║
28
+ * ║ to disable the module across every environment in one change — snap ║
29
+ * ║ pass falls back to BPM math safely. ║
30
+ * ╚═══════════════════════════════════════════════════════════════════════╝
31
+ *
32
+ * Operationally:
33
+ * - Lazy-loads the WASM module on first call (~5MB; once per worker boot)
34
+ * - Downloads the audio file to memory, decodes via audio-decode (MIT)
35
+ * - Mixes to mono (essentia algorithms expect a single channel)
36
+ * - Runs RhythmExtractor2013 → returns { bpm, beats: number[] (seconds) }
37
+ * - 12s hard timeout — long enough for a 3-min track on a cold WASM load,
38
+ * short enough that the planner endpoint stays responsive on a miss
39
+ * - In-memory cache keyed by URL — same music re-snaps for free
40
+ *
41
+ * Failure mode: returns undefined. Caller (snapPlanToBeats) falls back to
42
+ * uniform BPM math. Onset detection is enhancement, never a blocker.
43
+ */
44
+ export interface OnsetAnalysis {
45
+ bpm: number;
46
+ /** Beat / onset timestamps in seconds, sorted ascending. */
47
+ onsets: number[];
48
+ }
49
+ export declare function detectOnsets(audioUrl: string): Promise<OnsetAnalysis | undefined>;
50
+ //# sourceMappingURL=onsetDetection.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onsetDetection.service.d.ts","sourceRoot":"","sources":["../../../src/services/audioAnalysis/onsetDetection.service.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAwFD,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAcvF"}