strapi-content-embeddings 0.1.8 → 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-TWbcT-zJ.js","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/custom/RobotIcon.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/components/custom/MarkdownEditor.tsx","../../admin/src/components/custom/EmbeddingsModal.tsx","../../admin/src/components/custom/EmbeddingsWidget.tsx","../../admin/src/index.tsx"],"sourcesContent":["export const PLUGIN_ID = 'strapi-content-embeddings';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import React from \"react\";\n\ninterface RobotIconProps {\n height?: string | number;\n width?: string | number;\n}\n\nexport function RobotIcon({ height = 48, width = 48 }: RobotIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n height={height}\n viewBox=\"0 -960 960 960\"\n width={width}\n fill=\"currentColor\"\n >\n <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\" />\n </svg>\n );\n}\n","import { RobotIcon } from './custom/RobotIcon';\n\nconst PluginIcon = () => <RobotIcon height={24} width={24} />;\n\nexport { PluginIcon };\n","import { useState } from 'react';\nimport { Box } from '@strapi/design-system';\nimport styled, { createGlobalStyle } from 'styled-components';\nimport {\n MDXEditor,\n headingsPlugin,\n listsPlugin,\n quotePlugin,\n thematicBreakPlugin,\n markdownShortcutPlugin,\n linkPlugin,\n linkDialogPlugin,\n toolbarPlugin,\n BoldItalicUnderlineToggles,\n BlockTypeSelect,\n CreateLink,\n ListsToggle,\n UndoRedo,\n Separator,\n} from '@mdxeditor/editor';\n\ninterface MarkdownEditorProps {\n content: string;\n onChange: (content: string) => void;\n height?: number;\n}\n\nconst MDXEditorStyles = createGlobalStyle`\n /* MDXEditor CSS Variables */\n :root {\n --mdx-spacing-0_5: 0.125rem;\n --mdx-spacing-1: 0.25rem;\n --mdx-spacing-1_5: 0.375rem;\n --mdx-spacing-2: 0.5rem;\n --mdx-spacing-3: 0.75rem;\n --mdx-spacing-4: 1rem;\n --mdx-spacing-36: 9rem;\n --mdx-radius-base: 0.25rem;\n --mdx-radius-medium: 0.375rem;\n --mdx-text-sm: 0.875rem;\n --mdx-baseBg: #f6f6f9;\n --mdx-baseBgActive: #e8e8ec;\n --mdx-basePageBg: #ffffff;\n --mdx-baseBorder: #dcdce4;\n --mdx-baseBorderHover: #b9bbc6;\n --mdx-baseBase: #e0e1e6;\n --mdx-baseTextContrast: #1c2024;\n --mdx-accentText: #4945ff;\n }\n\n /* Toolbar Root - critical for horizontal layout */\n [class*=\"_toolbarRoot\"] {\n z-index: 2;\n display: flex !important;\n flex-direction: row !important;\n flex-wrap: wrap !important;\n gap: var(--mdx-spacing-1);\n border-radius: var(--mdx-radius-medium);\n padding: var(--mdx-spacing-1_5);\n align-items: center !important;\n overflow-x: auto;\n position: sticky;\n top: 0;\n background-color: var(--mdx-baseBg) !important;\n border-bottom: 1px solid var(--mdx-baseBorder);\n width: 100%;\n }\n\n [class*=\"_toolbarRoot\"] div[role='separator'] {\n margin: var(--mdx-spacing-2) var(--mdx-spacing-1);\n border-left: 1px solid var(--mdx-baseBorder);\n border-right: 1px solid var(--mdx-baseBase);\n height: var(--mdx-spacing-4);\n }\n\n [class*=\"_toolbarRoot\"] svg {\n color: var(--mdx-baseTextContrast);\n display: block;\n }\n\n /* Toolbar button groups */\n [class*=\"_toolbarGroupOfGroups\"] {\n display: flex;\n margin: 0 var(--mdx-spacing-1);\n }\n\n [class*=\"_toolbarToggleSingleGroup\"] {\n display: flex;\n align-items: center;\n white-space: nowrap;\n }\n\n /* Toolbar buttons and toggle items */\n [class*=\"_toolbarToggleItem\"],\n [class*=\"_toolbarButton\"] {\n border: 0;\n background-color: transparent;\n font-size: inherit;\n appearance: none;\n box-sizing: border-box;\n cursor: pointer;\n padding: var(--mdx-spacing-0_5);\n border-radius: var(--mdx-radius-base);\n }\n\n [class*=\"_toolbarToggleItem\"]:hover,\n [class*=\"_toolbarButton\"]:hover {\n background-color: var(--mdx-baseBgActive);\n }\n\n [class*=\"_toolbarToggleItem\"][data-state='on'],\n [class*=\"_toolbarButton\"][data-state='on'],\n [class*=\"_toolbarToggleItem\"]:active,\n [class*=\"_toolbarButton\"]:active {\n color: var(--mdx-baseTextContrast);\n background-color: var(--mdx-baseBgActive);\n }\n\n /* Block type select dropdown */\n [class*=\"_toolbarNodeKindSelectTrigger\"],\n [class*=\"_selectTrigger\"] {\n border: 0;\n display: flex;\n color: inherit;\n align-items: center;\n width: var(--mdx-spacing-36);\n padding: var(--mdx-spacing-0_5) var(--mdx-spacing-1);\n padding-inline-start: var(--mdx-spacing-2);\n border-radius: var(--mdx-radius-medium);\n white-space: nowrap;\n font-size: var(--mdx-text-sm);\n background-color: var(--mdx-basePageBg);\n margin: 0 var(--mdx-spacing-1);\n cursor: pointer;\n }\n\n /* Dropdown containers */\n [class*=\"_toolbarNodeKindSelectContainer\"],\n [class*=\"_selectContainer\"] {\n filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.2));\n z-index: 100;\n width: var(--mdx-spacing-36);\n border-radius: var(--mdx-radius-base);\n background-color: var(--mdx-basePageBg);\n font-size: var(--mdx-text-sm);\n }\n\n /* Select items */\n [class*=\"_toolbarNodeKindSelectItem\"],\n [class*=\"_selectItem\"] {\n cursor: pointer;\n display: flex;\n padding: var(--mdx-spacing-2);\n }\n\n [class*=\"_toolbarNodeKindSelectItem\"][data-highlighted],\n [class*=\"_selectItem\"][data-highlighted],\n [class*=\"_toolbarNodeKindSelectItem\"][data-state='checked'],\n [class*=\"_selectItem\"][data-state='checked'] {\n background-color: var(--mdx-baseBg);\n outline: none;\n }\n\n /* Dropdown arrow */\n [class*=\"_selectDropdownArrow\"] {\n margin-left: auto;\n display: flex;\n align-items: center;\n }\n\n /* Content editable area */\n [class*=\"_contentEditable\"] {\n box-sizing: border-box;\n width: 100%;\n color: var(--mdx-baseTextContrast);\n padding: var(--mdx-spacing-3);\n min-height: 200px;\n outline: none;\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-size: 14px;\n line-height: 1.6;\n }\n\n [class*=\"_contentEditable\"]:focus {\n outline: none;\n }\n\n /* Placeholder positioning - ensure it's at the top */\n [class*=\"_contentEditable\"] {\n position: relative;\n }\n\n [class*=\"_contentEditable\"][data-placeholder]::before {\n position: absolute;\n top: var(--mdx-spacing-3);\n left: var(--mdx-spacing-3);\n color: #a5a5ba;\n pointer-events: none;\n }\n\n /* MDXEditor/Lexical placeholder styles */\n [class*=\"_placeholder\"],\n [class*=\"ContentEditable__placeholder\"],\n [class*=\"editor-placeholder\"] {\n position: absolute !important;\n top: var(--mdx-spacing-3) !important;\n left: var(--mdx-spacing-3) !important;\n color: #a5a5ba;\n pointer-events: none;\n overflow: hidden;\n text-overflow: ellipsis;\n user-select: none;\n display: inline-block;\n }\n\n /* Editor root wrapper needs relative positioning for placeholder */\n [class*=\"_rootContentEditableWrapper\"],\n [class*=\"_editorWrapper\"] {\n position: relative;\n display: flex;\n flex-direction: column;\n }\n\n /* Heading styles */\n [class*=\"_contentEditable\"] h1 {\n font-size: 1.75rem;\n font-weight: 600;\n margin: 0 0 1rem;\n }\n\n [class*=\"_contentEditable\"] h2 {\n font-size: 1.5rem;\n font-weight: 600;\n margin: 1rem 0 0.75rem;\n }\n\n [class*=\"_contentEditable\"] h3 {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 1rem 0 0.5rem;\n }\n\n /* Paragraph and list styles */\n [class*=\"_contentEditable\"] p {\n margin: 0 0 1rem;\n }\n\n [class*=\"_contentEditable\"] ul,\n [class*=\"_contentEditable\"] ol {\n margin: 0 0 1rem;\n padding-left: 1.5rem;\n }\n\n [class*=\"_contentEditable\"] li {\n margin: 0.25rem 0;\n }\n\n /* Code styles */\n [class*=\"_contentEditable\"] code {\n background: #f0f0f5;\n padding: 0.2em 0.4em;\n border-radius: 3px;\n font-family: \"Monaco\", \"Menlo\", monospace;\n font-size: 0.9em;\n }\n\n [class*=\"_contentEditable\"] pre {\n background: #2d2d2d;\n color: #f8f8f2;\n padding: 1rem;\n border-radius: 4px;\n overflow-x: auto;\n margin: 0 0 1rem;\n }\n\n [class*=\"_contentEditable\"] pre code {\n background: none;\n padding: 0;\n }\n\n /* Blockquote */\n [class*=\"_contentEditable\"] blockquote {\n border-left: 3px solid #dcdce4;\n margin: 0 0 1rem;\n padding-left: 1rem;\n color: #666;\n }\n\n /* Links */\n [class*=\"_contentEditable\"] a {\n color: #4945ff;\n text-decoration: underline;\n }\n\n /* Horizontal rule */\n [class*=\"_contentEditable\"] hr {\n border: none;\n border-top: 1px solid #dcdce4;\n margin: 1.5rem 0;\n }\n\n /* Editor root */\n [class*=\"_editorRoot\"] {\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n color: var(--mdx-baseTextContrast);\n background: var(--mdx-basePageBg);\n }\n\n /* Link dialog */\n [class*=\"_linkDialogPopoverContent\"] {\n display: flex;\n flex-direction: column;\n gap: var(--mdx-spacing-2);\n padding: var(--mdx-spacing-3);\n background-color: var(--mdx-basePageBg);\n border-radius: var(--mdx-radius-medium);\n box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);\n z-index: 100;\n }\n\n [class*=\"_linkDialogInputWrapper\"] {\n display: flex;\n gap: var(--mdx-spacing-1);\n }\n\n [class*=\"_linkDialogInputWrapper\"] input {\n flex: 1;\n padding: var(--mdx-spacing-1) var(--mdx-spacing-2);\n border: 1px solid var(--mdx-baseBorder);\n border-radius: var(--mdx-radius-base);\n font-size: var(--mdx-text-sm);\n }\n\n [class*=\"_linkDialogInputWrapper\"] button {\n padding: var(--mdx-spacing-1) var(--mdx-spacing-2);\n background-color: var(--mdx-accentText);\n color: white;\n border: none;\n border-radius: var(--mdx-radius-base);\n cursor: pointer;\n }\n\n /* Popover positioning */\n [data-radix-popper-content-wrapper] {\n z-index: 100 !important;\n }\n`;\n\nconst EditorWrapper = styled(Box)<{ $isFocused: boolean }>`\n border: 1px solid ${({ $isFocused }) => ($isFocused ? '#4945ff' : '#dcdce4')};\n border-radius: 4px;\n overflow: hidden;\n background: #fff;\n transition: border-color 0.2s, box-shadow 0.2s;\n box-shadow: ${({ $isFocused }) => ($isFocused ? '0 0 0 2px rgba(73, 69, 255, 0.2)' : 'none')};\n`;\n\n// Toolbar contents component defined outside to prevent re-renders\nfunction ToolbarContents() {\n return (\n <>\n <UndoRedo />\n <Separator />\n <BlockTypeSelect />\n <Separator />\n <BoldItalicUnderlineToggles />\n <Separator />\n <CreateLink />\n <Separator />\n <ListsToggle />\n </>\n );\n}\n\nexport function MarkdownEditor({ content, onChange, height = 300 }: Readonly<MarkdownEditorProps>) {\n const [isFocused, setIsFocused] = useState(false);\n\n return (\n <>\n <MDXEditorStyles />\n <EditorWrapper\n $isFocused={isFocused}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n >\n <div style={{ minHeight: `${height}px` }}>\n <MDXEditor\n markdown={content}\n onChange={onChange}\n placeholder=\"Write your content here...\"\n plugins={[\n headingsPlugin(),\n listsPlugin(),\n quotePlugin(),\n thematicBreakPlugin(),\n linkPlugin(),\n linkDialogPlugin(),\n markdownShortcutPlugin(),\n toolbarPlugin({\n toolbarContents: ToolbarContents,\n }),\n ]}\n />\n </div>\n </EditorWrapper>\n </>\n );\n}\n","import React, { useState, useEffect, useCallback } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport styled from \"styled-components\";\nimport qs from \"qs\";\nimport {\n unstable_useContentManagerContext as useContentManagerContext,\n useFetchClient,\n useNotification,\n} from \"@strapi/strapi/admin\";\nimport {\n Button,\n Typography,\n Box,\n Modal,\n Field,\n TextInput,\n Loader,\n Flex,\n SingleSelect,\n SingleSelectOption,\n} from \"@strapi/design-system\";\nimport { Plus, Eye } from \"@strapi/icons\";\nimport { PLUGIN_ID } from \"../../pluginId\";\nimport { MarkdownEditor } from \"./MarkdownEditor\";\n\nconst StyledTypography = styled(Typography)`\n display: block;\n margin-top: 1rem;\n margin-bottom: 0.5rem;\n`;\n\nconst CHUNK_SIZE = 4000; // Content over this will be auto-chunked\n\ninterface ExistingEmbedding {\n documentId: string;\n title: string;\n content?: string;\n}\n\ninterface TextFieldOption {\n name: string;\n label: string;\n value: string;\n charCount: number;\n}\n\nexport function EmbeddingsModal() {\n const { post, get } = useFetchClient();\n const { toggleNotification } = useNotification();\n const navigate = useNavigate();\n\n // Access content manager context\n const context = useContentManagerContext();\n const { form, id, slug, collectionType } = context;\n\n const modifiedValues = form?.values || {};\n\n const [isVisible, setIsVisible] = useState(false);\n const [title, setTitle] = useState(\"\");\n const [content, setContent] = useState(\"\");\n const [fieldName, setFieldName] = useState(\"\");\n const [availableFields, setAvailableFields] = useState<TextFieldOption[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [isCheckingExisting, setIsCheckingExisting] = useState(true);\n const [existingEmbedding, setExistingEmbedding] = useState<ExistingEmbedding | null>(null);\n\n // Check for existing embedding when component mounts or id changes\n useEffect(() => {\n async function checkExistingEmbedding() {\n if (!id || !slug) {\n setIsCheckingExisting(false);\n return;\n }\n\n try {\n // Query embeddings filtered by metadata containing this documentId\n const query = qs.stringify({\n filters: {\n metadata: { $containsi: id },\n },\n });\n\n const response = await get(`/${PLUGIN_ID}/embeddings/find?${query}`);\n\n // Handle response - could be { data: [...] } or { data: { data: [...] } }\n const embeddings = response.data?.data || response.data || [];\n\n if (Array.isArray(embeddings) && embeddings.length > 0) {\n // Found existing embedding for this content\n setExistingEmbedding({\n documentId: embeddings[0].documentId,\n title: embeddings[0].title,\n content: embeddings[0].content,\n });\n }\n } catch (error) {\n console.error(\"Failed to check for existing embedding:\", error);\n } finally {\n setIsCheckingExisting(false);\n }\n }\n\n checkExistingEmbedding();\n }, [id, slug, get]);\n\n // Extract text value from a field (handles strings, blocks, and dynamic zones)\n const extractTextFromField = useCallback((value: any, depth: number = 0): string => {\n if (!value || depth > 5) return \"\"; // Prevent infinite recursion\n\n // Handle string values\n if (typeof value === \"string\") {\n return value.trim();\n }\n\n // Handle arrays (could be blocks, dynamic zones, or repeatable components)\n if (Array.isArray(value)) {\n const texts: string[] = [];\n\n for (const item of value) {\n // Check if it's a dynamic zone component (has __component property)\n if (item && typeof item === \"object\" && item.__component) {\n // Extract text from all fields in the component\n for (const [key, fieldValue] of Object.entries(item)) {\n if (key === \"__component\" || key === \"id\") continue;\n const extracted = extractTextFromField(fieldValue, depth + 1);\n if (extracted) texts.push(extracted);\n }\n }\n // Check if it's a blocks format item (rich text)\n else if (item && item.children) {\n const blockText = item.children\n .map((child: any) => child.text || \"\")\n .join(\"\");\n if (blockText) texts.push(blockText);\n }\n // Recursively handle nested arrays/objects\n else if (item && typeof item === \"object\") {\n const extracted = extractTextFromField(item, depth + 1);\n if (extracted) texts.push(extracted);\n }\n }\n\n return texts.join(\"\\n\\n\").trim();\n }\n\n // Handle objects (could be a component or relation)\n if (typeof value === \"object\") {\n const texts: string[] = [];\n\n for (const [key, fieldValue] of Object.entries(value)) {\n // Skip metadata fields\n if ([\"id\", \"__component\", \"documentId\", \"createdAt\", \"updatedAt\"].includes(key)) continue;\n const extracted = extractTextFromField(fieldValue, depth + 1);\n if (extracted) texts.push(extracted);\n }\n\n return texts.join(\"\\n\\n\").trim();\n }\n\n return \"\";\n }, []);\n\n // Check if a value is a dynamic zone\n const isDynamicZone = (value: any): boolean => {\n return Array.isArray(value) && value.length > 0 && value[0]?.__component;\n };\n\n // Detect all available text fields from form values\n const detectTextFields = useCallback((): TextFieldOption[] => {\n if (!modifiedValues) return [];\n\n const fields: TextFieldOption[] = [];\n\n // Check all fields in form values\n for (const [name, value] of Object.entries(modifiedValues)) {\n // Skip non-content fields\n if ([\"id\", \"documentId\", \"createdAt\", \"updatedAt\", \"publishedAt\", \"locale\", \"localizations\"].includes(name)) {\n continue;\n }\n\n const textValue = extractTextFromField(value);\n if (textValue && textValue.length > 0) {\n // Create a readable label from field name\n let label = name\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (str) => str.toUpperCase())\n .trim();\n\n // Add indicator for dynamic zones\n if (isDynamicZone(value)) {\n const componentCount = (value as any[]).length;\n label += ` (${componentCount} component${componentCount > 1 ? \"s\" : \"\"})`;\n }\n\n fields.push({\n name,\n label,\n value: textValue,\n charCount: textValue.length,\n });\n }\n }\n\n // Sort by character count (longest first) to prioritize main content\n fields.sort((a, b) => b.charCount - a.charCount);\n\n return fields;\n }, [modifiedValues, extractTextFromField]);\n\n // Update available fields when form values change\n useEffect(() => {\n const fields = detectTextFields();\n setAvailableFields(fields);\n\n // Auto-select first field if none selected\n if (fields.length > 0 && !fieldName) {\n setFieldName(fields[0].name);\n setContent(fields[0].value);\n }\n }, [detectTextFields, fieldName]);\n\n // Handle field selection change\n const handleFieldChange = (selectedFieldName: string) => {\n setFieldName(selectedFieldName);\n const selectedField = availableFields.find(f => f.name === selectedFieldName);\n if (selectedField) {\n setContent(selectedField.value);\n }\n };\n\n const contentLength = content.length;\n const willChunk = contentLength > CHUNK_SIZE;\n const estimatedChunks = willChunk ? Math.ceil(contentLength / (CHUNK_SIZE - 200)) : 1;\n // Check if content is saved (has an id) - don't require publish\n const isSaved = !!id;\n\n // Auto-generate metadata from collection context\n function generateMetadata(): Record<string, any> {\n return {\n source: \"content-manager\",\n collectionType: slug || collectionType || \"unknown\",\n fieldName: fieldName || \"content\",\n documentId: id,\n updatedAt: new Date().toISOString(),\n };\n }\n\n const isValid = title.trim() && content.trim(); // No length limit - auto-chunks if needed\n\n function handleOpenCreate() {\n setTitle(\"\");\n // Refresh available fields and select first one\n const fields = detectTextFields();\n setAvailableFields(fields);\n if (fields.length > 0) {\n setFieldName(fields[0].name);\n setContent(fields[0].value);\n }\n setIsVisible(true);\n }\n\n async function handleSubmit(e: React.FormEvent) {\n e.preventDefault();\n\n if (!title.trim()) {\n toggleNotification({\n type: \"warning\",\n message: \"Embeddings title is required\",\n });\n return;\n }\n\n if (!content.trim()) {\n toggleNotification({\n type: \"warning\",\n message: \"Embeddings content is required\",\n });\n return;\n }\n\n setIsLoading(true);\n\n try {\n const contentToEmbed = content.trim();\n const shouldChunk = contentToEmbed.length > CHUNK_SIZE;\n const chunks = shouldChunk ? Math.ceil(contentToEmbed.length / CHUNK_SIZE) : 1;\n\n if (shouldChunk) {\n console.log(`Creating chunked embedding: ${contentToEmbed.length} chars (~${chunks} parts)`);\n }\n\n const result = await post(`/${PLUGIN_ID}/embeddings/create-embedding`, {\n data: {\n title: title.trim(),\n content: contentToEmbed,\n collectionType: slug || collectionType,\n fieldName,\n metadata: generateMetadata(),\n autoChunk: shouldChunk,\n },\n });\n\n const responseData = result?.data || result;\n\n if (responseData?.documentId) {\n setExistingEmbedding({\n documentId: responseData.documentId,\n title: responseData.title,\n content: responseData.content,\n });\n }\n setIsVisible(false);\n\n const message = shouldChunk\n ? `Embedding created and chunked into ${chunks} parts`\n : \"Embedding created successfully\";\n toggleNotification({ type: \"success\", message });\n } catch (error: any) {\n console.error(\"Failed to create embedding:\", error);\n toggleNotification({\n type: \"danger\",\n message: error.message || \"Failed to create embedding\",\n });\n } finally {\n setIsLoading(false);\n }\n }\n\n function handleViewEmbedding() {\n if (existingEmbedding?.documentId) {\n navigate(`/plugins/${PLUGIN_ID}/embeddings/${existingEmbedding.documentId}`);\n }\n }\n\n // Don't render if not in edit view context\n if (!form || !id) {\n return null;\n }\n\n // Show loading state while checking for existing embedding\n if (isCheckingExisting) {\n return (\n <Box paddingTop={2}>\n <Loader small>Checking embeddings...</Loader>\n </Box>\n );\n }\n\n const submitButtonText = isLoading ? \"Creating...\" : \"Create Embedding\";\n\n return (\n <Box paddingTop={2}>\n {existingEmbedding ? (\n <Button onClick={handleViewEmbedding} startIcon={<Eye />} fullWidth>\n View Embedding\n </Button>\n ) : (\n <Button\n onClick={handleOpenCreate}\n startIcon={<Plus />}\n disabled={!isSaved}\n fullWidth\n >\n Create Embedding\n </Button>\n )}\n\n {!isSaved && !existingEmbedding && (\n <Typography variant=\"pi\" textColor=\"neutral600\" style={{ display: \"block\", marginTop: \"0.5rem\" }}>\n Save content first to create embedding\n </Typography>\n )}\n\n <Modal.Root open={isVisible} onOpenChange={setIsVisible}>\n <Modal.Content>\n <Modal.Header>\n <Modal.Title>Create Embedding from Content</Modal.Title>\n </Modal.Header>\n <Modal.Body>\n <Box>\n <Box marginBottom={4}>\n <Field.Root>\n <Field.Label>Title</Field.Label>\n <TextInput\n placeholder=\"Enter embedding title\"\n value={title}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setTitle(e.target.value)\n }\n />\n </Field.Root>\n </Box>\n\n {availableFields.length > 0 && (\n <Box marginBottom={4}>\n <Field.Root>\n <Field.Label>Source Field</Field.Label>\n <Field.Hint>Select which field to use for the embedding content</Field.Hint>\n </Field.Root>\n <SingleSelect\n value={fieldName}\n onChange={(value: string) => handleFieldChange(value)}\n placeholder=\"Select a field\"\n >\n {availableFields.map((field) => (\n <SingleSelectOption key={field.name} value={field.name}>\n {field.label} ({field.charCount.toLocaleString()} chars)\n </SingleSelectOption>\n ))}\n </SingleSelect>\n </Box>\n )}\n\n <Box marginBottom={4}>\n <Flex justifyContent=\"space-between\" alignItems=\"center\">\n <Field.Root>\n <Field.Label>Content Preview</Field.Label>\n </Field.Root>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {contentLength.toLocaleString()} characters\n {willChunk && (\n <Typography textColor=\"primary600\"> (~{estimatedChunks} chunks)</Typography>\n )}\n </Typography>\n </Flex>\n <MarkdownEditor\n content={content}\n onChange={setContent}\n height={200}\n />\n </Box>\n </Box>\n </Modal.Body>\n <Modal.Footer>\n <Modal.Close>\n <Button variant=\"tertiary\">Cancel</Button>\n </Modal.Close>\n <Button\n onClick={handleSubmit}\n disabled={isLoading || !isValid}\n loading={isLoading}\n >\n {submitButtonText}\n </Button>\n </Modal.Footer>\n </Modal.Content>\n </Modal.Root>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box } from \"@strapi/design-system\";\nimport { EmbeddingsModal } from \"./EmbeddingsModal\";\n\nexport function EmbeddingsWidget() {\n return (\n <Box>\n <EmbeddingsModal />\n </Box>\n );\n}\n","import React from 'react';\nimport { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\nimport { EmbeddingsWidget } from './components/custom/EmbeddingsWidget';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n bootstrap(app: any) {\n app.getPlugin('content-manager').injectComponent('editView', 'right-links', {\n name: \"open-ai-embeddings\",\n Component: () => <EmbeddingsWidget />\n })\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":["useRef","useEffect","jsx","createGlobalStyle","styled","Box","jsxs","Fragment","UndoRedo","Separator","BlockTypeSelect","BoldItalicUnderlineToggles","CreateLink","ListsToggle","useState","MDXEditor","headingsPlugin","listsPlugin","quotePlugin","thematicBreakPlugin","linkPlugin","linkDialogPlugin","markdownShortcutPlugin","toolbarPlugin","Typography","useFetchClient","useNotification","useNavigate","useContentManagerContext","qs","useCallback","Loader","Button","Eye","Plus","Modal","Field","TextInput","SingleSelect","SingleSelectOption","Flex"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useRef, useEffect, useState, useCallback } from "react";
3
- import { Box, Typography, Loader, Button, Modal, Field, TextInput } from "@strapi/design-system";
3
+ import { Box, Typography, Loader, Button, Modal, Field, TextInput, SingleSelect, SingleSelectOption, Flex } from "@strapi/design-system";
4
4
  import { useNavigate } from "react-router-dom";
