fix(payload-ai): convert server actions to api endpoints, drop @payload-config dependency
All checks were successful
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 2s
Monorepo Pipeline / 🧪 Test (push) Successful in 1m20s
Monorepo Pipeline / 🏗️ Build (push) Successful in 3m22s
Monorepo Pipeline / 🧹 Lint (push) Successful in 3m33s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
All checks were successful
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 2s
Monorepo Pipeline / 🧪 Test (push) Successful in 1m20s
Monorepo Pipeline / 🏗️ Build (push) Successful in 3m22s
Monorepo Pipeline / 🧹 Lint (push) Successful in 3m33s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mintel/payload-ai",
|
"name": "@mintel/payload-ai",
|
||||||
"version": "1.9.10",
|
"version": "1.9.13",
|
||||||
"description": "Reusable Payload CMS AI Extensions",
|
"description": "Reusable Payload CMS AI Extensions",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import type { Config, Plugin } from 'payload'
|
import type { Config, Plugin } from 'payload'
|
||||||
import { AIChatPermissionsCollection } from './collections/AIChatPermissions.js'
|
import { AIChatPermissionsCollection } from './collections/AIChatPermissions.js'
|
||||||
import type { PayloadChatPluginConfig } from './types.js'
|
import type { PayloadChatPluginConfig } from './types.js'
|
||||||
|
import { optimizePostEndpoint } from './endpoints/optimizeEndpoint.js'
|
||||||
|
import { generateSlugEndpoint, generateThumbnailEndpoint, generateSingleFieldEndpoint } from './endpoints/generateEndpoints.js'
|
||||||
|
|
||||||
export const payloadChatPlugin =
|
export const payloadChatPlugin =
|
||||||
(pluginOptions: PayloadChatPluginConfig): Plugin =>
|
(pluginOptions: PayloadChatPluginConfig): Plugin =>
|
||||||
@@ -48,6 +50,26 @@ export const payloadChatPlugin =
|
|||||||
return Response.json({ message: "Chat endpoint active" })
|
return Response.json({ message: "Chat endpoint active" })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/api/mintel-ai/optimize',
|
||||||
|
method: 'post',
|
||||||
|
handler: optimizePostEndpoint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/api/mintel-ai/generate-slug',
|
||||||
|
method: 'post',
|
||||||
|
handler: generateSlugEndpoint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/api/mintel-ai/generate-thumbnail',
|
||||||
|
method: 'post',
|
||||||
|
handler: generateThumbnailEndpoint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/api/mintel-ai/generate-single-field',
|
||||||
|
method: 'post',
|
||||||
|
handler: generateSingleFieldEndpoint,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// 3. Inject Chat React Component into Admin UI
|
// 3. Inject Chat React Component into Admin UI
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useField, useDocumentInfo, useForm } from "@payloadcms/ui";
|
import { useField, useDocumentInfo, useForm } from "@payloadcms/ui";
|
||||||
import { generateSingleFieldAction } from "../../actions/generateField.js";
|
|
||||||
|
|
||||||
export function AiFieldButton({ path, field }: { path: string; field: any }) {
|
export function AiFieldButton({ path, field }: { path: string; field: any }) {
|
||||||
const [isGenerating, setIsGenerating] = useState(false);
|
const [isGenerating, setIsGenerating] = useState(false);
|
||||||
const [instructions, setInstructions] = useState("");
|
const [instructions, setInstructions] = useState("");
|
||||||
@@ -44,19 +42,26 @@ export function AiFieldButton({ path, field }: { path: string; field: any }) {
|
|||||||
? field.admin.description
|
? field.admin.description
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const res = await generateSingleFieldAction(
|
const resData = await fetch("/api/api/mintel-ai/generate-single-field", {
|
||||||
(title as string) || "",
|
method: "POST",
|
||||||
draftContent,
|
headers: { "Content-Type": "application/json" },
|
||||||
fieldName,
|
body: JSON.stringify({
|
||||||
fieldDescription,
|
documentTitle: (title as string) || "",
|
||||||
instructions,
|
documentContent: draftContent,
|
||||||
);
|
fieldName,
|
||||||
|
fieldDescription,
|
||||||
|
instructions,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const res = await resData.json();
|
||||||
|
|
||||||
if (res.success && res.text) {
|
if (res.success && res.text) {
|
||||||
setValue(res.text);
|
setValue(res.text);
|
||||||
} else {
|
} else {
|
||||||
alert("Fehler: " + res.error);
|
alert("Fehler: " + res.error);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
|
console.error(e)
|
||||||
alert("Fehler bei der Generierung.");
|
alert("Fehler bei der Generierung.");
|
||||||
} finally {
|
} finally {
|
||||||
setIsGenerating(false);
|
setIsGenerating(false);
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useForm, useField } from "@payloadcms/ui";
|
import { useForm, useField } from "@payloadcms/ui";
|
||||||
import { generateSlugAction } from "../../actions/generateField.js";
|
|
||||||
|
|
||||||
export function GenerateSlugButton({ path }: { path: string }) {
|
export function GenerateSlugButton({ path }: { path: string }) {
|
||||||
const [isGenerating, setIsGenerating] = useState(false);
|
const [isGenerating, setIsGenerating] = useState(false);
|
||||||
const [instructions, setInstructions] = useState("");
|
const [instructions, setInstructions] = useState("");
|
||||||
@@ -45,18 +43,24 @@ export function GenerateSlugButton({ path }: { path: string }) {
|
|||||||
|
|
||||||
setIsGenerating(true);
|
setIsGenerating(true);
|
||||||
try {
|
try {
|
||||||
const res = await generateSlugAction(
|
const resData = await fetch("/api/api/mintel-ai/generate-slug", {
|
||||||
title,
|
method: "POST",
|
||||||
draftContent,
|
headers: { "Content-Type": "application/json" },
|
||||||
initialValue as string,
|
body: JSON.stringify({
|
||||||
instructions,
|
title,
|
||||||
);
|
draftContent,
|
||||||
|
oldSlug: initialValue as string,
|
||||||
|
instructions,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const res = await resData.json();
|
||||||
|
|
||||||
if (res.success && res.slug) {
|
if (res.success && res.slug) {
|
||||||
setValue(res.slug);
|
setValue(res.slug);
|
||||||
} else {
|
} else {
|
||||||
alert("Fehler: " + res.error);
|
alert("Fehler: " + res.error);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
alert("Unerwarteter Fehler.");
|
alert("Unerwarteter Fehler.");
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useForm, useField } from "@payloadcms/ui";
|
import { useForm, useField } from "@payloadcms/ui";
|
||||||
import { generateThumbnailAction } from "../../actions/generateField.js";
|
|
||||||
|
|
||||||
export function GenerateThumbnailButton({ path }: { path: string }) {
|
export function GenerateThumbnailButton({ path }: { path: string }) {
|
||||||
const [isGenerating, setIsGenerating] = useState(false);
|
const [isGenerating, setIsGenerating] = useState(false);
|
||||||
const [instructions, setInstructions] = useState("");
|
const [instructions, setInstructions] = useState("");
|
||||||
@@ -45,17 +43,23 @@ export function GenerateThumbnailButton({ path }: { path: string }) {
|
|||||||
|
|
||||||
setIsGenerating(true);
|
setIsGenerating(true);
|
||||||
try {
|
try {
|
||||||
const res = await generateThumbnailAction(
|
const resData = await fetch("/api/api/mintel-ai/generate-thumbnail", {
|
||||||
draftContent,
|
method: "POST",
|
||||||
title,
|
headers: { "Content-Type": "application/json" },
|
||||||
instructions,
|
body: JSON.stringify({
|
||||||
);
|
draftContent,
|
||||||
|
title,
|
||||||
|
instructions,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const res = await resData.json();
|
||||||
|
|
||||||
if (res.success && res.mediaId) {
|
if (res.success && res.mediaId) {
|
||||||
setValue(res.mediaId);
|
setValue(res.mediaId);
|
||||||
} else {
|
} else {
|
||||||
alert("Fehler: " + res.error);
|
alert("Fehler: " + res.error);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
alert("Unerwarteter Fehler.");
|
alert("Unerwarteter Fehler.");
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useForm, useDocumentInfo } from "@payloadcms/ui";
|
import { useForm, useDocumentInfo } from "@payloadcms/ui";
|
||||||
import { optimizePostText } from "../actions/optimizePost.js";
|
|
||||||
import { Button } from "@payloadcms/ui";
|
import { Button } from "@payloadcms/ui";
|
||||||
|
|
||||||
export function OptimizeButton() {
|
export function OptimizeButton() {
|
||||||
@@ -57,7 +56,12 @@ export function OptimizeButton() {
|
|||||||
// 2. We inject the title so the AI knows what it's writing about
|
// 2. We inject the title so the AI knows what it's writing about
|
||||||
const payloadText = `---\ntitle: "${title}"\n---\n\n${draftContent}`;
|
const payloadText = `---\ntitle: "${title}"\n---\n\n${draftContent}`;
|
||||||
|
|
||||||
const response = await optimizePostText(payloadText, instructions);
|
const res = await fetch("/api/api/mintel-ai/optimize", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ draftContent: payloadText, instructions }),
|
||||||
|
});
|
||||||
|
const response = await res.json();
|
||||||
|
|
||||||
if (response.success && response.lexicalAST) {
|
if (response.success && response.lexicalAST) {
|
||||||
// 3. Inject the new Lexical AST directly into the field form state
|
// 3. Inject the new Lexical AST directly into the field form state
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
"use server";
|
import { PayloadRequest } from "payload";
|
||||||
|
|
||||||
import { getPayloadHMR } from "@payloadcms/next/utilities";
|
|
||||||
// @ts-ignore - dynamic config resolution from next.js payload plugin
|
|
||||||
import configPromise from "@payload-config";
|
|
||||||
import * as fs from "node:fs/promises";
|
import * as fs from "node:fs/promises";
|
||||||
import * as path from "node:path";
|
import * as path from "node:path";
|
||||||
import * as os from "node:os";
|
import * as os from "node:os";
|
||||||
@@ -30,13 +26,9 @@ async function getOrchestrator() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateSlugAction(
|
export const generateSlugEndpoint = async (req: PayloadRequest) => {
|
||||||
title: string,
|
|
||||||
draftContent: string,
|
|
||||||
oldSlug?: string,
|
|
||||||
instructions?: string,
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
|
const { title, draftContent, oldSlug, instructions } = (await req.json?.() || {}) as any;
|
||||||
const orchestrator = await getOrchestrator();
|
const orchestrator = await getOrchestrator();
|
||||||
const newSlug = await orchestrator.generateSlug(
|
const newSlug = await orchestrator.generateSlug(
|
||||||
draftContent,
|
draftContent,
|
||||||
@@ -45,9 +37,8 @@ export async function generateSlugAction(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (oldSlug && oldSlug !== newSlug) {
|
if (oldSlug && oldSlug !== newSlug) {
|
||||||
const payload = await getPayloadHMR({ config: configPromise as any });
|
await req.payload.create({
|
||||||
await payload.create({
|
collection: "redirects" as any,
|
||||||
collection: "redirects",
|
|
||||||
data: {
|
data: {
|
||||||
from: oldSlug,
|
from: oldSlug,
|
||||||
to: newSlug,
|
to: newSlug,
|
||||||
@@ -55,42 +46,25 @@ export async function generateSlugAction(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true, slug: newSlug };
|
return Response.json({ success: true, slug: newSlug });
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return { success: false, error: e.message };
|
return Response.json({ success: false, error: e.message }, { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateThumbnailAction(
|
export const generateThumbnailEndpoint = async (req: PayloadRequest) => {
|
||||||
draftContent: string,
|
|
||||||
title?: string,
|
|
||||||
instructions?: string,
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const payload = await getPayloadHMR({ config: configPromise as any });
|
const { draftContent, title, instructions } = (await req.json?.() || {}) as any;
|
||||||
const OPENROUTER_KEY =
|
const OPENROUTER_KEY =
|
||||||
process.env.OPENROUTER_KEY || process.env.OPENROUTER_API_KEY;
|
process.env.OPENROUTER_KEY || process.env.OPENROUTER_API_KEY;
|
||||||
const REPLICATE_KEY = process.env.REPLICATE_API_KEY;
|
const REPLICATE_KEY = process.env.REPLICATE_API_KEY;
|
||||||
|
|
||||||
if (!OPENROUTER_KEY) {
|
if (!OPENROUTER_KEY) throw new Error("Missing OPENROUTER_API_KEY in .env");
|
||||||
throw new Error("Missing OPENROUTER_API_KEY in .env");
|
if (!REPLICATE_KEY) throw new Error("Missing REPLICATE_API_KEY in .env");
|
||||||
}
|
|
||||||
if (!REPLICATE_KEY) {
|
|
||||||
throw new Error(
|
|
||||||
"Missing REPLICATE_API_KEY in .env (Required for Thumbnails)",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const importDynamic = new Function(
|
const importDynamic = new Function("modulePath", "return import(modulePath)");
|
||||||
"modulePath",
|
const { AiBlogPostOrchestrator } = await importDynamic("@mintel/content-engine");
|
||||||
"return import(modulePath)",
|
const { ThumbnailGenerator } = await importDynamic("@mintel/thumbnail-generator");
|
||||||
);
|
|
||||||
const { AiBlogPostOrchestrator } = await importDynamic(
|
|
||||||
"@mintel/content-engine",
|
|
||||||
);
|
|
||||||
const { ThumbnailGenerator } = await importDynamic(
|
|
||||||
"@mintel/thumbnail-generator",
|
|
||||||
);
|
|
||||||
|
|
||||||
const orchestrator = new AiBlogPostOrchestrator({
|
const orchestrator = new AiBlogPostOrchestrator({
|
||||||
apiKey: OPENROUTER_KEY,
|
apiKey: OPENROUTER_KEY,
|
||||||
@@ -112,8 +86,8 @@ export async function generateThumbnailAction(
|
|||||||
const stat = await fs.stat(tmpPath);
|
const stat = await fs.stat(tmpPath);
|
||||||
const fileName = path.basename(tmpPath);
|
const fileName = path.basename(tmpPath);
|
||||||
|
|
||||||
const newMedia = await payload.create({
|
const newMedia = await req.payload.create({
|
||||||
collection: "media",
|
collection: "media" as any,
|
||||||
data: {
|
data: {
|
||||||
alt: title ? `Thumbnail for ${title}` : "AI Generated Thumbnail",
|
alt: title ? `Thumbnail for ${title}` : "AI Generated Thumbnail",
|
||||||
},
|
},
|
||||||
@@ -125,31 +99,24 @@ export async function generateThumbnailAction(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cleanup temp file
|
|
||||||
await fs.unlink(tmpPath).catch(() => { });
|
await fs.unlink(tmpPath).catch(() => { });
|
||||||
|
|
||||||
return { success: true, mediaId: newMedia.id };
|
return Response.json({ success: true, mediaId: newMedia.id });
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return { success: false, error: e.message };
|
return Response.json({ success: false, error: e.message }, { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function generateSingleFieldAction(
|
|
||||||
documentTitle: string,
|
export const generateSingleFieldEndpoint = async (req: PayloadRequest) => {
|
||||||
documentContent: string,
|
|
||||||
fieldName: string,
|
|
||||||
fieldDescription: string,
|
|
||||||
instructions?: string,
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
|
const { documentTitle, documentContent, fieldName, fieldDescription, instructions } = (await req.json?.() || {}) as any;
|
||||||
|
|
||||||
const OPENROUTER_KEY =
|
const OPENROUTER_KEY =
|
||||||
process.env.OPENROUTER_KEY || process.env.OPENROUTER_API_KEY;
|
process.env.OPENROUTER_KEY || process.env.OPENROUTER_API_KEY;
|
||||||
if (!OPENROUTER_KEY) throw new Error("Missing OPENROUTER_API_KEY");
|
if (!OPENROUTER_KEY) throw new Error("Missing OPENROUTER_API_KEY");
|
||||||
|
|
||||||
const payload = await getPayloadHMR({ config: configPromise as any });
|
const contextDocsData = await req.payload.find({
|
||||||
|
collection: "context-files" as any,
|
||||||
// Fetch context documents from DB
|
|
||||||
const contextDocsData = await payload.find({
|
|
||||||
collection: "context-files",
|
|
||||||
limit: 100,
|
limit: 100,
|
||||||
});
|
});
|
||||||
const projectContext = contextDocsData.docs
|
const projectContext = contextDocsData.docs
|
||||||
@@ -184,8 +151,8 @@ CRITICAL RULES:
|
|||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const text = data.choices?.[0]?.message?.content?.trim() || "";
|
const text = data.choices?.[0]?.message?.content?.trim() || "";
|
||||||
return { success: true, text };
|
return Response.json({ success: true, text });
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return { success: false, error: e.message };
|
return Response.json({ success: false, error: e.message }, { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
"use server";
|
import { PayloadRequest } from 'payload'
|
||||||
|
import { parseMarkdownToLexical } from "../utils/lexicalParser.js";
|
||||||
|
|
||||||
import { parseMarkdownToLexical } from "../utils/lexicalParser";
|
export const optimizePostEndpoint = async (req: PayloadRequest) => {
|
||||||
import { getPayloadHMR } from "@payloadcms/next/utilities";
|
|
||||||
// @ts-ignore - dynamic config resolution from next.js payload plugin
|
|
||||||
import configPromise from "@payload-config";
|
|
||||||
|
|
||||||
export async function optimizePostText(
|
|
||||||
draftContent: string,
|
|
||||||
instructions?: string,
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const payload = await getPayloadHMR({ config: configPromise as any });
|
const { draftContent, instructions } = (await req.json?.() || {}) as { draftContent: string; instructions?: string };
|
||||||
const globalAiSettings = (await payload.findGlobal({ slug: "ai-settings" })) as any;
|
|
||||||
|
if (!draftContent) {
|
||||||
|
return Response.json({ error: 'Missing draftContent' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const globalAiSettings = (await req.payload.findGlobal({ slug: "ai-settings" })) as any;
|
||||||
const customSources =
|
const customSources =
|
||||||
globalAiSettings?.customSources?.map((s: any) => s.sourceName) || [];
|
globalAiSettings?.customSources?.map((s: any) => s.sourceName) || [];
|
||||||
|
|
||||||
@@ -20,18 +18,12 @@ export async function optimizePostText(
|
|||||||
const REPLICATE_KEY = process.env.REPLICATE_API_KEY;
|
const REPLICATE_KEY = process.env.REPLICATE_API_KEY;
|
||||||
|
|
||||||
if (!OPENROUTER_KEY) {
|
if (!OPENROUTER_KEY) {
|
||||||
throw new Error(
|
return Response.json({ error: "OPENROUTER_KEY not found in environment." }, { status: 500 })
|
||||||
"OPENROUTER_KEY or OPENROUTER_API_KEY not found in environment.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const importDynamic = new Function(
|
// Dynamically import to avoid bundling it into client components that might accidentally import this file
|
||||||
"modulePath",
|
const importDynamic = new Function("modulePath", "return import(modulePath)");
|
||||||
"return import(modulePath)",
|
const { AiBlogPostOrchestrator } = await importDynamic("@mintel/content-engine");
|
||||||
);
|
|
||||||
const { AiBlogPostOrchestrator } = await importDynamic(
|
|
||||||
"@mintel/content-engine",
|
|
||||||
);
|
|
||||||
|
|
||||||
const orchestrator = new AiBlogPostOrchestrator({
|
const orchestrator = new AiBlogPostOrchestrator({
|
||||||
apiKey: OPENROUTER_KEY,
|
apiKey: OPENROUTER_KEY,
|
||||||
@@ -39,9 +31,8 @@ export async function optimizePostText(
|
|||||||
model: "google/gemini-3-flash-preview",
|
model: "google/gemini-3-flash-preview",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch context documents purely from DB
|
const contextDocsData = await req.payload.find({
|
||||||
const contextDocsData = await payload.find({
|
collection: "context-files" as any,
|
||||||
collection: "context-files",
|
|
||||||
limit: 100,
|
limit: 100,
|
||||||
});
|
});
|
||||||
const projectContext = contextDocsData.docs.map((doc: any) => doc.content);
|
const projectContext = contextDocsData.docs.map((doc: any) => doc.content);
|
||||||
@@ -49,19 +40,19 @@ export async function optimizePostText(
|
|||||||
const optimizedMarkdown = await orchestrator.optimizeDocument({
|
const optimizedMarkdown = await orchestrator.optimizeDocument({
|
||||||
content: draftContent,
|
content: draftContent,
|
||||||
projectContext,
|
projectContext,
|
||||||
availableComponents: [], // Removed hardcoded config.components dependency
|
availableComponents: [],
|
||||||
instructions,
|
instructions,
|
||||||
internalLinks: [],
|
internalLinks: [],
|
||||||
customSources,
|
customSources,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!optimizedMarkdown || typeof optimizedMarkdown !== "string") {
|
if (!optimizedMarkdown || typeof optimizedMarkdown !== "string") {
|
||||||
throw new Error("AI returned invalid markup.");
|
return Response.json({ error: "AI returned invalid markup." }, { status: 500 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const blocks = parseMarkdownToLexical(optimizedMarkdown);
|
const blocks = parseMarkdownToLexical(optimizedMarkdown);
|
||||||
|
|
||||||
return {
|
return Response.json({
|
||||||
success: true,
|
success: true,
|
||||||
lexicalAST: {
|
lexicalAST: {
|
||||||
root: {
|
root: {
|
||||||
@@ -73,12 +64,12 @@ export async function optimizePostText(
|
|||||||
direction: "ltr",
|
direction: "ltr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
})
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("Failed to optimize post:", error);
|
console.error("Failed to optimize post in endpoint:", error);
|
||||||
return {
|
return Response.json({
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || "An unknown error occurred during optimization.",
|
error: error.message || "An unknown error occurred during optimization.",
|
||||||
};
|
}, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,8 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './globals/AiSettings';
|
export * from './globals/AiSettings';
|
||||||
export * from './actions/generateField';
|
|
||||||
export * from './actions/optimizePost';
|
|
||||||
export * from './components/FieldGenerators/AiFieldButton';
|
export * from './components/FieldGenerators/AiFieldButton';
|
||||||
export * from './components/AiMediaButtons';
|
export * from './components/AiMediaButtons';
|
||||||
export * from './components/OptimizeButton';
|
export * from './components/OptimizeButton';
|
||||||
|
|||||||
11
packages/payload-ai/src/types.d.ts
vendored
11
packages/payload-ai/src/types.d.ts
vendored
@@ -1,5 +1,8 @@
|
|||||||
declare module "@payload-config" {
|
export type PayloadChatPluginConfig = {
|
||||||
import { Config } from "payload";
|
enabled?: boolean
|
||||||
const configPromise: Promise<any>;
|
/** Render the chat bubble on the bottom right? Defaults to true */
|
||||||
export default configPromise;
|
renderChatBubble?: boolean
|
||||||
|
allowedCollections?: string[]
|
||||||
|
mcpServers?: any[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user