@zenith-open/zenithcms-plugin-ai-architect 1.0.0-beta.10 → 1.0.0-beta.31
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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/providers.d.ts +8 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +124 -0
- package/dist/providers.js.map +1 -0
- package/dist/router.d.ts +4 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +283 -0
- package/dist/router.js.map +1 -0
- package/dist/service.d.ts +77 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +666 -0
- package/dist/service.js.map +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAiB,MAAM,8BAA8B,CAAA;AAI1E,eAAO,MAAM,iBAAiB,QAAO,YAapC,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.aiArchitectPlugin = void 0;
|
|
4
|
+
const router_1 = require("./router");
|
|
5
|
+
const zenithcms_core_1 = require("@zenith-open/zenithcms-core");
|
|
6
|
+
const aiArchitectPlugin = () => {
|
|
7
|
+
return {
|
|
8
|
+
id: 'ai-architect',
|
|
9
|
+
name: 'AI Architect',
|
|
10
|
+
description: 'Provides generative AI schemas, real-time SEO analysis, and semantic tools.',
|
|
11
|
+
apply: (config) => config,
|
|
12
|
+
onInit: async (ctx) => {
|
|
13
|
+
// Mount the API routers over the legacy endpoints for backwards compatibility
|
|
14
|
+
;
|
|
15
|
+
ctx.app.use('/api/v1/content-tools', router_1.contentToolsRouter);
|
|
16
|
+
ctx.app.use('/api/v1/system', router_1.systemAiRouter);
|
|
17
|
+
zenithcms_core_1.logger.info('[AI Architect Plugin] Mounted /api/v1/content-tools and /api/v1/system AI extensions');
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
exports.aiArchitectPlugin = aiArchitectPlugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,qCAA6D;AAC7D,gEAAoD;AAE7C,MAAM,iBAAiB,GAAG,GAAiB,EAAE;IAClD,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,6EAA6E;QAC1F,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;QACzB,MAAM,EAAE,KAAK,EAAE,GAAkB,EAAE,EAAE;YACnC,8EAA8E;YAC9E,CAAC;YAAC,GAAG,CAAC,GAAW,CAAC,GAAG,CAAC,uBAAuB,EAAE,2BAAkB,CAAC,CACjE;YAAC,GAAG,CAAC,GAAW,CAAC,GAAG,CAAC,gBAAgB,EAAE,uBAAc,CAAC,CAAA;YACvD,uBAAM,CAAC,IAAI,CAAC,sFAAsF,CAAC,CAAA;QACrG,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAbY,QAAA,iBAAiB,qBAa7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"AAEA,qBAAa,iBAAiB;WACR,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAwD/D,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAmD3G"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AIProviderService = void 0;
|
|
4
|
+
const zenithcms_core_1 = require("@zenith-open/zenithcms-core");
|
|
5
|
+
class AIProviderService {
|
|
6
|
+
static async validateKey(provider, apiKey) {
|
|
7
|
+
try {
|
|
8
|
+
let res;
|
|
9
|
+
switch (provider) {
|
|
10
|
+
case 'openrouter':
|
|
11
|
+
res = await fetch('https://openrouter.ai/api/v1/auth/key', {
|
|
12
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
13
|
+
});
|
|
14
|
+
if (!res.ok)
|
|
15
|
+
throw new Error(`Status ${res.status}`);
|
|
16
|
+
return true;
|
|
17
|
+
case 'openai':
|
|
18
|
+
res = await fetch('https://api.openai.com/v1/models', {
|
|
19
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
20
|
+
});
|
|
21
|
+
if (!res.ok)
|
|
22
|
+
throw new Error(`Status ${res.status}`);
|
|
23
|
+
return true;
|
|
24
|
+
case 'anthropic':
|
|
25
|
+
// Anthropic doesn't have a simple auth endpoint, so we test a fast models list or mock request
|
|
26
|
+
res = await fetch('https://api.anthropic.com/v1/messages', {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'x-api-key': apiKey,
|
|
30
|
+
'anthropic-version': '2023-06-01',
|
|
31
|
+
'content-type': 'application/json'
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
model: "claude-3-haiku-20240307",
|
|
35
|
+
max_tokens: 1,
|
|
36
|
+
messages: [{ role: "user", content: "hi" }]
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
// Anthropic throws 400 Bad Request if key is valid but body is wrong. If 401, it's invalid.
|
|
41
|
+
if (res.status === 400)
|
|
42
|
+
return true;
|
|
43
|
+
throw new Error(`Status ${res.status}`);
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
case 'nvidia': // Nvidia NIM
|
|
47
|
+
res = await fetch('https://integrate.api.nvidia.com/v1/models', {
|
|
48
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok)
|
|
51
|
+
throw new Error(`Status ${res.status}`);
|
|
52
|
+
return true;
|
|
53
|
+
case 'google': // Google Gemini / Vertex
|
|
54
|
+
res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`);
|
|
55
|
+
if (!res.ok)
|
|
56
|
+
throw new Error(`Status ${res.status}`);
|
|
57
|
+
return true;
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported AI provider: ${provider}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
zenithcms_core_1.logger.error(`Validation failed for provider ${provider}: ${err.message}`);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
static async fetchModels(provider, apiKey) {
|
|
68
|
+
try {
|
|
69
|
+
let res;
|
|
70
|
+
let data;
|
|
71
|
+
switch (provider) {
|
|
72
|
+
case 'openrouter': {
|
|
73
|
+
res = await fetch('https://openrouter.ai/api/v1/models', {
|
|
74
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
75
|
+
});
|
|
76
|
+
if (!res.ok)
|
|
77
|
+
throw new Error(`Status ${res.status}`);
|
|
78
|
+
data = await res.json();
|
|
79
|
+
return data.data.map((m) => ({ id: m.id, name: m.name || m.id }));
|
|
80
|
+
}
|
|
81
|
+
case 'openai': {
|
|
82
|
+
res = await fetch('https://api.openai.com/v1/models', {
|
|
83
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
84
|
+
});
|
|
85
|
+
if (!res.ok)
|
|
86
|
+
throw new Error(`Status ${res.status}`);
|
|
87
|
+
data = await res.json();
|
|
88
|
+
return data.data.map((m) => ({ id: m.id, name: m.id }));
|
|
89
|
+
}
|
|
90
|
+
case 'anthropic': {
|
|
91
|
+
return [
|
|
92
|
+
{ id: 'claude-3-5-sonnet-20241022', name: 'Claude 3.5 Sonnet' },
|
|
93
|
+
{ id: 'claude-3-opus-20240229', name: 'Claude 3 Opus' },
|
|
94
|
+
{ id: 'claude-3-haiku-20240307', name: 'Claude 3 Haiku' },
|
|
95
|
+
{ id: 'claude-3-5-haiku-20241022', name: 'Claude 3.5 Haiku' }
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
case 'nvidia': {
|
|
99
|
+
res = await fetch('https://integrate.api.nvidia.com/v1/models', {
|
|
100
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok)
|
|
103
|
+
throw new Error(`Status ${res.status}`);
|
|
104
|
+
data = await res.json();
|
|
105
|
+
return data.data.map((m) => ({ id: m.id, name: m.id }));
|
|
106
|
+
}
|
|
107
|
+
case 'google': {
|
|
108
|
+
res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`);
|
|
109
|
+
if (!res.ok)
|
|
110
|
+
throw new Error(`Status ${res.status}`);
|
|
111
|
+
data = await res.json();
|
|
112
|
+
return data.models.map((m) => ({ id: m.name, name: m.displayName || m.name }));
|
|
113
|
+
}
|
|
114
|
+
default:
|
|
115
|
+
throw new Error(`Unsupported AI provider: ${provider}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
zenithcms_core_1.logger.error(`Fetch models failed for provider ${provider}: ${err.message}`);
|
|
120
|
+
throw new Error('Failed to fetch models from provider');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.AIProviderService = AIProviderService;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"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"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAA;AAUnD,eAAO,MAAM,kBAAkB,EAAE,MAAiB,CAAA;AAkMlD,eAAO,MAAM,cAAc,EAAE,MAAiB,CAAA"}
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.systemAiRouter = exports.contentToolsRouter = void 0;
|
|
7
|
+
const zenithcms_core_1 = require("@zenith-open/zenithcms-core");
|
|
8
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
9
|
+
const express_1 = require("express");
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
12
|
+
const service_1 = require("./service");
|
|
13
|
+
exports.contentToolsRouter = (0, express_1.Router)();
|
|
14
|
+
exports.contentToolsRouter.use(zenithcms_core_1.requireAuth);
|
|
15
|
+
// Protect AI endpoints from billing exhaustion
|
|
16
|
+
const aiLimiter = (0, express_rate_limit_1.default)({
|
|
17
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
18
|
+
max: 20, // limit each IP to 20 AI generation requests per window
|
|
19
|
+
standardHeaders: true,
|
|
20
|
+
legacyHeaders: false,
|
|
21
|
+
message: { error: { message: 'Too many AI generation requests from this IP, please try again after 15 minutes' } }
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Zenith Content Tools API
|
|
25
|
+
* ─────────────────────────────────────────────────────────────────
|
|
26
|
+
* Features that non-technical content managers and editors will love.
|
|
27
|
+
* All endpoints are behind /api/v1/content-tools
|
|
28
|
+
*
|
|
29
|
+
* POST /seo-analysis — Real-time SEO score for a document
|
|
30
|
+
* POST /quality — Readability + content quality score
|
|
31
|
+
* POST /ai/generate — Generate text with AI
|
|
32
|
+
* POST /ai/improve — Improve existing text with AI
|
|
33
|
+
* POST /ai/meta-description — Auto-generate a meta description
|
|
34
|
+
* POST /ai/alt-text — Generate image alt text
|
|
35
|
+
*/
|
|
36
|
+
// ── POST /api/v1/content-tools/seo-analysis ──────────────────────────────────
|
|
37
|
+
exports.contentToolsRouter.post('/seo-analysis', async (req, res, next) => {
|
|
38
|
+
try {
|
|
39
|
+
const { title, description, content, slug } = req.body;
|
|
40
|
+
const result = service_1.AIService.analyzeSeo({ title, description, content, slug });
|
|
41
|
+
res.json((0, zenithcms_core_1.createResponse)(result));
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
next(err);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
// ── POST /api/v1/content-tools/quality ───────────────────────────────────────
|
|
48
|
+
exports.contentToolsRouter.post('/quality', async (req, res, next) => {
|
|
49
|
+
try {
|
|
50
|
+
const { content } = req.body;
|
|
51
|
+
if (!content || typeof content !== 'string') {
|
|
52
|
+
throw new zenithcms_core_1.InvalidPayloadError('"content" string is required');
|
|
53
|
+
}
|
|
54
|
+
const result = service_1.AIService.analyzeContentQuality(content);
|
|
55
|
+
res.json((0, zenithcms_core_1.createResponse)(result));
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
next(err);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
// ── POST /api/v1/content-tools/ai/generate ───────────────────────────────────
|
|
62
|
+
exports.contentToolsRouter.post('/ai/generate', aiLimiter, async (req, res, next) => {
|
|
63
|
+
try {
|
|
64
|
+
const { prompt } = req.body;
|
|
65
|
+
if (!prompt)
|
|
66
|
+
throw new zenithcms_core_1.InvalidPayloadError('"prompt" is required');
|
|
67
|
+
const siteId = req.headers['x-zenith-site-id'];
|
|
68
|
+
const result = await service_1.AIService.generateContent(prompt, siteId);
|
|
69
|
+
res.json((0, zenithcms_core_1.createResponse)({ text: result }));
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
next(err);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// ── POST /api/v1/content-tools/ai/improve ────────────────────────────────────
|
|
76
|
+
exports.contentToolsRouter.post('/ai/improve', aiLimiter, async (req, res, next) => {
|
|
77
|
+
try {
|
|
78
|
+
const { text, instruction } = req.body;
|
|
79
|
+
if (!text || !instruction)
|
|
80
|
+
throw new zenithcms_core_1.InvalidPayloadError('"text" and "instruction" are required');
|
|
81
|
+
const siteId = req.headers['x-zenith-site-id'];
|
|
82
|
+
const result = await service_1.AIService.improveText(text, instruction, siteId);
|
|
83
|
+
res.json((0, zenithcms_core_1.createResponse)({ text: result }));
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
next(err);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// ── POST /api/v1/content-tools/ai/meta-description ───────────────────────────
|
|
90
|
+
exports.contentToolsRouter.post('/ai/meta-description', aiLimiter, async (req, res, next) => {
|
|
91
|
+
try {
|
|
92
|
+
const { title, content } = req.body;
|
|
93
|
+
if (!title || !content)
|
|
94
|
+
throw new zenithcms_core_1.InvalidPayloadError('"title" and "content" are required');
|
|
95
|
+
const siteId = req.headers['x-zenith-site-id'];
|
|
96
|
+
const description = await service_1.AIService.generateMetaDescription(title, content, siteId);
|
|
97
|
+
res.json((0, zenithcms_core_1.createResponse)({ description }));
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
next(err);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// ── POST /api/v1/content-tools/ai/alt-text ───────────────────────────────────
|
|
104
|
+
exports.contentToolsRouter.post('/ai/alt-text', aiLimiter, async (req, res, next) => {
|
|
105
|
+
try {
|
|
106
|
+
const { imageUrl, context } = req.body;
|
|
107
|
+
if (!imageUrl)
|
|
108
|
+
throw new zenithcms_core_1.InvalidPayloadError('"imageUrl" is required');
|
|
109
|
+
const siteId = req.headers['x-zenith-site-id'];
|
|
110
|
+
const altText = await service_1.AIService.generateAltText(imageUrl, context, siteId);
|
|
111
|
+
res.json((0, zenithcms_core_1.createResponse)({ altText }));
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
next(err);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// ── POST /api/v1/content-tools/auto-link ─────────────────────────────────────
|
|
118
|
+
exports.contentToolsRouter.post('/auto-link', async (req, res, next) => {
|
|
119
|
+
try {
|
|
120
|
+
const { content } = req.body;
|
|
121
|
+
if (!content || typeof content !== 'string') {
|
|
122
|
+
throw new zenithcms_core_1.InvalidPayloadError('"content" string is required');
|
|
123
|
+
}
|
|
124
|
+
const adapter = req.zenith?.adapter || zenithcms_core_1.AdapterFactory.getActiveAdapter();
|
|
125
|
+
// @ts-ignore: TS2532 - unresolved type from removing @ts-nocheck
|
|
126
|
+
const config = req.zenith.config;
|
|
127
|
+
const siteId = req.headers['x-zenith-site-id'];
|
|
128
|
+
const suggestions = [];
|
|
129
|
+
for (const col of config.collections) {
|
|
130
|
+
// Check if collection has a title or name field we can match against
|
|
131
|
+
const hasTitle = col.fields.some((f) => f.name === 'title' && ['text', 'string'].includes(f.type));
|
|
132
|
+
const hasName = col.fields.some((f) => f.name === 'name' && ['text', 'string'].includes(f.type));
|
|
133
|
+
if (!hasTitle && !hasName)
|
|
134
|
+
continue;
|
|
135
|
+
let docs = [];
|
|
136
|
+
try {
|
|
137
|
+
// Production Hardening: Limit to 100 docs per collection to prevent OOM crashes
|
|
138
|
+
const filter = {};
|
|
139
|
+
if (siteId)
|
|
140
|
+
filter.siteId = siteId;
|
|
141
|
+
docs = await adapter.find(col.slug, filter, { limit: 100 });
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
for (const doc of docs) {
|
|
147
|
+
const keyword = doc.title || doc.name;
|
|
148
|
+
if (!keyword || keyword.length < 4)
|
|
149
|
+
continue; // Ignore very short generic words
|
|
150
|
+
// Case-insensitive exact word boundary match
|
|
151
|
+
const regex = new RegExp(`\\b${escapeRegExp(keyword)}\\b`, 'i');
|
|
152
|
+
if (regex.test(content)) {
|
|
153
|
+
suggestions.push({
|
|
154
|
+
text: keyword,
|
|
155
|
+
url: `/${col.slug}/${doc.slug || doc.id || doc._id}`,
|
|
156
|
+
collection: col.name,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
res.json((0, zenithcms_core_1.createResponse)({ suggestions }));
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
next(err);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
function escapeRegExp(string) {
|
|
168
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
169
|
+
}
|
|
170
|
+
const VALID_FIELD_TYPES = [
|
|
171
|
+
'text', 'number', 'email', 'textarea', 'checkbox',
|
|
172
|
+
'date', 'select', 'media', 'richtext', 'relation',
|
|
173
|
+
'json', 'slug', 'array', 'blocks',
|
|
174
|
+
];
|
|
175
|
+
const AIFieldSchema = zod_1.z.object({
|
|
176
|
+
name: zod_1.z.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'Field name must be a valid identifier'),
|
|
177
|
+
type: zod_1.z.enum(VALID_FIELD_TYPES),
|
|
178
|
+
label: zod_1.z.string().optional(),
|
|
179
|
+
required: zod_1.z.boolean().optional(),
|
|
180
|
+
unique: zod_1.z.boolean().optional(),
|
|
181
|
+
options: zod_1.z.array(zod_1.z.object({ label: zod_1.z.string(), value: zod_1.z.string() })).optional(),
|
|
182
|
+
defaultValue: zod_1.z.any().optional(),
|
|
183
|
+
});
|
|
184
|
+
const AICollectionSchema = zod_1.z.object({
|
|
185
|
+
name: zod_1.z.string().min(1),
|
|
186
|
+
slug: zod_1.z.string().min(1).regex(/^[a-z0-9-]+$/, 'Slug must be lowercase alphanumeric with hyphens'),
|
|
187
|
+
labels: zod_1.z.object({ singular: zod_1.z.string(), plural: zod_1.z.string() }).optional(),
|
|
188
|
+
drafts: zod_1.z.boolean().optional(),
|
|
189
|
+
timestamps: zod_1.z.boolean().optional(),
|
|
190
|
+
fields: zod_1.z.array(AIFieldSchema).min(1).max(50),
|
|
191
|
+
});
|
|
192
|
+
exports.systemAiRouter = (0, express_1.Router)();
|
|
193
|
+
exports.systemAiRouter.use(zenithcms_core_1.requireAuth);
|
|
194
|
+
exports.systemAiRouter.post('/ai/models/fetch', aiLimiter, (0, zenithcms_core_1.requireRole)('admin'), async (req, res, next) => {
|
|
195
|
+
try {
|
|
196
|
+
const { provider, apiKey } = req.body;
|
|
197
|
+
if (!provider)
|
|
198
|
+
throw new zenithcms_core_1.InvalidPayloadError('Provider is required');
|
|
199
|
+
let finalApiKey = apiKey;
|
|
200
|
+
if (!finalApiKey || finalApiKey === '[MASKED_CREDENTIAL]') {
|
|
201
|
+
const adapter = req.zenith?.adapter;
|
|
202
|
+
const siteId = req.headers['x-zenith-site-id'];
|
|
203
|
+
// ISOLATION FIX: scope settings lookup to siteId
|
|
204
|
+
const settingsQuery = siteId ? { siteId } : {};
|
|
205
|
+
const settings = await adapter?.findOne('z_settings', settingsQuery);
|
|
206
|
+
const keyMap = {
|
|
207
|
+
openrouter: 'openRouterApiKey',
|
|
208
|
+
openai: 'openaiApiKey',
|
|
209
|
+
anthropic: 'anthropicApiKey',
|
|
210
|
+
google: 'googleApiKey',
|
|
211
|
+
groq: 'groqApiKey',
|
|
212
|
+
nvidia: 'nvidiaApiKey',
|
|
213
|
+
together: 'togetherApiKey',
|
|
214
|
+
mistral: 'mistralApiKey',
|
|
215
|
+
cohere: 'cohereApiKey',
|
|
216
|
+
xai: 'xaiApiKey'
|
|
217
|
+
};
|
|
218
|
+
const dbKey = settings?.[keyMap[provider]];
|
|
219
|
+
if (dbKey && dbKey !== '[MASKED_CREDENTIAL]') {
|
|
220
|
+
finalApiKey = dbKey;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (!finalApiKey || finalApiKey === '[MASKED_CREDENTIAL]') {
|
|
224
|
+
throw new zenithcms_core_1.InvalidPayloadError(`No valid API key provided or found for ${provider}`);
|
|
225
|
+
}
|
|
226
|
+
const models = await service_1.AIService.fetchModels(provider, finalApiKey);
|
|
227
|
+
res.json((0, zenithcms_core_1.createResponse)({ models }));
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
next(err);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
exports.systemAiRouter.post('/ai/test', aiLimiter, (0, zenithcms_core_1.requireRole)('admin'), async (req, res, next) => {
|
|
234
|
+
try {
|
|
235
|
+
const { provider, model, apiKey } = req.body;
|
|
236
|
+
if (!provider || !model)
|
|
237
|
+
throw new zenithcms_core_1.InvalidPayloadError('Provider and Model are required');
|
|
238
|
+
let finalApiKey = apiKey;
|
|
239
|
+
if (!finalApiKey || finalApiKey === '[MASKED_CREDENTIAL]') {
|
|
240
|
+
const adapter = req.zenith?.adapter;
|
|
241
|
+
const siteId = req.headers['x-zenith-site-id'];
|
|
242
|
+
// ISOLATION FIX: scope settings lookup to siteId
|
|
243
|
+
const settingsQuery = siteId ? { siteId } : {};
|
|
244
|
+
const settings = await adapter?.findOne('z_settings', settingsQuery);
|
|
245
|
+
const keyMap = {
|
|
246
|
+
openrouter: 'openRouterApiKey',
|
|
247
|
+
openai: 'openaiApiKey',
|
|
248
|
+
anthropic: 'anthropicApiKey',
|
|
249
|
+
google: 'googleApiKey',
|
|
250
|
+
groq: 'groqApiKey',
|
|
251
|
+
nvidia: 'nvidiaApiKey',
|
|
252
|
+
together: 'togetherApiKey',
|
|
253
|
+
mistral: 'mistralApiKey',
|
|
254
|
+
cohere: 'cohereApiKey',
|
|
255
|
+
xai: 'xaiApiKey'
|
|
256
|
+
};
|
|
257
|
+
const dbKey = settings?.[keyMap[provider]];
|
|
258
|
+
if (dbKey && dbKey !== '[MASKED_CREDENTIAL]') {
|
|
259
|
+
finalApiKey = dbKey;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (!finalApiKey || finalApiKey === '[MASKED_CREDENTIAL]') {
|
|
263
|
+
throw new zenithcms_core_1.InvalidPayloadError(`No valid API key provided or found for ${provider}`);
|
|
264
|
+
}
|
|
265
|
+
const result = await service_1.AIService.testConnection(provider, model, finalApiKey);
|
|
266
|
+
res.json((0, zenithcms_core_1.createResponse)({ result }));
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
next(err);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
exports.systemAiRouter.post('/ai/tag-image', aiLimiter, async (req, res, next) => {
|
|
273
|
+
try {
|
|
274
|
+
const { imageUrl } = req.body;
|
|
275
|
+
if (!imageUrl)
|
|
276
|
+
throw new zenithcms_core_1.InvalidPayloadError('imageUrl is required');
|
|
277
|
+
const result = await service_1.AIService.generateImageTags(imageUrl);
|
|
278
|
+
res.json((0, zenithcms_core_1.createResponse)(result));
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
next(err);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export interface ContentQualityResult {
|
|
2
|
+
score: number;
|
|
3
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
4
|
+
readabilityScore: number;
|
|
5
|
+
wordCount: number;
|
|
6
|
+
sentenceCount: number;
|
|
7
|
+
avgWordsPerSentence: number;
|
|
8
|
+
issues: string[];
|
|
9
|
+
suggestions: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface SeoAnalysis {
|
|
12
|
+
score: number;
|
|
13
|
+
titleLength: number;
|
|
14
|
+
descriptionLength: number;
|
|
15
|
+
issues: string[];
|
|
16
|
+
suggestions: string[];
|
|
17
|
+
passed: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface SmartTagResult {
|
|
20
|
+
tags: string[];
|
|
21
|
+
categories: string[];
|
|
22
|
+
colors: string[];
|
|
23
|
+
mood: string;
|
|
24
|
+
description: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Zenith AI Service
|
|
28
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
29
|
+
* Enterprise multi-provider AI engine with automatic fallback chain.
|
|
30
|
+
*
|
|
31
|
+
* Supported providers (in priority order):
|
|
32
|
+
* 1. OpenRouter — 200+ models via unified gateway (OPENROUTER_API_KEY)
|
|
33
|
+
* 2. xAI / Grok — Grok models from xAI (XAI_API_KEY)
|
|
34
|
+
* 3. NVIDIA NIM — GPU-accelerated open models (NVIDIA_API_KEY)
|
|
35
|
+
* 4. Groq — Ultra-fast LPU inference (GROQ_API_KEY)
|
|
36
|
+
* 5. Together AI — Open-source models at scale (TOGETHER_API_KEY)
|
|
37
|
+
* 6. Mistral AI — Mistral & Codestral models (MISTRAL_API_KEY)
|
|
38
|
+
* 7. Cohere — Enterprise RAG-optimized models (COHERE_API_KEY)
|
|
39
|
+
* 8. OpenAI — GPT-4o, o1, o3 family (OPENAI_API_KEY)
|
|
40
|
+
* 9. Anthropic — Claude 3.5 Sonnet/Haiku/Opus (ANTHROPIC_API_KEY)
|
|
41
|
+
* 10. Google Gemini— Gemini Pro/Flash (GOOGLE_API_KEY)
|
|
42
|
+
*
|
|
43
|
+
* Keys can be set via environment variables OR via the z_settings database
|
|
44
|
+
* record (configured through the Admin UI — takes precedence over env).
|
|
45
|
+
*/
|
|
46
|
+
export declare class AIService {
|
|
47
|
+
private static fetchWithTimeout;
|
|
48
|
+
private static sanitizeInput;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve all AI credentials — DB settings take precedence over env vars.
|
|
51
|
+
* This allows keys configured via the Admin UI to override local .env values.
|
|
52
|
+
*/
|
|
53
|
+
private static resolveKeys;
|
|
54
|
+
/**
|
|
55
|
+
* Core dispatch — calls the preferred provider based on aiProvider setting,
|
|
56
|
+
* then falls back through the full chain if that fails.
|
|
57
|
+
*/
|
|
58
|
+
private static callAI;
|
|
59
|
+
static testConnection(provider: string, model: string, apiKey: string): Promise<string>;
|
|
60
|
+
static generateContent(prompt: string, siteId?: string): Promise<string>;
|
|
61
|
+
static improveText(text: string, instruction: string, siteId?: string): Promise<string>;
|
|
62
|
+
static generateMetaDescription(title: string, content: string, siteId?: string): Promise<string>;
|
|
63
|
+
static generateAltText(imageUrl: string, context?: string, siteId?: string): Promise<string>;
|
|
64
|
+
static generateImageTags(imageUrl: string, siteId?: string): Promise<SmartTagResult>;
|
|
65
|
+
static analyzeContentQuality(text: string): ContentQualityResult;
|
|
66
|
+
static analyzeSeo(data: {
|
|
67
|
+
title?: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
content?: string;
|
|
70
|
+
slug?: string;
|
|
71
|
+
}): SeoAnalysis;
|
|
72
|
+
static fetchModels(provider: string, apiKey: string): Promise<Array<{
|
|
73
|
+
value: string;
|
|
74
|
+
label: string;
|
|
75
|
+
}>>;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAClC,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,SAAS;mBACC,gBAAgB;IAUrC,OAAO,CAAC,MAAM,CAAC,aAAa;IAQ5B;;;OAGG;mBACkB,WAAW;IAqEhC;;;OAGG;mBACkB,MAAM;WAuMd,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAoBhF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAIjE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAMhF,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAOzF,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAgBrF,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA8G1F,MAAM,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB;IA8ChE,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW;WAkElG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CA+E7G"}
|