5
5
  import styled, { createGlobalStyle } from "styled-components";
6
6
  import qs from "qs";
@@ -421,7 +421,7 @@ function MarkdownEditor({ content, onChange, height = 300 }) {
421
421
  )
422
422
  ] });
423
423
  }
424
- const StyledTypography = styled(Typography)`
424
+ styled(Typography)`
425
425
  display: block;
426
426
  margin-top: 1rem;
427
427
  margin-bottom: 0.5rem;
@@ -438,6 +438,7 @@ function EmbeddingsModal() {
438
438
  const [title, setTitle] = useState("");
439
439
  const [content, setContent] = useState("");
440
440
  const [fieldName, setFieldName] = useState("");
441
+ const [availableFields, setAvailableFields] = useState([]);
441
442
  const [isLoading, setIsLoading] = useState(false);
442
443
  const [isCheckingExisting, setIsCheckingExisting] = useState(true);
443
444
  const [existingEmbedding, setExistingEmbedding] = useState(null);
@@ -470,37 +471,84 @@ function EmbeddingsModal() {
470
471
  }
471
472
  checkExistingEmbedding();
472
473
  }, [id, slug, get]);
473
- const extractContentFromForm = useCallback(() => {
474
- if (!modifiedValues) return "";
475
- const textFieldNames = ["content", "description", "body", "text", "richtext", "markdown"];
476
- for (const name of textFieldNames) {
477
- const value = modifiedValues[name];
478
- if (value) {
479
- if (typeof value === "string" && value.trim()) {
480
- setFieldName(name);
481
- return value;
482
- } else if (Array.isArray(value)) {
483
- const text = value.map((block) => {
484
- if (block.children) {
485
- return block.children.map((child) => child.text || "").join("");
486
- }
487
- return "";
488
- }).join("\n\n");
489
- if (text.trim()) {
490
- setFieldName(name);
491
- return text;
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);
492
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);
493
494
  }
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();
495
506
  }
496
507
  return "";
497
- }, [modifiedValues]);
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]);
498
537
  useEffect(() => {
499
- const formContent = extractContentFromForm();
500
- if (formContent) {
501
- setContent(formContent);
538
+ const fields = detectTextFields();
539
+ setAvailableFields(fields);
540
+ if (fields.length > 0 && !fieldName) {
541
+ setFieldName(fields[0].name);
542
+ setContent(fields[0].value);
502
543
  }
503
- }, [extractContentFromForm]);
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
+ };
504
552
  const contentLength = content.length;
