Skip to content

Commit 8e8ad03

Browse files
committed
feat: configurable tvs & resource fields
1 parent 62ae55d commit 8e8ad03

File tree

6 files changed

+291
-110
lines changed

6 files changed

+291
-110
lines changed

_build/gpm.yaml

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,31 @@ systemSettings:
3030
value: 2048
3131
description: "To manage costs, 1000 tokens is roughly equal to 750 words."
3232

33-
- key: prompt.base
34-
area: prompt
33+
- key: global.base.prompt
34+
area: global
3535
type: 'textarea'
3636
description: "This is an overall instruction modifier that is added to each API request by default, similar to what you would enter for Customize ChatGPT on their website."
37-
- key: prompt.pagetitle
38-
area: prompt
37+
38+
- key: res.fields
39+
area: resource
40+
value: 'pagetitle,longtitle,introtext,description,content'
41+
42+
- key: res.pagetitle.prompt
43+
area: resource
3944
type: 'textarea'
4045
value: "- You are a SEO expert\n- Your task is to generate a Page Title from from the page content for use as the main H1 tag on the page.\n- The Title shouldn't exceed 60 characters, though shorter is also OK\n- Don't use any HTML or markdown tags"
41-
- key: prompt.longtitle
42-
area: prompt
46+
- key: res.longtitle.prompt
47+
area: resource
4348
type: 'textarea'
4449
value: "- You are a SEO expert\n- Your task is to generate an optimal Meta Title from the page content.\n- The Meta Title can't exceed 70 characters\n- Don't use any HTML or markdown tags\n- Don't wrap the Meta Title in quotes"
4550
description: "Use this for the meta title—also works with SEO Suite."
46-
- key: prompt.introtext
47-
area: prompt
51+
- key: res.introtext.prompt
52+
area: resource
4853
type: 'textarea'
4954
value: "- You are an assistant that summarizes content.\n- Your task is to generate concise summary of the page content.\n- Don't use any HTML or markdown tags"
5055
description: "Use this to generate a summary of the page content—used as starting point for image generation."
51-
- key: prompt.description
52-
area: prompt
56+
- key: res.description.prompt
57+
area: resource
5358
type: 'textarea'
5459
value: "- You are a SEO expert\n- Your task is to generate SEO Meta Description\n- Description can't exceed 155 characters\n- Don't use any HTML or markdown tags"
5560
description: "Use this for the meta description—also works with SEO Suite."
@@ -76,3 +81,5 @@ systemSettings:
7681
value: standard
7782
description: "Valid options are `standard` (default) and `hd`."
7883

84+
- key: tvs
85+
area: tvs

assets/components/modai/js/mgr/autosummary.js

