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