505
553
  const willChunk = contentLength > CHUNK_SIZE;
506
554
  const estimatedChunks = willChunk ? Math.ceil(contentLength / (CHUNK_SIZE - 200)) : 1;
@@ -517,9 +565,11 @@ function EmbeddingsModal() {
517
565
  const isValid = title.trim() && content.trim();
518
566
  function handleOpenCreate() {
519
567
  setTitle("");
520
- const formContent = extractContentFromForm();
521
- if (formContent) {
522
- setContent(formContent);
568
+ const fields = detectTextFields();
569
+ setAvailableFields(fields);
570
+ if (fields.length > 0) {
571
+ setFieldName(fields[0].name);
572
+ setContent(fields[0].value);
523
573
  }
524
574
  setIsVisible(true);
525
575
  }
@@ -605,16 +655,6 @@ function EmbeddingsModal() {
605
655
  /* @__PURE__ */ jsx(Modal.Root, { open: isVisible, onOpenChange: setIsVisible, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
606
656
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: "Create Embedding from Content" }) }),
607
657
  /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Box, { children: [
608
- /* @__PURE__ */ jsxs(StyledTypography, { variant: "omega", textColor: "neutral600", children: [
609
- "Content: ",
610
- contentLength,
611
- " characters",
612
- willChunk && /* @__PURE__ */ jsxs(Typography, { textColor: "primary600", children: [
613
- " (will create ~",
614
- estimatedChunks,
615
- " embeddings)"
616
- ] })
617
- ] }),
618
658
  /* @__PURE__ */ jsx(Box, { marginBottom: 4, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
619
659
  /* @__PURE__ */ jsx(Field.Label, { children: "Title" }),
620
660
  /* @__PURE__ */ jsx(
@@ -626,10 +666,38 @@ function EmbeddingsModal() {
626
666
  }
627
667
  )
628
668
  ] }) }),
