@effectnode/media 0.1.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 (133) hide show
  1. package/bin/effectnode-media +2 -0
  2. package/dist/backend/index.d.ts +8 -0
  3. package/dist/backend/index.js +13 -0
  4. package/dist/backend/movie-backend/agent/agent-backend.d.ts +16 -0
  5. package/dist/backend/movie-backend/agent/agent-backend.js +703 -0
  6. package/dist/backend/movie-backend/agent/storyprompt.d.ts +1 -0
  7. package/dist/backend/movie-backend/agent/storyprompt.js +90 -0
  8. package/dist/backend/movie-backend/agent/tools/edit-image.d.ts +3 -0
  9. package/dist/backend/movie-backend/agent/tools/edit-image.js +192 -0
  10. package/dist/backend/movie-backend/agent/tools/get-time.d.ts +3 -0
  11. package/dist/backend/movie-backend/agent/tools/get-time.js +7 -0
  12. package/dist/backend/movie-backend/agent/tools/grep-files.d.ts +3 -0
  13. package/dist/backend/movie-backend/agent/tools/grep-files.js +59 -0
  14. package/dist/backend/movie-backend/agent/tools/image-to-video-generation.d.ts +3 -0
  15. package/dist/backend/movie-backend/agent/tools/image-to-video-generation.js +160 -0
  16. package/dist/backend/movie-backend/agent/tools/index.d.ts +7 -0
  17. package/dist/backend/movie-backend/agent/tools/index.js +59 -0
  18. package/dist/backend/movie-backend/agent/tools/list-files.d.ts +3 -0
  19. package/dist/backend/movie-backend/agent/tools/list-files.js +17 -0
  20. package/dist/backend/movie-backend/agent/tools/read-file.d.ts +3 -0
  21. package/dist/backend/movie-backend/agent/tools/read-file.js +28 -0
  22. package/dist/backend/movie-backend/agent/tools/remove-file.d.ts +3 -0
  23. package/dist/backend/movie-backend/agent/tools/remove-file.js +22 -0
  24. package/dist/backend/movie-backend/agent/tools/rename-file.d.ts +3 -0
  25. package/dist/backend/movie-backend/agent/tools/rename-file.js +37 -0
  26. package/dist/backend/movie-backend/agent/tools/show-image.d.ts +3 -0
  27. package/dist/backend/movie-backend/agent/tools/show-image.js +28 -0
  28. package/dist/backend/movie-backend/agent/tools/stitch-videos.d.ts +3 -0
  29. package/dist/backend/movie-backend/agent/tools/stitch-videos.js +96 -0
  30. package/dist/backend/movie-backend/agent/tools/text-to-video-generation.d.ts +3 -0
  31. package/dist/backend/movie-backend/agent/tools/text-to-video-generation.js +125 -0
  32. package/dist/backend/movie-backend/agent/tools/types.d.ts +15 -0
  33. package/dist/backend/movie-backend/agent/tools/types.js +1 -0
  34. package/dist/backend/movie-backend/agent/tools/update-file.d.ts +3 -0
  35. package/dist/backend/movie-backend/agent/tools/update-file.js +27 -0
  36. package/dist/backend/movie-backend/agent/tools/write-file.d.ts +3 -0
  37. package/dist/backend/movie-backend/agent/tools/write-file.js +26 -0
  38. package/dist/backend/movie-backend/agent/workspace.d.ts +25 -0
  39. package/dist/backend/movie-backend/agent/workspace.js +124 -0
  40. package/dist/backend/movie-backend/core.d.ts +4 -0
  41. package/dist/backend/movie-backend/core.js +1167 -0
  42. package/dist/backend/movie-backend/generation-queue.d.ts +24 -0
  43. package/dist/backend/movie-backend/generation-queue.js +766 -0
  44. package/dist/backend/movie-backend/process.d.ts +21 -0
  45. package/dist/backend/movie-backend/process.js +98 -0
  46. package/dist/backend/movie-backend/render-media.d.ts +48 -0
  47. package/dist/backend/movie-backend/render-media.js +3311 -0
  48. package/dist/backend/routes/health.d.ts +1 -0
  49. package/dist/backend/routes/health.js +9 -0
  50. package/dist/backend/routes/index.d.ts +1 -0
  51. package/dist/backend/routes/index.js +11 -0
  52. package/dist/backend/routes/media.d.ts +1 -0
  53. package/dist/backend/routes/media.js +13 -0
  54. package/dist/backend/routes/projects.d.ts +8 -0
  55. package/dist/backend/routes/projects.js +68 -0
  56. package/dist/backend/routes/voice.d.ts +1 -0
  57. package/dist/backend/routes/voice.js +39 -0
  58. package/dist/backend/routes.d.ts +1 -0
  59. package/dist/backend/routes.js +20 -0
  60. package/dist/backend/server.d.ts +1 -0
  61. package/dist/backend/server.js +23 -0
  62. package/dist/backend/workspace.d.ts +5 -0
  63. package/dist/backend/workspace.js +27 -0
  64. package/dist/backend/ws/index.d.ts +3 -0
  65. package/dist/backend/ws/index.js +27 -0
  66. package/dist/backend/ws/messages.d.ts +8 -0
  67. package/dist/backend/ws/messages.js +21 -0
  68. package/dist/backend/ws.d.ts +3 -0
  69. package/dist/backend/ws.js +29 -0
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.js +80 -0
  72. package/frontend/index.html +22 -0
  73. package/frontend/public/ffmpeg/ffmpeg-core.js +16 -0
  74. package/frontend/public/ffmpeg/ffmpeg-core.wasm +0 -0
  75. package/frontend/src/index.css +46 -0
  76. package/frontend/src/main.tsx +13 -0
  77. package/frontend/src/movie-app/AppRouter.tsx +14 -0
  78. package/frontend/src/movie-app/MediaStudio.tsx +9 -0
  79. package/frontend/src/movie-app/SetupPage.tsx +293 -0
  80. package/frontend/src/movie-app/components/AgentWorkspace.tsx +574 -0
  81. package/frontend/src/movie-app/components/ChatUI/ChatUI.tsx +655 -0
  82. package/frontend/src/movie-app/components/ChatUI/MarkdownMessage.tsx +267 -0
  83. package/frontend/src/movie-app/components/EditorTabs/AgentTab.tsx +61 -0
  84. package/frontend/src/movie-app/components/EditorTabs/BatchImageToVideoTab.tsx +927 -0
  85. package/frontend/src/movie-app/components/EditorTabs/BatchVideoTab.tsx +777 -0
  86. package/frontend/src/movie-app/components/EditorTabs/BatchVoiceVideoTab.tsx +913 -0
  87. package/frontend/src/movie-app/components/EditorTabs/CharacterSheet.tsx +234 -0
  88. package/frontend/src/movie-app/components/EditorTabs/CharactersTab.tsx +664 -0
  89. package/frontend/src/movie-app/components/EditorTabs/CropTool.tsx +251 -0
  90. package/frontend/src/movie-app/components/EditorTabs/ExtendVideoTab.tsx +305 -0
  91. package/frontend/src/movie-app/components/EditorTabs/ExtractImageTab.tsx +249 -0
  92. package/frontend/src/movie-app/components/EditorTabs/FastImageEditTab.tsx +555 -0
  93. package/frontend/src/movie-app/components/EditorTabs/GenerateVideoTab.tsx +722 -0
  94. package/frontend/src/movie-app/components/EditorTabs/LlmServerTab.tsx +40 -0
  95. package/frontend/src/movie-app/components/EditorTabs/MlxVlmServerPanel.tsx +490 -0
  96. package/frontend/src/movie-app/components/EditorTabs/MovieStudioTab.tsx +938 -0
  97. package/frontend/src/movie-app/components/EditorTabs/ReferencesToVideoTab.tsx +881 -0
  98. package/frontend/src/movie-app/components/EditorTabs/SceneVisualTab.tsx +267 -0
  99. package/frontend/src/movie-app/components/EditorTabs/StoryWriterTab.tsx +51 -0
  100. package/frontend/src/movie-app/components/EditorTabs/TaskQueuePanel.tsx +246 -0
  101. package/frontend/src/movie-app/components/EditorTabs/TerminalLogPanel.tsx +49 -0
  102. package/frontend/src/movie-app/components/EditorTabs/TextToImageTab.tsx +574 -0
  103. package/frontend/src/movie-app/components/EditorTabs/VoiceChatPanel.tsx +320 -0
  104. package/frontend/src/movie-app/components/ProjectEditorPage.tsx +636 -0
  105. package/frontend/src/movie-app/components/ProjectManager.tsx +381 -0
  106. package/frontend/src/movie-app/index.css +46 -0
  107. package/frontend/src/movie-app/index.html +16 -0
  108. package/frontend/src/movie-app/lambobo.png +0 -0
  109. package/frontend/src/movie-app/lib/batchImageToVideoStorage.ts +69 -0
  110. package/frontend/src/movie-app/lib/batchVideoStorage.ts +68 -0
  111. package/frontend/src/movie-app/lib/batchVoiceStorage.ts +75 -0
  112. package/frontend/src/movie-app/lib/ffmpeg.ts +42 -0
  113. package/frontend/src/movie-app/lib/referencesToVideoStorage.ts +64 -0
  114. package/frontend/src/movie-app/lib/textToImageStorage.ts +61 -0
  115. package/frontend/src/movie-app/public/ffmpeg/ffmpeg-core.js +16 -0
  116. package/frontend/src/movie-app/public/ffmpeg/ffmpeg-core.wasm +0 -0
  117. package/frontend/src/movie-app/stores/batchImageToVideoStore.ts +736 -0
  118. package/frontend/src/movie-app/stores/batchVideoStore.ts +670 -0
  119. package/frontend/src/movie-app/stores/batchVoiceStore.ts +990 -0
  120. package/frontend/src/movie-app/stores/characterStore.ts +109 -0
  121. package/frontend/src/movie-app/stores/chatStore.ts +459 -0
  122. package/frontend/src/movie-app/stores/generationStore.ts +2140 -0
  123. package/frontend/src/movie-app/stores/logStore.ts +25 -0
  124. package/frontend/src/movie-app/stores/movieStudioStore.ts +709 -0
  125. package/frontend/src/movie-app/stores/projectStore.ts +124 -0
  126. package/frontend/src/movie-app/stores/queueStore.ts +214 -0
  127. package/frontend/src/movie-app/stores/referencesToVideoStore.ts +467 -0
  128. package/frontend/src/movie-app/stores/sceneVisualStore.ts +251 -0
  129. package/frontend/src/movie-app/stores/voiceChatStore.ts +170 -0
  130. package/frontend/src/movie-app/stores/workspaceStore.ts +158 -0
  131. package/frontend/src/vite-env.d.ts +1 -0
  132. package/frontend/tsconfig.json +19 -0
  133. package/package.json +65 -0
