venice-video-harness 2.4.0

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 (264) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +598 -0
  4. package/dist/assembly/manifest-builder.d.ts +8 -0
  5. package/dist/assembly/manifest-builder.d.ts.map +1 -0
  6. package/dist/assembly/manifest-builder.js +196 -0
  7. package/dist/assembly/manifest-builder.js.map +1 -0
  8. package/dist/assembly/remotion-scaffold.d.ts +14 -0
  9. package/dist/assembly/remotion-scaffold.d.ts.map +1 -0
  10. package/dist/assembly/remotion-scaffold.js +292 -0
  11. package/dist/assembly/remotion-scaffold.js.map +1 -0
  12. package/dist/assembly/types.d.ts +67 -0
  13. package/dist/assembly/types.d.ts.map +1 -0
  14. package/dist/assembly/types.js +5 -0
  15. package/dist/assembly/types.js.map +1 -0
  16. package/dist/characters/describer.d.ts +32 -0
  17. package/dist/characters/describer.d.ts.map +1 -0
  18. package/dist/characters/describer.js +309 -0
  19. package/dist/characters/describer.js.map +1 -0
  20. package/dist/characters/extractor.d.ts +27 -0
  21. package/dist/characters/extractor.d.ts.map +1 -0
  22. package/dist/characters/extractor.js +274 -0
  23. package/dist/characters/extractor.js.map +1 -0
  24. package/dist/characters/reference-manager.d.ts +95 -0
  25. package/dist/characters/reference-manager.d.ts.map +1 -0
  26. package/dist/characters/reference-manager.js +346 -0
  27. package/dist/characters/reference-manager.js.map +1 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +310 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/config.d.ts +22 -0
  33. package/dist/config.d.ts.map +1 -0
  34. package/dist/config.js +66 -0
  35. package/dist/config.js.map +1 -0
  36. package/dist/editing/aligner.d.ts +44 -0
  37. package/dist/editing/aligner.d.ts.map +1 -0
  38. package/dist/editing/aligner.js +201 -0
  39. package/dist/editing/aligner.js.map +1 -0
  40. package/dist/editing/edl.d.ts +45 -0
  41. package/dist/editing/edl.d.ts.map +1 -0
  42. package/dist/editing/edl.js +133 -0
  43. package/dist/editing/edl.js.map +1 -0
  44. package/dist/editing/overlays.d.ts +97 -0
  45. package/dist/editing/overlays.d.ts.map +1 -0
  46. package/dist/editing/overlays.js +41 -0
  47. package/dist/editing/overlays.js.map +1 -0
  48. package/dist/editing/packer.d.ts +52 -0
  49. package/dist/editing/packer.d.ts.map +1 -0
  50. package/dist/editing/packer.js +170 -0
  51. package/dist/editing/packer.js.map +1 -0
  52. package/dist/editing/providers/whisper-cpp.d.ts +32 -0
  53. package/dist/editing/providers/whisper-cpp.d.ts.map +1 -0
  54. package/dist/editing/providers/whisper-cpp.js +239 -0
  55. package/dist/editing/providers/whisper-cpp.js.map +1 -0
  56. package/dist/editing/render.d.ts +36 -0
  57. package/dist/editing/render.d.ts.map +1 -0
  58. package/dist/editing/render.js +227 -0
  59. package/dist/editing/render.js.map +1 -0
  60. package/dist/editing/self-eval.d.ts +48 -0
  61. package/dist/editing/self-eval.d.ts.map +1 -0
  62. package/dist/editing/self-eval.js +293 -0
  63. package/dist/editing/self-eval.js.map +1 -0
  64. package/dist/editing/silence.d.ts +76 -0
  65. package/dist/editing/silence.d.ts.map +1 -0
  66. package/dist/editing/silence.js +189 -0
  67. package/dist/editing/silence.js.map +1 -0
  68. package/dist/editing/types.d.ts +178 -0
  69. package/dist/editing/types.d.ts.map +1 -0
  70. package/dist/editing/types.js +13 -0
  71. package/dist/editing/types.js.map +1 -0
  72. package/dist/index.d.ts +6 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +5 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/interactive.d.ts +12 -0
  77. package/dist/interactive.d.ts.map +1 -0
  78. package/dist/interactive.js +78 -0
  79. package/dist/interactive.js.map +1 -0
  80. package/dist/mini-drama/assembler.d.ts +61 -0
  81. package/dist/mini-drama/assembler.d.ts.map +1 -0
  82. package/dist/mini-drama/assembler.js +466 -0
  83. package/dist/mini-drama/assembler.js.map +1 -0
  84. package/dist/mini-drama/audio-mix.d.ts +65 -0
  85. package/dist/mini-drama/audio-mix.d.ts.map +1 -0
  86. package/dist/mini-drama/audio-mix.js +118 -0
  87. package/dist/mini-drama/audio-mix.js.map +1 -0
  88. package/dist/mini-drama/cli.d.ts +3 -0
  89. package/dist/mini-drama/cli.d.ts.map +1 -0
  90. package/dist/mini-drama/cli.js +2869 -0
  91. package/dist/mini-drama/cli.js.map +1 -0
  92. package/dist/mini-drama/fcpxml-export.d.ts +2 -0
  93. package/dist/mini-drama/fcpxml-export.d.ts.map +1 -0
  94. package/dist/mini-drama/fcpxml-export.js +5 -0
  95. package/dist/mini-drama/fcpxml-export.js.map +1 -0
  96. package/dist/mini-drama/generation-planner.d.ts +24 -0
  97. package/dist/mini-drama/generation-planner.d.ts.map +1 -0
  98. package/dist/mini-drama/generation-planner.js +304 -0
  99. package/dist/mini-drama/generation-planner.js.map +1 -0
  100. package/dist/mini-drama/location-generator.d.ts +23 -0
  101. package/dist/mini-drama/location-generator.d.ts.map +1 -0
  102. package/dist/mini-drama/location-generator.js +144 -0
  103. package/dist/mini-drama/location-generator.js.map +1 -0
  104. package/dist/mini-drama/music-cues.d.ts +96 -0
  105. package/dist/mini-drama/music-cues.d.ts.map +1 -0
  106. package/dist/mini-drama/music-cues.js +332 -0
  107. package/dist/mini-drama/music-cues.js.map +1 -0
  108. package/dist/mini-drama/panel-fixer.d.ts +12 -0
  109. package/dist/mini-drama/panel-fixer.d.ts.map +1 -0
  110. package/dist/mini-drama/panel-fixer.js +319 -0
  111. package/dist/mini-drama/panel-fixer.js.map +1 -0
  112. package/dist/mini-drama/prompt-builder.d.ts +149 -0
  113. package/dist/mini-drama/prompt-builder.d.ts.map +1 -0
  114. package/dist/mini-drama/prompt-builder.js +722 -0
  115. package/dist/mini-drama/prompt-builder.js.map +1 -0
  116. package/dist/mini-drama/reference-slots.d.ts +31 -0
  117. package/dist/mini-drama/reference-slots.d.ts.map +1 -0
  118. package/dist/mini-drama/reference-slots.js +161 -0
  119. package/dist/mini-drama/reference-slots.js.map +1 -0
  120. package/dist/mini-drama/shot-paths.d.ts +77 -0
  121. package/dist/mini-drama/shot-paths.d.ts.map +1 -0
  122. package/dist/mini-drama/shot-paths.js +101 -0
  123. package/dist/mini-drama/shot-paths.js.map +1 -0
  124. package/dist/mini-drama/storyboard-reference-generator.d.ts +47 -0
  125. package/dist/mini-drama/storyboard-reference-generator.d.ts.map +1 -0
  126. package/dist/mini-drama/storyboard-reference-generator.js +293 -0
  127. package/dist/mini-drama/storyboard-reference-generator.js.map +1 -0
  128. package/dist/mini-drama/subtitle-generator.d.ts +12 -0
  129. package/dist/mini-drama/subtitle-generator.d.ts.map +1 -0
  130. package/dist/mini-drama/subtitle-generator.js +139 -0
  131. package/dist/mini-drama/subtitle-generator.js.map +1 -0
  132. package/dist/mini-drama/timeline-export/davinci-fcpxml.d.ts +3 -0
  133. package/dist/mini-drama/timeline-export/davinci-fcpxml.d.ts.map +1 -0
  134. package/dist/mini-drama/timeline-export/davinci-fcpxml.js +150 -0
  135. package/dist/mini-drama/timeline-export/davinci-fcpxml.js.map +1 -0
  136. package/dist/mini-drama/timeline-export/fcpxml.d.ts +11 -0
  137. package/dist/mini-drama/timeline-export/fcpxml.d.ts.map +1 -0
  138. package/dist/mini-drama/timeline-export/fcpxml.js +140 -0
  139. package/dist/mini-drama/timeline-export/fcpxml.js.map +1 -0
  140. package/dist/mini-drama/timeline-export/index.d.ts +13 -0
  141. package/dist/mini-drama/timeline-export/index.d.ts.map +1 -0
  142. package/dist/mini-drama/timeline-export/index.js +26 -0
  143. package/dist/mini-drama/timeline-export/index.js.map +1 -0
  144. package/dist/mini-drama/timeline-export/premiere-xmeml.d.ts +3 -0
  145. package/dist/mini-drama/timeline-export/premiere-xmeml.d.ts.map +1 -0
  146. package/dist/mini-drama/timeline-export/premiere-xmeml.js +211 -0
  147. package/dist/mini-drama/timeline-export/premiere-xmeml.js.map +1 -0
  148. package/dist/mini-drama/timeline-export/probe.d.ts +53 -0
  149. package/dist/mini-drama/timeline-export/probe.d.ts.map +1 -0
  150. package/dist/mini-drama/timeline-export/probe.js +89 -0
  151. package/dist/mini-drama/timeline-export/probe.js.map +1 -0
  152. package/dist/mini-drama/timeline-export/types.d.ts +57 -0
  153. package/dist/mini-drama/timeline-export/types.d.ts.map +1 -0
  154. package/dist/mini-drama/timeline-export/types.js +14 -0
  155. package/dist/mini-drama/timeline-export/types.js.map +1 -0
  156. package/dist/mini-drama/video-generator.d.ts +22 -0
  157. package/dist/mini-drama/video-generator.d.ts.map +1 -0
  158. package/dist/mini-drama/video-generator.js +1305 -0
  159. package/dist/mini-drama/video-generator.js.map +1 -0
  160. package/dist/mini-drama/voice-reference.d.ts +42 -0
  161. package/dist/mini-drama/voice-reference.d.ts.map +1 -0
  162. package/dist/mini-drama/voice-reference.js +170 -0
  163. package/dist/mini-drama/voice-reference.js.map +1 -0
  164. package/dist/output/html-renderer.d.ts +2 -0
  165. package/dist/output/html-renderer.d.ts.map +1 -0
  166. package/dist/output/html-renderer.js +37 -0
  167. package/dist/output/html-renderer.js.map +1 -0
  168. package/dist/parsers/fountain-parser.d.ts +34 -0
  169. package/dist/parsers/fountain-parser.d.ts.map +1 -0
  170. package/dist/parsers/fountain-parser.js +71 -0
  171. package/dist/parsers/fountain-parser.js.map +1 -0
  172. package/dist/parsers/pdf-parser.d.ts +24 -0
  173. package/dist/parsers/pdf-parser.d.ts.map +1 -0
  174. package/dist/parsers/pdf-parser.js +237 -0
  175. package/dist/parsers/pdf-parser.js.map +1 -0
  176. package/dist/parsers/scene-extractor.d.ts +41 -0
  177. package/dist/parsers/scene-extractor.d.ts.map +1 -0
  178. package/dist/parsers/scene-extractor.js +400 -0
  179. package/dist/parsers/scene-extractor.js.map +1 -0
  180. package/dist/series/manager.d.ts +64 -0
  181. package/dist/series/manager.d.ts.map +1 -0
  182. package/dist/series/manager.js +282 -0
  183. package/dist/series/manager.js.map +1 -0
  184. package/dist/series/types.d.ts +641 -0
  185. package/dist/series/types.d.ts.map +1 -0
  186. package/dist/series/types.js +304 -0
  187. package/dist/series/types.js.map +1 -0
  188. package/dist/storyboard/assembler.d.ts +134 -0
  189. package/dist/storyboard/assembler.d.ts.map +1 -0
  190. package/dist/storyboard/assembler.js +319 -0
  191. package/dist/storyboard/assembler.js.map +1 -0
  192. package/dist/storyboard/prompt-builder.d.ts +113 -0
  193. package/dist/storyboard/prompt-builder.d.ts.map +1 -0
  194. package/dist/storyboard/prompt-builder.js +578 -0
  195. package/dist/storyboard/prompt-builder.js.map +1 -0
  196. package/dist/storyboard/shot-planner.d.ts +34 -0
  197. package/dist/storyboard/shot-planner.d.ts.map +1 -0
  198. package/dist/storyboard/shot-planner.js +446 -0
  199. package/dist/storyboard/shot-planner.js.map +1 -0
  200. package/dist/user-config.d.ts +15 -0
  201. package/dist/user-config.d.ts.map +1 -0
  202. package/dist/user-config.js +103 -0
  203. package/dist/user-config.js.map +1 -0
  204. package/dist/venice/audio-preflight.d.ts +80 -0
  205. package/dist/venice/audio-preflight.d.ts.map +1 -0
  206. package/dist/venice/audio-preflight.js +142 -0
  207. package/dist/venice/audio-preflight.js.map +1 -0
  208. package/dist/venice/audio.d.ts +88 -0
  209. package/dist/venice/audio.d.ts.map +1 -0
  210. package/dist/venice/audio.js +234 -0
  211. package/dist/venice/audio.js.map +1 -0
  212. package/dist/venice/client.d.ts +86 -0
  213. package/dist/venice/client.d.ts.map +1 -0
  214. package/dist/venice/client.js +375 -0
  215. package/dist/venice/client.js.map +1 -0
  216. package/dist/venice/edit.d.ts +57 -0
  217. package/dist/venice/edit.d.ts.map +1 -0
  218. package/dist/venice/edit.js +100 -0
  219. package/dist/venice/edit.js.map +1 -0
  220. package/dist/venice/generate.d.ts +47 -0
  221. package/dist/venice/generate.d.ts.map +1 -0
  222. package/dist/venice/generate.js +150 -0
  223. package/dist/venice/generate.js.map +1 -0
  224. package/dist/venice/image-bytes.d.ts +26 -0
  225. package/dist/venice/image-bytes.d.ts.map +1 -0
  226. package/dist/venice/image-bytes.js +101 -0
  227. package/dist/venice/image-bytes.js.map +1 -0
  228. package/dist/venice/models.d.ts +143 -0
  229. package/dist/venice/models.d.ts.map +1 -0
  230. package/dist/venice/models.js +984 -0
  231. package/dist/venice/models.js.map +1 -0
  232. package/dist/venice/multi-edit.d.ts +40 -0
  233. package/dist/venice/multi-edit.d.ts.map +1 -0
  234. package/dist/venice/multi-edit.js +97 -0
  235. package/dist/venice/multi-edit.js.map +1 -0
  236. package/dist/venice/provenance.d.ts +66 -0
  237. package/dist/venice/provenance.d.ts.map +1 -0
  238. package/dist/venice/provenance.js +151 -0
  239. package/dist/venice/provenance.js.map +1 -0
  240. package/dist/venice/recipe.d.ts +69 -0
  241. package/dist/venice/recipe.d.ts.map +1 -0
  242. package/dist/venice/recipe.js +103 -0
  243. package/dist/venice/recipe.js.map +1 -0
  244. package/dist/venice/rejection.d.ts +63 -0
  245. package/dist/venice/rejection.d.ts.map +1 -0
  246. package/dist/venice/rejection.js +111 -0
  247. package/dist/venice/rejection.js.map +1 -0
  248. package/dist/venice/seedance-preflight.d.ts +38 -0
  249. package/dist/venice/seedance-preflight.d.ts.map +1 -0
  250. package/dist/venice/seedance-preflight.js +29 -0
  251. package/dist/venice/seedance-preflight.js.map +1 -0
  252. package/dist/venice/types.d.ts +212 -0
  253. package/dist/venice/types.d.ts.map +1 -0
  254. package/dist/venice/types.js +9 -0
  255. package/dist/venice/types.js.map +1 -0
  256. package/dist/venice/video.d.ts +77 -0
  257. package/dist/venice/video.d.ts.map +1 -0
  258. package/dist/venice/video.js +163 -0
  259. package/dist/venice/video.js.map +1 -0
  260. package/dist/venice/voices.d.ts +40 -0
  261. package/dist/venice/voices.d.ts.map +1 -0
  262. package/dist/venice/voices.js +194 -0
  263. package/dist/venice/voices.js.map +1 -0
  264. package/package.json +79 -0
