@vishu1301/script-writing 1.1.4 → 1.1.6

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 CHANGED
@@ -1390,7 +1390,7 @@ function useScreenplayEditor(options) {
1390
1390
  [blocks, handleBlockTextChange]
1391
1391
  );
1392
1392
  const handleScriptImport = react.useCallback(
1393
- (title, content, preParsedBlocks) => {
1393
+ (title, content, preParsedBlocks, isInitialLoad) => {
1394
1394
  let parsedBlocks = [];
1395
1395
  if (preParsedBlocks && preParsedBlocks.length > 0) {
1396
1396
  parsedBlocks = preParsedBlocks.map((b) => ({
@@ -1446,8 +1446,10 @@ function useScreenplayEditor(options) {
1446
1446
  }).join("");
1447
1447
  if (sbxData !== lastSavedContent.current) {
1448
1448
  lastSavedContent.current = sbxData;
1449
- const blob = new Blob([sbxData], { type: "text/plain" });
1450
- onSaveRef.current(blob);
1449
+ if (!isInitialLoad) {
1450
+ const blob = new Blob([sbxData], { type: "text/plain" });
1451
+ onSaveRef.current(blob);
1452
+ }
1451
1453
  }
1452
1454
  }
1453
1455
  setTimeout(() => {
@@ -1495,7 +1497,7 @@ function useScreenplayEditor(options) {
1495
1497
  }, 200);
1496
1498
  }, []);
1497
1499
  const loadFromUrl = react.useCallback(
1498
- async (url, fetchOptions = {}) => {
1500
+ async (url, fetchOptions = {}, isInitialLoad) => {
1499
1501
  var _a;
1500
1502
  try {
1501
1503
  const response = await fetch(url, fetchOptions);
@@ -1567,7 +1569,7 @@ function useScreenplayEditor(options) {
1567
1569
  }
1568
1570
  }
1569
1571
  const filename = ((_a = url.split("/").pop()) == null ? void 0 : _a.replace(/\.sbx$/i, "")) || "Imported from URL";
1570
- handleScriptImport(filename, scriptContent, preParsedBlocks);
1572
+ handleScriptImport(filename, scriptContent, preParsedBlocks, isInitialLoad);
1571
1573
  } catch (error) {
1572
1574
  console.error(
1573
1575
  "[useScreenplayEditor] Error loading script from URL:",
@@ -1581,7 +1583,7 @@ function useScreenplayEditor(options) {
1581
1583
  react.useEffect(() => {
1582
1584
  if ((options == null ? void 0 : options.initialUrl) && options.initialUrl !== loadedUrlRef.current) {
1583
1585
  loadedUrlRef.current = options.initialUrl;
1584
- loadFromUrl(options.initialUrl, options.fetchOptions);
1586
+ loadFromUrl(options.initialUrl, options.fetchOptions, true);
1585
1587
  }
1586
1588
  }, [options == null ? void 0 : options.initialUrl, options == null ? void 0 : options.fetchOptions, loadFromUrl]);
1587
1589
  return {
@@ -1753,6 +1755,166 @@ var CATEGORIES = [
1753
1755
  { id: "LOCATION", label: "Location", color: "#FFB300", hex: "#FFE082" },
1754
1756
  { id: "OTHER", label: "Other", color: "#9E9E9E", hex: "#E0E0E0" }
1755
1757
  ];
1758
+ var PopcornIcon = ({ isSummarizing }) => /* @__PURE__ */ jsxRuntime.jsxs(
1759
+ "svg",
1760
+ {
1761
+ xmlns: "http://www.w3.org/2000/svg",
1762
+ width: "24",
1763
+ height: "24",
1764
+ viewBox: "0 0 24 24",
1765
+ fill: "none",
1766
+ strokeLinecap: "round",
1767
+ strokeLinejoin: "round",
1768
+ className: `w-6 h-6 transition-all duration-500 ${isSummarizing ? "animate-cook" : "group-hover:scale-110 group-hover:-rotate-12"}`,
1769
+ children: [
1770
+ /* @__PURE__ */ jsxRuntime.jsx(
1771
+ "path",
1772
+ {
1773
+ d: "M18 8a2 2 0 0 0 0-4 2 2 0 0 0-4 0 2 2 0 0 0-4 0 2 2 0 0 0-4 0 2 2 0 0 0 0 4",
1774
+ className: "stroke-yellow-400",
1775
+ strokeWidth: "2"
1776
+ }
1777
+ ),
1778
+ /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "stroke-red-500", strokeWidth: "2", children: [
1779
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 8c.5 0 .9.4.8 1l-2.6 12c-.1.5-.7 1-1.2 1H7c-.6 0-1.1-.4-1.2-1L3.2 9c-.1-.6.3-1 .8-1Z" }),
1780
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 22 9 8", className: "stroke-red-500", strokeWidth: "1" }),
1781
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m14 22 1-14", className: "stroke-red-500", strokeWidth: "1" })
1782
+ ] })
1783
+ ]
1784
+ }
1785
+ );
1786
+ var SummarizeButton = ({
1787
+ onSummarize,
1788
+ isSummarizing
1789
+ }) => {
1790
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1791
+ "button",
1792
+ {
1793
+ onClick: onSummarize,
1794
+ disabled: isSummarizing,
1795
+ className: `group relative w-full py-4 px-8 rounded-[3rem] transition-all duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] border ${isSummarizing ? "bg-zinc-100 border-zinc-300 opacity-100 cursor-wait shadow-inner" : "bg-gradient-to-b from-white via-zinc-50 to-zinc-100 border-white/70 shadow-[0_10px_30px_-10px_rgba(0,0,0,0.12),inset_0_1px_0_rgba(255,255,255,0.8)] hover:shadow-[0_20px_50px_-15px_rgba(139,92,246,0.3)] hover:-translate-y-[2px] active:scale-[0.98]"}`,
1796
+ children: [
1797
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition duration-700", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 bg-[conic-gradient(from_0deg_at_50%_50%,#c084fc,transparent_60%,#fb7185,transparent_90%)] blur-3xl opacity-20 animate-[spin_10s_linear_infinite]" }) }),
1798
+ /* @__PURE__ */ jsxRuntime.jsx(
1799
+ "span",
1800
+ {
1801
+ className: `absolute inset-0 transition-opacity duration-700 bg-[radial-gradient(circle_at_50%_50%,rgba(139,92,246,0.1),transparent_70%)] ${isSummarizing ? "opacity-100" : "opacity-0"}`
1802
+ }
1803
+ ),
1804
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center gap-4", children: [
1805
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1806
+ @keyframes kernel-pop {
1807
+ 0% { transform: translate(0, 0) scale(0) rotate(0deg); opacity: 0; }
1808
+ 10% { opacity: 1; transform: translate(var(--tx1), var(--ty1)) scale(1.3) rotate(45deg); }
1809
+ 40% { transform: translate(var(--tx2), var(--ty2)) scale(1) rotate(180deg); opacity: 1; }
1810
+ 100% { transform: translate(var(--tx3), var(--ty3)) scale(0.4) rotate(360deg); opacity: 0; }
1811
+ }
1812
+ @keyframes icon-cook {
1813
+ 0%, 100% { transform: scale(1.1) translateY(0); }
1814
+ 50% { transform: scale(0.9, 1.1) translateY(-3px) rotate(3deg); }
1815
+ }
1816
+ .animate-kernel {
1817
+ animation: kernel-pop var(--dur) cubic-bezier(0.34, 1.56, 0.64, 1) infinite;
1818
+ animation-delay: var(--delay);
1819
+ filter: drop-shadow(0 4px 6px rgba(0,0,0,0.15)); /* Added shadow for visibility */
1820
+ }
1821
+ .animate-cook { animation: icon-cook 0.3s ease-in-out infinite; }
1822
+ ` }),
1823
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
1824
+ /* @__PURE__ */ jsxRuntime.jsx(PopcornIcon, { isSummarizing }),
1825
+ isSummarizing && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", children: [
1826
+ /* @__PURE__ */ jsxRuntime.jsx(
1827
+ "svg",
1828
+ {
1829
+ className: "animate-kernel absolute w-4 h-4",
1830
+ style: {
1831
+ "--dur": "1.2s",
1832
+ "--delay": "0s",
1833
+ "--tx1": "-18px",
1834
+ "--ty1": "-22px",
1835
+ "--tx2": "-28px",
1836
+ "--ty2": "-28px",
1837
+ "--tx3": "-38px",
1838
+ "--ty3": "12px"
1839
+ },
1840
+ viewBox: "0 0 24 24",
1841
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1842
+ "path",
1843
+ {
1844
+ d: "M12 2a4 4 0 0 0-4 4 4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0 4-4 4 4 0 0 0-4-4 4 4 0 0 0-4-4z",
1845
+ fill: "#FBBF24",
1846
+ stroke: "#F59E0B",
1847
+ strokeWidth: "0.5"
1848
+ }
1849
+ )
1850
+ }
1851
+ ),
1852
+ /* @__PURE__ */ jsxRuntime.jsx(
1853
+ "svg",
1854
+ {
1855
+ className: "animate-kernel absolute w-3.5 h-3.5",
1856
+ style: {
1857
+ "--dur": "1.5s",
1858
+ "--delay": "0.3s",
1859
+ "--tx1": "18px",
1860
+ "--ty1": "-28px",
1861
+ "--tx2": "28px",
1862
+ "--ty2": "-38px",
1863
+ "--tx3": "38px",
1864
+ "--ty3": "18px"
1865
+ },
1866
+ viewBox: "0 0 24 24",
1867
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1868
+ "path",
1869
+ {
1870
+ d: "M12 3c-2 0-3 1-4 2-1-1-3-1-4 1-1 2 0 4 1 5-1 1-1 3 1 4 2 1 4 0 6-1 2 1 4 2 6 1 2-1 2-3 1-4 1-1 2-3 1-5-1-2-3-2-4-1-1-1-2-2-4-2z",
1871
+ fill: "#FDE68A",
1872
+ stroke: "#FBBF24",
1873
+ strokeWidth: "0.5"
1874
+ }
1875
+ )
1876
+ }
1877
+ ),
1878
+ /* @__PURE__ */ jsxRuntime.jsx(
1879
+ "svg",
1880
+ {
1881
+ className: "animate-kernel absolute w-4 h-4",
1882
+ style: {
1883
+ "--dur": "1.8s",
1884
+ "--delay": "0.7s",
1885
+ "--tx1": "-2px",
1886
+ "--ty1": "-28px",
1887
+ "--tx2": "5px",
1888
+ "--ty2": "-48px",
1889
+ "--tx3": "10px",
1890
+ "--ty3": "18px"
1891
+ },
1892
+ viewBox: "0 0 24 24",
1893
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1894
+ "path",
1895
+ {
1896
+ d: "M12 2a4 4 0 0 0-4 4 4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0 4-4 4 4 0 0 0-4-4 4 4 0 0 0-4-4z",
1897
+ fill: "#FEF3C7"
1898
+ }
1899
+ )
1900
+ }
1901
+ )
1902
+ ] })
1903
+ ] }),
1904
+ /* @__PURE__ */ jsxRuntime.jsx(
1905
+ "span",
1906
+ {
1907
+ className: `text-[12px] font-bold tracking-[0.25em] uppercase transition-all duration-300 ${isSummarizing ? "text-violet-700" : "text-zinc-500 group-hover:text-zinc-900"}`,
1908
+ children: isSummarizing ? "Summarizing..." : "Summarize Scene"
1909
+ }
1910
+ )
1911
+ ] }),
1912
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute bottom-0 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-white/40 to-transparent" })
1913
+ ]
1914
+ }
1915
+ );
1916
+ };
1917
+ var summarize_button_default = SummarizeButton;
1756
1918
  function ScriptBreakdownSceneView({
1757
1919
  blocks,
1758
1920
  characters,
@@ -1998,7 +2160,7 @@ function ScriptBreakdownSceneView({
1998
2160
  value: sceneBrief,
1999
2161
  onChange: (e) => setSceneBrief(e.target.value),
2000
2162
  placeholder: "Write a brief description or notes for this scene...",
2001
- className: "w-full min-h-[120px] bg-transparent outline-none resize-y text-zinc-700 placeholder:text-zinc-400 text-sm md:text-base custom-scrollbar font-sans",
2163
+ className: "w-full min-h-[120px] bg-transparent outline-none resize-y text-zinc-700 placeholder:text-zinc-400 text-sm md:text-base custom-scrollbar font-sans select-none",
2002
2164
  style: {
2003
2165
  lineHeight: "1.6"
2004
2166
  }
@@ -2006,27 +2168,15 @@ function ScriptBreakdownSceneView({
2006
2168
  ) })
2007
2169
  ] })
2008
2170
  ] }),
2009
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full lg:w-80 flex-shrink-0 flex flex-col gap-6 sticky top-6", children: [
2010
- /* @__PURE__ */ jsxRuntime.jsxs(
2011
- "button",
2171
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex flex-col gap-6 sticky top-6", children: [
2172
+ /* @__PURE__ */ jsxRuntime.jsx(
2173
+ summarize_button_default,
2012
2174
  {
2013
- onClick: onSummarize,
2014
- disabled: isSummarizing,
2015
- className: `group relative w-full py-4 px-6 rounded-[3rem] overflow-hidden bg-gradient-to-b from-white via-zinc-50 to-zinc-100 border border-white/70 shadow-[0_10px_30px_-10px_rgba(0,0,0,0.15),inset_0_1px_0_rgba(255,255,255,0.9)] transition-all duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] ${isSummarizing ? "opacity-70 cursor-wait" : "hover:shadow-[0_20px_50px_-15px_rgba(139,92,246,0.35)] hover:-translate-y-[2px] active:scale-[0.97]"}`,
2016
- children: [
2017
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition duration-700", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 bg-[conic-gradient(from_180deg_at_50%_50%,#8b5cf6,transparent_40%,#d946ef,transparent_70%)] blur-2xl opacity-30 animate-[spin_6s_linear_infinite]" }) }),
2018
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition duration-500 bg-[radial-gradient(circle_at_50%_40%,rgba(139,92,246,0.18),transparent_70%)]" }),
2019
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-[1px] rounded-[inherit] bg-gradient-to-b from-white/90 to-transparent pointer-events-none" }),
2020
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -left-[100%] top-0 h-full w-[60%] bg-gradient-to-r from-transparent via-white/60 to-transparent skew-x-[-20deg] group-hover:left-[120%] transition-all duration-[1200ms]" }) }),
2021
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-[2px] rounded-[inherit] opacity-0 group-hover:opacity-100 bg-gradient-to-r from-violet-200/40 via-white/40 to-fuchsia-200/40 blur-md transition duration-500" }),
2022
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center gap-3", children: [
2023
- isSummarizing ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-4 h-4 text-violet-500 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-4 h-4 text-violet-500 transition-all duration-500 group-hover:-rotate-12 group-hover:scale-125" }),
2024
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold tracking-[0.32em] uppercase text-zinc-800 group-hover:text-zinc-950 transition-all duration-300", children: isSummarizing ? "Summarizing..." : "Summarize Scene" })
2025
- ] })
2026
- ]
2175
+ isSummarizing,
2176
+ onSummarize
2027
2177
  }
2028
2178
  ),
2029
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white/50 backdrop-blur-2xl border border-white shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-[2.5rem] p-8", children: [
2179
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white/50 backdrop-blur-2xl border border-white shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-[2.5rem] p-8 w-full", children: [
2030
2180
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-xs font-extrabold text-slate-800 uppercase tracking-[0.25em] mb-8 flex items-center gap-3", children: [
2031
2181
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-8 h-8 rounded-full bg-white/80 shadow-[0_4px_15px_rgb(0,0,0,0.04)] border border-white", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tags, { className: "w-3.5 h-3.5 text-slate-500" }) }),
2032
2182
  "Tags",
@@ -2138,96 +2288,39 @@ function ScriptBreakdownSceneView({
2138
2288
  ] })
2139
2289
  ] }) });
2140
2290
  }
2141
- function useScriptBreakdown({
2142
- scenes
2143
- }) {
2144
- const [parsedScenes, setParsedScenes] = react.useState(scenes || []);
2145
- const [isLoading, setIsLoading] = react.useState(false);
2146
- const [error, setError] = react.useState(null);
2147
- const [hasFetchedFallback, setHasFetchedFallback] = react.useState(false);
2148
- react.useEffect(() => {
2149
- if (scenes && scenes.length > 0) {
2150
- setParsedScenes(scenes);
2151
- return;
2152
- }
2153
- if (hasFetchedFallback) return;
2154
- const fetchFallback = async () => {
2155
- setIsLoading(true);
2156
- setHasFetchedFallback(true);
2157
- try {
2158
- const response = await fetch(
2159
- "https://pub-4c2073ce6f434c4e92ed33f8e1c7f9ea.r2.dev/screenplay%20(1).sbx"
2160
- );
2161
- if (!response.ok) {
2162
- throw new Error(
2163
- `Failed to fetch fallback script: ${response.status}`
2164
- );
2165
- }
2166
- let text = await response.text();
2167
- if (text.includes("<div")) {
2168
- const textarea = document.createElement("textarea");
2169
- textarea.innerHTML = text;
2170
- text = textarea.value;
2171
- }
2172
- const parser = new DOMParser();
2173
- const doc = parser.parseFromString(text, "text/html");
2174
- const divs = Array.from(doc.querySelectorAll("div"));
2175
- const extractedScenes = [];
2176
- let currentSceneNumber = "1";
2177
- let currentContent = "";
2178
- let hasSeenFirstSceneHeading = false;
2179
- divs.forEach((div) => {
2180
- var _a;
2181
- const isSceneHeading = div.classList.contains("divtype0");
2182
- const divText = ((_a = div.textContent) == null ? void 0 : _a.trim()) || "";
2183
- if (!divText) return;
2184
- if (isSceneHeading) {
2185
- if (hasSeenFirstSceneHeading) {
2186
- extractedScenes.push({
2187
- scene_number: currentSceneNumber,
2188
- content: currentContent.trim()
2189
- });
2190
- currentContent = "";
2191
- }
2192
- hasSeenFirstSceneHeading = true;
2193
- currentSceneNumber = div.getAttribute("data-scene") || String(extractedScenes.length + 1);
2194
- }
2195
- currentContent += div.outerHTML + "\n";
2196
- });
2197
- if (currentContent.trim()) {
2198
- extractedScenes.push({
2199
- scene_number: currentSceneNumber,
2200
- content: currentContent.trim()
2201
- });
2202
- }
2203
- setParsedScenes(extractedScenes);
2204
- } catch (err) {
2205
- console.error("Error fetching fallback script:", err);
2206
- setError(err instanceof Error ? err : new Error("Unknown error"));
2207
- } finally {
2208
- setIsLoading(false);
2209
- }
2210
- };
2211
- fetchFallback();
2212
- }, [scenes, hasFetchedFallback]);
2213
- return { scenes: parsedScenes, isLoading, error };
2214
- }
2215
- var use_script_breakdown_default = useScriptBreakdown;
2216
-
2217
- // app/hook/use-script-breakdown-scene.ts
2218
- function useScriptBreakdownScene(sceneNumber) {
2219
- const { scenes, isLoading, error } = use_script_breakdown_default({ scenes: [] });
2291
+ function useScriptBreakdownScene(scene_url, fetchOptions, onAISummarize, onTagAdded, onTagRemoved) {
2220
2292
  const [tags, setTags] = react.useState([]);
2221
2293
  const [selectionMenu, setSelectionMenu] = react.useState(null);
2222
2294
  const autoTaggedSceneRef = react.useRef(null);
2295
+ const [scene, setScene] = react.useState(null);
2223
2296
  const [menuPlacement, setMenuPlacement] = react.useState("top");
2224
2297
  const [subLocations, setSubLocations] = react.useState([]);
2225
2298
  const [sceneBrief, setSceneBrief] = react.useState("");
2226
2299
  const [isSummarizing, setIsSummarizing] = react.useState(false);
2300
+ const [isLoading, setIsLoading] = react.useState(true);
2301
+ const [error, setError] = react.useState(false);
2227
2302
  const menuRef = react.useRef(null);
2228
- const scene = react.useMemo(() => {
2229
- return scenes.find((s) => s.scene_number === sceneNumber);
2230
- }, [scenes, sceneNumber]);
2303
+ react.useEffect(() => {
2304
+ setIsLoading(true);
2305
+ const fetchScene = async () => {
2306
+ try {
2307
+ const response = await fetch(scene_url, fetchOptions);
2308
+ if (response.ok) {
2309
+ const text = await response.text();
2310
+ setScene({ content: text });
2311
+ } else {
2312
+ console.error("Failed to fetch scene:", response);
2313
+ setError(true);
2314
+ }
2315
+ setIsLoading(false);
2316
+ } catch (error2) {
2317
+ setError(true);
2318
+ setIsLoading(false);
2319
+ console.error("Error fetching scene:", error2);
2320
+ }
2321
+ };
2322
+ fetchScene();
2323
+ }, []);
2231
2324
  const blocks = react.useMemo(() => {
2232
2325
  if (!scene || !scene.content) return [];
2233
2326
  const parser = new DOMParser();
@@ -2269,24 +2362,15 @@ function useScriptBreakdownScene(sceneNumber) {
2269
2362
  }, [blocks]);
2270
2363
  const handleAISummarize = async () => {
2271
2364
  setIsSummarizing(true);
2272
- const res = await fetch(
2273
- "https://nonfibrous-extrafloral-verlene.ngrok-free.dev/extract",
2274
- {
2275
- method: "POST",
2276
- headers: {
2277
- "Content-Type": "application/json",
2278
- "ngrok-skip-browser-warning": "true"
2279
- },
2280
- body: JSON.stringify({
2281
- script: (scene == null ? void 0 : scene.content) || ""
2282
- })
2283
- }
2284
- );
2365
+ const res = await (onAISummarize == null ? void 0 : onAISummarize(scene.content));
2285
2366
  if (res.ok) {
2286
2367
  const data = await res.json();
2287
2368
  setIsSummarizing(false);
2288
- const parsedData = JSON.parse(data.data) || [];
2289
- console.log("AI Tags:", parsedData);
2369
+ const normalData = JSON.parse(data.data);
2370
+ const parsedData = Array.isArray(normalData) ? normalData[0] : [];
2371
+ const summary = Array.isArray(normalData) ? normalData[1] : "";
2372
+ const parsedSummaryData = summary[0];
2373
+ setSceneBrief(parsedSummaryData.summarise);
2290
2374
  const newTags = [];
2291
2375
  parsedData.forEach((aiTag) => {
2292
2376
  if (!aiTag.block_id || !aiTag.category_id || typeof aiTag.start_index !== "number" || typeof aiTag.end_index !== "number") {
@@ -2335,9 +2419,9 @@ function useScriptBreakdownScene(sceneNumber) {
2335
2419
  setSubLocations([]);
2336
2420
  setSceneBrief("");
2337
2421
  autoTaggedSceneRef.current = null;
2338
- }, [sceneNumber]);
2422
+ }, [scene_url]);
2339
2423
  react.useEffect(() => {
2340
- if (blocks.length > 0 && characters.length > 0 && autoTaggedSceneRef.current !== sceneNumber) {
2424
+ if (blocks.length > 0 && characters.length > 0 && autoTaggedSceneRef.current !== scene) {
2341
2425
  const autoTags = [];
2342
2426
  const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2343
2427
  const sortedChars = [...characters].sort((a, b) => b.length - a.length);
@@ -2367,9 +2451,9 @@ function useScriptBreakdownScene(sceneNumber) {
2367
2451
  });
2368
2452
  });
2369
2453
  setTags(autoTags);
2370
- autoTaggedSceneRef.current = sceneNumber;
2454
+ autoTaggedSceneRef.current = scene;
2371
2455
  }
2372
- }, [blocks, characters, sceneNumber]);
2456
+ }, [blocks, characters, scene]);
2373
2457
  const clearSelection = react.useCallback(() => {
2374
2458
  var _a;
2375
2459
  setSelectionMenu(null);
@@ -2456,7 +2540,7 @@ function useScriptBreakdownScene(sceneNumber) {
2456
2540
  });
2457
2541
  }
2458
2542
  };
2459
- const addTag = (categoryId) => {
2543
+ const addTag = async (categoryId) => {
2460
2544
  if (!selectionMenu) return;
2461
2545
  const newTag = {
2462
2546
  id: uuid(),
@@ -2473,12 +2557,26 @@ function useScriptBreakdownScene(sceneNumber) {
2473
2557
  return [...filtered, newTag];
2474
2558
  });
2475
2559
  clearSelection();
2560
+ try {
2561
+ await (onTagAdded == null ? void 0 : onTagAdded(newTag));
2562
+ } catch (error2) {
2563
+ console.error("Failed to add tag:", error2);
2564
+ setTags((prev) => prev.filter((t) => t.id !== newTag.id));
2565
+ }
2476
2566
  };
2477
- const removeTag = (e, id) => {
2567
+ const removeTag = async (e, id) => {
2478
2568
  e.stopPropagation();
2479
2569
  e.preventDefault();
2570
+ const tagToRemove = tags.find((t) => t.id === id);
2571
+ if (!tagToRemove) return;
2480
2572
  setTags((prev) => prev.filter((t) => t.id !== id));
2481
2573
  clearSelection();
2574
+ try {
2575
+ await (onTagRemoved == null ? void 0 : onTagRemoved(id));
2576
+ } catch (error2) {
2577
+ console.error("Failed to remove tag:", error2);
2578
+ setTags((prev) => [...prev, tagToRemove]);
2579
+ }
2482
2580
  };
2483
2581
  return {
2484
2582
  scene,