@vishu1301/script-writing 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +177 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -8
- package/dist/index.d.ts +6 -8
- package/dist/index.js +178 -122
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -72,7 +72,7 @@ interface ScriptBreakdown {
|
|
|
72
72
|
scene_number: string;
|
|
73
73
|
content: string;
|
|
74
74
|
}
|
|
75
|
-
type ElementCategory = "CAST" | "PROP" | "COSTUME" | "VEHICLE" | "SET_PROP" | "EXTRA" | "LOCATION" | "OTHER";
|
|
75
|
+
type ElementCategory = "CAST" | "PROP" | "COSTUME" | "VEHICLE" | "SET_PROP" | "EXTRA" | "LOCATION" | "SUBLOCATION" | "OTHER";
|
|
76
76
|
interface Tag {
|
|
77
77
|
id?: string;
|
|
78
78
|
scene_id?: string | number;
|
|
@@ -91,7 +91,7 @@ declare const CATEGORIES: {
|
|
|
91
91
|
hex: string;
|
|
92
92
|
}[];
|
|
93
93
|
|
|
94
|
-
declare function ScriptBreakdownSceneView({ blocks, characters, isLoading, sceneNumber, tags, selectionMenu, handleMouseUp, addTag, removeTag, clearSelection, menuPlacement, menuRef,
|
|
94
|
+
declare function ScriptBreakdownSceneView({ blocks, characters, isLoading, sceneNumber, tags, selectionMenu, handleMouseUp, addTag, updateTag, removeTag, clearSelection, menuPlacement, menuRef, sceneBrief, setSceneBrief, onSummarize, isSummarizing, }: {
|
|
95
95
|
blocks: Block[];
|
|
96
96
|
characters: string[];
|
|
97
97
|
isLoading: boolean;
|
|
@@ -107,13 +107,11 @@ declare function ScriptBreakdownSceneView({ blocks, characters, isLoading, scene
|
|
|
107
107
|
} | null;
|
|
108
108
|
handleMouseUp: () => void;
|
|
109
109
|
addTag: (c: ElementCategory) => void;
|
|
110
|
+
updateTag?: (id: string, categoryId: ElementCategory) => void;
|
|
110
111
|
removeTag: (e: React__default.MouseEvent, id?: string) => void;
|
|
111
112
|
clearSelection: () => void;
|
|
112
113
|
menuPlacement: "top" | "bottom";
|
|
113
114
|
menuRef: React__default.RefObject<HTMLDivElement | null>;
|
|
114
|
-
subLocations: string[];
|
|
115
|
-
addSubLocation: (loc: string) => void;
|
|
116
|
-
removeSubLocation: (loc: string) => void;
|
|
117
115
|
sceneBrief: string;
|
|
118
116
|
setSceneBrief: (brief: string) => void;
|
|
119
117
|
onSummarize?: () => void;
|
|
@@ -125,7 +123,9 @@ interface UseScriptBreakdownSceneOptions {
|
|
|
125
123
|
fetchOptions?: RequestInit;
|
|
126
124
|
onAISummarize?: (scene: any) => void;
|
|
127
125
|
onTagAdded?: (tag: Tag) => void;
|
|
126
|
+
onTagsBulkAdded?: (tags: Tag[], summary?: string) => Promise<void>;
|
|
128
127
|
onTagRemoved?: (tagId: string) => void;
|
|
128
|
+
onTagUpdated?: (tagId: string, categoryId: ElementCategory) => void;
|
|
129
129
|
preLoadedTags?: Tag[];
|
|
130
130
|
}
|
|
131
131
|
declare function useScriptBreakdownScene(options: UseScriptBreakdownSceneOptions): {
|
|
@@ -145,13 +145,11 @@ declare function useScriptBreakdownScene(options: UseScriptBreakdownSceneOptions
|
|
|
145
145
|
} | null;
|
|
146
146
|
handleMouseUp: () => void;
|
|
147
147
|
addTag: (categoryId: ElementCategory) => Promise<void>;
|
|
148
|
+
updateTag: (id: string, categoryId: ElementCategory) => Promise<void>;
|
|
148
149
|
removeTag: (e: React.MouseEvent, id: string) => Promise<void>;
|
|
149
150
|
clearSelection: () => void;
|
|
150
151
|
menuPlacement: "bottom" | "top";
|
|
151
152
|
menuRef: React$1.RefObject<HTMLDivElement | null>;
|
|
152
|
-
subLocations: string[];
|
|
153
|
-
addSubLocation: (subLocation: string) => void;
|
|
154
|
-
removeSubLocation: (subLocation: string) => void;
|
|
155
153
|
sceneBrief: string;
|
|
156
154
|
setSceneBrief: React$1.Dispatch<React$1.SetStateAction<string>>;
|
|
157
155
|
handleAISummarize: () => Promise<any>;
|
package/dist/index.d.ts
CHANGED
|
@@ -72,7 +72,7 @@ interface ScriptBreakdown {
|
|
|
72
72
|
scene_number: string;
|
|
73
73
|
content: string;
|
|
74
74
|
}
|
|
75
|
-
type ElementCategory = "CAST" | "PROP" | "COSTUME" | "VEHICLE" | "SET_PROP" | "EXTRA" | "LOCATION" | "OTHER";
|
|
75
|
+
type ElementCategory = "CAST" | "PROP" | "COSTUME" | "VEHICLE" | "SET_PROP" | "EXTRA" | "LOCATION" | "SUBLOCATION" | "OTHER";
|
|
76
76
|
interface Tag {
|
|
77
77
|
id?: string;
|
|
78
78
|
scene_id?: string | number;
|
|
@@ -91,7 +91,7 @@ declare const CATEGORIES: {
|
|
|
91
91
|
hex: string;
|
|
92
92
|
}[];
|
|
93
93
|
|
|
94
|
-
declare function ScriptBreakdownSceneView({ blocks, characters, isLoading, sceneNumber, tags, selectionMenu, handleMouseUp, addTag, removeTag, clearSelection, menuPlacement, menuRef,
|
|
94
|
+
declare function ScriptBreakdownSceneView({ blocks, characters, isLoading, sceneNumber, tags, selectionMenu, handleMouseUp, addTag, updateTag, removeTag, clearSelection, menuPlacement, menuRef, sceneBrief, setSceneBrief, onSummarize, isSummarizing, }: {
|
|
95
95
|
blocks: Block[];
|
|
96
96
|
characters: string[];
|
|
97
97
|
isLoading: boolean;
|
|
@@ -107,13 +107,11 @@ declare function ScriptBreakdownSceneView({ blocks, characters, isLoading, scene
|
|
|
107
107
|
} | null;
|
|
108
108
|
handleMouseUp: () => void;
|
|
109
109
|
addTag: (c: ElementCategory) => void;
|
|
110
|
+
updateTag?: (id: string, categoryId: ElementCategory) => void;
|
|
110
111
|
removeTag: (e: React__default.MouseEvent, id?: string) => void;
|
|
111
112
|
clearSelection: () => void;
|
|
112
113
|
menuPlacement: "top" | "bottom";
|
|
113
114
|
menuRef: React__default.RefObject<HTMLDivElement | null>;
|
|
114
|
-
subLocations: string[];
|
|
115
|
-
addSubLocation: (loc: string) => void;
|
|
116
|
-
removeSubLocation: (loc: string) => void;
|
|
117
115
|
sceneBrief: string;
|
|
118
116
|
setSceneBrief: (brief: string) => void;
|
|
119
117
|
onSummarize?: () => void;
|
|
@@ -125,7 +123,9 @@ interface UseScriptBreakdownSceneOptions {
|
|
|
125
123
|
fetchOptions?: RequestInit;
|
|
126
124
|
onAISummarize?: (scene: any) => void;
|
|
127
125
|
onTagAdded?: (tag: Tag) => void;
|
|
126
|
+
onTagsBulkAdded?: (tags: Tag[], summary?: string) => Promise<void>;
|
|
128
127
|
onTagRemoved?: (tagId: string) => void;
|
|
128
|
+
onTagUpdated?: (tagId: string, categoryId: ElementCategory) => void;
|
|
129
129
|
preLoadedTags?: Tag[];
|
|
130
130
|
}
|
|
131
131
|
declare function useScriptBreakdownScene(options: UseScriptBreakdownSceneOptions): {
|
|
@@ -145,13 +145,11 @@ declare function useScriptBreakdownScene(options: UseScriptBreakdownSceneOptions
|
|
|
145
145
|
} | null;
|
|
146
146
|
handleMouseUp: () => void;
|
|
147
147
|
addTag: (categoryId: ElementCategory) => Promise<void>;
|
|
148
|
+
updateTag: (id: string, categoryId: ElementCategory) => Promise<void>;
|
|
148
149
|
removeTag: (e: React.MouseEvent, id: string) => Promise<void>;
|
|
149
150
|
clearSelection: () => void;
|
|
150
151
|
menuPlacement: "bottom" | "top";
|
|
151
152
|
menuRef: React$1.RefObject<HTMLDivElement | null>;
|
|
152
|
-
subLocations: string[];
|
|
153
|
-
addSubLocation: (subLocation: string) => void;
|
|
154
|
-
removeSubLocation: (subLocation: string) => void;
|
|
155
153
|
sceneBrief: string;
|
|
156
154
|
setSceneBrief: React$1.Dispatch<React$1.SetStateAction<string>>;
|
|
157
155
|
handleAISummarize: () => Promise<any>;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
|
2
|
-
import { ArrowRightLeft, MessageCircle, Brackets, UserRound, Sparkles, Clapperboard, Upload, Lock, Unlock, Save, FileDown, RefreshCcw, Cog, ArrowRight, User, ChevronRight, Loader2, AlignLeft, Tags
|
|
2
|
+
import { ArrowRightLeft, MessageCircle, Brackets, UserRound, Sparkles, Clapperboard, Upload, Lock, Unlock, Save, FileDown, RefreshCcw, Cog, ArrowRight, User, ChevronRight, Loader2, AlignLeft, Tags } from 'lucide-react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import * as pdfjs from 'pdfjs-dist';
|
|
5
5
|
import jsPDF from 'jspdf';
|
|
@@ -1728,6 +1728,7 @@ var CATEGORIES = [
|
|
|
1728
1728
|
{ id: "SET_PROP", label: "Set Prop", color: "#00C853", hex: "#69F0AE" },
|
|
1729
1729
|
{ id: "EXTRA", label: "Extra", color: "#00B8D4", hex: "#62EFFF" },
|
|
1730
1730
|
{ id: "LOCATION", label: "Location", color: "#FFB300", hex: "#FFE082" },
|
|
1731
|
+
{ id: "SUBLOCATION", label: "Sublocation", color: "#004CFF", hex: "#004CFF" },
|
|
1731
1732
|
{ id: "OTHER", label: "Other", color: "#9E9E9E", hex: "#E0E0E0" }
|
|
1732
1733
|
];
|
|
1733
1734
|
var PopcornIcon = ({ isSummarizing }) => /* @__PURE__ */ jsxs(
|
|
@@ -1915,31 +1916,17 @@ function ScriptBreakdownSceneView({
|
|
|
1915
1916
|
selectionMenu,
|
|
1916
1917
|
handleMouseUp,
|
|
1917
1918
|
addTag,
|
|
1919
|
+
updateTag,
|
|
1918
1920
|
removeTag,
|
|
1919
1921
|
clearSelection,
|
|
1920
1922
|
menuPlacement,
|
|
1921
1923
|
menuRef,
|
|
1922
|
-
subLocations,
|
|
1923
|
-
addSubLocation,
|
|
1924
|
-
removeSubLocation,
|
|
1925
1924
|
sceneBrief,
|
|
1926
1925
|
setSceneBrief,
|
|
1927
1926
|
onSummarize,
|
|
1928
1927
|
isSummarizing
|
|
1929
1928
|
}) {
|
|
1930
1929
|
const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
|
|
1931
|
-
const [isSubLocOpen, setIsSubLocOpen] = useState(false);
|
|
1932
|
-
const [subLocInput, setSubLocInput] = useState("");
|
|
1933
|
-
const subLocPopoverRef = useRef(null);
|
|
1934
|
-
useEffect(() => {
|
|
1935
|
-
const handleClickOutside = (e) => {
|
|
1936
|
-
if (isSubLocOpen && subLocPopoverRef.current && !subLocPopoverRef.current.contains(e.target)) {
|
|
1937
|
-
setIsSubLocOpen(false);
|
|
1938
|
-
}
|
|
1939
|
-
};
|
|
1940
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
1941
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1942
|
-
}, [isSubLocOpen]);
|
|
1943
1930
|
useEffect(() => {
|
|
1944
1931
|
const fontId = "google-font-courier-prime";
|
|
1945
1932
|
const styleId = "screenplay-editor-force-v4";
|
|
@@ -2083,11 +2070,20 @@ function ScriptBreakdownSceneView({
|
|
|
2083
2070
|
] }),
|
|
2084
2071
|
/* @__PURE__ */ jsxs("div", { className: "relative z-10 flex flex-col gap-1", children: [
|
|
2085
2072
|
CATEGORIES.filter(
|
|
2086
|
-
(cat) => !(cat.id === "LOCATION" && hasLocationTag)
|
|
2073
|
+
(cat) => !(cat.id === "LOCATION" && hasLocationTag) && !(cat.id === "SUBLOCATION" && !hasLocationTag)
|
|
2087
2074
|
).map((cat) => /* @__PURE__ */ jsxs(
|
|
2088
2075
|
"button",
|
|
2089
2076
|
{
|
|
2090
|
-
onClick: () =>
|
|
2077
|
+
onClick: () => {
|
|
2078
|
+
const existingTag = tags.find(
|
|
2079
|
+
(t) => t.block_id === block.id && t.start_index === selectionMenu.startIndex && t.end_index === selectionMenu.endIndex
|
|
2080
|
+
);
|
|
2081
|
+
if (existingTag && existingTag.id) {
|
|
2082
|
+
updateTag == null ? void 0 : updateTag(existingTag.id, cat.id);
|
|
2083
|
+
} else {
|
|
2084
|
+
addTag(cat.id);
|
|
2085
|
+
}
|
|
2086
|
+
},
|
|
2091
2087
|
className: "group w-full text-[12px] font-bold px-3 py-2 rounded-xl transition-all duration-300 text-left flex items-center justify-between hover:bg-white/80 hover:shadow-[0_2px_10px_rgb(0,0,0,0.02)] active:scale-[0.98]",
|
|
2092
2088
|
style: { color: cat.color },
|
|
2093
2089
|
children: [
|
|
@@ -2174,6 +2170,7 @@ function ScriptBreakdownSceneView({
|
|
|
2174
2170
|
/* @__PURE__ */ jsx("span", { className: "ml-auto bg-slate-100/80 text-slate-500 px-2.5 py-1 rounded-lg text-[10px] font-bold tracking-widest border border-slate-200/50 shadow-inner", children: tags.length })
|
|
2175
2171
|
] }),
|
|
2176
2172
|
tags.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-8", children: CATEGORIES.map((cat) => {
|
|
2173
|
+
if (cat.id === "SUBLOCATION" && !hasLocationTag) return null;
|
|
2177
2174
|
const catTags = Array.from(
|
|
2178
2175
|
new Map(
|
|
2179
2176
|
tags.filter((t) => t.category_id === cat.id).map((tag) => [tag.name.toLowerCase(), tag])
|
|
@@ -2191,88 +2188,15 @@ function ScriptBreakdownSceneView({
|
|
|
2191
2188
|
),
|
|
2192
2189
|
cat.label
|
|
2193
2190
|
] }),
|
|
2194
|
-
/* @__PURE__ */
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
)),
|
|
2204
|
-
cat.id === "LOCATION" && /* @__PURE__ */ jsxs(
|
|
2205
|
-
"div",
|
|
2206
|
-
{
|
|
2207
|
-
className: "relative flex items-center",
|
|
2208
|
-
ref: subLocPopoverRef,
|
|
2209
|
-
children: [
|
|
2210
|
-
/* @__PURE__ */ jsx(
|
|
2211
|
-
"button",
|
|
2212
|
-
{
|
|
2213
|
-
onClick: () => setIsSubLocOpen(!isSubLocOpen),
|
|
2214
|
-
className: "flex items-center justify-center w-5 h-5 rounded-full hover:bg-slate-200 transition-colors",
|
|
2215
|
-
title: "Add Sub Location",
|
|
2216
|
-
children: /* @__PURE__ */ jsx(Plus, { className: "w-3 h-3 text-slate-500" })
|
|
2217
|
-
}
|
|
2218
|
-
),
|
|
2219
|
-
isSubLocOpen && /* @__PURE__ */ jsxs("div", { className: "absolute left-0 top-full mt-2 w-56 bg-white backdrop-blur-2xl shadow-[0_10px_40px_rgb(0,0,0,0.06)] border border-white rounded-[1.5rem] p-3 z-50 animate-in fade-in zoom-in-95", children: [
|
|
2220
|
-
/* @__PURE__ */ jsx("p", { className: "text-[9px] font-extrabold tracking-[0.2em] text-slate-400 uppercase mb-2 px-1", children: "Add Sub Location" }),
|
|
2221
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
2222
|
-
/* @__PURE__ */ jsx(
|
|
2223
|
-
"input",
|
|
2224
|
-
{
|
|
2225
|
-
type: "text",
|
|
2226
|
-
value: subLocInput,
|
|
2227
|
-
onChange: (e) => setSubLocInput(e.target.value),
|
|
2228
|
-
onKeyDown: (e) => {
|
|
2229
|
-
if (e.key === "Enter") {
|
|
2230
|
-
addSubLocation(subLocInput);
|
|
2231
|
-
setSubLocInput("");
|
|
2232
|
-
setIsSubLocOpen(false);
|
|
2233
|
-
}
|
|
2234
|
-
},
|
|
2235
|
-
className: "w-full text-xs px-3 py-2 bg-white/50 border border-white/60 rounded-xl outline-none focus:bg-white/80 focus:border-white transition-all text-slate-700 font-bold shadow-[0_2px_10px_rgb(0,0,0,0.02)] placeholder:font-medium placeholder:text-slate-400",
|
|
2236
|
-
placeholder: "Sub location...",
|
|
2237
|
-
autoFocus: true
|
|
2238
|
-
}
|
|
2239
|
-
),
|
|
2240
|
-
/* @__PURE__ */ jsx(
|
|
2241
|
-
"button",
|
|
2242
|
-
{
|
|
2243
|
-
onClick: () => {
|
|
2244
|
-
addSubLocation(subLocInput);
|
|
2245
|
-
setSubLocInput("");
|
|
2246
|
-
setIsSubLocOpen(false);
|
|
2247
|
-
},
|
|
2248
|
-
className: "flex items-center justify-center shrink-0 bg-slate-800 text-white px-3.5 py-2 rounded-xl text-[11px] font-bold hover:bg-slate-700 hover:shadow-md transition-all active:scale-95",
|
|
2249
|
-
children: "Add"
|
|
2250
|
-
}
|
|
2251
|
-
)
|
|
2252
|
-
] })
|
|
2253
|
-
] })
|
|
2254
|
-
]
|
|
2255
|
-
}
|
|
2256
|
-
),
|
|
2257
|
-
cat.id === "LOCATION" && subLocations.map((subLoc) => /* @__PURE__ */ jsxs(
|
|
2258
|
-
"span",
|
|
2259
|
-
{
|
|
2260
|
-
className: "group flex items-center gap-1.5 text-[11px] font-bold px-3 py-1.5 rounded-xl bg-white backdrop-blur-md border border-slate-200/50 shadow-[0_4px_15px_rgb(0,0,0,0.03)] transition-all duration-300 cursor-default text-slate-500",
|
|
2261
|
-
children: [
|
|
2262
|
-
subLoc,
|
|
2263
|
-
/* @__PURE__ */ jsx(
|
|
2264
|
-
"button",
|
|
2265
|
-
{
|
|
2266
|
-
onClick: () => removeSubLocation(subLoc),
|
|
2267
|
-
className: "w-3.5 h-3.5 rounded-full hover:bg-slate-300/50 flex items-center justify-center transition-colors opacity-0 group-hover:opacity-100",
|
|
2268
|
-
children: /* @__PURE__ */ jsx(X, { className: "w-2.5 h-2.5" })
|
|
2269
|
-
}
|
|
2270
|
-
)
|
|
2271
|
-
]
|
|
2272
|
-
},
|
|
2273
|
-
`sub-${subLoc}`
|
|
2274
|
-
))
|
|
2275
|
-
] })
|
|
2191
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: catTags.map((tag, index) => /* @__PURE__ */ jsx(
|
|
2192
|
+
"span",
|
|
2193
|
+
{
|
|
2194
|
+
className: "text-[11px] font-bold px-3 py-1.5 rounded-xl bg-white/80 backdrop-blur-md border border-white shadow-[0_4px_15px_rgb(0,0,0,0.03)] hover:shadow-[0_4px_20px_rgb(0,0,0,0.06)] hover:-translate-y-0.5 transition-all duration-300 cursor-default",
|
|
2195
|
+
style: { color: cat.color },
|
|
2196
|
+
children: tag.name
|
|
2197
|
+
},
|
|
2198
|
+
index
|
|
2199
|
+
)) })
|
|
2276
2200
|
] }, cat.id);
|
|
2277
2201
|
}) }) : /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-slate-400 italic bg-white/40 p-6 rounded-[2rem] border border-white border-dashed text-center shadow-[0_4px_20px_rgb(0,0,0,0.02)]", children: "Highlight text to tag elements." })
|
|
2278
2202
|
] })
|
|
@@ -2285,7 +2209,6 @@ function useScriptBreakdownScene(options) {
|
|
|
2285
2209
|
const autoTaggedSceneRef = useRef(null);
|
|
2286
2210
|
const [scene, setScene] = useState(null);
|
|
2287
2211
|
const [menuPlacement, setMenuPlacement] = useState("top");
|
|
2288
|
-
const [subLocations, setSubLocations] = useState([]);
|
|
2289
2212
|
const [sceneBrief, setSceneBrief] = useState("");
|
|
2290
2213
|
const [isSummarizing, setIsSummarizing] = useState(false);
|
|
2291
2214
|
const [isLoading, setIsLoading] = useState(true);
|
|
@@ -2385,9 +2308,122 @@ function useScriptBreakdownScene(options) {
|
|
|
2385
2308
|
end_index: aiTag.end_index
|
|
2386
2309
|
});
|
|
2387
2310
|
});
|
|
2311
|
+
if (newTags.length > 0) {
|
|
2312
|
+
const originalTags = tags;
|
|
2313
|
+
setTags((prev) => {
|
|
2314
|
+
const merged = [...prev];
|
|
2315
|
+
newTags.forEach((newTag) => {
|
|
2316
|
+
const isOverlapping = merged.some(
|
|
2317
|
+
(t) => t.block_id === newTag.block_id && newTag.end_index > t.start_index && newTag.start_index < t.end_index
|
|
2318
|
+
);
|
|
2319
|
+
if (!isOverlapping) {
|
|
2320
|
+
merged.push(newTag);
|
|
2321
|
+
}
|
|
2322
|
+
});
|
|
2323
|
+
return merged;
|
|
2324
|
+
});
|
|
2325
|
+
try {
|
|
2326
|
+
if (options.onTagsBulkAdded) {
|
|
2327
|
+
await options.onTagsBulkAdded(newTags, parsedSummaryData.summarise);
|
|
2328
|
+
}
|
|
2329
|
+
} catch (error2) {
|
|
2330
|
+
console.error("Failed to bulk add AI-generated tags:", error2);
|
|
2331
|
+
setTags(originalTags);
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
return data;
|
|
2335
|
+
} else {
|
|
2336
|
+
setIsSummarizing(false);
|
|
2337
|
+
console.error("Failed to summarize scene:", res);
|
|
2338
|
+
}
|
|
2339
|
+
};
|
|
2340
|
+
const bulkCreateTags = useCallback(async () => {
|
|
2341
|
+
if (blocks.length === 0) return;
|
|
2342
|
+
const newTags = [];
|
|
2343
|
+
const seenCharacters = /* @__PURE__ */ new Set();
|
|
2344
|
+
const timeOfDays = ["DAY", "NIGHT"];
|
|
2345
|
+
const isTimeOfDay = (str) => timeOfDays.includes(str.toUpperCase());
|
|
2346
|
+
blocks.forEach((block) => {
|
|
2347
|
+
if (block.type === "CHARACTER") {
|
|
2348
|
+
const text = block.text.trim();
|
|
2349
|
+
const parenIndex = text.indexOf("(");
|
|
2350
|
+
const charName = parenIndex > -1 ? text.substring(0, parenIndex).trim() : text;
|
|
2351
|
+
if (charName && !seenCharacters.has(charName.toUpperCase())) {
|
|
2352
|
+
seenCharacters.add(charName.toUpperCase());
|
|
2353
|
+
const startIndex = text.indexOf(charName);
|
|
2354
|
+
if (startIndex !== -1) {
|
|
2355
|
+
newTags.push({
|
|
2356
|
+
id: uuid(),
|
|
2357
|
+
block_id: block.id,
|
|
2358
|
+
category_id: "CAST",
|
|
2359
|
+
name: charName,
|
|
2360
|
+
start_index: startIndex,
|
|
2361
|
+
end_index: startIndex + charName.length
|
|
2362
|
+
});
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
} else if (block.type === "SCENE_HEADING") {
|
|
2366
|
+
const text = block.text.trim();
|
|
2367
|
+
const typeMatch = text.match(
|
|
2368
|
+
/^(INT\/EXT|INT\.?\/EXT\.?|INT\.EXT\.?|INT|EXT|I\/E)\.?\s+/i
|
|
2369
|
+
);
|
|
2370
|
+
let remainingText = text;
|
|
2371
|
+
let offset = 0;
|
|
2372
|
+
if (typeMatch) {
|
|
2373
|
+
offset = typeMatch[0].length;
|
|
2374
|
+
remainingText = text.substring(offset);
|
|
2375
|
+
}
|
|
2376
|
+
const parts = remainingText.split(/\s+-\s+/);
|
|
2377
|
+
if (parts.length > 0) {
|
|
2378
|
+
const locationName = parts[0].trim();
|
|
2379
|
+
const locStart = text.indexOf(locationName, offset);
|
|
2380
|
+
if (locStart !== -1 && locationName) {
|
|
2381
|
+
newTags.push({
|
|
2382
|
+
id: uuid(),
|
|
2383
|
+
block_id: block.id,
|
|
2384
|
+
category_id: "LOCATION",
|
|
2385
|
+
name: locationName,
|
|
2386
|
+
start_index: locStart,
|
|
2387
|
+
end_index: locStart + locationName.length
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
if (parts.length > 1) {
|
|
2391
|
+
const secondPart = parts[1].trim();
|
|
2392
|
+
const isLast = parts.length === 2;
|
|
2393
|
+
if (!isLast || !isTimeOfDay(secondPart)) {
|
|
2394
|
+
const subLocStart = text.indexOf(
|
|
2395
|
+
secondPart,
|
|
2396
|
+
locStart + locationName.length
|
|
2397
|
+
);
|
|
2398
|
+
if (subLocStart !== -1 && secondPart) {
|
|
2399
|
+
newTags.push({
|
|
2400
|
+
id: uuid(),
|
|
2401
|
+
block_id: block.id,
|
|
2402
|
+
category_id: "SUBLOCATION",
|
|
2403
|
+
name: secondPart,
|
|
2404
|
+
start_index: subLocStart,
|
|
2405
|
+
end_index: subLocStart + secondPart.length
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2413
|
+
if (newTags.length > 0) {
|
|
2414
|
+
const originalTags = tags;
|
|
2388
2415
|
setTags((prev) => {
|
|
2389
2416
|
const merged = [...prev];
|
|
2417
|
+
const existingChars = new Set(
|
|
2418
|
+
merged.filter(
|
|
2419
|
+
(t) => t.category_id === "CHARACTER" || t.category_id === "CAST"
|
|
2420
|
+
).map((t) => t.name.toUpperCase())
|
|
2421
|
+
);
|
|
2390
2422
|
newTags.forEach((newTag) => {
|
|
2423
|
+
if (newTag.category_id === "CHARACTER") {
|
|
2424
|
+
if (existingChars.has(newTag.name.toUpperCase())) return;
|
|
2425
|
+
existingChars.add(newTag.name.toUpperCase());
|
|
2426
|
+
}
|
|
2391
2427
|
const isOverlapping = merged.some(
|
|
2392
2428
|
(t) => t.block_id === newTag.block_id && newTag.end_index > t.start_index && newTag.start_index < t.end_index
|
|
2393
2429
|
);
|
|
@@ -2397,26 +2433,17 @@ function useScriptBreakdownScene(options) {
|
|
|
2397
2433
|
});
|
|
2398
2434
|
return merged;
|
|
2399
2435
|
});
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
(subLocation) => {
|
|
2408
|
-
const trimmed = subLocation.trim();
|
|
2409
|
-
if (trimmed && !subLocations.includes(trimmed)) {
|
|
2410
|
-
setSubLocations((prev) => [...prev, trimmed]);
|
|
2436
|
+
try {
|
|
2437
|
+
if (options.onTagsBulkAdded) {
|
|
2438
|
+
await options.onTagsBulkAdded(newTags);
|
|
2439
|
+
}
|
|
2440
|
+
} catch (error2) {
|
|
2441
|
+
console.error("Failed to bulk create tags:", error2);
|
|
2442
|
+
setTags(originalTags);
|
|
2411
2443
|
}
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
);
|
|
2415
|
-
const removeSubLocation = useCallback((subLocation) => {
|
|
2416
|
-
setSubLocations((prev) => prev.filter((loc) => loc !== subLocation));
|
|
2417
|
-
}, []);
|
|
2444
|
+
}
|
|
2445
|
+
}, [blocks, tags, options.onTagsBulkAdded]);
|
|
2418
2446
|
useEffect(() => {
|
|
2419
|
-
setSubLocations([]);
|
|
2420
2447
|
setSceneBrief("");
|
|
2421
2448
|
autoTaggedSceneRef.current = null;
|
|
2422
2449
|
}, [options.scene_url]);
|
|
@@ -2430,6 +2457,18 @@ function useScriptBreakdownScene(options) {
|
|
|
2430
2457
|
});
|
|
2431
2458
|
}
|
|
2432
2459
|
}, [options.preLoadedTags]);
|
|
2460
|
+
useEffect(() => {
|
|
2461
|
+
const doBulkCreate = async () => {
|
|
2462
|
+
if (blocks.length > 0 && !autoTaggedSceneRef.current) {
|
|
2463
|
+
const hasPreloadedTags = options.preLoadedTags && options.preLoadedTags.length > 0;
|
|
2464
|
+
if (!hasPreloadedTags) {
|
|
2465
|
+
autoTaggedSceneRef.current = options.scene_url;
|
|
2466
|
+
await bulkCreateTags();
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
};
|
|
2470
|
+
doBulkCreate();
|
|
2471
|
+
}, [blocks, options.scene_url, options.preLoadedTags, bulkCreateTags]);
|
|
2433
2472
|
const clearSelection = useCallback(() => {
|
|
2434
2473
|
var _a;
|
|
2435
2474
|
setSelectionMenu(null);
|
|
@@ -2556,6 +2595,25 @@ function useScriptBreakdownScene(options) {
|
|
|
2556
2595
|
setTags((prev) => [...prev, tagToRemove]);
|
|
2557
2596
|
}
|
|
2558
2597
|
};
|
|
2598
|
+
const updateTag = async (id, categoryId) => {
|
|
2599
|
+
var _a;
|
|
2600
|
+
const tagToUpdate = tags.find((t) => t.id === id);
|
|
2601
|
+
if (!tagToUpdate) return;
|
|
2602
|
+
setTags(
|
|
2603
|
+
(prev) => prev.map((t) => t.id === id ? __spreadProps(__spreadValues({}, t), { category_id: categoryId }) : t)
|
|
2604
|
+
);
|
|
2605
|
+
clearSelection();
|
|
2606
|
+
try {
|
|
2607
|
+
await ((_a = options.onTagUpdated) == null ? void 0 : _a.call(options, id, categoryId));
|
|
2608
|
+
} catch (error2) {
|
|
2609
|
+
console.error("Failed to update tag:", error2);
|
|
2610
|
+
setTags(
|
|
2611
|
+
(prev) => prev.map(
|
|
2612
|
+
(t) => t.id === id ? __spreadProps(__spreadValues({}, t), { category_id: tagToUpdate.category_id }) : t
|
|
2613
|
+
)
|
|
2614
|
+
);
|
|
2615
|
+
}
|
|
2616
|
+
};
|
|
2559
2617
|
return {
|
|
2560
2618
|
scene,
|
|
2561
2619
|
blocks,
|
|
@@ -2566,13 +2624,11 @@ function useScriptBreakdownScene(options) {
|
|
|
2566
2624
|
selectionMenu,
|
|
2567
2625
|
handleMouseUp,
|
|
2568
2626
|
addTag,
|
|
2627
|
+
updateTag,
|
|
2569
2628
|
removeTag,
|
|
2570
2629
|
clearSelection,
|
|
2571
2630
|
menuPlacement,
|
|
2572
2631
|
menuRef,
|
|
2573
|
-
subLocations,
|
|
2574
|
-
addSubLocation,
|
|
2575
|
-
removeSubLocation,
|
|
2576
2632
|
sceneBrief,
|
|
2577
2633
|
setSceneBrief,
|
|
2578
2634
|
handleAISummarize,
|