@@ -0,0 +1,309 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Character description synthesis.
3
+ // Transforms raw CharacterProfile data into structured, prompt-ready
4
+ // descriptions suitable for injection into image generation requests.
5
+ // ---------------------------------------------------------------------------
6
+ // ---- Extraction patterns --------------------------------------------------
7
+ /**
8
+ * Each entry maps a regex to one or more attribute fields.
9
+ * Patterns are applied against physical-description lines to populate
10
+ * the PhysicalAttributes struct.
11
+ */
12
+ const ATTRIBUTE_EXTRACTORS = [
13
+ // Age
14
+ {
15
+ pattern: /\b(\d{1,2})s?\s*(?:years?\s*old|year[- ]old)\b/i,
16
+ field: "ageRange",
17
+ transform: (m) => `${m[1]}s`,
18
+ },
19
+ {
20
+ pattern: /\b(early|mid|late)\s*(\d{1,2})s\b/i,
21
+ field: "ageRange",
22
+ transform: (m) => `${m[1]} ${m[2]}s`,
23
+ },
24
+ {
25
+ pattern: /\b(teenage|elderly|middle[- ]aged|young|older|youthful)\b/i,
26
+ field: "ageRange",
27
+ transform: (m) => m[1].toLowerCase(),
28
+ },
29
+ // Hair color
30
+ {
31
+ pattern: /\b(blonde|blond|brunette|brown|black|red|auburn|grey|gray|silver|white|dark|light|sandy|strawberry[- ]blonde|platinum|golden|chestnut|raven)\s*hair\b/i,
32
+ field: "hairColor",
33
+ transform: (m) => m[1].toLowerCase(),
34
+ },
35
+ {
36
+ pattern: /\bhair\b.*?\b(blonde|blond|brunette|brown|black|red|auburn|grey|gray|silver|white|dark|light|sandy|platinum|golden|chestnut|raven)\b/i,
37
+ field: "hairColor",
38
+ transform: (m) => m[1].toLowerCase(),
39
+ },
40
+ // Hair length
41
+ {
42
+ pattern: /\b(short|long|shoulder[- ]length|cropped|close[- ]cropped|medium[- ]length|waist[- ]length)\s*hair\b/i,
43
+ field: "hairLength",
44
+ transform: (m) => m[1].toLowerCase(),
45
+ },
46
+ // Hair style
47
+ {
48
+ pattern: /\b(curly|straight|wavy|braided|braids|ponytail|bun|dreadlocks|dreads|mohawk|buzz[- ]cut|slicked[- ]back|tousled|messy|neat|pulled[- ]back|afro)\b/i,
49
+ field: "hairStyle",
50
+ transform: (m) => m[1].toLowerCase(),
51
+ },
52
+ {
53
+ pattern: /\bbald\b/i,
54
+ field: "hairStyle",
55
+ transform: () => "bald",
56
+ },
57
+ // Eye color
58
+ {
59
+ pattern: /\b(blue|green|brown|hazel|grey|gray|dark|light|amber|violet|black|ice[- ]blue)\s*eyes?\b/i,
60
+ field: "eyeColor",
61
+ transform: (m) => m[1].toLowerCase(),
62
+ },
63
+ {
64
+ pattern: /\beyes?\b.*?\b(blue|green|brown|hazel|grey|gray|dark|light|amber|violet|black)\b/i,
65
+ field: "eyeColor",
66
+ transform: (m) => m[1].toLowerCase(),
67
+ },
68
+ // Eye shape
69
+ {
70
+ pattern: /\b(narrow|wide|almond[- ]shaped|deep[- ]set|round|hooded|piercing|bright|sharp|tired|sunken)\s*eyes?\b/i,
71
+ field: "eyeShape",
72
+ transform: (m) => m[1].toLowerCase(),
73
+ },
74
+ // Build
75
+ {
76
+ pattern: /\b(muscular|slender|stocky|thin|heavy|heavyset|lean|athletic|wiry|burly|petite|portly|stout|gaunt|lanky|broad[- ]shouldered|slight)\b/i,
77
+ field: "build",
78
+ transform: (m) => m[1].toLowerCase(),
79
+ },
80
+ // Height
81
+ {
82
+ pattern: /\b(tall|short|average[- ]height|towering|diminutive|petite)\b/i,
83
+ field: "height",
84
+ transform: (m) => m[1].toLowerCase(),
85
+ },
86
+ {
87
+ pattern: /\b(\d['']?\s*\d{1,2}"?)\b/,
88
+ field: "height",
89
+ transform: (m) => m[1],
90
+ },
91
+ // Ethnicity / appearance
92
+ {
93
+ pattern: /\b(African[- ]American|Black|Caucasian|White|Asian|Latino|Latina|Hispanic|Native\s*American|Indigenous|Middle\s*Eastern|South\s*Asian|East\s*Asian|Pacific\s*Islander|mixed[- ]race|biracial)\b/i,
94
+ field: "ethnicity",
95
+ transform: (m) => m[1],
96
+ },
97
+ // Face features (collected as array)
98
+ {
99
+ pattern: /\b(beard|bearded|mustache|moustache|goatee|stubble|clean[- ]shaven|scar|scarred|freckles|freckled|wrinkles|wrinkled|dimples|dimpled|angular|chiseled|round[- ]faced|square[- ]jawed|high\s*cheekbones)\b/i,
100
+ field: "faceFeatures",
101
+ transform: (m) => m[1].toLowerCase(),
102
+ },
103
+ // Distinguishing features (collected as array)
104
+ {
105
+ pattern: /\b(tattoo|tattooed|piercing|pierced|birthmark|mole|limp|eye[- ]patch|prosthetic|glasses|spectacles|monocle|hearing\s*aid|cane|wheelchair)\b/i,
106
+ field: "distinguishingFeatures",
107
+ transform: (m) => m[1].toLowerCase(),
108
+ },
109
+ ];
110
+ // ---- Wardrobe extraction --------------------------------------------------
111
+ const WARDROBE_PATTERN = /\b(?:wearing|wears|dressed\s+in|clad\s+in|in\s+a|outfit|suit|uniform|shirt|blouse|coat|jacket|jeans|pants|trousers|skirt|dress|boots|shoes|sneakers|heels|sandals|hat|cap|helmet|gloves|scarf|tie|vest|sweater|hoodie|tank\s*top|t-shirt|tuxedo|gown|armor|cloak|robe|overalls|apron)\b/i;
112
+ /**
113
+ * Extract wardrobe-related fragments from a line of text.
114
+ * Returns the full sentence/clause containing the wardrobe keyword.
115
+ */
116
+ function extractWardrobeFragment(line) {
117
+ if (!WARDROBE_PATTERN.test(line))
118
+ return null;
119
+ // Try to extract just the clause that mentions clothing.
120
+ // Split on common clause delimiters and find the relevant part.
121
+ const clauses = line.split(/[,.;]/).map((c) => c.trim());
122
+ for (const clause of clauses) {
123
+ if (WARDROBE_PATTERN.test(clause) && clause.length > 5) {
124
+ return clause;
125
+ }
126
+ }
127
+ return line.trim();
128
+ }
129
+ // ---- Attribute extraction -------------------------------------------------
130
+ function createEmptyAttributes() {
131
+ return {
132
+ ageRange: "unspecified",
133
+ ethnicity: "unspecified",
134
+ hairColor: "unspecified",
135
+ hairLength: "unspecified",
136
+ hairStyle: "unspecified",
137
+ eyeColor: "unspecified",
138
+ eyeShape: "unspecified",
139
+ faceFeatures: [],
140
+ build: "unspecified",
141
+ height: "unspecified",
142
+ distinguishingFeatures: [],
143
+ };
144
+ }
145
+ /**
146
+ * Run all attribute extractors against the provided description lines.
147
+ * First match wins for scalar fields; array fields accumulate.
148
+ */
149
+ function extractAttributes(lines) {
150
+ const attrs = createEmptyAttributes();
151
+ for (const line of lines) {
152
+ for (const extractor of ATTRIBUTE_EXTRACTORS) {
153
+ const match = line.match(extractor.pattern);
154
+ if (!match)
155
+ continue;
156
+ const value = extractor.transform
157
+ ? extractor.transform(match)
158
+ : match[1].toLowerCase();
159
+ const field = extractor.field;
160
+ if (field === "faceFeatures" || field === "distinguishingFeatures") {
161
+ // Array fields -- accumulate unique entries.
162
+ const arr = attrs[field];
163
+ if (!arr.includes(value)) {
164
+ arr.push(value);
165
+ }
166
+ }
167
+ else {
168
+ // Scalar fields -- first match wins (don't overwrite).
169
+ if (attrs[field] === "unspecified") {
170
+ attrs[field] = value;
171
+ }
172
+ }
173
+ }
174
+ }
175
+ return attrs;
176
+ }
177
+ // ---- Description builders -------------------------------------------------
178
+ /**
179
+ * Build a short 1-2 sentence description from extracted attributes.
180
+ */
181
+ function buildShortDescription(name, attrs) {
182
+ const parts = [];
183
+ // Age + build/height
184
+ const agePart = attrs.ageRange !== "unspecified" ? attrs.ageRange : null;
185
+ const buildPart = attrs.build !== "unspecified" ? attrs.build : null;
186
+ const heightPart = attrs.height !== "unspecified" ? attrs.height : null;
187
+ if (agePart || buildPart || heightPart) {
188
+ const descriptors = [agePart, heightPart, buildPart].filter(Boolean);
189
+ parts.push(descriptors.join(", "));
190
+ }
191
+ // Hair
192
+ if (attrs.hairColor !== "unspecified" || attrs.hairStyle !== "unspecified") {
193
+ const hairParts = [attrs.hairColor, attrs.hairLength, attrs.hairStyle]
194
+ .filter((v) => v !== "unspecified");
195
+ if (hairParts.length > 0) {
196
+ parts.push(`${hairParts.join(" ")} hair`);
197
+ }
198
+ }
199
+ // Eyes
200
+ if (attrs.eyeColor !== "unspecified") {
201
+ parts.push(`${attrs.eyeColor} eyes`);
202
+ }
203
+ if (parts.length === 0) {
204
+ return `${name}, a character whose physical appearance is not described in the screenplay.`;
205
+ }
206
+ return `${name}: ${parts.join(", ")}.`;
207
+ }
208
+ /**
209
+ * Build an exhaustive paragraph covering all known attributes.
210
+ * Formatted for direct injection into image generation prompts.
211
+ * Unspecified fields are explicitly noted to prevent hallucination
212
+ * by the image model.
213
+ */
214
+ function buildFullDescription(name, attrs) {
215
+ const sections = [];
216
+ // Identity line
217
+ sections.push(`Character: ${name}.`);
218
+ // Age
219
+ sections.push(attrs.ageRange !== "unspecified"
220
+ ? `Age range: ${attrs.ageRange}.`
221
+ : "Age: unspecified.");
222
+ // Ethnicity / general appearance
223
+ sections.push(attrs.ethnicity !== "unspecified"
224
+ ? `Ethnicity/appearance: ${attrs.ethnicity}.`
225
+ : "Ethnicity/appearance: unspecified.");
226
+ // Hair
227
+ const hairDescriptors = [attrs.hairColor, attrs.hairLength, attrs.hairStyle]
228
+ .filter((v) => v !== "unspecified");
229
+ if (hairDescriptors.length > 0) {
230
+ sections.push(`Hair: ${hairDescriptors.join(", ")}.`);
231
+ }
232
+ else {
233
+ sections.push("Hair: unspecified.");
234
+ }
235
+ // Eyes
236
+ const eyeDescriptors = [attrs.eyeColor, attrs.eyeShape].filter((v) => v !== "unspecified");
237
+ if (eyeDescriptors.length > 0) {
238
+ sections.push(`Eyes: ${eyeDescriptors.join(", ")}.`);
239
+ }
240
+ else {
241
+ sections.push("Eyes: unspecified.");
242
+ }
243
+ // Face
244
+ if (attrs.faceFeatures.length > 0) {
245
+ sections.push(`Face features: ${attrs.faceFeatures.join(", ")}.`);
246
+ }
247
+ else {
248
+ sections.push("Face features: unspecified.");
249
+ }
250
+ // Build / Height
251
+ const bodyDescriptors = [
252
+ attrs.build !== "unspecified" ? `build: ${attrs.build}` : null,
253
+ attrs.height !== "unspecified" ? `height: ${attrs.height}` : null,
254
+ ].filter(Boolean);
255
+ if (bodyDescriptors.length > 0) {
256
+ sections.push(`Body: ${bodyDescriptors.join(", ")}.`);
257
+ }
258
+ else {
259
+ sections.push("Build/height: unspecified.");
260
+ }
261
+ // Distinguishing features
262
+ if (attrs.distinguishingFeatures.length > 0) {
263
+ sections.push(`Distinguishing features: ${attrs.distinguishingFeatures.join(", ")}.`);
264
+ }
265
+ return sections.join(" ");
266
+ }
267
+ // ---- Main export ----------------------------------------------------------
268
+ /**
269
+ * Transform an array of `CharacterProfile` objects into structured
270
+ * `CharacterDescription` entries. Each description synthesizes scattered
271
+ * physical-description fragments into a coherent, prompt-ready format.
272
+ *
273
+ * @param profiles - Array of profiles from `extractCharacterProfiles`.
274
+ * @returns Array of `CharacterDescription` in the same order as input.
275
+ */
276
+ export function buildCharacterDescriptions(profiles) {
277
+ return profiles.map((profile) => {
278
+ // Extract structured attributes from physical description lines.
279
+ const attrs = extractAttributes(profile.physicalDescriptions);
280
+ // Build the short and full descriptions.
281
+ const shortDescription = buildShortDescription(profile.name, attrs);
282
+ const fullDescription = buildFullDescription(profile.name, attrs);
283
+ // Extract wardrobe -- default and per-scene.
284
+ const wardrobeByScene = new Map();
285
+ const allWardrobeFragments = [];
286
+ // physicalDescriptions and mentions may overlap; deduplicate.
287
+ const allLines = [...profile.physicalDescriptions, ...profile.mentions];
288
+ const uniqueLines = Array.from(new Set(allLines));
289
+ for (const line of uniqueLines) {
290
+ const fragment = extractWardrobeFragment(line);
291
+ if (fragment) {
292
+ allWardrobeFragments.push(fragment);
293
+ }
294
+ }
295
+ // Deduplicate wardrobe fragments.
296
+ const uniqueWardrobe = Array.from(new Set(allWardrobeFragments));
297
+ const wardrobe = uniqueWardrobe.length > 0
298
+ ? uniqueWardrobe.join("; ")
299
+ : "unspecified";
300
+ return {
301
+ name: profile.name,
302
+ shortDescription,
303
+ fullDescription,
304
+ wardrobe,
305
+ wardrobeByScene,
306
+ };
307
+ });
308
+ }
309
+ //# sourceMappingURL=describer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describer.js","sourceRoot":"","sources":["../../src/characters/describer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { Scene } from "../parsers/scene-extractor.js";
2
+ /** Aggregated profile for a single character across the entire screenplay. */
3
+ export interface CharacterProfile {
4
+ /** Canonical uppercase character name (e.g. "MARCUS"). */
5
+ name: string;
6
+ /** Every line of action or dialogue text that mentions this character. */
7
+ mentions: string[];
8
+ /** Extracted physical-description fragments found in action lines. */
9
+ physicalDescriptions: string[];
10
+ /** 1-based scene numbers in which the character appears. */
11
+ scenesPresent: number[];
12
+ /** Total number of dialogue lines attributed to this character. */
13
+ dialogueCount: number;
14
+ }
15
+ /**
16
+ * Extract character profiles from an array of parsed scenes.
17
+ *
18
+ * The function iterates every scene and inspects both dialogue attributions
19
+ * and action/description text to build a comprehensive profile for each
20
+ * unique character. Profiles are sorted by `dialogueCount` descending so
21
+ * that principal characters appear first.
22
+ *
23
+ * @param scenes - Array of `Scene` objects produced by the scene parser.
24
+ * @returns Deduplicated, sorted array of `CharacterProfile` entries.
25
+ */
26
+ export declare function extractCharacterProfiles(scenes: Scene[]): CharacterProfile[];
27
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/characters/extractor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAI3D,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IAEb,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;IAEnB,sEAAsE;IACtE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAE/B,4DAA4D;IAC5D,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAC;CACvB;AAyHD;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,gBAAgB,EAAE,CAsK5E"}
@@ -0,0 +1,274 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Character profile extraction from parsed screenplay scenes.
3
+ // Scans dialogue, action, and scene headers to build rich character profiles
4
+ // that drive downstream description synthesis and reference image generation.
5
+ // ---------------------------------------------------------------------------
6
+ // ---- Internal constants ---------------------------------------------------
7
+ /**
8
+ * Keywords that commonly appear in physical descriptions of characters.
9
+ * Used to filter action lines for appearance-related text.
10
+ */
11
+ const PHYSICAL_KEYWORDS = [
12
+ "hair",
13
+ "eyes",
14
+ "eye",
15
+ "tall",
16
+ "short",
17
+ "wearing",
18
+ "wears",
19
+ "dressed",
20
+ "dress",
21
+ "outfit",
22
+ "suit",
23
+ "shirt",
24
+ "coat",
25
+ "jacket",
26
+ "jeans",
27
+ "pants",
28
+ "skirt",
29
+ "boots",
30
+ "shoes",
31
+ "hat",
32
+ "glasses",
33
+ "age",
34
+ "aged",
35
+ "old",
36
+ "young",
37
+ "elderly",
38
+ "teenage",
39
+ "middle-aged",
40
+ "skin",
41
+ "complexion",
42
+ "build",
43
+ "muscular",
44
+ "slender",
45
+ "stocky",
46
+ "thin",
47
+ "heavy",
48
+ "heavyset",
49
+ "lean",
50
+ "athletic",
51
+ "face",
52
+ "facial",
53
+ "beard",
54
+ "mustache",
55
+ "moustache",
56
+ "clean-shaven",
57
+ "scar",
58
+ "scarred",
59
+ "tattoo",
60
+ "tattooed",
61
+ "piercing",
62
+ "freckles",
63
+ "wrinkles",
64
+ "handsome",
65
+ "beautiful",
66
+ "pretty",
67
+ "rugged",
68
+ "height",
69
+ "weight",
70
+ "blonde",
71
+ "brunette",
72
+ "redhead",
73
+ "bald",
74
+ "curly",
75
+ "straight",
76
+ "shoulder-length",
77
+ "ponytail",
78
+ "braids",
79
+ "uniform",
80
+ "armor",
81
+ "cloak",
82
+ "robe",
83
+ ];
84
+ /** Pre-compiled regex for matching any physical keyword in a line. */
85
+ const PHYSICAL_KEYWORD_PATTERN = new RegExp(`\\b(?:${PHYSICAL_KEYWORDS.join("|")})\\b`, "i");
86
+ // ---- Helpers --------------------------------------------------------------
87
+ /**
88
+ * Normalise a character name to a canonical uppercase form.
89
+ * Strips parenthetical extensions like "(V.O.)" or "(CONT'D)".
90
+ */
91
+ function canonicalizeName(raw) {
92
+ return raw
93
+ .replace(/\s*\(.*?\)\s*/g, "")
94
+ .trim()
95
+ .toUpperCase();
96
+ }
97
+ /**
98
+ * Test whether an action line contains the character name as a whole word.
99
+ * Uses a word-boundary regex so "MARK" does not match inside "MARKET".
100
+ */
101
+ function lineContainsName(line, name) {
102
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
103
+ const pattern = new RegExp(`\\b${escaped}\\b`, "i");
104
+ return pattern.test(line);
105
+ }
106
+ /**
107
+ * Determine whether an action line that mentions a character also contains
108
+ * physical-description content worth extracting.
109
+ */
110
+ function hasPhysicalDescription(line) {
111
+ return PHYSICAL_KEYWORD_PATTERN.test(line);
112
+ }
113
+ // ---- Core extraction ------------------------------------------------------
114
+ /**
115
+ * Extract character profiles from an array of parsed scenes.
116
+ *
117
+ * The function iterates every scene and inspects both dialogue attributions
118
+ * and action/description text to build a comprehensive profile for each
119
+ * unique character. Profiles are sorted by `dialogueCount` descending so
120
+ * that principal characters appear first.
121
+ *
122
+ * @param scenes - Array of `Scene` objects produced by the scene parser.
123
+ * @returns Deduplicated, sorted array of `CharacterProfile` entries.
124
+ */
125
+ export function extractCharacterProfiles(scenes) {
126
+ const profileMap = new Map();
127
+ /** Retrieve or create a fresh profile entry for the given name. */
128
+ function getOrCreate(name) {
129
+ const canonical = canonicalizeName(name);
130
+ let profile = profileMap.get(canonical);
131
+ if (!profile) {
132
+ profile = {
133
+ name: canonical,
134
+ mentions: [],
135
+ physicalDescriptions: [],
136
+ scenesPresent: [],
137
+ dialogueCount: 0,
138
+ };
139
+ profileMap.set(canonical, profile);
140
+ }
141
+ return profile;
142
+ }
143
+ for (const scene of scenes) {
144
+ const sceneNum = scene.number;
145
+ // --- Dialogue pass ---
146
+ // Each dialogue entry attributes a line to a named character.
147
+ if (scene.dialogue) {
148
+ for (const entry of scene.dialogue) {
149
+ const profile = getOrCreate(entry.character);
150
+ // Track scene presence (deduplicated later).
151
+ if (!profile.scenesPresent.includes(sceneNum)) {
152
+ profile.scenesPresent.push(sceneNum);
153
+ }
154
+ // Each DialogueLine represents one dialogue line.
155
+ profile.dialogueCount += 1;
156
+ // Dialogue lines themselves can sometimes contain self-referential
157
+ // physical description ("I cut my hair"), but we focus on action
158
+ // lines for more reliable extraction.
159
+ }
160
+ }
161
+ // --- Action / description pass ---
162
+ // Scan action lines for character name mentions and physical descriptors.
163
+ const actionLines = scene.action ?? [];
164
+ // Collect all known character names so far (including those just discovered
165
+ // in dialogue above) to search action text against.
166
+ const knownNames = Array.from(profileMap.keys());
167
+ for (const line of actionLines) {
168
+ for (const name of knownNames) {
169
+ if (!lineContainsName(line, name)) {
170
+ continue;
171
+ }
172
+ const profile = getOrCreate(name);
173
+ // Record the mention.
174
+ profile.mentions.push(line);
175
+ // Track scene presence.
176
+ if (!profile.scenesPresent.includes(sceneNum)) {
177
+ profile.scenesPresent.push(sceneNum);
178
+ }
179
+ // Check for physical description content.
180
+ if (hasPhysicalDescription(line)) {
181
+ profile.physicalDescriptions.push(line);
182
+ }
183
+ }
184
+ }
185
+ // --- Second discovery pass ---
186
+ // Some characters appear only in action text (e.g. background characters
187
+ // whose names are introduced in ALL CAPS inline). Screenplay convention
188
+ // introduces a character name in uppercase the first time they appear in
189
+ // action. We detect standalone uppercase words (2+ letters, not scene
190
+ // slugline terms) that could be character introductions.
191
+ for (const line of actionLines) {
192
+ // Match words that are fully uppercase and at least 2 characters,
193
+ // filtering out common screenplay terms and slugline fragments.
194
+ const uppercaseWords = line.match(/\b[A-Z][A-Z'-]{1,}\b/g);
195
+ if (!uppercaseWords)
196
+ continue;
197
+ const sluglineNoise = new Set([
198
+ "INT",
199
+ "EXT",
200
+ "DAY",
201
+ "NIGHT",
202
+ "MORNING",
203
+ "EVENING",
204
+ "DAWN",
205
+ "DUSK",
206
+ "LATER",
207
+ "CONTINUOUS",
208
+ "CONT",
209
+ "CUT",
210
+ "FADE",
211
+ "DISSOLVE",
212
+ "SMASH",
213
+ "MATCH",
214
+ "ANGLE",
215
+ "CLOSE",
216
+ "WIDE",
217
+ "POV",
218
+ "INSERT",
219
+ "FLASHBACK",
220
+ "INTERCUT",
221
+ "SUPER",
222
+ "TITLE",
223
+ "THE",
224
+ "AND",
225
+ "WITH",
226
+ "FROM",
227
+ "BACK",
228
+ "END",
229
+ "OVER",
230
+ "ON",
231
+ "TO",
232
+ "IN",
233
+ "AT",
234
+ "OF",
235
+ "OS",
236
+ "VO",
237
+ ]);
238
+ for (const word of uppercaseWords) {
239
+ if (sluglineNoise.has(word))
240
+ continue;
241
+ if (profileMap.has(word)) {
242
+ // Already known -- just make sure this action line is recorded.
243
+ const profile = profileMap.get(word);
244
+ if (!profile.mentions.includes(line)) {
245
+ profile.mentions.push(line);
246
+ }
247
+ if (!profile.scenesPresent.includes(sceneNum)) {
248
+ profile.scenesPresent.push(sceneNum);
249
+ }
250
+ if (hasPhysicalDescription(line)) {
251
+ if (!profile.physicalDescriptions.includes(line)) {
252
+ profile.physicalDescriptions.push(line);
253
+ }
254
+ }
255
+ }
256
+ // We intentionally do NOT create new profiles for every uppercase word
257
+ // found here -- that would produce excessive false positives ("FBI",
258
+ // "CIA", location names, etc.). New character creation is limited to
259
+ // dialogue attributions, which are the most reliable signal.
260
+ }
261
+ }
262
+ }
263
+ // Sort by dialogue count descending (main characters first), with a
264
+ // secondary alphabetical sort for stability.
265
+ const profiles = Array.from(profileMap.values());
266
+ profiles.sort((a, b) => {
267
+ if (b.dialogueCount !== a.dialogueCount) {
268
+ return b.dialogueCount - a.dialogueCount;
269
+ }
270
+ return a.name.localeCompare(b.name);
271
+ });
272
+ return profiles;
273
+ }
274
+ //# sourceMappingURL=extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/characters/extractor.ts"],"names":[],"mappings":"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"}