vidspotai-shared 1.0.82-dev.0 → 1.0.83

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 (468) hide show
  1. package/lib/globals/aiModels/enums.d.ts +11 -1
  2. package/lib/globals/aiModels/enums.d.ts.map +1 -1
  3. package/lib/globals/aiModels/enums.js +24 -1
  4. package/lib/globals/aiModels/index.d.ts.map +1 -1
  5. package/lib/globals/aiModels/index.js +2 -0
  6. package/lib/globals/aiModels/providers/anthropic.d.ts +12 -0
  7. package/lib/globals/aiModels/providers/anthropic.d.ts.map +1 -0
  8. package/lib/globals/aiModels/providers/anthropic.js +88 -0
  9. package/lib/globals/aiModels/providers/google.d.ts.map +1 -1
  10. package/lib/globals/aiModels/providers/google.js +115 -10
  11. package/lib/globals/aiModels/providers/openai.d.ts.map +1 -1
  12. package/lib/globals/aiModels/providers/openai.js +63 -4
  13. package/lib/globals/aiModels/tierHelpers.d.ts +12 -0
  14. package/lib/globals/aiModels/tierHelpers.d.ts.map +1 -1
  15. package/lib/globals/aiModels/tierHelpers.js +83 -0
  16. package/lib/globals/aiModels/types.d.ts +19 -0
  17. package/lib/globals/aiModels/types.d.ts.map +1 -1
  18. package/lib/globals/types.d.ts +120 -1
  19. package/lib/globals/types.d.ts.map +1 -1
  20. package/lib/globals/types.js +135 -1
  21. package/lib/models/agent.model.d.ts +41 -1
  22. package/lib/models/agent.model.d.ts.map +1 -1
  23. package/lib/models/index.d.ts +1 -0
  24. package/lib/models/index.d.ts.map +1 -1
  25. package/lib/models/index.js +1 -0
  26. package/lib/models/social.model.d.ts +180 -0
  27. package/lib/models/social.model.d.ts.map +1 -0
  28. package/lib/models/social.model.js +2 -0
  29. package/lib/models/user.model.d.ts +10 -0
  30. package/lib/models/user.model.d.ts.map +1 -1
  31. package/lib/models/video.model.d.ts +6 -0
  32. package/lib/models/video.model.d.ts.map +1 -1
  33. package/lib/schemas/brief.schema.d.ts +46 -0
  34. package/lib/schemas/brief.schema.d.ts.map +1 -1
  35. package/lib/schemas/brief.schema.js +72 -1
  36. package/lib/schemas/index.d.ts +1 -0
  37. package/lib/schemas/index.d.ts.map +1 -1
  38. package/lib/schemas/index.js +1 -0
  39. package/lib/schemas/project.schema.d.ts +70 -3
  40. package/lib/schemas/project.schema.d.ts.map +1 -1
  41. package/lib/schemas/project.schema.js +12 -0
  42. package/lib/schemas/social.schema.d.ts +91 -0
  43. package/lib/schemas/social.schema.d.ts.map +1 -0
  44. package/lib/schemas/social.schema.js +114 -0
  45. package/lib/schemas/videoPlan.schema.d.ts +117 -3
  46. package/lib/schemas/videoPlan.schema.d.ts.map +1 -1
  47. package/lib/schemas/videoPlan.schema.js +141 -1
  48. package/lib/services/agent/chatAgent.d.ts +25 -1
  49. package/lib/services/agent/chatAgent.d.ts.map +1 -1
  50. package/lib/services/agent/chatAgent.js +145 -9
  51. package/lib/services/agent/costPreflight.d.ts +11 -1
  52. package/lib/services/agent/costPreflight.d.ts.map +1 -1
  53. package/lib/services/agent/costPreflight.js +18 -1
  54. package/lib/services/agent/covers/coverPlanner.d.ts +41 -0
  55. package/lib/services/agent/covers/coverPlanner.d.ts.map +1 -0
  56. package/lib/services/agent/covers/coverPlanner.js +278 -0
  57. package/lib/services/agent/covers/covers.schema.d.ts +158 -0
  58. package/lib/services/agent/covers/covers.schema.d.ts.map +1 -0
  59. package/lib/services/agent/covers/covers.schema.js +166 -0
  60. package/lib/services/agent/covers/index.d.ts +3 -0
  61. package/lib/services/agent/covers/index.d.ts.map +1 -0
  62. package/lib/services/agent/covers/index.js +18 -0
  63. package/lib/services/agent/critic.d.ts +10 -0
  64. package/lib/services/agent/critic.d.ts.map +1 -1
  65. package/lib/services/agent/critic.js +37 -1
  66. package/lib/services/agent/editClassifier.d.ts +4 -4
  67. package/lib/services/agent/editClassifier.js +2 -2
  68. package/lib/services/agent/editExisting/editAssembler.d.ts +78 -0
  69. package/lib/services/agent/editExisting/editAssembler.d.ts.map +1 -0
  70. package/lib/services/agent/editExisting/editAssembler.js +172 -0
  71. package/lib/services/agent/editExisting/editExisting.schema.d.ts +119 -0
  72. package/lib/services/agent/editExisting/editExisting.schema.d.ts.map +1 -0
  73. package/lib/services/agent/editExisting/editExisting.schema.js +157 -0
  74. package/lib/services/agent/editExisting/highlightPicker.d.ts +48 -0
  75. package/lib/services/agent/editExisting/highlightPicker.d.ts.map +1 -0
  76. package/lib/services/agent/editExisting/highlightPicker.js +199 -0
  77. package/lib/services/agent/editExisting/index.d.ts +4 -0
  78. package/lib/services/agent/editExisting/index.d.ts.map +1 -0
  79. package/lib/services/agent/editExisting/index.js +19 -0
  80. package/lib/services/agent/eval/recorder.d.ts +13 -1
  81. package/lib/services/agent/eval/recorder.d.ts.map +1 -1
  82. package/lib/services/agent/eval/recorder.js +59 -0
  83. package/lib/services/agent/eval/seedBriefs.d.ts +4 -3
  84. package/lib/services/agent/eval/seedBriefs.d.ts.map +1 -1
  85. package/lib/services/agent/eval/seedBriefs.js +283 -3
  86. package/lib/services/agent/eval/types.d.ts +10 -0
  87. package/lib/services/agent/eval/types.d.ts.map +1 -1
  88. package/lib/services/agent/executor/core.d.ts +70 -0
  89. package/lib/services/agent/executor/core.d.ts.map +1 -0
  90. package/lib/services/agent/executor/core.js +250 -0
  91. package/lib/services/agent/executor/duration.d.ts +20 -0
  92. package/lib/services/agent/executor/duration.d.ts.map +1 -0
  93. package/lib/services/agent/executor/duration.js +46 -0
  94. package/lib/services/agent/executor/index.d.ts +15 -0
  95. package/lib/services/agent/executor/index.d.ts.map +1 -0
  96. package/lib/services/agent/executor/index.js +32 -0
  97. package/lib/services/agent/executor/types.d.ts +183 -0
  98. package/lib/services/agent/executor/types.d.ts.map +1 -0
  99. package/lib/services/agent/executor/types.js +29 -0
  100. package/lib/services/agent/executor/visual.d.ts +32 -0
  101. package/lib/services/agent/executor/visual.d.ts.map +1 -0
  102. package/lib/services/agent/executor/visual.js +400 -0
  103. package/lib/services/agent/executor/voice.d.ts +17 -0
  104. package/lib/services/agent/executor/voice.d.ts.map +1 -0
  105. package/lib/services/agent/executor/voice.js +119 -0
  106. package/lib/services/agent/extendChain.d.ts +101 -0
  107. package/lib/services/agent/extendChain.d.ts.map +1 -0
  108. package/lib/services/agent/extendChain.js +177 -0
  109. package/lib/services/agent/index.d.ts +11 -1
  110. package/lib/services/agent/index.d.ts.map +1 -1
  111. package/lib/services/agent/index.js +11 -1
  112. package/lib/services/agent/llmCaller.d.ts +7 -8
  113. package/lib/services/agent/llmCaller.d.ts.map +1 -1
  114. package/lib/services/agent/llmCallerAnthropic.d.ts +44 -31
  115. package/lib/services/agent/llmCallerAnthropic.d.ts.map +1 -1
  116. package/lib/services/agent/llmCallerAnthropic.js +135 -60
  117. package/lib/services/agent/llmCallerFactory.d.ts +34 -0
  118. package/lib/services/agent/llmCallerFactory.d.ts.map +1 -0
  119. package/lib/services/agent/llmCallerFactory.js +31 -0
  120. package/lib/services/agent/llmCallerGemini.d.ts +62 -0
  121. package/lib/services/agent/llmCallerGemini.d.ts.map +1 -0
  122. package/lib/services/agent/llmCallerGemini.js +235 -0
  123. package/lib/services/agent/llmCallerOpenai.d.ts +56 -0
  124. package/lib/services/agent/llmCallerOpenai.d.ts.map +1 -0
  125. package/lib/services/agent/llmCallerOpenai.js +230 -0
  126. package/lib/services/agent/llmCallerRegistry.d.ts.map +1 -1
  127. package/lib/services/agent/llmCallerRegistry.js +7 -7
  128. package/lib/services/agent/llmCallerRouting.d.ts +63 -0
  129. package/lib/services/agent/llmCallerRouting.d.ts.map +1 -0
  130. package/lib/services/agent/llmCallerRouting.js +124 -0
  131. package/lib/services/agent/llmModelRegistry.d.ts +59 -0
  132. package/lib/services/agent/llmModelRegistry.d.ts.map +1 -0
  133. package/lib/services/agent/llmModelRegistry.js +168 -0
  134. package/lib/services/agent/llmRetry.d.ts +57 -0
  135. package/lib/services/agent/llmRetry.d.ts.map +1 -0
  136. package/lib/services/agent/llmRetry.js +102 -0
  137. package/lib/services/agent/modelRouter.d.ts +3 -3
  138. package/lib/services/agent/modelRouter.d.ts.map +1 -1
  139. package/lib/services/agent/modelRouter.js +27 -13
  140. package/lib/services/agent/planMutations.d.ts +54 -1
  141. package/lib/services/agent/planMutations.d.ts.map +1 -1
  142. package/lib/services/agent/planMutations.js +78 -0
  143. package/lib/services/agent/planner/Planner.d.ts +0 -17
  144. package/lib/services/agent/planner/Planner.d.ts.map +1 -1
  145. package/lib/services/agent/planner/Planner.js +67 -303
  146. package/lib/services/agent/planner/overlayRegen.d.ts +38 -0
  147. package/lib/services/agent/planner/overlayRegen.d.ts.map +1 -0
  148. package/lib/services/agent/planner/overlayRegen.js +145 -0
  149. package/lib/services/agent/planner/plannerMessages.d.ts +34 -0
  150. package/lib/services/agent/planner/plannerMessages.d.ts.map +1 -0
  151. package/lib/services/agent/planner/plannerMessages.js +185 -0
  152. package/lib/services/agent/planner/promptSections.d.ts +12 -0
  153. package/lib/services/agent/planner/promptSections.d.ts.map +1 -1
  154. package/lib/services/agent/planner/promptSections.js +57 -0
  155. package/lib/services/agent/planner/scriptFirstPlanner.d.ts +35 -0
  156. package/lib/services/agent/planner/scriptFirstPlanner.d.ts.map +1 -0
  157. package/lib/services/agent/planner/scriptFirstPlanner.js +140 -0
  158. package/lib/services/agent/planner/structuralRules.d.ts +10 -0
  159. package/lib/services/agent/planner/structuralRules.d.ts.map +1 -1
  160. package/lib/services/agent/planner/structuralRules.js +92 -9
  161. package/lib/services/agent/planner/validators.d.ts +18 -0
  162. package/lib/services/agent/planner/validators.d.ts.map +1 -1
  163. package/lib/services/agent/planner/validators.js +97 -0
  164. package/lib/services/agent/planner.d.ts +2 -1
  165. package/lib/services/agent/planner.d.ts.map +1 -1
  166. package/lib/services/agent/planner.js +5 -1
  167. package/lib/services/agent/priorProject.d.ts +26 -0
  168. package/lib/services/agent/priorProject.d.ts.map +1 -0
  169. package/lib/services/agent/priorProject.js +51 -0
  170. package/lib/services/agent/providerFallback/chains.d.ts.map +1 -1
  171. package/lib/services/agent/providerFallback/chains.js +27 -15
  172. package/lib/services/agent/repurpose/index.d.ts +3 -0
  173. package/lib/services/agent/repurpose/index.d.ts.map +1 -0
  174. package/lib/services/agent/repurpose/index.js +18 -0
  175. package/lib/services/agent/repurpose/repurpose.schema.d.ts +132 -0
  176. package/lib/services/agent/repurpose/repurpose.schema.d.ts.map +1 -0
  177. package/lib/services/agent/repurpose/repurpose.schema.js +144 -0
  178. package/lib/services/agent/repurpose/shortsPicker.d.ts +25 -0
  179. package/lib/services/agent/repurpose/shortsPicker.d.ts.map +1 -0
  180. package/lib/services/agent/repurpose/shortsPicker.js +218 -0
  181. package/lib/services/agent/runHelpers.d.ts +21 -2
  182. package/lib/services/agent/runHelpers.d.ts.map +1 -1
  183. package/lib/services/agent/runHelpers.js +71 -2
  184. package/lib/services/agent/tools/animateImage.tool.d.ts +1 -0
  185. package/lib/services/agent/tools/animateImage.tool.d.ts.map +1 -1
  186. package/lib/services/agent/tools/animateImage.tool.js +12 -0
  187. package/lib/services/agent/tools/chapterOutline.tool.d.ts +42 -0
  188. package/lib/services/agent/tools/chapterOutline.tool.d.ts.map +1 -0
  189. package/lib/services/agent/tools/chapterOutline.tool.js +115 -0
  190. package/lib/services/agent/tools/composeScene.tool.d.ts +65 -2
  191. package/lib/services/agent/tools/composeScene.tool.d.ts.map +1 -1
  192. package/lib/services/agent/tools/estimateCost.tool.d.ts +28 -1
  193. package/lib/services/agent/tools/estimateCost.tool.d.ts.map +1 -1
  194. package/lib/services/agent/tools/estimateCost.tool.js +55 -7
  195. package/lib/services/agent/tools/extendVideo.tool.d.ts +26 -0
  196. package/lib/services/agent/tools/extendVideo.tool.d.ts.map +1 -0
  197. package/lib/services/agent/tools/extendVideo.tool.js +149 -0
  198. package/lib/services/agent/tools/generateScript.tool.d.ts +184 -0
  199. package/lib/services/agent/tools/generateScript.tool.d.ts.map +1 -0
  200. package/lib/services/agent/tools/generateScript.tool.js +123 -0
  201. package/lib/services/agent/tools/generateVideo.tool.d.ts +1 -0
  202. package/lib/services/agent/tools/generateVideo.tool.d.ts.map +1 -1
  203. package/lib/services/agent/tools/generateVideo.tool.js +20 -1
  204. package/lib/services/agent/tools/index.d.ts +4 -0
  205. package/lib/services/agent/tools/index.d.ts.map +1 -1
  206. package/lib/services/agent/tools/index.js +4 -0
  207. package/lib/services/agent/tools/matchBrollToScript.tool.d.ts +50 -0
  208. package/lib/services/agent/tools/matchBrollToScript.tool.d.ts.map +1 -0
  209. package/lib/services/agent/tools/matchBrollToScript.tool.js +139 -0
  210. package/lib/services/agent/tools/planVideo.tool.d.ts +57 -1
  211. package/lib/services/agent/tools/planVideo.tool.d.ts.map +1 -1
  212. package/lib/services/agent/tools/planVideo.tool.js +3 -3
  213. package/lib/services/agent/tools/render.tool.d.ts +22 -1
  214. package/lib/services/agent/tools/render.tool.d.ts.map +1 -1
  215. package/lib/services/aiGen/aiGenFactory.service.d.ts.map +1 -1
  216. package/lib/services/aiGen/aiGenFactory.service.js +18 -3
  217. package/lib/services/aiGen/helpers.d.ts +8 -0
  218. package/lib/services/aiGen/helpers.d.ts.map +1 -1
  219. package/lib/services/aiGen/helpers.js +12 -0
  220. package/lib/services/aiGen/providers/anthropic/anthropic.service.d.ts +26 -0
  221. package/lib/services/aiGen/providers/anthropic/anthropic.service.d.ts.map +1 -0
  222. package/lib/services/aiGen/providers/anthropic/anthropic.service.js +95 -0
  223. package/lib/services/aiGen/providers/google/google.service.d.ts +25 -1
  224. package/lib/services/aiGen/providers/google/google.service.d.ts.map +1 -1
  225. package/lib/services/aiGen/providers/google/google.service.js +136 -237
  226. package/lib/services/aiGen/providers/google/googleApiKeys.d.ts +71 -0
  227. package/lib/services/aiGen/providers/google/googleApiKeys.d.ts.map +1 -0
  228. package/lib/services/aiGen/providers/google/googleApiKeys.js +137 -0
  229. package/lib/services/aiGen/providers/google/googleErrors.d.ts +13 -0
  230. package/lib/services/aiGen/providers/google/googleErrors.d.ts.map +1 -0
  231. package/lib/services/aiGen/providers/google/googleErrors.js +102 -0
  232. package/lib/services/aiGen/providers/google/googleFetch.d.ts +8 -0
  233. package/lib/services/aiGen/providers/google/googleFetch.d.ts.map +1 -0
  234. package/lib/services/aiGen/providers/google/googleFetch.js +96 -0
  235. package/lib/services/aiGen/providers/google/googleKeyPool.d.ts +52 -0
  236. package/lib/services/aiGen/providers/google/googleKeyPool.d.ts.map +1 -0
  237. package/lib/services/aiGen/providers/google/googleKeyPool.js +129 -0
  238. package/lib/services/aiGen/providers/google/googleMusic.d.ts +15 -0
  239. package/lib/services/aiGen/providers/google/googleMusic.d.ts.map +1 -0
  240. package/lib/services/aiGen/providers/google/googleMusic.js +77 -0
  241. package/lib/services/aiGen/providers/kling/kling.service.d.ts +7 -3
  242. package/lib/services/aiGen/providers/kling/kling.service.d.ts.map +1 -1
  243. package/lib/services/aiGen/providers/kling/kling.service.js +23 -367
  244. package/lib/services/aiGen/providers/kling/klingCredits.d.ts +9 -0
  245. package/lib/services/aiGen/providers/kling/klingCredits.d.ts.map +1 -0
  246. package/lib/services/aiGen/providers/kling/klingCredits.js +63 -0
  247. package/lib/services/aiGen/providers/kling/klingRequests.d.ts +32 -0
  248. package/lib/services/aiGen/providers/kling/klingRequests.d.ts.map +1 -0
  249. package/lib/services/aiGen/providers/kling/klingRequests.js +194 -0
  250. package/lib/services/aiGen/providers/kling/klingStatus.d.ts +16 -0
  251. package/lib/services/aiGen/providers/kling/klingStatus.d.ts.map +1 -0
  252. package/lib/services/aiGen/providers/kling/klingStatus.js +173 -0
  253. package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
  254. package/lib/services/aiGen/providers/pixverse/pixverse.service.js +7 -1
  255. package/lib/services/bullmq.service.d.ts +61 -0
  256. package/lib/services/bullmq.service.d.ts.map +1 -1
  257. package/lib/services/bullmq.service.js +124 -2
  258. package/lib/services/crypto/index.d.ts +2 -0
  259. package/lib/services/crypto/index.d.ts.map +1 -0
  260. package/lib/services/crypto/index.js +17 -0
  261. package/lib/services/crypto/tokenVault.d.ts +47 -0
  262. package/lib/services/crypto/tokenVault.d.ts.map +1 -0
  263. package/lib/services/crypto/tokenVault.js +179 -0
  264. package/lib/services/editor/captionStyleHint.d.ts +3 -0
  265. package/lib/services/editor/captionStyleHint.d.ts.map +1 -0
  266. package/lib/services/editor/captionStyleHint.js +112 -0
  267. package/lib/services/editor/planToProject.d.ts +7 -66
  268. package/lib/services/editor/planToProject.d.ts.map +1 -1
  269. package/lib/services/editor/planToProject.helpers.d.ts +40 -0
  270. package/lib/services/editor/planToProject.helpers.d.ts.map +1 -0
  271. package/lib/services/editor/planToProject.helpers.js +177 -0
  272. package/lib/services/editor/planToProject.js +197 -180
  273. package/lib/services/editor/planToProject.types.d.ts +94 -0
  274. package/lib/services/editor/planToProject.types.d.ts.map +1 -0
  275. package/lib/services/editor/planToProject.types.js +2 -0
  276. package/lib/services/firestore.service.d.ts +5 -0
  277. package/lib/services/firestore.service.d.ts.map +1 -1
  278. package/lib/services/firestore.service.js +13 -0
  279. package/lib/services/index.d.ts +13 -0
  280. package/lib/services/index.d.ts.map +1 -1
  281. package/lib/services/index.js +13 -0
  282. package/lib/services/promptEnhancer/index.d.ts +18 -0
  283. package/lib/services/promptEnhancer/index.d.ts.map +1 -0
  284. package/lib/services/promptEnhancer/index.js +33 -0
  285. package/lib/services/promptEnhancer/models.d.ts +54 -0
  286. package/lib/services/promptEnhancer/models.d.ts.map +1 -0
  287. package/lib/services/promptEnhancer/models.js +37 -0
  288. package/lib/services/promptEnhancer/profiles/agent.profile.d.ts +14 -0
  289. package/lib/services/promptEnhancer/profiles/agent.profile.d.ts.map +1 -0
  290. package/lib/services/promptEnhancer/profiles/agent.profile.js +40 -0
  291. package/lib/services/promptEnhancer/profiles/avatar.profile.d.ts +13 -0
  292. package/lib/services/promptEnhancer/profiles/avatar.profile.d.ts.map +1 -0
  293. package/lib/services/promptEnhancer/profiles/avatar.profile.js +40 -0
  294. package/lib/services/promptEnhancer/profiles/base.d.ts +28 -0
  295. package/lib/services/promptEnhancer/profiles/base.d.ts.map +1 -0
  296. package/lib/services/promptEnhancer/profiles/base.js +35 -0
  297. package/lib/services/promptEnhancer/profiles/image.profile.d.ts +11 -0
  298. package/lib/services/promptEnhancer/profiles/image.profile.d.ts.map +1 -0
  299. package/lib/services/promptEnhancer/profiles/image.profile.js +42 -0
  300. package/lib/services/promptEnhancer/profiles/index.d.ts +12 -0
  301. package/lib/services/promptEnhancer/profiles/index.d.ts.map +1 -0
  302. package/lib/services/promptEnhancer/profiles/index.js +33 -0
  303. package/lib/services/promptEnhancer/profiles/video.profile.d.ts +15 -0
  304. package/lib/services/promptEnhancer/profiles/video.profile.d.ts.map +1 -0
  305. package/lib/services/promptEnhancer/profiles/video.profile.js +81 -0
  306. package/lib/services/promptEnhancer/promptEnhancer.service.d.ts +45 -0
  307. package/lib/services/promptEnhancer/promptEnhancer.service.d.ts.map +1 -0
  308. package/lib/services/promptEnhancer/promptEnhancer.service.js +157 -0
  309. package/lib/services/promptEnhancer/schema.d.ts +19 -0
  310. package/lib/services/promptEnhancer/schema.d.ts.map +1 -0
  311. package/lib/services/promptEnhancer/schema.js +43 -0
  312. package/lib/services/promptEnhancer/types.d.ts +112 -0
  313. package/lib/services/promptEnhancer/types.d.ts.map +1 -0
  314. package/lib/services/promptEnhancer/types.js +2 -0
  315. package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts +60 -5
  316. package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts.map +1 -1
  317. package/lib/services/rateLimiter/distributedRateLimiter.service.js +184 -16
  318. package/lib/services/socialAI/captionGen.d.ts +81 -0
  319. package/lib/services/socialAI/captionGen.d.ts.map +1 -0
  320. package/lib/services/socialAI/captionGen.js +206 -0
  321. package/lib/services/socialAI/hookScore.d.ts +85 -0
  322. package/lib/services/socialAI/hookScore.d.ts.map +1 -0
  323. package/lib/services/socialAI/hookScore.js +170 -0
  324. package/lib/services/socialAI/index.d.ts +3 -0
  325. package/lib/services/socialAI/index.d.ts.map +1 -0
  326. package/lib/services/socialAI/index.js +18 -0
  327. package/lib/services/socialAccounts/index.d.ts +2 -0
  328. package/lib/services/socialAccounts/index.d.ts.map +1 -0
  329. package/lib/services/socialAccounts/index.js +17 -0
  330. package/lib/services/socialAccounts/socialAccountService.d.ts +25 -0
  331. package/lib/services/socialAccounts/socialAccountService.d.ts.map +1 -0
  332. package/lib/services/socialAccounts/socialAccountService.js +105 -0
  333. package/lib/services/socialEngage/factory.d.ts +7 -0
  334. package/lib/services/socialEngage/factory.d.ts.map +1 -0
  335. package/lib/services/socialEngage/factory.js +25 -0
  336. package/lib/services/socialEngage/index.d.ts +6 -0
  337. package/lib/services/socialEngage/index.d.ts.map +1 -0
  338. package/lib/services/socialEngage/index.js +21 -0
  339. package/lib/services/socialEngage/meta.engage.d.ts +17 -0
  340. package/lib/services/socialEngage/meta.engage.d.ts.map +1 -0
  341. package/lib/services/socialEngage/meta.engage.js +128 -0
  342. package/lib/services/socialEngage/metaWebhook.d.ts +50 -0
  343. package/lib/services/socialEngage/metaWebhook.d.ts.map +1 -0
  344. package/lib/services/socialEngage/metaWebhook.js +93 -0
  345. package/lib/services/socialEngage/types.d.ts +72 -0
  346. package/lib/services/socialEngage/types.d.ts.map +1 -0
  347. package/lib/services/socialEngage/types.js +10 -0
  348. package/lib/services/socialEngage/youtube.engage.d.ts +9 -0
  349. package/lib/services/socialEngage/youtube.engage.d.ts.map +1 -0
  350. package/lib/services/socialEngage/youtube.engage.js +87 -0
  351. package/lib/services/socialFormat/aspectGeometry.d.ts +74 -0
  352. package/lib/services/socialFormat/aspectGeometry.d.ts.map +1 -0
  353. package/lib/services/socialFormat/aspectGeometry.js +135 -0
  354. package/lib/services/socialFormat/index.d.ts +2 -0
  355. package/lib/services/socialFormat/index.d.ts.map +1 -0
  356. package/lib/services/socialFormat/index.js +19 -0
  357. package/lib/services/socialInsights/index.d.ts +3 -0
  358. package/lib/services/socialInsights/index.d.ts.map +1 -0
  359. package/lib/services/socialInsights/index.js +18 -0
  360. package/lib/services/socialInsights/recommendations.d.ts +131 -0
  361. package/lib/services/socialInsights/recommendations.d.ts.map +1 -0
  362. package/lib/services/socialInsights/recommendations.js +277 -0
  363. package/lib/services/socialInsights/timeBuckets.d.ts +35 -0
  364. package/lib/services/socialInsights/timeBuckets.d.ts.map +1 -0
  365. package/lib/services/socialInsights/timeBuckets.js +78 -0
  366. package/lib/services/socialMetrics/factory.d.ts +5 -0
  367. package/lib/services/socialMetrics/factory.d.ts.map +1 -0
  368. package/lib/services/socialMetrics/factory.js +24 -0
  369. package/lib/services/socialMetrics/index.d.ts +6 -0
  370. package/lib/services/socialMetrics/index.d.ts.map +1 -0
  371. package/lib/services/socialMetrics/index.js +21 -0
  372. package/lib/services/socialMetrics/meta.metrics.d.ts +22 -0
  373. package/lib/services/socialMetrics/meta.metrics.d.ts.map +1 -0
  374. package/lib/services/socialMetrics/meta.metrics.js +137 -0
  375. package/lib/services/socialMetrics/tiktok.metrics.d.ts +8 -0
  376. package/lib/services/socialMetrics/tiktok.metrics.d.ts.map +1 -0
  377. package/lib/services/socialMetrics/tiktok.metrics.js +43 -0
  378. package/lib/services/socialMetrics/types.d.ts +54 -0
  379. package/lib/services/socialMetrics/types.d.ts.map +1 -0
  380. package/lib/services/socialMetrics/types.js +2 -0
  381. package/lib/services/socialMetrics/youtube.metrics.d.ts +8 -0
  382. package/lib/services/socialMetrics/youtube.metrics.d.ts.map +1 -0
  383. package/lib/services/socialMetrics/youtube.metrics.js +43 -0
  384. package/lib/services/socialOAuth/factory.d.ts +7 -0
  385. package/lib/services/socialOAuth/factory.d.ts.map +1 -0
  386. package/lib/services/socialOAuth/factory.js +42 -0
  387. package/lib/services/socialOAuth/index.d.ts +11 -0
  388. package/lib/services/socialOAuth/index.d.ts.map +1 -0
  389. package/lib/services/socialOAuth/index.js +26 -0
  390. package/lib/services/socialOAuth/linkedin.oauth.d.ts +14 -0
  391. package/lib/services/socialOAuth/linkedin.oauth.d.ts.map +1 -0
  392. package/lib/services/socialOAuth/linkedin.oauth.js +127 -0
  393. package/lib/services/socialOAuth/meta.oauth.d.ts +31 -0
  394. package/lib/services/socialOAuth/meta.oauth.d.ts.map +1 -0
  395. package/lib/services/socialOAuth/meta.oauth.js +214 -0
  396. package/lib/services/socialOAuth/oauthState.d.ts +14 -0
  397. package/lib/services/socialOAuth/oauthState.d.ts.map +1 -0
  398. package/lib/services/socialOAuth/oauthState.js +66 -0
  399. package/lib/services/socialOAuth/pinterest.oauth.d.ts +15 -0
  400. package/lib/services/socialOAuth/pinterest.oauth.d.ts.map +1 -0
  401. package/lib/services/socialOAuth/pinterest.oauth.js +126 -0
  402. package/lib/services/socialOAuth/threads.oauth.d.ts +14 -0
  403. package/lib/services/socialOAuth/threads.oauth.d.ts.map +1 -0
  404. package/lib/services/socialOAuth/threads.oauth.js +129 -0
  405. package/lib/services/socialOAuth/tiktok.oauth.d.ts +15 -0
  406. package/lib/services/socialOAuth/tiktok.oauth.d.ts.map +1 -0
  407. package/lib/services/socialOAuth/tiktok.oauth.js +151 -0
  408. package/lib/services/socialOAuth/types.d.ts +67 -0
  409. package/lib/services/socialOAuth/types.d.ts.map +1 -0
  410. package/lib/services/socialOAuth/types.js +2 -0
  411. package/lib/services/socialOAuth/x.oauth.d.ts +17 -0
  412. package/lib/services/socialOAuth/x.oauth.d.ts.map +1 -0
  413. package/lib/services/socialOAuth/x.oauth.js +134 -0
  414. package/lib/services/socialOAuth/youtube.oauth.d.ts +15 -0
  415. package/lib/services/socialOAuth/youtube.oauth.d.ts.map +1 -0
  416. package/lib/services/socialOAuth/youtube.oauth.js +156 -0
  417. package/lib/services/socialPublish/factory.d.ts +5 -0
  418. package/lib/services/socialPublish/factory.d.ts.map +1 -0
  419. package/lib/services/socialPublish/factory.js +32 -0
  420. package/lib/services/socialPublish/index.d.ts +10 -0
  421. package/lib/services/socialPublish/index.d.ts.map +1 -0
  422. package/lib/services/socialPublish/index.js +25 -0
  423. package/lib/services/socialPublish/linkedin.publish.d.ts +9 -0
  424. package/lib/services/socialPublish/linkedin.publish.d.ts.map +1 -0
  425. package/lib/services/socialPublish/linkedin.publish.js +143 -0
  426. package/lib/services/socialPublish/meta.publish.d.ts +28 -0
  427. package/lib/services/socialPublish/meta.publish.d.ts.map +1 -0
  428. package/lib/services/socialPublish/meta.publish.js +149 -0
  429. package/lib/services/socialPublish/pinterest.publish.d.ts +13 -0
  430. package/lib/services/socialPublish/pinterest.publish.d.ts.map +1 -0
  431. package/lib/services/socialPublish/pinterest.publish.js +130 -0
  432. package/lib/services/socialPublish/threads.publish.d.ts +12 -0
  433. package/lib/services/socialPublish/threads.publish.d.ts.map +1 -0
  434. package/lib/services/socialPublish/threads.publish.js +96 -0
  435. package/lib/services/socialPublish/tiktok.publish.d.ts +13 -0
  436. package/lib/services/socialPublish/tiktok.publish.d.ts.map +1 -0
  437. package/lib/services/socialPublish/tiktok.publish.js +118 -0
  438. package/lib/services/socialPublish/types.d.ts +47 -0
  439. package/lib/services/socialPublish/types.d.ts.map +1 -0
  440. package/lib/services/socialPublish/types.js +2 -0
  441. package/lib/services/socialPublish/x.publish.d.ts +12 -0
  442. package/lib/services/socialPublish/x.publish.d.ts.map +1 -0
  443. package/lib/services/socialPublish/x.publish.js +147 -0
  444. package/lib/services/socialPublish/youtube.publish.d.ts +9 -0
  445. package/lib/services/socialPublish/youtube.publish.d.ts.map +1 -0
  446. package/lib/services/socialPublish/youtube.publish.js +107 -0
  447. package/lib/services/stock/index.d.ts +2 -0
  448. package/lib/services/stock/index.d.ts.map +1 -0
  449. package/lib/services/stock/index.js +17 -0
  450. package/lib/services/stock/realPersonSafety.d.ts +99 -0
  451. package/lib/services/stock/realPersonSafety.d.ts.map +1 -0
  452. package/lib/services/stock/realPersonSafety.js +248 -0
  453. package/lib/services/translation/index.d.ts +2 -0
  454. package/lib/services/translation/index.d.ts.map +1 -0
  455. package/lib/services/translation/index.js +9 -0
  456. package/lib/services/translation/translation.service.d.ts +50 -0
  457. package/lib/services/translation/translation.service.d.ts.map +1 -0
  458. package/lib/services/translation/translation.service.js +211 -0
  459. package/lib/utils/helpers.d.ts +2 -4
  460. package/lib/utils/helpers.d.ts.map +1 -1
  461. package/lib/utils/helpers.js +9 -63
  462. package/lib/utils/index.d.ts +1 -0
  463. package/lib/utils/index.d.ts.map +1 -1
  464. package/lib/utils/index.js +1 -0
  465. package/lib/utils/renderTier.d.ts +26 -0
  466. package/lib/utils/renderTier.d.ts.map +1 -0
  467. package/lib/utils/renderTier.js +34 -0
  468. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"distributedRateLimiter.service.d.ts","sourceRoot":"","sources":["../../../src/services/rateLimiter/distributedRateLimiter.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAU5D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,UAAU,4BAA4B;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAuDD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAyB;gBAE9B,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B;IAOlE;;;;;OAKG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAUzC;;;;;OAKG;IACG,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;IAInD,gEAAgE;IAChE,WAAW,IAAI,IAAI;IAInB,IAAI,qBAAqB,IAAI,MAAM,CAElC;IAEK,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC;YAoC5B,iBAAiB;IAc/B,OAAO,CAAC,iBAAiB;YAQX,iBAAiB;CA6DhC;AAwBD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,WAAW,GACpB,sBAAsB,CAaxB;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,WAAW,GACpB,sBAAsB,CAexB;AAED;4DAC4D;AAC5D,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAM1E"}