629
- /* @__PURE__ */ jsxs(Box, { marginBottom: 4, children: [
669
+ availableFields.length > 0 && /* @__PURE__ */ jsxs(Box, { marginBottom: 4, children: [
630
670
  /* @__PURE__ */ jsxs(Field.Root, { children: [
631
- /* @__PURE__ */ jsx(Field.Label, { children: "Content" }),
632
- /* @__PURE__ */ jsx(Field.Hint, { children: fieldName ? `From field: ${fieldName}` : "Enter content manually" })
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
+ ] })
633
701
  ] }),
634
702
  /* @__PURE__ */ jsx(
635
703
  MarkdownEditor,
@@ -669,7 +737,7 @@ const index = {
669
737
  defaultMessage: PLUGIN_ID
670
738
  },
671
739
  Component: async () => {
672
- const { App } = await import("./App-sRU0Nh3x.mjs");
740
+ const { App } = await import("./App-MjsTrWRS.mjs");
673
741
  return App;
674
742
  }
675
743
  });
@@ -712,3 +780,4 @@ export {
712
780
  RobotIcon as R,
713
781
  index as i
714
782
  };
783
+ //# sourceMappingURL=index-ifqYByO5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-ifqYByO5.mjs","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/custom/RobotIcon.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/components/custom/MarkdownEditor.tsx","../../admin/src/components/custom/EmbeddingsModal.tsx","../../admin/src/components/custom/EmbeddingsWidget.tsx","../../admin/src/index.tsx"],"sourcesContent":["export const PLUGIN_ID = 'strapi-content-embeddings';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import React from \"react\";\n\ninterface RobotIconProps {\n height?: string | number;\n width?: string | number;\n}\n\nexport function RobotIcon({ height = 48, width = 48 }: RobotIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n height={height}\n viewBox=\"0 -960 960 960\"\n width={width}\n fill=\"currentColor\"\n >\n <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\" />\n </svg>\n );\n}\n","import { RobotIcon } from './custom/RobotIcon';\n\nconst PluginIcon = () => <RobotIcon height={24} width={24} />;\n\nexport { PluginIcon };\n","import { useState } from 'react';\nimport { Box } from '@strapi/design-system';\nimport styled, { createGlobalStyle } from 'styled-components';\nimport {\n MDXEditor,\n headingsPlugin,\n listsPlugin,\n quotePlugin,\n thematicBreakPlugin,\n markdownShortcutPlugin,\n linkPlugin,\n linkDialogPlugin,\n toolbarPlugin,\n BoldItalicUnderlineToggles,\n BlockTypeSelect,\n CreateLink,\n ListsToggle,\n UndoRedo,\n Separator,\n} from '@mdxeditor/editor';\n\ninterface MarkdownEditorProps {\n content: string;\n onChange: (content: string) => void;\n height?: number;\n}\n\nconst MDXEditorStyles = createGlobalStyle`\n /* MDXEditor CSS Variables */\n :root {\n --mdx-spacing-0_5: 0.125rem;\n --mdx-spacing-1: 0.25rem;\n --mdx-spacing-1_5: 0.375rem;\n --mdx-spacing-2: 0.5rem;\n --mdx-spacing-3: 0.75rem;\n --mdx-spacing-4: 1rem;\n --mdx-spacing-36: 9rem;\n --mdx-radius-base: 0.25rem;\n --mdx-radius-medium: 0.375rem;\n --mdx-text-sm: 0.875rem;\n --mdx-baseBg: #f6f6f9;\n --mdx-baseBgActive: #e8e8ec;\n --mdx-basePageBg: #ffffff;\n --mdx-baseBorder: #dcdce4;\n --mdx-baseBorderHover: #b9bbc6;\n --mdx-baseBase: #e0e1e6;\n --mdx-baseTextContrast: #1c2024;\n --mdx-accentText: #4945ff;\n }\n\n /* Toolbar Root - critical for horizontal layout */\n [class*=\"_toolbarRoot\"] {\n z-index: 2;\n display: flex !important;\n flex-direction: row !important;\n flex-wrap: wrap !important;\n gap: var(--mdx-spacing-1);\n border-radius: var(--mdx-radius-medium);\n padding: var(--mdx-spacing-1_5);\n align-items: center !important;\n overflow-x: auto;\n position: sticky;\n top: 0;\n background-color: var(--mdx-baseBg) !important;\n border-bottom: 1px solid var(--mdx-baseBorder);\n width: 100%;\n }\n\n [class*=\"_toolbarRoot\"] div[role='separator'] {\n margin: var(--mdx-spacing-2) var(--mdx-spacing-1);\n border-left: 1px solid var(--mdx-baseBorder);\n border-right: 1px solid var(--mdx-baseBase);\n height: var(--mdx-spacing-4);\n }\n\n [class*=\"_toolbarRoot\"] svg {\n color: var(--mdx-baseTextContrast);\n display: block;\n }\n\n /* Toolbar button groups */\n [class*=\"_toolbarGroupOfGroups\"] {\n display: flex;\n margin: 0 var(--mdx-spacing-1);\n }\n\n [class*=\"_toolbarToggleSingleGroup\"] {\n display: flex;\n align-items: center;\n white-space: nowrap;\n }\n\n /* Toolbar buttons and toggle items */\n [class*=\"_toolbarToggleItem\"],\n [class*=\"_toolbarButton\"] {\n border: 0;\n background-color: transparent;\n font-size: inherit;\n appearance: none;\n box-sizing: border-box;\n cursor: pointer;\n padding: var(--mdx-spacing-0_5);\n border-radius: var(--mdx-radius-base);\n }\n\n [class*=\"_toolbarToggleItem\"]:hover,\n [class*=\"_toolbarButton\"]:hover {\n background-color: var(--mdx-baseBgActive);\n }\n\n [class*=\"_toolbarToggleItem\"][data-state='on'],\n [class*=\"_toolbarButton\"][data-state='on'],\n [class*=\"_toolbarToggleItem\"]:active,\n [class*=\"_toolbarButton\"]:active {\n color: var(--mdx-baseTextContrast);\n background-color: var(--mdx-baseBgActive);\n }\n\n /* Block type select dropdown */\n [class*=\"_toolbarNodeKindSelectTrigger\"],\n [class*=\"_selectTrigger\"] {\n border: 0;\n display: flex;\n color: inherit;\n align-items: center;\n width: var(--mdx-spacing-36);\n padding: var(--mdx-spacing-0_5) var(--mdx-spacing-1);\n padding-inline-start: var(--mdx-spacing-2);\n border-radius: var(--mdx-radius-medium);\n white-space: nowrap;\n font-size: var(--mdx-text-sm);\n background-color: var(--mdx-basePageBg);\n margin: 0 var(--mdx-spacing-1);\n cursor: pointer;\n }\n\n /* Dropdown containers */\n [class*=\"_toolbarNodeKindSelectContainer\"],\n [class*=\"_selectContainer\"] {\n filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.2));\n z-index: 100;\n width: var(--mdx-spacing-36);\n border-radius: var(--mdx-radius-base);\n background-color: var(--mdx-basePageBg);\n font-size: var(--mdx-text-sm);\n }\n\n /* Select items */\n [class*=\"_toolbarNodeKindSelectItem\"],\n [class*=\"_selectItem\"] {\n cursor: pointer;\n display: flex;\n padding: var(--mdx-spacing-2);\n }\n\n [class*=\"_toolbarNodeKindSelectItem\"][data-highlighted],\n [class*=\"_selectItem\"][data-highlighted],\n [class*=\"_toolbarNodeKindSelectItem\"][data-state='checked'],\n [class*=\"_selectItem\"][data-state='checked'] {\n background-color: var(--mdx-baseBg);\n outline: none;\n }\n\n /* Dropdown arrow */\n [class*=\"_selectDropdownArrow\"] {\n margin-left: auto;\n display: flex;\n align-items: center;\n }\n\n /* Content editable area */\n [class*=\"_contentEditable\"] {\n box-sizing: border-box;\n width: 100%;\n color: var(--mdx-baseTextContrast);\n padding: var(--mdx-spacing-3);\n min-height: 200px;\n outline: none;\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-size: 14px;\n line-height: 1.6;\n }\n\n [class*=\"_contentEditable\"]:focus {\n outline: none;\n }\n\n /* Placeholder positioning - ensure it's at the top */\n [class*=\"_contentEditable\"] {\n position: relative;\n }\n\n [class*=\"_contentEditable\"][data-placeholder]::before {\n position: absolute;\n top: var(--mdx-spacing-3);\n left: var(--mdx-spacing-3);\n color: #a5a5ba;\n pointer-events: none;\n }\n\n /* MDXEditor/Lexical placeholder styles */\n [class*=\"_placeholder\"],\n [class*=\"ContentEditable__placeholder\"],\n [class*=\"editor-placeholder\"] {\n position: absolute !important;\n top: var(--mdx-spacing-3) !important;\n left: var(--mdx-spacing-3) !important;\n color: #a5a5ba;\n pointer-events: none;\n overflow: hidden;\n text-overflow: ellipsis;\n user-select: none;\n display: inline-block;\n }\n\n /* Editor root wrapper needs relative positioning for placeholder */\n [class*=\"_rootContentEditableWrapper\"],\n [class*=\"_editorWrapper\"] {\n position: relative;\n display: flex;\n flex-direction: column;\n }\n\n /* Heading styles */\n [class*=\"_contentEditable\"] h1 {\n font-size: 1.75rem;\n font-weight: 600;\n margin: 0 0 1rem;\n }\n\n [class*=\"_contentEditable\"] h2 {\n font-size: 1.5rem;\n font-weight: 600;\n margin: 1rem 0 0.75rem;\n }\n\n [class*=\"_contentEditable\"] h3 {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 1rem 0 0.5rem;\n }\n\n /* Paragraph and list styles */\n [class*=\"_contentEditable\"] p {\n margin: 0 0 1rem;\n }\n\n [class*=\"_contentEditable\"] ul,\n [class*=\"_contentEditable\"] ol {\n margin: 0 0 1rem;\n padding-left: 1.5rem;\n }\n\n [class*=\"_contentEditable\"] li {\n margin: 0.25rem 0;\n }\n\n /* Code styles */\n [class*=\"_contentEditable\"] code {\n background: #f0f0f5;\n padding: 0.2em 0.4em;\n border-radius: 3px;\n font-family: \"Monaco\", \"Menlo\", monospace;\n font-size: 0.9em;\n }\n\n [class*=\"_contentEditable\"] pre {\n background: #2d2d2d;\n color: #f8f8f2;\n padding: 1rem;\n border-radius: 4px;\n overflow-x: auto;\n margin: 0 0 1rem;\n }\n\n [class*=\"_contentEditable\"] pre code {\n background: none;\n padding: 0;\n }\n\n /* Blockquote */\n [class*=\"_contentEditable\"] blockquote {\n border-left: 3px solid #dcdce4;\n margin: 0 0 1rem;\n padding-left: 1rem;\n color: #666;\n }\n\n /* Links */\n [class*=\"_contentEditable\"] a {\n color: #4945ff;\n text-decoration: underline;\n }\n\n /* Horizontal rule */\n [class*=\"_contentEditable\"] hr {\n border: none;\n border-top: 1px solid #dcdce4;\n margin: 1.5rem 0;\n }\n\n /* Editor root */\n [class*=\"_editorRoot\"] {\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n color: var(--mdx-baseTextContrast);\n background: var(--mdx-basePageBg);\n }\n\n /* Link dialog */\n [class*=\"_linkDialogPopoverContent\"] {\n display: flex;\n flex-direction: column;\n gap: var(--mdx-spacing-2);\n padding: var(--mdx-spacing-3);\n background-color: var(--mdx-basePageBg);\n border-radius: var(--mdx-radius-medium);\n box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);\n z-index: 100;\n }\n\n [class*=\"_linkDialogInputWrapper\"] {\n display: flex;\n gap: var(--mdx-spacing-1);\n }\n\n [class*=\"_linkDialogInputWrapper\"] input {\n flex: 1;\n padding: var(--mdx-spacing-1) var(--mdx-spacing-2);\n border: 1px solid var(--mdx-baseBorder);\n border-radius: var(--mdx-radius-base);\n font-size: var(--mdx-text-sm);\n }\n\n [class*=\"_linkDialogInputWrapper\"] button {\n padding: var(--mdx-spacing-1) var(--mdx-spacing-2);\n background-color: var(--mdx-accentText);\n color: white;\n border: none;\n border-radius: var(--mdx-radius-base);\n cursor: pointer;\n }\n\n /* Popover positioning */\n [data-radix-popper-content-wrapper] {\n z-index: 100 !important;\n }\n`;\n\nconst EditorWrapper = styled(Box)<{ $isFocused: boolean }>`\n border: 1px solid ${({ $isFocused }) => ($isFocused ? '#4945ff' : '#dcdce4')};\n border-radius: 4px;\n overflow: hidden;\n background: #fff;\n transition: border-color 0.2s, box-shadow 0.2s;\n box-shadow: ${({ $isFocused }) => ($isFocused ? '0 0 0 2px rgba(73, 69, 255, 0.2)' : 'none')};\n`;\n\n// Toolbar contents component defined outside to prevent re-renders\nfunction ToolbarContents() {\n return (\n <>\n <UndoRedo />\n <Separator />\n <BlockTypeSelect />\n <Separator />\n <BoldItalicUnderlineToggles />\n <Separator />\n <CreateLink />\n <Separator />\n <ListsToggle />\n </>\n );\n}\n\nexport function MarkdownEditor({ content, onChange, height = 300 }: Readonly<MarkdownEditorProps>) {\n const [isFocused, setIsFocused] = useState(false);\n\n return (\n <>\n <MDXEditorStyles />\n <EditorWrapper\n $isFocused={isFocused}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n >\n <div style={{ minHeight: `${height}px` }}>\n <MDXEditor\n markdown={content}\n onChange={onChange}\n placeholder=\"Write your content here...\"\n plugins={[\n headingsPlugin(),\n listsPlugin(),\n quotePlugin(),\n thematicBreakPlugin(),\n linkPlugin(),\n linkDialogPlugin(),\n markdownShortcutPlugin(),\n toolbarPlugin({\n toolbarContents: ToolbarContents,\n }),\n ]}\n />\n </div>\n </EditorWrapper>\n </>\n );\n}\n","import React, { useState, useEffect, useCallback } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport styled from \"styled-components\";\nimport qs from \"qs\";\nimport {\n unstable_useContentManagerContext as useContentManagerContext,\n useFetchClient,\n useNotification,\n} from \"@strapi/strapi/admin\";\nimport {\n Button,\n Typography,\n Box,\n Modal,\n Field,\n TextInput,\n Loader,\n Flex,\n SingleSelect,\n SingleSelectOption,\n} from \"@strapi/design-system\";\nimport { Plus, Eye } from \"@strapi/icons\";\nimport { PLUGIN_ID } from \"../../pluginId\";\nimport { MarkdownEditor } from \"./MarkdownEditor\";\n\nconst StyledTypography = styled(Typography)`\n display: block;\n margin-top: 1rem;\n margin-bottom: 0.5rem;\n`;\n\nconst CHUNK_SIZE = 4000; // Content over this will be auto-chunked\n\ninterface ExistingEmbedding {\n documentId: string;\n title: string;\n content?: string;\n}\n\ninterface TextFieldOption {\n name: string;\n label: string;\n value: string;\n charCount: number;\n}\n\nexport function EmbeddingsModal() {\n const { post, get } = useFetchClient();\n const { toggleNotification } = useNotification();\n const navigate = useNavigate();\n\n // Access content manager context\n const context = useContentManagerContext();\n const { form, id, slug, collectionType } = context;\n\n const modifiedValues = form?.values || {};\n\n const [isVisible, setIsVisible] = useState(false);\n const [title, setTitle] = useState(\"\");\n const [content, setContent] = useState(\"\");\n const [fieldName, setFieldName] = useState(\"\");\n const [availableFields, setAvailableFields] = useState<TextFieldOption[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [isCheckingExisting, setIsCheckingExisting] = useState(true);\n const [existingEmbedding, setExistingEmbedding] = useState<ExistingEmbedding | null>(null);\n\n // Check for existing embedding when component mounts or id changes\n useEffect(() => {\n async function checkExistingEmbedding() {\n if (!id || !slug) {\n setIsCheckingExisting(false);\n return;\n }\n\n try {\n // Query embeddings filtered by metadata containing this documentId\n const query = qs.stringify({\n filters: {\n metadata: { $containsi: id },\n },\n });\n\n const response = await get(`/${PLUGIN_ID}/embeddings/find?${query}`);\n\n // Handle response - could be { data: [...] } or { data: { data: [...] } }\n const embeddings = response.data?.data || response.data || [];\n\n if (Array.isArray(embeddings) && embeddings.length > 0) {\n // Found existing embedding for this content\n setExistingEmbedding({\n documentId: embeddings[0].documentId,\n title: embeddings[0].title,\n content: embeddings[0].content,\n });\n }\n } catch (error) {\n console.error(\"Failed to check for existing embedding:\", error);\n } finally {\n setIsCheckingExisting(false);\n }\n }\n\n checkExistingEmbedding();\n }, [id, slug, get]);\n\n // Extract text value from a field (handles strings, blocks, and dynamic zones)\n const extractTextFromField = useCallback((value: any, depth: number = 0): string => {\n if (!value || depth > 5) return \"\"; // Prevent infinite recursion\n\n // Handle string values\n if (typeof value === \"string\") {\n return value.trim();\n }\n\n // Handle arrays (could be blocks, dynamic zones, or repeatable components)\n if (Array.isArray(value)) {\n const texts: string[] = [];\n\n for (const item of value) {\n // Check if it's a dynamic zone component (has __component property)\n if (item && typeof item === \"object\" && item.__component) {\n // Extract text from all fields in the component\n for (const [key, fieldValue] of Object.entries(item)) {\n if (key === \"__component\" || key === \"id\") continue;\n const extracted = extractTextFromField(fieldValue, depth + 1);\n if (extracted) texts.push(extracted);\n }\n }\n // Check if it's a blocks format item (rich text)\n else if (item && item.children) {\n const blockText = item.children\n .map((child: any) => child.text || \"\")\n .join(\"\");\n if (blockText) texts.push(blockText);\n }\n // Recursively handle nested arrays/objects\n else if (item && typeof item === \"object\") {\n const extracted = extractTextFromField(item, depth + 1);\n if (extracted) texts.push(extracted);\n }\n }\n\n return texts.join(\"\\n\\n\").trim();\n }\n\n // Handle objects (could be a component or relation)\n if (typeof value === \"object\") {\n const texts: string[] = [];\n\n for (const [key, fieldValue] of Object.entries(value)) {\n // Skip metadata fields\n if ([\"id\", \"__component\", \"documentId\", \"createdAt\", \"updatedAt\"].includes(key)) continue;\n const extracted = extractTextFromField(fieldValue, depth + 1);\n if (extracted) texts.push(extracted);\n }\n\n return texts.join(\"\\n\\n\").trim();\n }\n\n return \"\";\n }, []);\n\n // Check if a value is a dynamic zone\n const isDynamicZone = (value: any): boolean => {\n return Array.isArray(value) && value.length > 0 && value[0]?.__component;\n };\n\n // Detect all available text fields from form values\n const detectTextFields = useCallback((): TextFieldOption[] => {\n if (!modifiedValues) return [];\n\n const fields: TextFieldOption[] = [];\n\n // Check all fields in form values\n for (const [name, value] of Object.entries(modifiedValues)) {\n // Skip non-content fields\n if ([\"id\", \"documentId\", \"createdAt\", \"updatedAt\", \"publishedAt\", \"locale\", \"localizations\"].includes(name)) {\n continue;\n }\n\n const textValue = extractTextFromField(value);\n if (textValue && textValue.length > 0) {\n // Create a readable label from field name\n let label = name\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (str) => str.toUpperCase())\n .trim();\n\n // Add indicator for dynamic zones\n if (isDynamicZone(value)) {\n const componentCount = (value as any[]).length;\n label += ` (${componentCount} component${componentCount > 1 ? \"s\" : \"\"})`;\n }\n\n fields.push({\n name,\n label,\n value: textValue,\n charCount: textValue.length,\n });\n }\n }\n\n // Sort by character count (longest first) to prioritize main content\n fields.sort((a, b) => b.charCount - a.charCount);\n\n return fields;\n }, [modifiedValues, extractTextFromField]);\n\n // Update available fields when form values change\n useEffect(() => {\n const fields = detectTextFields();\n setAvailableFields(fields);\n\n // Auto-select first field if none selected\n if (fields.length > 0 && !fieldName) {\n setFieldName(fields[0].name);\n setContent(fields[0].value);\n }\n }, [detectTextFields, fieldName]);\n\n // Handle field selection change\n const handleFieldChange = (selectedFieldName: string) => {\n setFieldName(selectedFieldName);\n const selectedField = availableFields.find(f => f.name === selectedFieldName);\n if (selectedField) {\n setContent(selectedField.value);\n }\n };\n\n const contentLength = content.length;\n const willChunk = contentLength > CHUNK_SIZE;\n const estimatedChunks = willChunk ? Math.ceil(contentLength / (CHUNK_SIZE - 200)) : 1;\n // Check if content is saved (has an id) - don't require publish\n const isSaved = !!id;\n\n // Auto-generate metadata from collection context\n function generateMetadata(): Record<string, any> {\n return {\n source: \"content-manager\",\n collectionType: slug || collectionType || \"unknown\",\n fieldName: fieldName || \"content\",\n documentId: id,\n updatedAt: new Date().toISOString(),\n };\n }\n\n const isValid = title.trim() && content.trim(); // No length limit - auto-chunks if needed\n\n function handleOpenCreate() {\n setTitle(\"\");\n // Refresh available fields and select first one\n const fields = detectTextFields();\n setAvailableFields(fields);\n if (fields.length > 0) {\n setFieldName(fields[0].name);\n setContent(fields[0].value);\n }\n setIsVisible(true);\n }\n\n async function handleSubmit(e: React.FormEvent) {\n e.preventDefault();\n\n if (!title.trim()) {\n toggleNotification({\n type: \"warning\",\n message: \"Embeddings title is required\",\n });\n return;\n }\n\n if (!content.trim()) {\n toggleNotification({\n type: \"warning\",\n message: \"Embeddings content is required\",\n });\n return;\n }\n\n setIsLoading(true);\n\n try {\n const contentToEmbed = content.trim();\n const shouldChunk = contentToEmbed.length > CHUNK_SIZE;\n const chunks = shouldChunk ? Math.ceil(contentToEmbed.length / CHUNK_SIZE) : 1;\n\n if (shouldChunk) {\n console.log(`Creating chunked embedding: ${contentToEmbed.length} chars (~${chunks} parts)`);\n }\n\n const result = await post(`/${PLUGIN_ID}/embeddings/create-embedding`, {\n data: {\n title: title.trim(),\n content: contentToEmbed,\n collectionType: slug || collectionType,\n fieldName,\n metadata: generateMetadata(),\n autoChunk: shouldChunk,\n },\n });\n\n const responseData = result?.data || result;\n\n if (responseData?.documentId) {\n setExistingEmbedding({\n documentId: responseData.documentId,\n title: responseData.title,\n content: responseData.content,\n });\n }\n setIsVisible(false);\n\n const message = shouldChunk\n ? `Embedding created and chunked into ${chunks} parts`\n : \"Embedding created successfully\";\n toggleNotification({ type: \"success\", message });\n } catch (error: any) {\n console.error(\"Failed to create embedding:\", error);\n toggleNotification({\n type: \"danger\",\n message: error.message || \"Failed to create embedding\",\n });\n } finally {\n setIsLoading(false);\n }\n }\n\n function handleViewEmbedding() {\n if (existingEmbedding?.documentId) {\n navigate(`/plugins/${PLUGIN_ID}/embeddings/${existingEmbedding.documentId}`);\n }\n }\n\n // Don't render if not in edit view context\n if (!form || !id) {\n return null;\n }\n\n // Show loading state while checking for existing embedding\n if (isCheckingExisting) {\n return (\n <Box paddingTop={2}>\n <Loader small>Checking embeddings...</Loader>\n </Box>\n );\n }\n\n const submitButtonText = isLoading ? \"Creating...\" : \"Create Embedding\";\n\n return (\n <Box paddingTop={2}>\n {existingEmbedding ? (\n <Button onClick={handleViewEmbedding} startIcon={<Eye />} fullWidth>\n View Embedding\n </Button>\n ) : (\n <Button\n onClick={handleOpenCreate}\n startIcon={<Plus />}\n disabled={!isSaved}\n fullWidth\n >\n Create Embedding\n </Button>\n )}\n\n {!isSaved && !existingEmbedding && (\n <Typography variant=\"pi\" textColor=\"neutral600\" style={{ display: \"block\", marginTop: \"0.5rem\" }}>\n Save content first to create embedding\n </Typography>\n )}\n\n <Modal.Root open={isVisible} onOpenChange={setIsVisible}>\n <Modal.Content>\n <Modal.Header>\n <Modal.Title>Create Embedding from Content</Modal.Title>\n </Modal.Header>\n <Modal.Body>\n <Box>\n <Box marginBottom={4}>\n <Field.Root>\n <Field.Label>Title</Field.Label>\n <TextInput\n placeholder=\"Enter embedding title\"\n value={title}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setTitle(e.target.value)\n }\n />\n </Field.Root>\n </Box>\n\n {availableFields.length > 0 && (\n <Box marginBottom={4}>\n <Field.Root>\n <Field.Label>Source Field</Field.Label>\n <Field.Hint>Select which field to use for the embedding content</Field.Hint>\n </Field.Root>\n <SingleSelect\n value={fieldName}\n onChange={(value: string) => handleFieldChange(value)}\n placeholder=\"Select a field\"\n >\n {availableFields.map((field) => (\n <SingleSelectOption key={field.name} value={field.name}>\n {field.label} ({field.charCount.toLocaleString()} chars)\n </SingleSelectOption>\n ))}\n </SingleSelect>\n </Box>\n )}\n\n <Box marginBottom={4}>\n <Flex justifyContent=\"space-between\" alignItems=\"center\">\n <Field.Root>\n <Field.Label>Content Preview</Field.Label>\n </Field.Root>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {contentLength.toLocaleString()} characters\n {willChunk && (\n <Typography textColor=\"primary600\"> (~{estimatedChunks} chunks)</Typography>\n )}\n </Typography>\n </Flex>\n <MarkdownEditor\n content={content}\n onChange={setContent}\n height={200}\n />\n </Box>\n </Box>\n </Modal.Body>\n <Modal.Footer>\n <Modal.Close>\n <Button variant=\"tertiary\">Cancel</Button>\n </Modal.Close>\n <Button\n onClick={handleSubmit}\n disabled={isLoading || !isValid}\n loading={isLoading}\n >\n {submitButtonText}\n </Button>\n </Modal.Footer>\n </Modal.Content>\n </Modal.Root>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box } from \"@strapi/design-system\";\nimport { EmbeddingsModal } from \"./EmbeddingsModal\";\n\nexport function EmbeddingsWidget() {\n return (\n <Box>\n <EmbeddingsModal />\n </Box>\n );\n}\n","import React from 'react';\nimport { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\nimport { EmbeddingsWidget } from './components/custom/EmbeddingsWidget';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n bootstrap(app: any) {\n app.getPlugin('content-manager').injectComponent('editView', 'right-links', {\n name: \"open-ai-embeddings\",\n Component: () => <EmbeddingsWidget />\n })\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":["useContentManagerContext"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-DkNKkHgk.js");
2
+ const index = require("../_chunks/index-TWbcT-zJ.js");
3
3
  require("react/jsx-runtime");
4
4
  module.exports = index.index;
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -1,5 +1,6 @@
1
- import { i } from "../_chunks/index-C58A29qR.mjs";
1
+ import { i } from "../_chunks/index-ifqYByO5.mjs";
2
2
  import "react/jsx-runtime";
3
3
  export {
4
4
  i as default
5
5
  };
6
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -2070,12 +2070,12 @@ const embeddings = ({ strapi }) => ({
2070
2070
  return chunks.length;
2071
2071
  },
2072
2072
  /**
2073
- * Update embeddings with automatic chunking support
2074
- * Handles re-chunking when content changes and exceeds chunk size
2073
+ * Update a single chunk's content and embedding
2074
+ * Updates only the specified chunk without affecting other chunks in the group
2075
2075
  */
2076
2076
  async updateChunkedEmbedding(id, data) {
2077
- const { title, content, metadata, autoChunk } = data.data;
2078
- const config2 = this.getConfig();
2077
+ const { title, content, metadata } = data.data;
2078
+ this.getConfig();
2079
2079
  const currentEntry = await strapi.documents(CONTENT_TYPE_UID$1).findOne({
2080
2080
  documentId: id
2081
2081
  });
@@ -2083,64 +2083,61 @@ const embeddings = ({ strapi }) => ({
2083
2083
  throw new Error(`Embedding with id ${id} not found`);
2084
2084
  }
2085
2085
  const currentMetadata = currentEntry.metadata;
2086
- const parentDocumentId = currentMetadata?.parentDocumentId || id;
2087
- const newContent = content ?? currentEntry.content;
2088
- const newTitle = title ?? currentMetadata?.originalTitle ?? currentEntry.title;
2089
- const shouldChunk = autoChunk ?? config2.autoChunk;
2090
- const chunkSize = config2.chunkSize || 4e3;
2091
- const contentNeedsChunking = shouldChunk && needsChunking(newContent, chunkSize);
2092
- const existingChunks = await this.findRelatedChunks(id);
2093
- let originalRelated;
2094
- const firstChunk = existingChunks.find(
2095
- (c) => c.metadata?.chunkIndex === 0 || c.documentId === parentDocumentId
2096
- );
2097
- if (firstChunk?.related) {
2098
- originalRelated = firstChunk.related;
2099
- }
2100
- const deletedCount = await this.deleteRelatedChunks(id);
2101
- console.log(`Deleted ${deletedCount} existing chunk(s) for update`);
2102
- const preservedMetadata = { ...metadata };
2103
- delete preservedMetadata?.isChunk;
2104
- delete preservedMetadata?.chunkIndex;
2105
- delete preservedMetadata?.totalChunks;
2106
- delete preservedMetadata?.startOffset;
2107
- delete preservedMetadata?.endOffset;
2108
- delete preservedMetadata?.originalTitle;
2109
- delete preservedMetadata?.parentDocumentId;
2110
- delete preservedMetadata?.estimatedTokens;
2111
- if (contentNeedsChunking) {
2112
- return await this.createChunkedEmbedding({
2113
- data: {
2114
- title: newTitle.replace(/\s*\[Part \d+\/\d+\]$/, ""),
2115
- // Remove old part suffix
2116
- content: newContent,
2117
- collectionType: currentEntry.collectionType || "standalone",
2118
- fieldName: currentEntry.fieldName || "content",
2119
- metadata: preservedMetadata,
2120
- related: originalRelated,
2121
- autoChunk: true
2122
- }
2123
- });
2124
- } else {
2125
- const entity = await this.createEmbedding({
2126
- data: {
2127
- title: newTitle.replace(/\s*\[Part \d+\/\d+\]$/, ""),
2128
- // Remove old part suffix
2086
+ const contentChanged = content !== void 0 && content !== currentEntry.content;
2087
+ console.log(`[updateChunkedEmbedding] Updating single chunk ${id}, contentChanged: ${contentChanged}`);
2088
+ const updateData = {};
2089
+ if (title !== void 0) {
2090
+ const currentTitle = currentEntry.title || "";
2091
+ const partMatch = currentTitle.match(/\s*\[Part \d+\/\d+\]$/);
2092
+ updateData.title = partMatch ? `${title}${partMatch[0]}` : title;
2093
+ }
2094
+ if (content !== void 0) {
2095
+ updateData.content = content;
2096
+ }
2097
+ if (metadata !== void 0) {
2098
+ updateData.metadata = {
2099
+ ...currentMetadata,
2100
+ ...metadata
2101
+ };
2102
+ if (contentChanged) {
2103
+ updateData.metadata.estimatedTokens = estimateTokens(updateData.content || currentEntry.content);
2104
+ }
2105
+ }
2106
+ const updatedEntity = await strapi.documents(CONTENT_TYPE_UID$1).update({
2107
+ documentId: id,
2108
+ data: updateData
2109
+ });
2110
+ if (pluginManager.isInitialized() && (contentChanged || title !== void 0)) {
2111
+ try {
2112
+ console.log(`[updateChunkedEmbedding] Updating embedding in Neon for chunk ${id}`);
2113
+ await pluginManager.deleteEmbedding(id);
2114
+ const newContent = updateData.content || currentEntry.content;
2115
+ const result = await pluginManager.createEmbedding({
2116
+ id,
2117
+ title: updatedEntity.title || currentEntry.title,
2129
2118
  content: newContent,
2130
2119
  collectionType: currentEntry.collectionType || "standalone",
2131
- fieldName: currentEntry.fieldName || "content",
2132
- metadata: preservedMetadata,
2133
- related: originalRelated,
2134
- autoChunk: false
2135
- }
2136
- });
2137
- return {
2138
- entity,
2139
- chunks: [entity],
2140
- totalChunks: 1,
2141
- wasChunked: false
2142
- };
2120
+ fieldName: currentEntry.fieldName || "content"
2121
+ });
2122
+ await strapi.documents(CONTENT_TYPE_UID$1).update({
2123
+ documentId: id,
2124
+ data: {
2125
+ embeddingId: result.embeddingId,
2126
+ embedding: result.embedding
2127
+ }
2128
+ });
2129
+ console.log(`[updateChunkedEmbedding] Successfully updated embedding for chunk ${id}`);
2130
+ } catch (error) {
2131
+ console.error(`Failed to update vector store for ${id}:`, error);
2132
+ }
2143
2133
  }
2134
+ const allChunks = await this.findRelatedChunks(id);
2135
+ return {
2136
+ entity: updatedEntity,
2137
+ chunks: allChunks,
2138
+ totalChunks: allChunks.length,
2139
+ wasChunked: allChunks.length > 1
2140
+ };
2144
2141
  },
2145
2142
  async updateEmbedding(id, data) {
2146
2143
  const { title, content: rawContent, metadata, autoChunk } = data.data;
@@ -2551,3 +2548,4 @@ const index = {
2551
2548
  middlewares
2552
2549
  };
2553
2550
  module.exports = index;
2551
+ //# sourceMappingURL=index.js.map