Lines changed: 202 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,89 @@ Ext.onReady(function() {
158158
return wrapper;
159159
}
160160

161-
const attach = (cmp, fieldName) => {
161+
const createFreeTextPrompt = (cacheKey) => {
162+
const wandEl = createWandEl();
163+
wandEl.addEventListener('click', () => {
164+
const win = MODx.load({
165+
xtype: 'modai-window-text_prompt',
166+
title: 'Text',
167+
cache: freePromptCache.get(cacheKey)
168+
});
169+
170+
win.show();
171+
});
172+
173+
return wandEl;
174+
}
175+
176+
const createForcedTextPrompt = (field, fieldName) => {
177+
const aiWrapper = document.createElement('span');
178+
const historyNav = createHistoryNav(field, fieldName);
179+
180+
aiWrapper.historyNav = historyNav;
181+
182+
const wandEl = createWandEl();
183+
wandEl.addEventListener('click', () => {
184+
Ext.Msg.wait('Generating ...', 'Please wait');
185+
186+
MODx.Ajax.request({
187+
url: MODx.config.connector_url,
188+
params: {
189+
action: 'modAI\\Processors\\Prompt\\Text',
190+
id: MODx.request.id,
191+
field: fieldName
192+
},
193+
listeners: {
194+
success: {
195+
fn: (r) => {
196+
cache.store(fieldName, r.object.content);
197+
Ext.Msg.hide();
198+
}
199+
},
200+
failure: {
201+
fn: function() {
202+
Ext.Msg.alert("Failed", "Failed to generated. Please try again.");
203+
Ext.Msg.hide();
204+
} ,
205+
scope: this
206+
}
207+
}
208+
});
209+
});
210+
211+
aiWrapper.appendChild(wandEl);
212+
aiWrapper.appendChild(historyNav);
213+
214+
cache.init(fieldName, field, aiWrapper);
215+
216+
return aiWrapper;
217+
}
218+
219+
const createImagePrompt = (defaultPrompt, onSuccess) => {
220+
const imageWand = createWandEl();
221+
imageWand.addEventListener('click', () => {
222+
const createColumn = MODx.load({
223+
xtype: 'modai-window-image_prompt',
224+
title: 'Image',
225+
record: {
226+
resource: MODx.request.id,
227+
prompt: defaultPrompt,
228+
},
229+
listeners: {
230+
success: {
231+
fn: onSuccess,
232+
scope:this
233+
}
234+
}
235+
});
236+
237+
createColumn.show();
238+
});
239+
240+
return imageWand;
241+
}
242+
243+
const attachField = (cmp, fieldName) => {
162244
const field = Ext.getCmp(cmp);
163245
if (!field) return;
164246

@@ -204,122 +286,153 @@ Ext.onReady(function() {
204286
field.label.appendChild(wrapper);
205287
}
206288

207-
const attachImagePlus = () => {
208-
document.querySelectorAll('.imageplus-panel-input').forEach((el) => {
209-
const imagePlus = Ext.getCmp(el.firstChild.id);
210-
211-
const imageWand = createWandEl();
212-
imageWand.addEventListener('click', () => {
213-
const createColumn = MODx.load({
214-
xtype: 'modai-window-image_prompt',
215-
title: 'Image',
216-
record: {
217-
resource: MODx.request.id,
218-
prompt: Ext.getCmp('modx-resource-introtext').getValue(),
219-
},
220-
listeners: {
221-
'success': {fn:function(res) {
222-
imagePlus.imageBrowser.setValue(res.a.result.object.url);
223-
imagePlus.onImageChange(res.a.result.object.url)
224-
},scope:this}
225-
}
226-
});
289+
const attachImagePlus = (imgPlusPanel) => {
290+
const imagePlus = Ext.getCmp(imgPlusPanel.firstChild.id);
227291

228-
createColumn.show();
229-
});
292+
const imageWand = createImagePrompt(
293+
// Ext.getCmp('modx-resource-introtext').getValue(),
294+
'',
295+
function(res) {
296+
imagePlus.imageBrowser.setValue(res.a.result.object.url);
297+
imagePlus.onImageChange(res.a.result.object.url)
298+
}
299+
);
230300

231-
const altTextWand = createWandEl();
232-
altTextWand.style.marginTop = '6px';
233-
altTextWand.addEventListener('click', () => {
234-
const imgElement = imagePlus.imagePreview.el.dom;
301+
const altTextWand = createWandEl();
302+
altTextWand.style.marginTop = '6px';
303+
altTextWand.addEventListener('click', () => {
304+
const imgElement = imagePlus.imagePreview.el.dom;
235305

236-
const canvas = document.createElement('canvas');
237-
const ctx = canvas.getContext('2d');
306+
const canvas = document.createElement('canvas');
307+
const ctx = canvas.getContext('2d');
238308

239-
canvas.width = imgElement.width;
240-
canvas.height = imgElement.height;
309+
canvas.width = imgElement.width;
310+
canvas.height = imgElement.height;
241311

242-
ctx.drawImage(imgElement, 0, 0);
312+
ctx.drawImage(imgElement, 0, 0);
243313

244-
const base64Data = canvas.toDataURL('image/png');
314+
const base64Data = canvas.toDataURL('image/png');
245315

246-
Ext.Msg.wait('Generating ...', 'Please wait');
316+
Ext.Msg.wait('Generating ...', 'Please wait');
247317

248-
MODx.Ajax.request({
249-
url: MODx.config.connector_url,
250-
params: {
251-
action: 'modAI\\Processors\\Prompt\\Vision',
252-
image: base64Data
253-
},
254-
listeners: {
255-
success: {
256-
fn: (r) => {
257-
imagePlus.altTextField.items.items[0].setValue(r.object.content);
258-
imagePlus.image.altTag = r.object.content;
259-
imagePlus.updateValue();
260-
Ext.Msg.hide();
261-
}
262-
},
263-
failure: {
264-
fn: function() {
265-
Ext.Msg.alert("Failed", "Failed to generated. Please try again.");
266-
Ext.Msg.hide();
267-
} ,
268-
scope: this
318+
MODx.Ajax.request({
319+
url: MODx.config.connector_url,
320+
params: {
321+
action: 'modAI\\Processors\\Prompt\\Vision',
322+
image: base64Data
323+
},
324+
listeners: {
325+
success: {
326+
fn: (r) => {
327+
imagePlus.altTextField.items.items[0].setValue(r.object.content);
328+
imagePlus.image.altTag = r.object.content;
329+
imagePlus.updateValue();
330+
Ext.Msg.hide();
269331
}
332+
},
333+
failure: {
334+
fn: function() {
335+
Ext.Msg.alert("Failed", "Failed to generated. Please try again.");
336+
Ext.Msg.hide();
337+
} ,
338+
scope: this
270339
}
271-
});
340+
}
272341
});
342+
});
273343

274-
imagePlus.altTextField.el.dom.style.display = 'flex';
275-
imagePlus.altTextField.el.dom.style.justifyItems = 'center';
276-
imagePlus.altTextField.el.dom.style.alignItems = 'center';
344+
imagePlus.altTextField.el.dom.style.display = 'flex';
345+
imagePlus.altTextField.el.dom.style.justifyItems = 'center';
346+
imagePlus.altTextField.el.dom.style.alignItems = 'center';
277347

278-
imagePlus.el.dom.parentElement.parentElement.parentElement.querySelector('label').appendChild(imageWand);
279-
imagePlus.altTextField.el.dom.appendChild(altTextWand);
280-
})
348+
imagePlus.el.dom.parentElement.parentElement.parentElement.querySelector('label').appendChild(imageWand);
349+
imagePlus.altTextField.el.dom.appendChild(altTextWand);
281350
};
282351

283352
const attachContent = () => {
284353
const cmp = Ext.getCmp('modx-resource-content');
285354
const label = cmp.el.dom.querySelector('label');
355+
label.appendChild(createFreeTextPrompt('modx-resource-content'));
356+
};
286357

287-
const wandEl = createWandEl();
288-
wandEl.addEventListener('click', () => {
289-
const win = MODx.load({
290-
xtype: 'modai-window-text_prompt',
291-
title: 'Text',
292-
cache: freePromptCache.get('modx-resource-content'),
293-
listeners: {
294-
success: {
295-
fn: function(res) {
296-
console.log(res);
297-
},
298-
scope:this
299-
}
358+
const attachTVs = () => {
359+
const form = Ext.getCmp('modx-panel-resource').getForm();
360+
for (const [tvId, tvName] of (modAI?.tvs || [])) {
361+
const wrapper = Ext.get(`tv${tvId}-tr`);
362+
if (!wrapper) {
363+
continue;
364+
}
365+
366+
const field = form.findField(`tv${tvId}`);
367+
if (!field) {
368+
const imgPlusPanel = wrapper.dom.querySelector('.imageplus-panel-input');
369+
if (imgPlusPanel) {
370+
attachImagePlus(imgPlusPanel);
300371
}
301-
});
372+
continue;
373+
}
302374

303-
win.show();
304-
});
375+
if (field.xtype === 'textfield') {
376+
const prompt = MODx.config[`modai.tv.${tvName}.prompt`];
305377

306-
label.appendChild(wandEl);
307-
};
378+
const label = wrapper.dom.querySelector('label');
308379

309-
Ext.defer(function() {
310-
attach('modx-resource-pagetitle', 'pagetitle');
380+
if (prompt) {
381+
label.appendChild(createForcedTextPrompt(field, `tv.${tvName}`));
382+
} else {
383+
label.appendChild(createFreeTextPrompt(`tv${tvId}`));
384+
}
385+
}
386+
387+
if (field.xtype === 'modx-panel-tv-image') {
388+
const imageWand = createImagePrompt(
389+
'',
390+
function(res) {
391+
const eventData = {
392+
relativeUrl: res.a.result.object.url,
393+
url: res.a.result.object.url
394+
};
395+
396+
field.items.items[1].fireEvent('select', eventData)
397+
field.fireEvent('select', eventData);
398+
}
399+
);
400+
401+
const label = wrapper.dom.querySelector('label');
402+
label.appendChild(imageWand);
403+
}
404+
}
311405

312-
attach('modx-resource-introtext', 'introtext');
406+
}
313407

314-
attach('modx-resource-longtitle', 'longtitle');
315-
attach('seosuite-longtitle', 'longtitle');
408+
const attachResourceFields = () => {
409+
const fieldsMap = {
410+
pagetitle: ['modx-resource-pagetitle'],
411+
longtitle: ['modx-resource-longtitle', 'seosuite-longtitle'],
412+
introtext: ['modx-resource-introtext'],
413+
description: ['modx-resource-description', 'seosuite-description'],
414+
content: ['modx-resource-content'],
415+
};
416+
417+
for (const field of modAI?.resourceFields || []) {
418+
if (!fieldsMap[field]) {
419+
continue;
420+
}
316421

317-
attach('modx-resource-description', 'description');
318-
attach('seosuite-description', 'description');
422+
if (field === 'content') {
423+
attachContent();
424+
continue;
425+
}
319426

320-
attachContent();
427+
fieldsMap[field].forEach((cmpId) => {
428+
attachField(cmpId, `res.${field}`);
429+
})
321430

322-
attachImagePlus();
431+
}
432+
}
323433

434+
Ext.defer(function() {
435+
attachResourceFields();
436+
attachTVs();
324437
}, 500);
325438
});

core/components/modai/elements/plugins/modai.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
<script type="text/javascript">
3333
Ext.onReady(function() {
3434
modAI.config = ' . $modx->toJSON($modAI->config) . ';
35+
modAI.tvs = ' . $modx->toJSON($modAI->getListOfTVsWithIDs()) . ';
36+
modAI.resourceFields = ' . $modx->toJSON($modAI->getResourceFields()) . ';
3537
});
3638
</script>
3739
');
@@ -41,4 +43,4 @@
4143
$modx->regClientStartupScript($assetsUrl . 'js/mgr/autosummary.js');
4244
$modx->regClientStartupScript($assetsUrl . 'js/mgr/widgets/image_prompt.window.js');
4345
$modx->regClientStartupScript($assetsUrl . 'js/mgr/widgets/text_prompt.window.js');
44-
}
46+
}

0 commit comments

Comments
 (0)