1
+ {"version":3,"file":"distributedRateLimiter.service.d.ts","sourceRoot":"","sources":["../../../src/services/rateLimiter/distributedRateLimiter.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAM5D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,SAAU,CAAC;AAC9C,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAQ3C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,UAAU,4BAA4B;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,eAAe,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,SAAS,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AA4DD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAyB;gBAE9B,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B;IAOlE;;;;;;;;;;;;OAYG;IACG,kBAAkB,CAAC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtE;;;;;;;;OAQG;IACG,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;IAInD;;;;;OAKG;IACG,eAAe,CACnB,mBAAmB,GAAE,MAA+B,GACnD,OAAO,CAAC,eAAe,CAAC;IAgF3B,gEAAgE;IAChE,WAAW,IAAI,IAAI;IAInB,IAAI,qBAAqB,IAAI,MAAM,CAElC;IAEK,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC;YAoC5B,iBAAiB;IAc/B,OAAO,CAAC,iBAAiB;YAQX,iBAAiB;CAoHhC;AAwBD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,WAAW,GACpB,sBAAsB,CA0BxB;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,WAAW,GACpB,sBAAsB,CAexB;AAED;4DAC4D;AAC5D,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAM1E"}
@@ -3,15 +3,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DistributedRateLimiter = void 0;
6
+ exports.DistributedRateLimiter = exports.DAILY_NEAR_RESET_MS = exports.MAX_ACCEPTABLE_WAIT_MS = void 0;
7
7
  exports.getAiGenModelRateLimiter = getAiGenModelRateLimiter;
8
8
  exports.getTtsProviderRateLimiter = getTtsProviderRateLimiter;
9
9
  exports.snapshotAllRateLimiters = snapshotAllRateLimiters;
10
10
  const crypto_1 = __importDefault(require("crypto"));
11
11
  const aiModels_1 = require("../../globals/aiModels");
12
12
  const ttsModels_1 = require("../../globals/ttsModels");
13
+ const googleApiKeys_1 = require("../aiGen/providers/google/googleApiKeys");
14
+ const errors_1 = require("../../utils/errors");
13
15
  const logger_1 = require("../../utils/logger");
14
16
  const redis_service_1 = require("../redis.service");
17
+ /**
18
+ * Capacity-planning thresholds (used by previewCapacity + the bounded gate).
19
+ *
20
+ * MAX_ACCEPTABLE_WAIT_MS — a model whose projected wait for a submit slot
21
+ * exceeds this is considered "not available" by previewCapacity, so the
22
+ * job-start selector spills to a less-loaded model in the same tier chain.
23
+ * DAILY_NEAR_RESET_MS — when a model's per-day cap is exhausted, we only wait
24
+ * it out if the UTC-midnight reset is within this window; otherwise the
25
+ * bounded gate fast-fails (VIDEO_PROVIDER_RATE_LIMITED) so the caller can
26
+ * fall back rather than block for hours.
27
+ */
28
+ exports.MAX_ACCEPTABLE_WAIT_MS = 180000; // 3 min
29
+ exports.DAILY_NEAR_RESET_MS = 120000; // 2 min
15
30
  // Module-level throttle so Redis outages don't fire a Slack error every
16
31
  // request. First failure goes through; subsequent failures within the
17
32
  // window log at warn level (Console + Loki only) until the window resets.
@@ -62,9 +77,14 @@ end
62
77
 
63
78
  redis.call('ZADD', minKey, nowMs, uniqueId)
64
79
  redis.call('PEXPIRE', minKey, 90000)
65
- local newDay = redis.call('INCR', dayKey)
66
- if newDay == 1 then
67
- redis.call('EXPIRE', dayKey, secsTilMidnight)
80
+ -- Only touch the day counter when a day limit applies. With dayLimit <= 0
81
+ -- (skipDay poll path, or a model with no per-day cap) we must NOT increment —
82
+ -- otherwise polls would burn the daily SUBMIT budget they're meant to bypass.
83
+ if dayLimit > 0 then
84
+ local newDay = redis.call('INCR', dayKey)
85
+ if newDay == 1 then
86
+ redis.call('EXPIRE', dayKey, secsTilMidnight)
87
+ end
68
88
  end
69
89
 
70
90
  return { 1, 0, 'ok' }
@@ -83,11 +103,18 @@ class DistributedRateLimiter {
83
103
  * a slot in each. Caller MUST call releaseSlot() when the in-flight task
84
104
  * settles — per-min / per-day auto-expire but the concurrent counter does
85
105
  * not. Mirrors the old AiGenModelRateLimiter API.
106
+ *
107
+ * `opts.maxWaitMs` bounds the rate-budget wait: if satisfying the per-day /
108
+ * per-minute gate would take longer than this, the call throws a
109
+ * `UserFacingError(VIDEO_PROVIDER_RATE_LIMITED)` instead of sleep-looping for
110
+ * hours. This is the backstop that stops jobs from piling up in-process when
111
+ * a daily cap is hit — the submit path passes it; legacy callers that omit
112
+ * it keep the original (unbounded) behavior.
86
113
  */
87
- async waitUntilAvailable() {
114
+ async waitUntilAvailable(opts) {
88
115
  await this.acquireConcurrent();
89
116
  try {
90
- await this.consumeRedisGates();
117
+ await this.consumeRedisGates({ maxWaitMs: opts?.maxWaitMs });
91
118
  }
92
119
  catch (err) {
93
120
  this.releaseConcurrent();
@@ -95,13 +122,99 @@ class DistributedRateLimiter {
95
122
  }
96
123
  }
97
124
  /**
98
- * Bumps per-min + per-day only — does NOT count toward the concurrent cap.
99
- * Use for short-lived calls that share a provider's rate budget but aren't
100
- * "in-flight tasks" (status polls, sync image/TTS gens that complete in the
101
- * same call). No release is needed Redis auto-expires the counters.
125
+ * Bumps per-MINUTE only — does NOT count toward the concurrent cap and does
126
+ * NOT consume/await the per-day gate. Use for short-lived calls that share a
127
+ * provider's per-minute budget but must not be blocked by the daily SUBMIT
128
+ * cap: status polls of already-running tasks (failing a poll on daily quota
129
+ * would abandon a video that's already generating), plus sync image/TTS gens
130
+ * (which have no per-day limit configured anyway). No release needed — Redis
131
+ * auto-expires the counters.
102
132
  */
103
133
  async waitUntilAvailableForOneShot() {
104
- await this.consumeRedisGates();
134
+ await this.consumeRedisGates({ skipDay: true });
135
+ }
136
+ /**
137
+ * Read-only capacity estimate — does NOT consume a slot. Reads current
138
+ * per-minute / per-day usage and concurrency pressure from Redis and
139
+ * projects how long a new submission would wait. Fails open (available:true,
140
+ * wait:0) on Redis errors / no client, matching the gate's fail-open policy.
141
+ */
142
+ async previewCapacity(maxAcceptableWaitMs = exports.MAX_ACCEPTABLE_WAIT_MS) {
143
+ const secsUntilDayReset = secsUntilMidnight();
144
+ const base = {
145
+ modelKey: this.modelKey,
146
+ perMinLimit: this.perMinLimit,
147
+ perDayLimit: this.perDayLimit,
148
+ concurrentLimit: this.concurrentLimit,
149
+ concurrentActive: this.activeRequests,
150
+ concurrentQueueDepth: this.waitQueue.length,
151
+ secsUntilDayReset,
152
+ };
153
+ const failOpen = {
154
+ ...base,
155
+ perMinUsed: 0,
156
+ perDayUsed: 0,
157
+ projectedWaitMs: 0,
158
+ available: true,
159
+ dailyExhausted: false,
160
+ };
161
+ const client = redis_service_1.redis.getClient();
162
+ if (!client)
163
+ return failOpen;
164
+ const minKey = `ratelimit:${this.modelKey}:min`;
165
+ const dayKey = `ratelimit:${this.modelKey}:day:${utcDateKey()}`;
166
+ let perMinUsed = 0;
167
+ let perDayUsed = 0;
168
+ try {
169
+ const now = Date.now();
170
+ const [minCount, dayRaw] = await Promise.all([
171
+ client.zcount(minKey, now - 60000, "+inf"),
172
+ client.get(dayKey),
173
+ ]);
174
+ perMinUsed = minCount;
175
+ perDayUsed = dayRaw ? Number(dayRaw) : 0;
176
+ }
177
+ catch (err) {
178
+ logger_1.logger.warn("distributedRateLimiter: previewCapacity read failed, assuming available", {
179
+ modelKey: this.modelKey,
180
+ err: err instanceof Error ? err.message : String(err),
181
+ });
182
+ return failOpen;
183
+ }
184
+ const dailyExhausted = this.perDayLimit > 0 && perDayUsed >= this.perDayLimit;
185
+ // Project the wait for a new submit slot.
186
+ let projectedWaitMs = 0;
187
+ if (dailyExhausted) {
188
+ projectedWaitMs = secsUntilDayReset * 1000;
189
+ }
190
+ else if (this.perMinLimit > 0) {
191
+ // Requests already queued on the concurrency gate are "ahead" of a new
192
+ // arrival competing for per-minute slots. Estimate how many 60s windows
193
+ // it takes to drain them past the per-minute throughput.
194
+ const pendingAhead = this.waitQueue.length;
195
+ const freeThisWindow = Math.max(0, this.perMinLimit - perMinUsed);
196
+ if (pendingAhead < freeThisWindow) {
197
+ projectedWaitMs = 0;
198
+ }
199
+ else {
200
+ const slotsNeeded = pendingAhead - freeThisWindow + 1;
201
+ const windowsNeeded = Math.ceil(slotsNeeded / this.perMinLimit);
202
+ projectedWaitMs = windowsNeeded * 60000;
203
+ }
204
+ }
205
+ // No per-minute gate (perMinLimit === 0): wait is concurrency-only; those
206
+ // models churn fast, so we treat backlog as drainable (projectedWaitMs 0).
207
+ const available = dailyExhausted
208
+ ? secsUntilDayReset * 1000 <= exports.DAILY_NEAR_RESET_MS
209
+ : projectedWaitMs <= maxAcceptableWaitMs;
210
+ return {
211
+ ...base,
212
+ perMinUsed,
213
+ perDayUsed,
214
+ projectedWaitMs,
215
+ available,
216
+ dailyExhausted,
217
+ };
105
218
  }
106
219
  /** Free a concurrent slot acquired via waitUntilAvailable(). */
107
220
  releaseSlot() {
@@ -165,8 +278,11 @@ class DistributedRateLimiter {
165
278
  if (next)
166
279
  next();
167
280
  }
168
- async consumeRedisGates() {
169
- if (!this.perMinLimit && !this.perDayLimit)
281
+ async consumeRedisGates(opts) {
282
+ // skipDay ignores the per-day cap entirely (poll path) — see
283
+ // waitUntilAvailableForOneShot.
284
+ const effectiveDayLimit = opts?.skipDay ? 0 : this.perDayLimit;
285
+ if (!this.perMinLimit && !effectiveDayLimit)
170
286
  return;
171
287
  const client = redis_service_1.redis.getClient();
172
288
  if (!client) {
@@ -179,6 +295,8 @@ class DistributedRateLimiter {
179
295
  const minKey = `ratelimit:${this.modelKey}:min`;
180
296
  const secsTilMidnight = secsUntilMidnight();
181
297
  const uniqueId = `${Date.now()}-${crypto_1.default.randomBytes(4).toString("hex")}`;
298
+ const startedAt = Date.now();
299
+ const maxWaitMs = opts?.maxWaitMs;
182
300
  while (true) {
183
301
  const nowMs = Date.now();
184
302
  // Day key resolved per-iteration so a retry across midnight UTC
@@ -186,7 +304,7 @@ class DistributedRateLimiter {
186
304
  const dayKey = `ratelimit:${this.modelKey}:day:${utcDateKey()}`;
187
305
  let result;
188
306
  try {
189
- result = (await client.eval(CONSUME_SCRIPT, 2, minKey, dayKey, String(nowMs), String(this.perMinLimit), String(this.perDayLimit), String(secsTilMidnight), uniqueId));
307
+ result = (await client.eval(CONSUME_SCRIPT, 2, minKey, dayKey, String(nowMs), String(this.perMinLimit), String(effectiveDayLimit), String(secsTilMidnight), uniqueId));
190
308
  }
191
309
  catch (err) {
192
310
  // Redis blip — fail open rather than blocking the pipeline. Throttle
@@ -210,6 +328,43 @@ class DistributedRateLimiter {
210
328
  }
211
329
  if (result[0] === 1)
212
330
  return;
331
+ // Bounded-wait backstop. Without it, a per-day-exhausted gate sleep-loops
332
+ // (60s cap per iteration) until UTC midnight — jobs pile up in-process,
333
+ // hold a worker + concurrency slot, and block graceful shutdown. When the
334
+ // caller passes maxWaitMs, fast-fail instead so the scene can fall back to
335
+ // another model (or surface a clean rate-limit error).
336
+ if (maxWaitMs != null) {
337
+ const reason = result[2];
338
+ // A 'day' block's TRUE wait is until midnight (result[1] is 60s-capped
339
+ // for sleep granularity, not the real ETA) — decide against the real ETA.
340
+ const trueWaitMs = reason === "day" ? secsTilMidnight * 1000 : Date.now() - startedAt + result[1];
341
+ if (trueWaitMs > maxWaitMs) {
342
+ // This is the terminal case: no fallback model had headroom either, so
343
+ // the scene fails with a clean rate-limit error. logger.error → Slack
344
+ // (error-only transport). Model + provider + cause live in the MESSAGE
345
+ // because the Slack dedup key is the message's first 80 chars — so each
346
+ // model fails its own alert (deduped to ~1/5min) and `day` vs `min`
347
+ // causes don't collapse into each other. This + the spill alert are
348
+ // the only signals Ammar gets that a provider is chronically over
349
+ // quota and needs more capacity. Provider-agnostic (every model + TTS).
350
+ const provider = this.modelKey.startsWith("tts:")
351
+ ? this.modelKey.slice(4)
352
+ : this.modelKey.split("-")[0];
353
+ logger_1.logger.error(`distributedRateLimiter: ${this.modelKey} hard rate-limit ${reason === "day" ? "daily-cap" : "throughput"} fail (provider ${provider})`, {
354
+ modelKey: this.modelKey,
355
+ provider,
356
+ cause: reason,
357
+ trueWaitMs,
358
+ maxWaitMs,
359
+ perMinLimit: this.perMinLimit,
360
+ perDayLimit: this.perDayLimit,
361
+ secsUntilDayReset: secsTilMidnight,
362
+ });
363
+ throw new errors_1.UserFacingError(reason === "day"
364
+ ? "This model has reached its daily generation limit."
365
+ : "This model is at capacity right now. Please try again shortly.", errors_1.USER_FACING_ERROR_CODES.VIDEO_PROVIDER_RATE_LIMITED);
366
+ }
367
+ }
213
368
  const waitMs = Math.max(50, Math.min(1000, result[1]));
214
369
  await sleep(waitMs);
215
370
  }
@@ -237,10 +392,23 @@ function getAiGenModelRateLimiter(modelKey) {
237
392
  if (!config) {
238
393
  throw new Error(`No model config for model key: ${modelKey}`);
239
394
  }
395
+ // Google model configs hold the SINGLE-KEY Tier-2 baseline. With a
396
+ // multi-key pool (separate GCP projects/billing accounts, see
397
+ // googleKeyPool), the real aggregate budget is the SUM of each key's
398
+ // tier-scaled budget — so scale the model-level gate up to match, else it
399
+ // would throttle at one key's worth while the pool has more headroom.
400
+ // Single/legacy key → factor 1 (unchanged).
401
+ const isGoogle = modelKey.startsWith("google-");
402
+ const rpmFactor = isGoogle ? (0, googleApiKeys_1.googleAggregateFactor)("rpm") : 1;
403
+ const rpdFactor = isGoogle ? (0, googleApiKeys_1.googleAggregateFactor)("rpd") : 1;
240
404
  aiModelLimiters[modelKey] = new DistributedRateLimiter(modelKey, {
241
405
  concurrentRequests: config.concurrentRequests,
242
- requestPerMin: config.requestPerMin,
243
- requestPerDay: config.requestPerDay,
406
+ requestPerMin: config.requestPerMin
407
+ ? Math.round(config.requestPerMin * rpmFactor)
408
+ : config.requestPerMin,
409
+ requestPerDay: config.requestPerDay
410
+ ? Math.round(config.requestPerDay * rpdFactor)
411
+ : config.requestPerDay,
244
412
  });
245
413
  }
246
414
  return aiModelLimiters[modelKey];
@@ -0,0 +1,81 @@
1
+ import { ESocialProvider } from "../../globals/types";
2
+ /**
3
+ * X8 Social Suite — E1: AI caption / hashtag / title generation (Phase 6 AI
4
+ * growth layer). Pure, dependency-free core: builds the LLM prompt, parses +
5
+ * clamps the model's JSON, and exposes `generateSocialSuggestionsCore(llm, ctx)`
6
+ * with the LLM injected so it's unit-/eval-testable away from the OpenAI client
7
+ * (planner-style `*Core(llm,…)` convention — see L-3/L-5).
8
+ *
9
+ * One round-trip produces a platform-agnostic BASE (caption + hashtags + title)
10
+ * that fills the composer's main fields, PLUS per-platform VARIANTS tailored to
11
+ * each requested provider's norms (char limits, hashtag conventions, title use)
12
+ * that pre-seed the composer's per-platform overrides. The composer applies the
13
+ * base by default and reveals the variants progressively (pro depth, beginner
14
+ * surface — plan §B1/§E1).
15
+ */
16
+ /** Input context for a suggestion request (no secrets — safe to log). */
17
+ export interface ISocialSuggestionContext {
18
+ /** Providers to tailor per-platform variants for (the composer's targets). */
19
+ providers: ESocialProvider[];
20
+ /** Title of the source video, if any. */
21
+ videoTitle?: string;
22
+ /** What the video is about — prompt / script summary that grounds the copy. */
23
+ videoSummary?: string;
24
+ /** ISO-639-1 / locale to WRITE the copy in (defaults to English). */
25
+ language?: string;
26
+ /** Optional brand-voice / tone steer (e.g. "playful, no emojis"). */
27
+ tone?: string;
28
+ }
29
+ /** A per-platform tailored caption + hashtag set. */
30
+ export interface ISocialSuggestionVariant {
31
+ provider: ESocialProvider;
32
+ caption: string;
33
+ hashtags: string[];
34
+ }
35
+ /** The full suggestion the composer renders. */
36
+ export interface ISocialSuggestion {
37
+ /** Platform-agnostic caption the composer fills into the main field. */
38
+ caption: string;
39
+ /** Platform-agnostic hashtag set (no leading '#', deduped). */
40
+ hashtags: string[];
41
+ /** Title (used by YouTube; harmless to ignore on caption-only platforms). */
42
+ title: string;
43
+ /** Per-platform variants for the requested providers (best-effort). */
44
+ variants: ISocialSuggestionVariant[];
45
+ }
46
+ /** A minimal LLM call: take chat messages, return the raw text completion. */
47
+ export type SuggestionLlm = (messages: Array<{
48
+ role: "system" | "user";
49
+ content: string;
50
+ }>) => Promise<string>;
51
+ /**
52
+ * Per-platform copy norms. `maxChars` clamps the caption; `maxHashtags` caps the
53
+ * tag list; `note` is fed to the model so each variant reads native to the
54
+ * platform. Hard limits (X = 280) are real product constraints, not style.
55
+ */
56
+ interface PlatformCopyHint {
57
+ maxChars: number;
58
+ maxHashtags: number;
59
+ note: string;
60
+ }
61
+ export declare const PLATFORM_COPY_HINTS: Record<ESocialProvider, PlatformCopyHint>;
62
+ /** Build the chat prompt for a suggestion request. Pure — no I/O. */
63
+ export declare function buildSuggestionPrompt(ctx: ISocialSuggestionContext): Array<{
64
+ role: "system" | "user";
65
+ content: string;
66
+ }>;
67
+ /**
68
+ * Parse + validate + clamp the model's JSON into an `ISocialSuggestion`.
69
+ * Defensive: malformed JSON degrades to a plain caption (the raw text) with no
70
+ * hashtags/variants rather than throwing, so the composer always gets something
71
+ * usable. Variants are kept only for providers the caller actually requested.
72
+ */
73
+ export declare function parseSocialSuggestion(raw: string, ctx: ISocialSuggestionContext): ISocialSuggestion;
74
+ /**
75
+ * Generate social suggestions with the LLM injected (testable). Builds the
76
+ * prompt, calls the model, parses + clamps the result. Never throws on a bad
77
+ * model response — it degrades to a usable caption (see `parseSocialSuggestion`).
78
+ */
79
+ export declare function generateSocialSuggestionsCore(llm: SuggestionLlm, ctx: ISocialSuggestionContext): Promise<ISocialSuggestion>;
80
+ export {};
81
+ //# sourceMappingURL=captionGen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captionGen.d.ts","sourceRoot":"","sources":["../../../src/services/socialAI/captionGen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AAEH,yEAAyE;AACzE,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qDAAqD;AACrD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,QAAQ,EAAE,wBAAwB,EAAE,CAAC;CACtC;AAED,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG,CAC1B,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,KAC1D,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB;;;;GAIG;AACH,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,eAAe,EAAE,gBAAgB,CAyCzE,CAAC;AAqCF,qEAAqE;AACrE,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,wBAAwB,GAC5B,KAAK,CAAC;IAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAkDrD;AAYD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,wBAAwB,GAC5B,iBAAiB,CA2DnB;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,wBAAwB,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAI5B"}
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLATFORM_COPY_HINTS = void 0;
4
+ exports.buildSuggestionPrompt = buildSuggestionPrompt;
5
+ exports.parseSocialSuggestion = parseSocialSuggestion;
6
+ exports.generateSocialSuggestionsCore = generateSocialSuggestionsCore;
7
+ const types_1 = require("../../globals/types");
8
+ exports.PLATFORM_COPY_HINTS = {
9
+ [types_1.ESocialProvider.YOUTUBE]: {
10
+ maxChars: 4900,
11
+ maxHashtags: 5,
12
+ note: "YouTube: a strong, searchable title carries the post; description can be longer and front-load the hook; 3–5 relevant hashtags.",
13
+ },
14
+ [types_1.ESocialProvider.INSTAGRAM]: {
15
+ maxChars: 2100,
16
+ maxHashtags: 12,
17
+ note: "Instagram Reels: hook in the first line (it's the only part shown collapsed); conversational; 8–12 niche, non-spammy hashtags.",
18
+ },
19
+ [types_1.ESocialProvider.TIKTOK]: {
20
+ maxChars: 2100,
21
+ maxHashtags: 6,
22
+ note: "TikTok: punchy, native, trend-aware; only ~150 chars show before the fold; 3–6 hashtags mixing broad + niche.",
23
+ },
24
+ [types_1.ESocialProvider.FACEBOOK]: {
25
+ maxChars: 4900,
26
+ maxHashtags: 3,
27
+ note: "Facebook: friendly and shareable; hashtags are sparse here — at most 1–3.",
28
+ },
29
+ [types_1.ESocialProvider.LINKEDIN]: {
30
+ maxChars: 2900,
31
+ maxHashtags: 5,
32
+ note: "LinkedIn: professional, value-first, minimal emojis; 3–5 industry hashtags.",
33
+ },
34
+ [types_1.ESocialProvider.X]: {
35
+ maxChars: 270,
36
+ maxHashtags: 2,
37
+ note: "X (Twitter): HARD 280-char limit including hashtags — keep it tight; at most 1–2 hashtags.",
38
+ },
39
+ [types_1.ESocialProvider.PINTEREST]: {
40
+ maxChars: 480,
41
+ maxHashtags: 5,
42
+ note: "Pinterest: keyword-rich and descriptive for search; 2–5 descriptive hashtags.",
43
+ },
44
+ [types_1.ESocialProvider.THREADS]: {
45
+ maxChars: 480,
46
+ maxHashtags: 3,
47
+ note: "Threads: casual and conversational; very few hashtags (Threads supports one primary topic tag).",
48
+ },
49
+ };
50
+ const VALID_PROVIDERS = new Set(Object.values(types_1.ESocialProvider));
51
+ /** Normalize a raw hashtag list: strip '#', spaces, dedupe (case-insensitive). */
52
+ function normalizeHashtags(raw, cap) {
53
+ if (!Array.isArray(raw))
54
+ return [];
55
+ const seen = new Set();
56
+ const out = [];
57
+ for (const item of raw) {
58
+ if (typeof item !== "string")
59
+ continue;
60
+ // Strip leading '#'s and all whitespace; a model sometimes returns "#a b".
61
+ const tag = item.replace(/^#+/, "").replace(/\s+/g, "").trim();
62
+ if (!tag)
63
+ continue;
64
+ const key = tag.toLowerCase();
65
+ if (seen.has(key))
66
+ continue;
67
+ seen.add(key);
68
+ out.push(tag);
69
+ if (out.length >= cap)
70
+ break;
71
+ }
72
+ return out;
73
+ }
74
+ /** Clamp to a max char length on a word boundary where possible. */
75
+ function clampText(text, maxChars) {
76
+ const t = (text ?? "").trim();
77
+ if (t.length <= maxChars)
78
+ return t;
79
+ const cut = t.slice(0, maxChars);
80
+ const lastSpace = cut.lastIndexOf(" ");
81
+ return (lastSpace > maxChars * 0.6 ? cut.slice(0, lastSpace) : cut).trim();
82
+ }
83
+ /** The loosest base limits (used for the platform-agnostic base caption). */
84
+ const BASE_CAPTION_MAX = 2200;
85
+ const BASE_HASHTAG_MAX = 15;
86
+ const TITLE_MAX = 100;
87
+ /** Build the chat prompt for a suggestion request. Pure — no I/O. */
88
+ function buildSuggestionPrompt(ctx) {
89
+ const providers = ctx.providers.filter((p) => VALID_PROVIDERS.has(p));
90
+ const lang = (ctx.language || "en").trim();
91
+ const toneLine = ctx.tone
92
+ ? `Brand voice / tone: ${ctx.tone}.`
93
+ : "Brand voice: authentic, energetic, and human — never corporate or spammy.";
94
+ const platformNotes = providers
95
+ .map((p) => `- ${p}: ${exports.PLATFORM_COPY_HINTS[p].note}`)
96
+ .join("\n");
97
+ const system = "You are an expert social media copywriter for short-form video creators. " +
98
+ "You write scroll-stopping captions, relevant non-spammy hashtags, and " +
99
+ "compelling titles that maximize reach and engagement. You always write in " +
100
+ `the requested language (${lang}) and respect each platform's norms and ` +
101
+ "character limits. You reply with ONLY a single JSON object, no prose, no " +
102
+ "code fences.";
103
+ const aboutLines = [
104
+ ctx.videoTitle ? `Working title: ${ctx.videoTitle}` : null,
105
+ ctx.videoSummary ? `What the video is about: ${ctx.videoSummary}` : null,
106
+ ].filter(Boolean);
107
+ const about = aboutLines.length
108
+ ? aboutLines.join("\n")
109
+ : "A short-form video (no further details provided — infer a generic but appealing angle).";
110
+ const user = `Write social copy in language "${lang}" for this video.\n\n${about}\n\n` +
111
+ `${toneLine}\n\n` +
112
+ `Target platforms:\n${platformNotes || "- (generic)"}\n\n` +
113
+ "Produce a platform-agnostic BASE (a strong caption, a hashtag set, and a " +
114
+ "title) AND one tailored VARIANT per target platform that respects that " +
115
+ "platform's note above (length, hashtag count, style). Hashtags must NOT " +
116
+ "include the '#' symbol and must be single words (no spaces). Do not invent " +
117
+ "facts about the video.\n\n" +
118
+ "Reply with ONLY this JSON shape:\n" +
119
+ "{\n" +
120
+ ' "title": "string (<= 100 chars, YouTube-style)",\n' +
121
+ ' "caption": "string (the base caption)",\n' +
122
+ ' "hashtags": ["tag1", "tag2"],\n' +
123
+ ' "variants": [\n' +
124
+ ' { "provider": "<one of the target platforms>", "caption": "string", "hashtags": ["tag1"] }\n' +
125
+ " ]\n" +
126
+ "}";
127
+ return [
128
+ { role: "system", content: system },
129
+ { role: "user", content: user },
130
+ ];
131
+ }
132
+ /** Strip a ```json … ``` fence the model may wrap the object in. */
133
+ function stripCodeFence(raw) {
134
+ const t = raw.trim();
135
+ if (!t.startsWith("```"))
136
+ return t;
137
+ return t
138
+ .replace(/^```(?:json)?\s*/i, "")
139
+ .replace(/\s*```$/, "")
140
+ .trim();
141
+ }
142
+ /**
143
+ * Parse + validate + clamp the model's JSON into an `ISocialSuggestion`.
144
+ * Defensive: malformed JSON degrades to a plain caption (the raw text) with no
145
+ * hashtags/variants rather than throwing, so the composer always gets something
146
+ * usable. Variants are kept only for providers the caller actually requested.
147
+ */
148
+ function parseSocialSuggestion(raw, ctx) {
149
+ const requested = new Set(ctx.providers.filter((p) => VALID_PROVIDERS.has(p)));
150
+ let obj = null;
151
+ try {
152
+ const parsed = JSON.parse(stripCodeFence(raw));
153
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
154
+ obj = parsed;
155
+ }
156
+ }
157
+ catch {
158
+ obj = null;
159
+ }
160
+ // Fallback: treat the whole response as the caption.
161
+ if (!obj) {
162
+ return {
163
+ caption: clampText(raw, BASE_CAPTION_MAX),
164
+ hashtags: [],
165
+ title: "",
166
+ variants: [],
167
+ };
168
+ }
169
+ const title = clampText(typeof obj.title === "string" ? obj.title : "", TITLE_MAX);
170
+ const caption = clampText(typeof obj.caption === "string" ? obj.caption : "", BASE_CAPTION_MAX);
171
+ const hashtags = normalizeHashtags(obj.hashtags, BASE_HASHTAG_MAX);
172
+ const variants = [];
173
+ const seenProviders = new Set();
174
+ if (Array.isArray(obj.variants)) {
175
+ for (const v of obj.variants) {
176
+ if (!v || typeof v !== "object")
177
+ continue;
178
+ const rec = v;
179
+ const provider = rec.provider;
180
+ if (typeof provider !== "string" || !requested.has(provider)) {
181
+ continue;
182
+ }
183
+ const p = provider;
184
+ if (seenProviders.has(p))
185
+ continue;
186
+ seenProviders.add(p);
187
+ const hint = exports.PLATFORM_COPY_HINTS[p];
188
+ variants.push({
189
+ provider: p,
190
+ caption: clampText(typeof rec.caption === "string" ? rec.caption : caption, hint.maxChars),
191
+ hashtags: normalizeHashtags(rec.hashtags, hint.maxHashtags),
192
+ });
193
+ }
194
+ }
195
+ return { caption, hashtags, title, variants };
196
+ }
197
+ /**
198
+ * Generate social suggestions with the LLM injected (testable). Builds the
199
+ * prompt, calls the model, parses + clamps the result. Never throws on a bad
200
+ * model response — it degrades to a usable caption (see `parseSocialSuggestion`).
201
+ */
202
+ async function generateSocialSuggestionsCore(llm, ctx) {
203
+ const messages = buildSuggestionPrompt(ctx);
204
+ const raw = await llm(messages);
205
+ return parseSocialSuggestion(raw, ctx);
206
+ }
@@ -0,0 +1,85 @@
1
+ import { ESocialProvider } from "../../globals/types";
2
+ /**
3
+ * X8 Social Suite — Phase 6 E4: hook / caption score predictor.
4
+ *
5
+ * Score a hook (the caption's first line / the on-screen opener) for predicted
6
+ * engagement BEFORE posting, and hand back concrete rewrites. This is the same
7
+ * `*Core(llm,…)` convention as captionGen (E1) — pure prompt-build + defensive
8
+ * parse/clamp with the LLM injected, so it's unit-/eval-testable away from the
9
+ * OpenAI client. It is a *predictor / coach*, not a guarantee: the score is the
10
+ * model's judgement against well-known short-form hook heuristics (scroll-stop,
11
+ * clarity, curiosity gap, relevance, platform fit), surfaced so the user can
12
+ * iterate the copy. Review-before-publish — nothing posts here.
13
+ *
14
+ * Why a separate brain from E1: E1 *writes* copy from a video; E4 *grades*
15
+ * arbitrary copy the user already has (typed or AI-written) and proposes
16
+ * stronger variants. Different prompt, different output shape, shared norms.
17
+ */
18
+ /** Input for a hook score request (no secrets — safe to log). */
19
+ export interface IHookScoreContext {
20
+ /** The hook / caption opener to grade (required). */
21
+ hook: string;
22
+ /** Platform the copy targets — tunes the rubric to that surface's norms. */
23
+ provider?: ESocialProvider;
24
+ /** What the video is about — lets the model judge relevance, not just craft. */
25
+ videoSummary?: string;
26
+ /** Language the copy is written in (defaults to English). */
27
+ language?: string;
28
+ }
29
+ /** The five engagement drivers we grade a hook on (each 0–100). */
30
+ export interface IHookScoreBreakdown {
31
+ /** Scroll-stopping power — does it arrest the thumb in the first beat? */
32
+ attention: number;
33
+ /** Is the promise/topic instantly legible (no decoding)? */
34
+ clarity: number;
35
+ /** Curiosity gap — does it open a loop the viewer must close? */
36
+ curiosity: number;
37
+ /** Does it match what the video actually delivers (no bait)? */
38
+ relevance: number;
39
+ /** Native fit for the target platform's length + tone conventions. */
40
+ platformFit: number;
41
+ }
42
+ /** Coarse band derived deterministically from the overall score. */
43
+ export type HookVerdict = "weak" | "okay" | "strong";
44
+ /** The full graded result the composer renders. */
45
+ export interface IHookScore {
46
+ /** Overall 0–100 predicted-engagement score. */
47
+ score: number;
48
+ /** Band derived from `score` (not trusted from the model). */
49
+ verdict: HookVerdict;
50
+ /** Per-driver sub-scores. */
51
+ breakdown: IHookScoreBreakdown;
52
+ /** What's working (short bullets). */
53
+ strengths: string[];
54
+ /** What's holding it back (short, actionable bullets). */
55
+ issues: string[];
56
+ /** 2–3 stronger rewrites the user can adopt with one tap. */
57
+ rewrites: string[];
58
+ }
59
+ /** A minimal LLM call: take chat messages, return the raw text completion. */
60
+ export type HookScoreLlm = (messages: Array<{
61
+ role: "system" | "user";
62
+ content: string;
63
+ }>) => Promise<string>;
64
+ /** Verdict bands: <40 weak, <70 okay, ≥70 strong. */
65
+ export declare function verdictForScore(score: number): HookVerdict;
66
+ /** Build the chat prompt for a hook-score request. Pure — no I/O. */
67
+ export declare function buildHookScorePrompt(ctx: IHookScoreContext): Array<{
68
+ role: "system" | "user";
69
+ content: string;
70
+ }>;
71
+ /**
72
+ * Parse + validate + clamp the model's JSON into an `IHookScore`. Defensive:
73
+ * malformed JSON degrades to a neutral 50 with empty coaching rather than
74
+ * throwing, so the composer always renders something. The verdict is ALWAYS
75
+ * recomputed from the clamped score (never trusted from the model) so the band
76
+ * and number can't disagree.
77
+ */
78
+ export declare function parseHookScore(raw: string): IHookScore;
79
+ /**
80
+ * Score a hook with the LLM injected (testable). Builds the prompt, calls the
81
+ * model, parses + clamps. Never throws on a bad model response — degrades to a
82
+ * neutral score (see `parseHookScore`).
83
+ */
84
+ export declare function scoreHookCore(llm: HookScoreLlm, ctx: IHookScoreContext): Promise<IHookScore>;
85
+ //# sourceMappingURL=hookScore.d.ts.map