strapi-content-embeddings 0.2.0 → 0.2.2

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 (38) hide show
  1. package/dist/_chunks/en-B4KWt_jN.js +0 -1
  2. package/dist/_chunks/en-Byx4XI2L.mjs +0 -1
  3. package/dist/admin/index.js +754 -4
  4. package/dist/admin/index.mjs +751 -4
  5. package/dist/server/index.js +234 -231
  6. package/dist/server/index.mjs +234 -231
  7. package/dist/server/src/index.d.ts +5 -0
  8. package/dist/server/src/mcp/schemas/index.d.ts +3 -0
  9. package/dist/server/src/mcp/tools/create-embedding.d.ts +3 -4
  10. package/dist/server/src/mcp/tools/get-embedding.d.ts +3 -3
  11. package/dist/server/src/mcp/tools/index.d.ts +1 -0
  12. package/dist/server/src/mcp/tools/list-embeddings.d.ts +3 -3
  13. package/dist/server/src/mcp/tools/rag-query.d.ts +3 -3
  14. package/dist/server/src/mcp/tools/semantic-search.d.ts +3 -3
  15. package/dist/server/src/services/ai-tools.d.ts +13 -0
  16. package/dist/server/src/services/index.d.ts +5 -0
  17. package/dist/server/src/tools/create-embedding.d.ts +9 -0
  18. package/dist/server/src/tools/get-embedding.d.ts +8 -0
  19. package/dist/server/src/tools/index.d.ts +14 -0
  20. package/dist/server/src/tools/list-embeddings.d.ts +8 -0
  21. package/dist/server/src/tools/rag-query.d.ts +8 -0
  22. package/dist/server/src/tools/semantic-search.d.ts +8 -0
  23. package/dist/server/src/tools/types.d.ts +14 -0
  24. package/package.json +3 -3
  25. package/dist/_chunks/App-ByRBbkZn.js +0 -1600
  26. package/dist/_chunks/App-ByRBbkZn.js.map +0 -1
  27. package/dist/_chunks/App-MjsTrWRS.mjs +0 -1596
  28. package/dist/_chunks/App-MjsTrWRS.mjs.map +0 -1
  29. package/dist/_chunks/en-B4KWt_jN.js.map +0 -1
  30. package/dist/_chunks/en-Byx4XI2L.mjs.map +0 -1
  31. package/dist/_chunks/index-TWbcT-zJ.js +0 -785
  32. package/dist/_chunks/index-TWbcT-zJ.js.map +0 -1
  33. package/dist/_chunks/index-ifqYByO5.mjs +0 -783
  34. package/dist/_chunks/index-ifqYByO5.mjs.map +0 -1
  35. package/dist/admin/index.js.map +0 -1
  36. package/dist/admin/index.mjs.map +0 -1
  37. package/dist/server/index.js.map +0 -1
  38. package/dist/server/index.mjs.map +0 -1
