@basementstudio/sanity-ai-image-plugin 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +300 -257
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/presets/article-featured-image.d.ts +3 -0
- package/dist/presets/article-featured-image.d.ts.map +1 -0
- package/dist/presets/article-featured-image.js +17 -0
- package/dist/presets/article-featured-image.js.map +1 -0
- package/dist/server/constants.d.ts +6 -0
- package/dist/server/constants.d.ts.map +1 -0
- package/{src/server/constants.ts → dist/server/constants.js} +17 -20
- package/dist/server/constants.js.map +1 -0
- package/dist/server/handle-request.d.ts +5 -0
- package/dist/server/handle-request.d.ts.map +1 -0
- package/dist/server/handle-request.js +122 -0
- package/dist/server/handle-request.js.map +1 -0
- package/dist/server/types.d.ts +28 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/utils.d.ts +50 -0
- package/dist/server/utils.d.ts.map +1 -0
- package/dist/server/utils.js +274 -0
- package/dist/server/utils.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +3 -0
- package/dist/server.js.map +1 -0
- package/dist/studio/components/asset-source.d.ts +4 -0
- package/dist/studio/components/asset-source.d.ts.map +1 -0
- package/dist/studio/components/asset-source.js +169 -0
- package/dist/studio/components/asset-source.js.map +1 -0
- package/dist/studio/components/frontend-rate-limit.d.ts +29 -0
- package/dist/studio/components/frontend-rate-limit.d.ts.map +1 -0
- package/dist/studio/components/frontend-rate-limit.js +197 -0
- package/dist/studio/components/frontend-rate-limit.js.map +1 -0
- package/dist/studio/components/generate-button-input.d.ts +8 -0
- package/dist/studio/components/generate-button-input.d.ts.map +1 -0
- package/dist/studio/components/generate-button-input.js +194 -0
- package/dist/studio/components/generate-button-input.js.map +1 -0
- package/dist/studio/components/input-router.d.ts +7 -0
- package/dist/studio/components/input-router.d.ts.map +1 -0
- package/dist/studio/components/input-router.js +21 -0
- package/dist/studio/components/input-router.js.map +1 -0
- package/dist/studio/files.d.ts +9 -0
- package/dist/studio/files.d.ts.map +1 -0
- package/dist/studio/files.js +86 -0
- package/dist/studio/files.js.map +1 -0
- package/dist/studio/frontend-rate-limit.d.ts +29 -0
- package/dist/studio/frontend-rate-limit.d.ts.map +1 -0
- package/dist/studio/frontend-rate-limit.js +197 -0
- package/dist/studio/frontend-rate-limit.js.map +1 -0
- package/dist/studio/plugin.d.ts +3 -0
- package/dist/studio/plugin.d.ts.map +1 -0
- package/dist/studio/plugin.js +47 -0
- package/dist/studio/plugin.js.map +1 -0
- package/dist/studio/settings/schema.d.ts +8 -0
- package/dist/studio/settings/schema.d.ts.map +1 -0
- package/dist/studio/settings/schema.js +110 -0
- package/dist/studio/settings/schema.js.map +1 -0
- package/dist/studio/settings/tool.d.ts +3 -0
- package/dist/studio/settings/tool.d.ts.map +1 -0
- package/dist/studio/settings/tool.js +292 -0
- package/dist/studio/settings/tool.js.map +1 -0
- package/dist/studio/settings-data.d.ts +24 -0
- package/dist/studio/settings-data.d.ts.map +1 -0
- package/dist/studio/settings-data.js +99 -0
- package/dist/studio/settings-data.js.map +1 -0
- package/dist/studio/shared-secret.d.ts +9 -0
- package/dist/studio/shared-secret.d.ts.map +1 -0
- package/dist/studio/shared-secret.js +37 -0
- package/dist/studio/shared-secret.js.map +1 -0
- package/dist/utils/config.d.ts +3 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +59 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/context-fields.d.ts +16 -0
- package/dist/utils/context-fields.d.ts.map +1 -0
- package/dist/utils/context-fields.js +104 -0
- package/dist/utils/context-fields.js.map +1 -0
- package/dist/utils/document-paths.d.ts +10 -0
- package/dist/utils/document-paths.d.ts.map +1 -0
- package/dist/utils/document-paths.js +33 -0
- package/dist/utils/document-paths.js.map +1 -0
- package/dist/utils/models.d.ts +22 -0
- package/dist/utils/models.d.ts.map +1 -0
- package/dist/utils/models.js +76 -0
- package/dist/utils/models.js.map +1 -0
- package/dist/utils/prompts.d.ts +2 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +7 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/shared.d.ts +96 -0
- package/dist/utils/shared.d.ts.map +1 -0
- package/dist/utils/shared.js +17 -0
- package/dist/utils/shared.js.map +1 -0
- package/package.json +73 -67
- package/src/index.ts +0 -23
- package/src/presets/article-featured-image.ts +0 -23
- package/src/server/handle-request.ts +0 -207
- package/src/server/types.ts +0 -30
- package/src/server/utils.ts +0 -395
- package/src/server.ts +0 -14
- package/src/studio/components/asset-source.tsx +0 -297
- package/src/studio/components/generate-button-input.tsx +0 -380
- package/src/studio/components/input-router.tsx +0 -41
- package/src/studio/files.ts +0 -114
- package/src/studio/plugin.tsx +0 -54
- package/src/studio/settings/schema.ts +0 -122
- package/src/studio/settings/tool.tsx +0 -587
- package/src/studio/settings-data.ts +0 -172
- package/src/utils/config.ts +0 -55
- package/src/utils/context-fields.ts +0 -172
- package/src/utils/document-paths.ts +0 -51
- package/src/utils/models.ts +0 -126
- package/src/utils/prompts.ts +0 -6
- package/src/utils/shared.ts +0 -88
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { useFormValue, type InputProps, type ObjectInputProps } from "sanity"
|
|
4
|
-
import type { ImageValue } from "sanity"
|
|
5
|
-
import { GenerateButtonInput } from "./generate-button-input"
|
|
6
|
-
import { doesTargetMatchField } from "../../utils/document-paths"
|
|
7
|
-
import type { ResolvedOptions } from "../../utils/shared"
|
|
8
|
-
|
|
9
|
-
export function InputRouter({
|
|
10
|
-
options,
|
|
11
|
-
props,
|
|
12
|
-
}: {
|
|
13
|
-
options: ResolvedOptions
|
|
14
|
-
props: InputProps
|
|
15
|
-
}) {
|
|
16
|
-
const documentType = useFormValue(["_type"]) as string | undefined
|
|
17
|
-
|
|
18
|
-
if (props.schemaType?.name !== "image") {
|
|
19
|
-
return props.renderDefault(props)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const target = options.targets.find((candidate) =>
|
|
23
|
-
doesTargetMatchField({
|
|
24
|
-
documentType,
|
|
25
|
-
path: props.path,
|
|
26
|
-
target: candidate,
|
|
27
|
-
})
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
if (!target) {
|
|
31
|
-
return props.renderDefault(props)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<GenerateButtonInput
|
|
36
|
-
options={options}
|
|
37
|
-
props={props as ObjectInputProps<ImageValue>}
|
|
38
|
-
target={target}
|
|
39
|
-
/>
|
|
40
|
-
)
|
|
41
|
-
}
|
package/src/studio/files.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
function getPngFilename(filename: string): string {
|
|
4
|
-
const basename = filename.replace(/\.[^/.]+$/, "")
|
|
5
|
-
return `${basename || "reference"}.png`
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export async function convertImageFileToPng(file: File): Promise<File> {
|
|
9
|
-
if (file.type === "image/png") {
|
|
10
|
-
return file
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const imageUrl = URL.createObjectURL(file)
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
const image = await new Promise<HTMLImageElement>((resolve, reject) => {
|
|
17
|
-
const nextImage = new Image()
|
|
18
|
-
nextImage.onload = () => resolve(nextImage)
|
|
19
|
-
nextImage.onerror = () =>
|
|
20
|
-
reject(new Error(`Unable to decode ${file.name} as an image.`))
|
|
21
|
-
nextImage.src = imageUrl
|
|
22
|
-
})
|
|
23
|
-
const canvas = document.createElement("canvas")
|
|
24
|
-
const width = image.naturalWidth || image.width
|
|
25
|
-
const height = image.naturalHeight || image.height
|
|
26
|
-
|
|
27
|
-
canvas.width = width
|
|
28
|
-
canvas.height = height
|
|
29
|
-
|
|
30
|
-
const context = canvas.getContext("2d")
|
|
31
|
-
|
|
32
|
-
if (!context) {
|
|
33
|
-
throw new Error("Unable to convert the reference image to PNG.")
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
context.drawImage(image, 0, 0, width, height)
|
|
37
|
-
|
|
38
|
-
const blob = await new Promise<Blob>((resolve, reject) => {
|
|
39
|
-
canvas.toBlob(
|
|
40
|
-
(nextBlob) => {
|
|
41
|
-
if (nextBlob) {
|
|
42
|
-
resolve(nextBlob)
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
reject(new Error("Unable to convert the reference image to PNG."))
|
|
47
|
-
},
|
|
48
|
-
"image/png",
|
|
49
|
-
1
|
|
50
|
-
)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
return new File([blob], getPngFilename(file.name), { type: "image/png" })
|
|
54
|
-
} finally {
|
|
55
|
-
URL.revokeObjectURL(imageUrl)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function base64ToBlob(base64: string, mimeType: string): Blob {
|
|
60
|
-
const binaryString = atob(base64)
|
|
61
|
-
const bytes = new Uint8Array(binaryString.length)
|
|
62
|
-
|
|
63
|
-
for (const [index, character] of Array.from(binaryString).entries()) {
|
|
64
|
-
bytes[index] = character.charCodeAt(0)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return new Blob([bytes], { type: mimeType })
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function fileExtensionFromMimeType(mimeType: string): string {
|
|
71
|
-
switch (mimeType) {
|
|
72
|
-
case "image/jpeg":
|
|
73
|
-
return "jpg"
|
|
74
|
-
case "image/webp":
|
|
75
|
-
return "webp"
|
|
76
|
-
default:
|
|
77
|
-
return "png"
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function formatFileSize(bytes: number): string {
|
|
82
|
-
if (bytes < 1024) {
|
|
83
|
-
return `${bytes} B`
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const kilobytes = bytes / 1024
|
|
87
|
-
|
|
88
|
-
if (kilobytes < 1024) {
|
|
89
|
-
return `${kilobytes.toFixed(1)} KB`
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return `${(kilobytes / 1024).toFixed(1)} MB`
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function createGeneratedFile(
|
|
96
|
-
result: { data: string; mimeType: string },
|
|
97
|
-
basename: string,
|
|
98
|
-
prefix = "ai-image-plugin"
|
|
99
|
-
): File {
|
|
100
|
-
const extension = fileExtensionFromMimeType(result.mimeType)
|
|
101
|
-
const timestamp = new Date().toISOString().replaceAll(/[:.]/g, "-")
|
|
102
|
-
const safeBasename = basename
|
|
103
|
-
.trim()
|
|
104
|
-
.toLowerCase()
|
|
105
|
-
.replaceAll(/[^a-z0-9]+/g, "-")
|
|
106
|
-
.replaceAll(/^-+|-+$/g, "")
|
|
107
|
-
.slice(0, 40)
|
|
108
|
-
const suffix = safeBasename || "generated"
|
|
109
|
-
const blob = base64ToBlob(result.data, result.mimeType)
|
|
110
|
-
|
|
111
|
-
return new File([blob], `${prefix}-${suffix}-${timestamp}.${extension}`, {
|
|
112
|
-
type: result.mimeType,
|
|
113
|
-
})
|
|
114
|
-
}
|
package/src/studio/plugin.tsx
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { definePlugin, type AssetSource, type InputProps } from "sanity"
|
|
2
|
-
import { createAssetSource } from "./components/asset-source"
|
|
3
|
-
import { InputRouter } from "./components/input-router"
|
|
4
|
-
import { createSettingsSchema } from "./settings/schema"
|
|
5
|
-
import { createSettingsTool } from "./settings/tool"
|
|
6
|
-
import { normalizeOptions } from "../utils/config"
|
|
7
|
-
import type { PluginOptions } from "../utils/shared"
|
|
8
|
-
|
|
9
|
-
export const aiImagePlugin = definePlugin<PluginOptions>((rawOptions) => {
|
|
10
|
-
const options = normalizeOptions(rawOptions)
|
|
11
|
-
const assetSource = options.assetSourceTarget
|
|
12
|
-
? createAssetSource(options)
|
|
13
|
-
: null
|
|
14
|
-
const settingsTool = createSettingsTool(options)
|
|
15
|
-
const settingsSchema = createSettingsSchema(options)
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
name: "ai-image-plugin",
|
|
19
|
-
...(options.registerSettingsSchemaType
|
|
20
|
-
? {
|
|
21
|
-
schema: {
|
|
22
|
-
types: [settingsSchema],
|
|
23
|
-
},
|
|
24
|
-
}
|
|
25
|
-
: {}),
|
|
26
|
-
tools: [
|
|
27
|
-
{
|
|
28
|
-
name: options.settingsToolName,
|
|
29
|
-
title: options.settingsToolTitle,
|
|
30
|
-
component: settingsTool,
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
form: {
|
|
34
|
-
...(assetSource
|
|
35
|
-
? {
|
|
36
|
-
image: {
|
|
37
|
-
assetSources: (previousAssetSources: AssetSource[]) =>
|
|
38
|
-
previousAssetSources.some(
|
|
39
|
-
(previousAssetSource) =>
|
|
40
|
-
previousAssetSource.name === assetSource.name
|
|
41
|
-
)
|
|
42
|
-
? previousAssetSources
|
|
43
|
-
: [...previousAssetSources, assetSource],
|
|
44
|
-
},
|
|
45
|
-
}
|
|
46
|
-
: {}),
|
|
47
|
-
components: {
|
|
48
|
-
input: (props: InputProps) => (
|
|
49
|
-
<InputRouter options={options} props={props} />
|
|
50
|
-
),
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
}
|
|
54
|
-
})
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { defineArrayMember, defineField, defineType } from "sanity"
|
|
2
|
-
import {
|
|
3
|
-
getDefaultAllowedAiImageModel,
|
|
4
|
-
getSupportedAiImageModelOptions,
|
|
5
|
-
} from "../../utils/models"
|
|
6
|
-
import {
|
|
7
|
-
SETTINGS_DOCUMENT_ID,
|
|
8
|
-
SETTINGS_SCHEMA_TYPE,
|
|
9
|
-
type ResolvedOptions,
|
|
10
|
-
} from "../../utils/shared"
|
|
11
|
-
|
|
12
|
-
export function createSettingsSchema(options: ResolvedOptions) {
|
|
13
|
-
return defineType({
|
|
14
|
-
name: SETTINGS_SCHEMA_TYPE,
|
|
15
|
-
title: "AI Image Plugin Settings",
|
|
16
|
-
type: "document",
|
|
17
|
-
fields: [
|
|
18
|
-
defineField({
|
|
19
|
-
name: "title",
|
|
20
|
-
title: "Title",
|
|
21
|
-
type: "string",
|
|
22
|
-
initialValue: "AI Image Plugin Settings",
|
|
23
|
-
readOnly: true,
|
|
24
|
-
}),
|
|
25
|
-
defineField({
|
|
26
|
-
name: "globalPrompt",
|
|
27
|
-
title: "Global Prompt",
|
|
28
|
-
type: "text",
|
|
29
|
-
rows: 8,
|
|
30
|
-
description:
|
|
31
|
-
"Prompt instructions automatically included in every AI Image Plugin generation.",
|
|
32
|
-
}),
|
|
33
|
-
defineField({
|
|
34
|
-
name: "globalModel",
|
|
35
|
-
title: "Default Model",
|
|
36
|
-
type: "string",
|
|
37
|
-
initialValue: getDefaultAllowedAiImageModel(options.allowedModels),
|
|
38
|
-
description:
|
|
39
|
-
"The AI image model used by the plugin unless a different allowed default is configured later.",
|
|
40
|
-
options: {
|
|
41
|
-
list: getSupportedAiImageModelOptions(options.allowedModels),
|
|
42
|
-
},
|
|
43
|
-
}),
|
|
44
|
-
defineField({
|
|
45
|
-
name: "globalReferenceImages",
|
|
46
|
-
title: "Global Reference Images",
|
|
47
|
-
type: "array",
|
|
48
|
-
description:
|
|
49
|
-
"Reference images automatically included in every AI Image Plugin generation.",
|
|
50
|
-
of: [
|
|
51
|
-
defineArrayMember({
|
|
52
|
-
type: "image",
|
|
53
|
-
options: { hotspot: true },
|
|
54
|
-
}),
|
|
55
|
-
],
|
|
56
|
-
}),
|
|
57
|
-
defineField({
|
|
58
|
-
name: "targetConfigs",
|
|
59
|
-
title: "Target Overrides",
|
|
60
|
-
type: "array",
|
|
61
|
-
description:
|
|
62
|
-
"Per-target prompt and reference images for specific AI Image Plugin entry points.",
|
|
63
|
-
of: [
|
|
64
|
-
defineArrayMember({
|
|
65
|
-
type: "object",
|
|
66
|
-
fields: [
|
|
67
|
-
defineField({
|
|
68
|
-
name: "targetId",
|
|
69
|
-
title: "Target ID",
|
|
70
|
-
type: "string",
|
|
71
|
-
validation: (Rule) => Rule.required(),
|
|
72
|
-
options: {
|
|
73
|
-
list: [
|
|
74
|
-
...(options.assetSourceTarget
|
|
75
|
-
? [
|
|
76
|
-
{
|
|
77
|
-
title:
|
|
78
|
-
options.assetSourceTarget.title ||
|
|
79
|
-
options.assetSourceTarget.id,
|
|
80
|
-
value: options.assetSourceTarget.id,
|
|
81
|
-
},
|
|
82
|
-
]
|
|
83
|
-
: []),
|
|
84
|
-
...options.targets.map((target) => ({
|
|
85
|
-
title: target.title || target.id,
|
|
86
|
-
value: target.id,
|
|
87
|
-
})),
|
|
88
|
-
],
|
|
89
|
-
},
|
|
90
|
-
}),
|
|
91
|
-
defineField({
|
|
92
|
-
name: "prompt",
|
|
93
|
-
title: "Prompt",
|
|
94
|
-
type: "text",
|
|
95
|
-
rows: 6,
|
|
96
|
-
}),
|
|
97
|
-
defineField({
|
|
98
|
-
name: "referenceImages",
|
|
99
|
-
title: "Reference Images",
|
|
100
|
-
type: "array",
|
|
101
|
-
of: [
|
|
102
|
-
defineArrayMember({
|
|
103
|
-
type: "image",
|
|
104
|
-
options: { hotspot: true },
|
|
105
|
-
}),
|
|
106
|
-
],
|
|
107
|
-
}),
|
|
108
|
-
],
|
|
109
|
-
}),
|
|
110
|
-
],
|
|
111
|
-
}),
|
|
112
|
-
],
|
|
113
|
-
preview: {
|
|
114
|
-
prepare() {
|
|
115
|
-
return {
|
|
116
|
-
title: "AI Image Plugin Settings",
|
|
117
|
-
subtitle: SETTINGS_DOCUMENT_ID,
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
})
|
|
122
|
-
}
|