@@ -0,0 +1,267 @@
1
+ import { isValidElement, useState, type ReactNode } from "react";
2
+ import ReactMarkdown, { type Components } from "react-markdown";
3
+ import remarkGfm from "remark-gfm";
4
+
5
+ interface Props {
6
+ content: string;
7
+ }
8
+
9
+ /** Recursively extract plain text from rendered markdown children. */
10
+ function extractText(node: ReactNode): string {
11
+ if (typeof node === "string" || typeof node === "number") return String(node);
12
+ if (Array.isArray(node)) return node.map(extractText).join("");
13
+ if (isValidElement(node)) {
14
+ const props = node.props as { children?: ReactNode };
15
+ return extractText(props.children);
16
+ }
17
+ return "";
18
+ }
19
+
20
+ const CopyIcon = (
21
+ <svg
22
+ width="12"
23
+ height="12"
24
+ viewBox="0 0 24 24"
25
+ fill="none"
26
+ stroke="currentColor"
27
+ strokeWidth="2"
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ >
31
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
32
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
33
+ </svg>
34
+ );
35
+
36
+ const CheckIcon = (
37
+ <svg
38
+ width="12"
39
+ height="12"
40
+ viewBox="0 0 24 24"
41
+ fill="none"
42
+ stroke="currentColor"
43
+ strokeWidth="2"
44
+ strokeLinecap="round"
45
+ strokeLinejoin="round"
46
+ >
47
+ <polyline points="20 6 9 17 4 12" />
48
+ </svg>
49
+ );
50
+
51
+ interface CodeBlockProps {
52
+ code: string;
53
+ children: ReactNode;
54
+ }
55
+
56
+ function CodeBlock({ code, children }: CodeBlockProps) {
57
+ const [copied, setCopied] = useState(false);
58
+
59
+ const handleCopy = async () => {
60
+ try {
61
+ await navigator.clipboard.writeText(code);
62
+ } catch {
63
+ const ta = document.createElement("textarea");
64
+ ta.value = code;
65
+ ta.style.position = "fixed";
66
+ ta.style.opacity = "0";
67
+ document.body.appendChild(ta);
68
+ ta.select();
69
+ document.execCommand("copy");
70
+ document.body.removeChild(ta);
71
+ }
72
+ setCopied(true);
73
+ window.setTimeout(() => setCopied(false), 1500);
74
+ };
75
+
76
+ return (
77
+ <div className="group relative my-2">
78
+ <button
79
+ onClick={handleCopy}
80
+ className="absolute right-2 top-2 z-10 flex items-center gap-1 rounded-lg border border-tiffany-500 bg-ink-200/80 px-1.5 py-1 text-[10px] font-medium text-ink-800 opacity-0 transition-opacity hover:bg-tiffany-600 focus:opacity-100 group-hover:opacity-100"
81
+ title={copied ? "Copied" : "Copy code"}
82
+ >
83
+ {copied ? CheckIcon : CopyIcon}
84
+ {copied ? "Copied" : "Copy"}
85
+ </button>
86
+ <pre className="overflow-x-auto rounded-xl bg-ink-100/95 p-4 pr-16 text-xs leading-relaxed text-ink-800">
87
+ {children}
88
+ </pre>
89
+ </div>
90
+ );
91
+ }
92
+
93
+ // ===== Story table (id / duration / t2i / i2v) =====
94
+
95
+ type HastNode = {
96
+ type?: string;
97
+ tagName?: string;
98
+ value?: string;
99
+ children?: HastNode[];
100
+ };
101
+
102
+ /** Flatten a HAST node into its plain text content. */
103
+ function hastText(node: HastNode | undefined): string {
104
+ if (!node) return "";
105
+ if (node.type === "text") return node.value ?? "";
106
+ if (Array.isArray(node.children)) return node.children.map(hastText).join("");
107
+ return "";
108
+ }
109
+
110
+ function getHeaderCells(node: HastNode | undefined): HastNode[] {
111
+ const thead = node?.children?.find((c) => c.tagName === "thead");
112
+ const tr = thead?.children?.find((c) => c.tagName === "tr");
113
+ return (tr?.children ?? []).filter((c) => c.tagName === "th");
114
+ }
115
+
116
+ function getBodyRows(node: HastNode | undefined): HastNode[][] {
117
+ const tbody = node?.children?.find((c) => c.tagName === "tbody");
118
+ return (tbody?.children ?? [])
119
+ .filter((c) => c.tagName === "tr")
120
+ .map((tr) => (tr.children ?? []).filter((c) => c.tagName === "td"));
121
+ }
122
+
123
+ /** Return the column index of the `duration` header, or -1 if absent. */
124
+ function getDurationIndex(node: HastNode | undefined): number {
125
+ return getHeaderCells(node).findIndex(
126
+ (th) => hastText(th).trim().toLowerCase() === "duration",
127
+ );
128
+ }
129
+
130
+ function StoryTable({ node }: { node?: HastNode }) {
131
+ const headers = getHeaderCells(node);
132
+ const rows = getBodyRows(node);
133
+
134
+ return (
135
+ <div className="my-2 overflow-x-auto rounded-xl border border-ink-200">
136
+ <table className="w-full border-collapse text-xs">
137
+ <thead className="bg-ink-50">
138
+ <tr className="border-b border-ink-200">
139
+ {headers.map((th, i) => (
140
+ <th
141
+ key={i}
142
+ className="whitespace-nowrap border border-ink-200 px-2 py-1 text-left font-semibold text-ink-700"
143
+ >
144
+ {hastText(th)}
145
+ </th>
146
+ ))}
147
+ </tr>
148
+ </thead>
149
+ <tbody>
150
+ {rows.map((cells, ri) => (
151
+ <tr key={ri} className="border-b border-ink-200">
152
+ {cells.map((cell, ci) => (
153
+ <td
154
+ key={ci}
155
+ className="border border-ink-200 px-2 py-1 align-top text-ink-800"
156
+ >
157
+ {hastText(cell)}
158
+ </td>
159
+ ))}
160
+ </tr>
161
+ ))}
162
+ </tbody>
163
+ </table>
164
+ </div>
165
+ );
166
+ }
167
+
168
+ const components: Components = {
169
+ p: ({ children }) => (
170
+ <p className="my-1 leading-relaxed first:mt-0 last:mb-0">{children}</p>
171
+ ),
172
+ strong: ({ children }) => (
173
+ <strong className="font-semibold text-ink-900">{children}</strong>
174
+ ),
175
+ em: ({ children }) => <em className="italic">{children}</em>,
176
+ a: ({ href, children }) => (
177
+ <a
178
+ href={href}
179
+ target="_blank"
180
+ rel="noreferrer"
181
+ className="text-tiffany-700 underline hover:text-tiffany-800"
182
+ >
183
+ {children}
184
+ </a>
185
+ ),
186
+ ul: ({ children }) => (
187
+ <ul className="my-1 list-disc pl-5 space-y-0.5">{children}</ul>
188
+ ),
189
+ ol: ({ children }) => (
190
+ <ol className="my-1 list-decimal pl-5 space-y-0.5">{children}</ol>
191
+ ),
192
+ li: ({ children }) => <li className="leading-relaxed">{children}</li>,
193
+ blockquote: ({ children }) => (
194
+ <blockquote className="my-1 border-l-2 border-ink-300 pl-3 italic text-ink-600">
195
+ {children}
196
+ </blockquote>
197
+ ),
198
+ hr: () => <hr className="my-2 border-ink-200" />,
199
+ h1: ({ children }) => (
200
+ <h1 className="mb-1 mt-2 text-base font-bold text-ink-900">{children}</h1>
201
+ ),
202
+ h2: ({ children }) => (
203
+ <h2 className="mb-1 mt-2 text-sm font-bold text-ink-900">{children}</h2>
204
+ ),
205
+ h3: ({ children }) => (
206
+ <h3 className="mb-1 mt-2 text-[13px] font-semibold text-ink-800">
207
+ {children}
208
+ </h3>
209
+ ),
210
+ h4: ({ children }) => (
211
+ <h4 className="mb-1 mt-1.5 text-xs font-semibold text-ink-800">
212
+ {children}
213
+ </h4>
214
+ ),
215
+ h5: ({ children }) => (
216
+ <h5 className="mb-0.5 mt-1 text-xs font-medium text-ink-700">{children}</h5>
217
+ ),
218
+ h6: ({ children }) => (
219
+ <h6 className="mb-0.5 mt-1 text-xs font-medium text-ink-700">{children}</h6>
220
+ ),
221
+ table: ({ node, children }) => {
222
+ if (getDurationIndex(node) >= 0) {
223
+ return <StoryTable node={node} />;
224
+ }
225
+ return (
226
+ <div className="my-2 overflow-x-auto rounded-xl border border-ink-200">
227
+ <table className="w-full border-collapse text-xs">{children}</table>
228
+ </div>
229
+ );
230
+ },
231
+ thead: ({ children }) => <thead className="bg-ink-50">{children}</thead>,
232
+ tr: ({ children }) => <tr className="border-b border-ink-200">{children}</tr>,
233
+ th: ({ children }) => (
234
+ <th className="whitespace-nowrap border border-ink-200 px-2 py-1 text-left font-semibold text-ink-700">
235
+ {children}
236
+ </th>
237
+ ),
238
+ td: ({ children }) => (
239
+ <td className="border border-ink-200 px-2 py-1 align-top text-ink-800">
240
+ {children}
241
+ </td>
242
+ ),
243
+ pre: ({ children }) => (
244
+ <CodeBlock code={extractText(children)}>{children}</CodeBlock>
245
+ ),
246
+ code: ({ className, children }) => {
247
+ const isBlock = /language-/.test(className ?? "");
248
+ if (isBlock) {
249
+ return <code className="font-mono">{children}</code>;
250
+ }
251
+ return (
252
+ <code className="rounded bg-ink-100 px-1.5 py-0.5 font-mono text-[11px] text-ink-700">
253
+ {children}
254
+ </code>
255
+ );
256
+ },
257
+ };
258
+
259
+ export function MarkdownMessage({ content }: Props) {
260
+ return (
261
+ <div className="font-serif">
262
+ <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>
263
+ {content}
264
+ </ReactMarkdown>
265
+ </div>
266
+ );
267
+ }
@@ -0,0 +1,61 @@
1
+ import { useGenerationStore } from "../../stores/generationStore";
2
+ import { ChatUI } from "../ChatUI/ChatUI";
3
+ import AgentWorkspace from "../AgentWorkspace";
4
+ import MlxVlmServerPanel from "./MlxVlmServerPanel";
5
+ // import MlxVlmServerPanel from "./MlxVlmServerPanel";
6
+
7
+ interface Props {
8
+ projectId: string;
9
+ }
10
+
11
+ export default function AgentTab({ projectId }: Props) {
12
+ const store = useGenerationStore();
13
+
14
+ // ========== SVG Icons ==========
15
+
16
+ const AgentIcon = (
17
+ <svg
18
+ width="18"
19
+ height="18"
20
+ viewBox="0 0 24 24"
21
+ fill="none"
22
+ stroke="currentColor"
23
+ strokeWidth="2"
24
+ strokeLinecap="round"
25
+ strokeLinejoin="round"
26
+ >
27
+ <rect x="4" y="4" width="16" height="16" rx="2" />
28
+ <circle cx="9" cy="9" r="1" />
29
+ <circle cx="15" cy="9" r="1" />
30
+ <line x1="9" y1="14" x2="15" y2="14" />
31
+ </svg>
32
+ );
33
+
34
+ return (
35
+ <div className="flex flex-col gap-7">
36
+ <div className="flex items-center gap-2">
37
+ <span className="text-tiffany-600">{AgentIcon}</span>
38
+ <h2 className="text-base font-semibold text-ink-900">Agent</h2>
39
+ </div>
40
+
41
+ {store.agent.serverRunning && store.agent.serverOnline ? null : (
42
+ <MlxVlmServerPanel />
43
+ )}
44
+
45
+ {store.agent.serverRunning && store.agent.serverOnline ? (
46
+ <div className="">
47
+ <ChatUI projectId={projectId} />
48
+ <div className="h-4" />
49
+ <AgentWorkspace projectId={projectId} />
50
+ </div>
51
+ ) : (
52
+ <div className="flex flex-col items-center justify-center gap-2 p-8 border border-dashed border-ink-200 rounded-2xl">
53
+ <span className="text-ink-500">{AgentIcon}</span>
54
+ <p className="text-xs text-ink-500 italic">
55
+ Start the LLM server to chat with the agent.{" "}
56
+ </p>
57
+ </div>
58
+ )}
59
+ </div>
60
+ );
61
+ }