@@ -1,6 +1,753 @@
1
- import { i } from "../_chunks/index-ifqYByO5.mjs";
2
- import "react/jsx-runtime";
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
+ import { useRef, useEffect, useState, useCallback } from "react";
3
+ import { Box, Typography, Loader, Button, Modal, Field, TextInput, SingleSelect, SingleSelectOption, Flex } from "@strapi/design-system";
4
+ import { useNavigate } from "react-router-dom";
5
+ import styled, { createGlobalStyle } from "styled-components";
6
+ import qs from "qs";
7
+ import { useFetchClient, useNotification, unstable_useContentManagerContext } from "@strapi/strapi/admin";
8
+ import { Eye, Plus } from "@strapi/icons";
9
+ import { MDXEditor, headingsPlugin, listsPlugin, quotePlugin, thematicBreakPlugin, linkPlugin, linkDialogPlugin, markdownShortcutPlugin, toolbarPlugin, UndoRedo, Separator, BlockTypeSelect, BoldItalicUnderlineToggles, CreateLink, ListsToggle } from "@mdxeditor/editor";
10
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
11
+ const v = glob[path];
12
+ if (v) {
13
+ return typeof v === "function" ? v() : Promise.resolve(v);
14
+ }
15
+ return new Promise((_, reject) => {
16
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
17
+ reject.bind(
18
+ null,
19
+ new Error(
20
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
21
+ )
22
+ )
23
+ );
24
+ });
25
+ };
26
+ const PLUGIN_ID = "strapi-content-embeddings";
27
+ const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
28
+ const Initializer = ({ setPlugin }) => {
29
+ const ref = useRef(setPlugin);
30
+ useEffect(() => {
31
+ ref.current(PLUGIN_ID);
32
+ }, []);
33
+ return null;
34
+ };
35
+ const MDXEditorStyles = createGlobalStyle`
36
+ /* MDXEditor CSS Variables */
37
+ :root {
38
+ --mdx-spacing-0_5: 0.125rem;
39
+ --mdx-spacing-1: 0.25rem;
40
+ --mdx-spacing-1_5: 0.375rem;
41
+ --mdx-spacing-2: 0.5rem;
42
+ --mdx-spacing-3: 0.75rem;
43
+ --mdx-spacing-4: 1rem;
44
+ --mdx-spacing-36: 9rem;
45
+ --mdx-radius-base: 0.25rem;
46
+ --mdx-radius-medium: 0.375rem;
47
+ --mdx-text-sm: 0.875rem;
48
+ --mdx-baseBg: #f6f6f9;
49
+ --mdx-baseBgActive: #e8e8ec;
50
+ --mdx-basePageBg: #ffffff;
51
+ --mdx-baseBorder: #dcdce4;
52
+ --mdx-baseBorderHover: #b9bbc6;
53
+ --mdx-baseBase: #e0e1e6;
54
+ --mdx-baseTextContrast: #1c2024;
55
+ --mdx-accentText: #4945ff;
56
+ }
57
+
58
+ /* Toolbar Root - critical for horizontal layout */
59
+ [class*="_toolbarRoot"] {
60
+ z-index: 2;
61
+ display: flex !important;
62
+ flex-direction: row !important;
63
+ flex-wrap: wrap !important;
64
+ gap: var(--mdx-spacing-1);
65
+ border-radius: var(--mdx-radius-medium);
66
+ padding: var(--mdx-spacing-1_5);
67
+ align-items: center !important;
68
+ overflow-x: auto;
69
+ position: sticky;
70
+ top: 0;
71
+ background-color: var(--mdx-baseBg) !important;
72
+ border-bottom: 1px solid var(--mdx-baseBorder);
73
+ width: 100%;
74
+ }
75
+
76
+ [class*="_toolbarRoot"] div[role='separator'] {
77
+ margin: var(--mdx-spacing-2) var(--mdx-spacing-1);
78
+ border-left: 1px solid var(--mdx-baseBorder);
79
+ border-right: 1px solid var(--mdx-baseBase);
80
+ height: var(--mdx-spacing-4);
81
+ }
82
+
83
+ [class*="_toolbarRoot"] svg {
84
+ color: var(--mdx-baseTextContrast);
85
+ display: block;
86
+ }
87
+
88
+ /* Toolbar button groups */
89
+ [class*="_toolbarGroupOfGroups"] {
90
+ display: flex;
91
+ margin: 0 var(--mdx-spacing-1);
92
+ }
93
+
94
+ [class*="_toolbarToggleSingleGroup"] {
95
+ display: flex;
96
+ align-items: center;
97
+ white-space: nowrap;
98
+ }
99
+
100
+ /* Toolbar buttons and toggle items */
101
+ [class*="_toolbarToggleItem"],
102
+ [class*="_toolbarButton"] {
103
+ border: 0;
104
+ background-color: transparent;
105
+ font-size: inherit;
106
+ appearance: none;
107
+ box-sizing: border-box;
108
+ cursor: pointer;
109
+ padding: var(--mdx-spacing-0_5);
110
+ border-radius: var(--mdx-radius-base);
111
+ }
112
+
113
+ [class*="_toolbarToggleItem"]:hover,
114
+ [class*="_toolbarButton"]:hover {
115
+ background-color: var(--mdx-baseBgActive);
116
+ }
117
+
118
+ [class*="_toolbarToggleItem"][data-state='on'],
119
+ [class*="_toolbarButton"][data-state='on'],
120
+ [class*="_toolbarToggleItem"]:active,
121
+ [class*="_toolbarButton"]:active {
122
+ color: var(--mdx-baseTextContrast);
123
+ background-color: var(--mdx-baseBgActive);
124
+ }
125
+
126
+ /* Block type select dropdown */
127
+ [class*="_toolbarNodeKindSelectTrigger"],
128
+ [class*="_selectTrigger"] {
129
+ border: 0;
130
+ display: flex;
131
+ color: inherit;
132
+ align-items: center;
133
+ width: var(--mdx-spacing-36);
134
+ padding: var(--mdx-spacing-0_5) var(--mdx-spacing-1);
135
+ padding-inline-start: var(--mdx-spacing-2);
136
+ border-radius: var(--mdx-radius-medium);
137
+ white-space: nowrap;
138
+ font-size: var(--mdx-text-sm);
139
+ background-color: var(--mdx-basePageBg);
140
+ margin: 0 var(--mdx-spacing-1);
141
+ cursor: pointer;
142
+ }
143
+
144
+ /* Dropdown containers */
145
+ [class*="_toolbarNodeKindSelectContainer"],
146
+ [class*="_selectContainer"] {
147
+ filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.2));
148
+ z-index: 100;
149
+ width: var(--mdx-spacing-36);
150
+ border-radius: var(--mdx-radius-base);
151
+ background-color: var(--mdx-basePageBg);
152
+ font-size: var(--mdx-text-sm);
153
+ }
154
+
155
+ /* Select items */
156
+ [class*="_toolbarNodeKindSelectItem"],
157
+ [class*="_selectItem"] {
158
+ cursor: pointer;
159
+ display: flex;
160
+ padding: var(--mdx-spacing-2);
161
+ }
162
+
163
+ [class*="_toolbarNodeKindSelectItem"][data-highlighted],
164
+ [class*="_selectItem"][data-highlighted],
165
+ [class*="_toolbarNodeKindSelectItem"][data-state='checked'],
166
+ [class*="_selectItem"][data-state='checked'] {
167
+ background-color: var(--mdx-baseBg);
168
+ outline: none;
169
+ }
170
+
171
+ /* Dropdown arrow */
172
+ [class*="_selectDropdownArrow"] {
173
+ margin-left: auto;
174
+ display: flex;
175
+ align-items: center;
176
+ }
177
+
178
+ /* Content editable area */
179
+ [class*="_contentEditable"] {
180
+ box-sizing: border-box;
181
+ width: 100%;
182
+ color: var(--mdx-baseTextContrast);
183
+ padding: var(--mdx-spacing-3);
184
+ min-height: 200px;
185
+ outline: none;
186
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
187
+ font-size: 14px;
188
+ line-height: 1.6;
189
+ }
190
+
191
+ [class*="_contentEditable"]:focus {
192
+ outline: none;
193
+ }
194
+
195
+ /* Placeholder positioning - ensure it's at the top */
196
+ [class*="_contentEditable"] {
197
+ position: relative;
198
+ }
199
+
200
+ [class*="_contentEditable"][data-placeholder]::before {
201
+ position: absolute;
202
+ top: var(--mdx-spacing-3);
203
+ left: var(--mdx-spacing-3);
204
+ color: #a5a5ba;
205
+ pointer-events: none;
206
+ }
207
+
208
+ /* MDXEditor/Lexical placeholder styles */
209
+ [class*="_placeholder"],
210
+ [class*="ContentEditable__placeholder"],
211
+ [class*="editor-placeholder"] {
212
+ position: absolute !important;
213
+ top: var(--mdx-spacing-3) !important;
214
+ left: var(--mdx-spacing-3) !important;
215
+ color: #a5a5ba;
216
+ pointer-events: none;
217
+ overflow: hidden;
218
+ text-overflow: ellipsis;
219
+ user-select: none;
220
+ display: inline-block;
221
+ }
222
+
223
+ /* Editor root wrapper needs relative positioning for placeholder */
224
+ [class*="_rootContentEditableWrapper"],
225
+ [class*="_editorWrapper"] {
226
+ position: relative;
227
+ display: flex;
228
+ flex-direction: column;
229
+ }
230
+
231
+ /* Heading styles */
232
+ [class*="_contentEditable"] h1 {
233
+ font-size: 1.75rem;
234
+ font-weight: 600;
235
+ margin: 0 0 1rem;
236
+ }
237
+
238
+ [class*="_contentEditable"] h2 {
239
+ font-size: 1.5rem;
240
+ font-weight: 600;
241
+ margin: 1rem 0 0.75rem;
242
+ }
243
+
244
+ [class*="_contentEditable"] h3 {
245
+ font-size: 1.25rem;
246
+ font-weight: 600;
247
+ margin: 1rem 0 0.5rem;
248
+ }
249
+
250
+ /* Paragraph and list styles */
251
+ [class*="_contentEditable"] p {
252
+ margin: 0 0 1rem;
253
+ }
254
+
255
+ [class*="_contentEditable"] ul,
256
+ [class*="_contentEditable"] ol {
257
+ margin: 0 0 1rem;
258
+ padding-left: 1.5rem;
259
+ }
260
+
261
+ [class*="_contentEditable"] li {
262
+ margin: 0.25rem 0;
263
+ }
264
+
265
+ /* Code styles */
266
+ [class*="_contentEditable"] code {
267
+ background: #f0f0f5;
268
+ padding: 0.2em 0.4em;
269
+ border-radius: 3px;
270
+ font-family: "Monaco", "Menlo", monospace;
271
+ font-size: 0.9em;
272
+ }
273
+
274
+ [class*="_contentEditable"] pre {
275
+ background: #2d2d2d;
276
+ color: #f8f8f2;
277
+ padding: 1rem;
278
+ border-radius: 4px;
279
+ overflow-x: auto;
280
+ margin: 0 0 1rem;
281
+ }
282
+
283
+ [class*="_contentEditable"] pre code {
284
+ background: none;
285
+ padding: 0;
286
+ }
287
+
288
+ /* Blockquote */
289
+ [class*="_contentEditable"] blockquote {
290
+ border-left: 3px solid #dcdce4;
291
+ margin: 0 0 1rem;
292
+ padding-left: 1rem;
293
+ color: #666;
294
+ }
295
+
296
+ /* Links */
297
+ [class*="_contentEditable"] a {
298
+ color: #4945ff;
299
+ text-decoration: underline;
300
+ }
301
+
302
+ /* Horizontal rule */
303
+ [class*="_contentEditable"] hr {
304
+ border: none;
305
+ border-top: 1px solid #dcdce4;
306
+ margin: 1.5rem 0;
307
+ }
308
+
309
+ /* Editor root */
310
+ [class*="_editorRoot"] {
311
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
312
+ color: var(--mdx-baseTextContrast);
313
+ background: var(--mdx-basePageBg);
314
+ }
315
+
316
+ /* Link dialog */
317
+ [class*="_linkDialogPopoverContent"] {
318
+ display: flex;
319
+ flex-direction: column;
320
+ gap: var(--mdx-spacing-2);
321
+ padding: var(--mdx-spacing-3);
322
+ background-color: var(--mdx-basePageBg);
323
+ border-radius: var(--mdx-radius-medium);
324
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
325
+ z-index: 100;
326
+ }
327
+
328
+ [class*="_linkDialogInputWrapper"] {
329
+ display: flex;
330
+ gap: var(--mdx-spacing-1);
331
+ }
332
+
333
+ [class*="_linkDialogInputWrapper"] input {
334
+ flex: 1;
335
+ padding: var(--mdx-spacing-1) var(--mdx-spacing-2);
336
+ border: 1px solid var(--mdx-baseBorder);
337
+ border-radius: var(--mdx-radius-base);
338
+ font-size: var(--mdx-text-sm);
339
+ }
340
+
341
+ [class*="_linkDialogInputWrapper"] button {
342
+ padding: var(--mdx-spacing-1) var(--mdx-spacing-2);
343
+ background-color: var(--mdx-accentText);
344
+ color: white;
345
+ border: none;
346
+ border-radius: var(--mdx-radius-base);
347
+ cursor: pointer;
348
+ }
349
+
350
+ /* Popover positioning */
351
+ [data-radix-popper-content-wrapper] {
352
+ z-index: 100 !important;
353
+ }
354
+ `;
355
+ const EditorWrapper = styled(Box)`
356
+ border: 1px solid ${({ $isFocused }) => $isFocused ? "#4945ff" : "#dcdce4"};
357
+ border-radius: 4px;
358
+ overflow: hidden;
359
+ background: #fff;
360
+ transition: border-color 0.2s, box-shadow 0.2s;
361
+ box-shadow: ${({ $isFocused }) => $isFocused ? "0 0 0 2px rgba(73, 69, 255, 0.2)" : "none"};
362
+ `;
363
+ function ToolbarContents() {
364
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
365
+ /* @__PURE__ */ jsx(UndoRedo, {}),
366
+ /* @__PURE__ */ jsx(Separator, {}),
367
+ /* @__PURE__ */ jsx(BlockTypeSelect, {}),
368
+ /* @__PURE__ */ jsx(Separator, {}),
369
+ /* @__PURE__ */ jsx(BoldItalicUnderlineToggles, {}),
370
+ /* @__PURE__ */ jsx(Separator, {}),
371
+ /* @__PURE__ */ jsx(CreateLink, {}),
372
+ /* @__PURE__ */ jsx(Separator, {}),
373
+ /* @__PURE__ */ jsx(ListsToggle, {})
374
+ ] });
375
+ }
376
+ function MarkdownEditor({ content, onChange, height = 300 }) {
377
+ const [isFocused, setIsFocused] = useState(false);
378
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
379
+ /* @__PURE__ */ jsx(MDXEditorStyles, {}),
380
+ /* @__PURE__ */ jsx(
381
+ EditorWrapper,
382
+ {
383
+ $isFocused: isFocused,
384
+ onFocus: () => setIsFocused(true),
385
+ onBlur: () => setIsFocused(false),
386
+ children: /* @__PURE__ */ jsx("div", { style: { minHeight: `${height}px` }, children: /* @__PURE__ */ jsx(
387
+ MDXEditor,
388
+ {
389
+ markdown: content,
390
+ onChange,
391
+ placeholder: "Write your content here...",
392
+ plugins: [
393
+ headingsPlugin(),
394
+ listsPlugin(),
395
+ quotePlugin(),
396
+ thematicBreakPlugin(),
397
+ linkPlugin(),
398
+ linkDialogPlugin(),
399
+ markdownShortcutPlugin(),
400
+ toolbarPlugin({
401
+ toolbarContents: ToolbarContents
402
+ })
403
+ ]
404
+ }
405
+ ) })
406
+ }
407
+ )
408
+ ] });
409
+ }
410
+ styled(Typography)`
411
+ display: block;
412
+ margin-top: 1rem;
413
+ margin-bottom: 0.5rem;
414
+ `;
415
+ const CHUNK_SIZE = 4e3;
416
+ function EmbeddingsModal() {
417
+ const { post, get } = useFetchClient();
418
+ const { toggleNotification } = useNotification();
419
+ const navigate = useNavigate();
420
+ const context = unstable_useContentManagerContext();
421
+ const { form, id, slug, collectionType } = context;
422
+ const modifiedValues = form?.values || {};
423
+ const [isVisible, setIsVisible] = useState(false);
424
+ const [title, setTitle] = useState("");
425
+ const [content, setContent] = useState("");
426
+ const [fieldName, setFieldName] = useState("");
427
+ const [availableFields, setAvailableFields] = useState([]);
428
+ const [isLoading, setIsLoading] = useState(false);
429
+ const [isCheckingExisting, setIsCheckingExisting] = useState(true);
430
+ const [existingEmbedding, setExistingEmbedding] = useState(null);
431
+ useEffect(() => {
432
+ async function checkExistingEmbedding() {
433
+ if (!id || !slug) {
434
+ setIsCheckingExisting(false);
435
+ return;
436
+ }
437
+ try {
438
+ const query = qs.stringify({
439
+ filters: {
440
+ metadata: { $containsi: id }
441
+ }
442
+ });
443
+ const response = await get(`/${PLUGIN_ID}/embeddings/find?${query}`);
444
+ const embeddings = response.data?.data || response.data || [];
445
+ if (Array.isArray(embeddings) && embeddings.length > 0) {
446
+ setExistingEmbedding({
447
+ documentId: embeddings[0].documentId,
448
+ title: embeddings[0].title,
449
+ content: embeddings[0].content
450
+ });
451
+ }
452
+ } catch (error) {
453
+ console.error("Failed to check for existing embedding:", error);
454
+ } finally {
455
+ setIsCheckingExisting(false);
456
+ }
457
+ }
458
+ checkExistingEmbedding();
459
+ }, [id, slug, get]);
460
+ const extractTextFromField = useCallback((value, depth = 0) => {
461
+ if (!value || depth > 5) return "";
462
+ if (typeof value === "string") {
463
+ return value.trim();
464
+ }
465
+ if (Array.isArray(value)) {
466
+ const texts = [];
467
+ for (const item of value) {
468
+ if (item && typeof item === "object" && item.__component) {
469
+ for (const [key, fieldValue] of Object.entries(item)) {
470
+ if (key === "__component" || key === "id") continue;
471
+ const extracted = extractTextFromField(fieldValue, depth + 1);
472
+ if (extracted) texts.push(extracted);
473
+ }
474
+ } else if (item && item.children) {
475
+ const blockText = item.children.map((child) => child.text || "").join("");
476
+ if (blockText) texts.push(blockText);
477
+ } else if (item && typeof item === "object") {
478
+ const extracted = extractTextFromField(item, depth + 1);
479
+ if (extracted) texts.push(extracted);
480
+ }
481
+ }
482
+ return texts.join("\n\n").trim();
483
+ }
484
+ if (typeof value === "object") {
485
+ const texts = [];
486
+ for (const [key, fieldValue] of Object.entries(value)) {
487
+ if (["id", "__component", "documentId", "createdAt", "updatedAt"].includes(key)) continue;
488
+ const extracted = extractTextFromField(fieldValue, depth + 1);
489
+ if (extracted) texts.push(extracted);
490
+ }
491
+ return texts.join("\n\n").trim();
492
+ }
493
+ return "";
494
+ }, []);
495
+ const isDynamicZone = (value) => {
496
+ return Array.isArray(value) && value.length > 0 && value[0]?.__component;
497
+ };
498
+ const detectTextFields = useCallback(() => {
499
+ if (!modifiedValues) return [];
500
+ const fields = [];
501
+ for (const [name, value] of Object.entries(modifiedValues)) {
502
+ if (["id", "documentId", "createdAt", "updatedAt", "publishedAt", "locale", "localizations"].includes(name)) {
503
+ continue;
504
+ }
505
+ const textValue = extractTextFromField(value);
506
+ if (textValue && textValue.length > 0) {
507
+ let label = name.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
508
+ if (isDynamicZone(value)) {
509
+ const componentCount = value.length;
510
+ label += ` (${componentCount} component${componentCount > 1 ? "s" : ""})`;
511
+ }
512
+ fields.push({
513
+ name,
514
+ label,
515
+ value: textValue,
516
+ charCount: textValue.length
517
+ });
518
+ }
519
+ }
520
+ fields.sort((a, b) => b.charCount - a.charCount);
521
+ return fields;
522
+ }, [modifiedValues, extractTextFromField]);
523
+ useEffect(() => {
524
+ const fields = detectTextFields();
525
+ setAvailableFields(fields);
526
+ if (fields.length > 0 && !fieldName) {
527
+ setFieldName(fields[0].name);
528
+ setContent(fields[0].value);
529
+ }
530
+ }, [detectTextFields, fieldName]);
531
+ const handleFieldChange = (selectedFieldName) => {
532
+ setFieldName(selectedFieldName);
533
+ const selectedField = availableFields.find((f) => f.name === selectedFieldName);
534
+ if (selectedField) {
535
+ setContent(selectedField.value);
536
+ }
537
+ };
538
+ const contentLength = content.length;
539
+ const willChunk = contentLength > CHUNK_SIZE;
540
+ const estimatedChunks = willChunk ? Math.ceil(contentLength / (CHUNK_SIZE - 200)) : 1;
541
+ const isSaved = !!id;
542
+ function generateMetadata() {
543
+ return {
544
+ source: "content-manager",
545
+ collectionType: slug || collectionType || "unknown",
546
+ fieldName: fieldName || "content",
547
+ documentId: id,
548
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
549
+ };
550
+ }
551
+ const isValid = title.trim() && content.trim();
552
+ function handleOpenCreate() {
553
+ setTitle("");
554
+ const fields = detectTextFields();
555
+ setAvailableFields(fields);
556
+ if (fields.length > 0) {
557
+ setFieldName(fields[0].name);
558
+ setContent(fields[0].value);
559
+ }
560
+ setIsVisible(true);
561
+ }
562
+ async function handleSubmit(e) {
563
+ e.preventDefault();
564
+ if (!title.trim()) {
565
+ toggleNotification({
566
+ type: "warning",
567
+ message: "Embeddings title is required"
568
+ });
569
+ return;
570
+ }
571
+ if (!content.trim()) {
572
+ toggleNotification({
573
+ type: "warning",
574
+ message: "Embeddings content is required"
575
+ });
576
+ return;
577
+ }
578
+ setIsLoading(true);
579
+ try {
580
+ const contentToEmbed = content.trim();
581
+ const shouldChunk = contentToEmbed.length > CHUNK_SIZE;
582
+ const chunks = shouldChunk ? Math.ceil(contentToEmbed.length / CHUNK_SIZE) : 1;
583
+ if (shouldChunk) {
584
+ console.log(`Creating chunked embedding: ${contentToEmbed.length} chars (~${chunks} parts)`);
585
+ }
586
+ const result = await post(`/${PLUGIN_ID}/embeddings/create-embedding`, {
587
+ data: {
588
+ title: title.trim(),
589
+ content: contentToEmbed,
590
+ collectionType: slug || collectionType,
591
+ fieldName,
592
+ metadata: generateMetadata(),
593
+ autoChunk: shouldChunk
594
+ }
595
+ });
596
+ const responseData = result?.data || result;
597
+ if (responseData?.documentId) {
598
+ setExistingEmbedding({
599
+ documentId: responseData.documentId,
600
+ title: responseData.title,
601
+ content: responseData.content
602
+ });
603
+ }
604
+ setIsVisible(false);
605
+ const message = shouldChunk ? `Embedding created and chunked into ${chunks} parts` : "Embedding created successfully";
606
+ toggleNotification({ type: "success", message });
607
+ } catch (error) {
608
+ console.error("Failed to create embedding:", error);
609
+ toggleNotification({
610
+ type: "danger",
611
+ message: error.message || "Failed to create embedding"
612
+ });
613
+ } finally {
614
+ setIsLoading(false);
615
+ }
616
+ }
617
+ function handleViewEmbedding() {
618
+ if (existingEmbedding?.documentId) {
619
+ navigate(`/plugins/${PLUGIN_ID}/embeddings/${existingEmbedding.documentId}`);
620
+ }
621
+ }
622
+ if (!form || !id) {
623
+ return null;
624
+ }
625
+ if (isCheckingExisting) {
626
+ return /* @__PURE__ */ jsx(Box, { paddingTop: 2, children: /* @__PURE__ */ jsx(Loader, { small: true, children: "Checking embeddings..." }) });
627
+ }
628
+ const submitButtonText = isLoading ? "Creating..." : "Create Embedding";
629
+ return /* @__PURE__ */ jsxs(Box, { paddingTop: 2, children: [
630
+ existingEmbedding ? /* @__PURE__ */ jsx(Button, { onClick: handleViewEmbedding, startIcon: /* @__PURE__ */ jsx(Eye, {}), fullWidth: true, children: "View Embedding" }) : /* @__PURE__ */ jsx(
631
+ Button,
632
+ {
633
+ onClick: handleOpenCreate,
634
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
635
+ disabled: !isSaved,
636
+ fullWidth: true,
637
+ children: "Create Embedding"
638
+ }
639
+ ),
640
+ !isSaved && !existingEmbedding && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { display: "block", marginTop: "0.5rem" }, children: "Save content first to create embedding" }),
641
+ /* @__PURE__ */ jsx(Modal.Root, { open: isVisible, onOpenChange: setIsVisible, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
642
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: "Create Embedding from Content" }) }),
643
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Box, { children: [
644
+ /* @__PURE__ */ jsx(Box, { marginBottom: 4, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
645
+ /* @__PURE__ */ jsx(Field.Label, { children: "Title" }),
646
+ /* @__PURE__ */ jsx(
647
+ TextInput,
648
+ {
649
+ placeholder: "Enter embedding title",
650
+ value: title,
651
+ onChange: (e) => setTitle(e.target.value)
652
+ }
653
+ )
654
+ ] }) }),
655
+ availableFields.length > 0 && /* @__PURE__ */ jsxs(Box, { marginBottom: 4, children: [
656
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
657
+ /* @__PURE__ */ jsx(Field.Label, { children: "Source Field" }),
658
+ /* @__PURE__ */ jsx(Field.Hint, { children: "Select which field to use for the embedding content" })
659
+ ] }),
660
+ /* @__PURE__ */ jsx(
661
+ SingleSelect,
662
+ {
663
+ value: fieldName,
664
+ onChange: (value) => handleFieldChange(value),
665
+ placeholder: "Select a field",
666
+ children: availableFields.map((field) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: field.name, children: [
667
+ field.label,
668
+ " (",
669
+ field.charCount.toLocaleString(),
670
+ " chars)"
671
+ ] }, field.name))
672
+ }
673
+ )
674
+ ] }),
675
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 4, children: [
676
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
677
+ /* @__PURE__ */ jsx(Field.Root, { children: /* @__PURE__ */ jsx(Field.Label, { children: "Content Preview" }) }),
678
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
679
+ contentLength.toLocaleString(),
680
+ " characters",
681
+ willChunk && /* @__PURE__ */ jsxs(Typography, { textColor: "primary600", children: [
682
+ " (~",
683
+ estimatedChunks,
684
+ " chunks)"
685
+ ] })
686
+ ] })
687
+ ] }),
688
+ /* @__PURE__ */ jsx(
689
+ MarkdownEditor,
690
+ {
691
+ content,
692
+ onChange: setContent,
693
+ height: 200
694
+ }
695
+ )
696
+ ] })
697
+ ] }) }),
698
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
699
+ /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: "Cancel" }) }),
700
+ /* @__PURE__ */ jsx(
701
+ Button,
702
+ {
703
+ onClick: handleSubmit,
704
+ disabled: isLoading || !isValid,
705
+ loading: isLoading,
706
+ children: submitButtonText
707
+ }
708
+ )
709
+ ] })
710
+ ] }) })
711
+ ] });
712
+ }
713
+ function EmbeddingsWidget() {
714
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(EmbeddingsModal, {}) });
715
+ }
716
+ const index = {
717
+ register(app) {
718
+ app.registerPlugin({
719
+ id: PLUGIN_ID,
720
+ initializer: Initializer,
721
+ isReady: false,
722
+ name: PLUGIN_ID
723
+ });
724
+ },
725
+ bootstrap(app) {
726
+ app.getPlugin("content-manager").injectComponent("editView", "right-links", {
727
+ name: "open-ai-embeddings",
728
+ Component: () => /* @__PURE__ */ jsx(EmbeddingsWidget, {})
729
+ });
730
+ },
731
+ async registerTrads(app) {
732
+ const { locales } = app;
733
+ const importedTranslations = await Promise.all(
734
+ locales.map((locale) => {
735
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("../_chunks/en-Byx4XI2L.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
736
+ return {
737
+ data: getTranslation(data),
738
+ locale
739
+ };
740
+ }).catch(() => {
741
+ return {
742
+ data: {},
743
+ locale
744
+ };
745
+ });
746
+ })
747
+ );
748
+ return importedTranslations;
749
+ }
750
+ };
3
751
  export {
4
- i as default
752
+ index as default
5
753
  };
6
- //# sourceMappingURL=index.mjs.map