UNPKG

json-object-editor

Version:

JOE the Json Object Editor | Platform Edition

323 lines (288 loc) 17 kB
var schema = { display:'Ai Prompt', title : 'Ai Prompt | ${name}', info:"An ai prompt that can be sent to openAi, etc", summary:{ description:'Reusable AI prompt definition that describes how to call the chatgpt plugin or Responses API.', purpose:'Use ai_prompt to define prompt methods, helper functions, and instructions for generating structured AI responses or content. Prompts can be tagged, scoped to datasets, and linked to ai_response records.', labelField:'name', defaultSort:{ field:'joeUpdated', dir:'desc' }, searchableFields:['name','info','prompt_method','ai_model','tags','datasets'], allowedSorts:['joeUpdated','created','name','ai_model'], relationships:{ outbound:[ { field:'status', targetSchema:'status', cardinality:'one' }, { field:'tags', targetSchema:'tag', cardinality:'many' }, { field:'datasets', targetSchema:'<schemaName>', cardinality:'many' } ], inbound:{ graphRef:'server/relationships.graph.json' } }, joeManagedFields:['created','joeUpdated'], fields:[ { name:'_id', type:'string', required:true }, { name:'itemtype', type:'string', required:true, const:'ai_prompt' }, { name:'name', type:'string', required:true }, { name:'info', type:'string' }, { name:'prompt_method', type:'string' }, { name:'content_items', type:'objectList' }, { name:'functions', type:'string' }, { name:'instructions_format', type:'string' }, { name:'instructions', type:'string' }, { name:'user_prompt', type:'string' }, { name:'status', type:'string', isReference:true, targetSchema:'status' }, { name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' }, { name:'ai_model', type:'string' }, { name:'temperature', type:'number' }, { name:'datasets', type:'string', isArray:true }, { name:'joeUpdated', type:'string', format:'date-time' }, { name:'created', type:'string', format:'date-time' } ] }, menuicon:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="-128 -128 1280 1280"> <path d="M356.52 692.84v31.84c0 11.07.47 17.51 1.4 19.31 1.19 2.44 3.42 4.2 6.07 4.8 4.53 1.05 9.18 1.49 13.83 1.31h8.55c9.29 0 13.93 2.98 13.93 8.94 0 6.89-4.9 11.11-14.71 12.66-12.05 1.35-24.18 1.91-36.31 1.66-14.75 0-25.19-2.86-31.32-8.58-6.13-5.72-9.21-15.51-9.23-29.36v-40.03c.42-5.59-.57-11.2-2.87-16.31-2.81-3.78-6.95-6.36-11.58-7.21-5.48-1.37-9.15-6.51-8.68-12.14-.53-5.64 3.17-10.81 8.68-12.14 4.65-.96 8.77-3.61 11.58-7.44 2.32-5.11 3.31-10.72 2.87-16.31v-39.93c0-13.64 3.07-23.32 9.2-29.04 6.13-5.72 16.57-8.57 31.32-8.55 12.9-.36 25.81.33 38.6 2.06 3.42.52 6.6 2.05 9.14 4.4 2.11 2.02 3.29 4.82 3.26 7.73 0 5.96-4.64 8.94-13.93 8.94h-8.81c-7.92 0-13.35.85-16.31 2.54-2.92 1.96-4.62 5.29-4.47 8.81v45.77c-.17 15.42-4.31 25.69-12.4 30.8-.64.43-1.02 1.16-1.01 1.92 0 1.2 1.45 2.99 4.34 5.38 3.23 2.94 5.58 6.73 6.79 10.93 1.58 5.6 2.28 11.41 2.09 17.23Zm90.28-100.23c16.42.07 29.72 13.37 29.79 29.79.25 8.33-3.05 16.37-9.07 22.12-11.82 11.24-30.37 11.24-42.18 0-6.02-5.75-9.32-13.79-9.07-22.12-.18-7.36 2.58-14.49 7.67-19.8 5.8-6.5 14.16-10.15 22.87-9.98Zm0 73.9c16.42.07 29.72 13.37 29.79 29.79.25 8.34-3.06 16.4-9.1 22.15-11.82 11.24-30.37 11.24-42.18 0-6.02-5.75-9.32-13.79-9.07-22.12-.18-7.36 2.58-14.49 7.67-19.8 5.8-6.52 14.17-10.18 22.9-10.02Zm89.36-40.03v-31.71c0-11.07-.47-17.51-1.4-19.31-1.19-2.44-3.42-4.2-6.07-4.8-4.53-1.05-9.18-1.49-13.83-1.31h-8.48c-9.29 0-13.93-2.98-13.93-8.94 0-6.89 4.9-11.07 14.71-12.53 12.05-1.35 24.18-1.9 36.31-1.66 14.75 0 25.19 2.86 31.32 8.58 6.13 5.72 9.2 15.4 9.2 29.04v40.13c-.44 5.59.55 11.2 2.87 16.31 2.84 3.76 6.96 6.35 11.58 7.28 5.51 1.34 9.2 6.53 8.65 12.17.37 4.53-1.99 8.85-6 10.99-2.02.92-4.11 1.65-6.26 2.19-4.2 1.33-7.58 4.48-9.2 8.58-1.34 4.52-1.9 9.23-1.66 13.93v40c0 13.72-3.07 23.44-9.2 29.13-6.13 5.7-16.57 8.56-31.32 8.58-12.9.36-25.81-.32-38.6-2.06-3.42-.52-6.6-2.05-9.14-4.4-2.13-2.06-3.31-4.9-3.26-7.86 0-5.96 4.64-8.94 13.93-8.94 1.11 0 4.05.09 8.81.26 5.55.28 11.11-.59 16.31-2.54 2.02-1.05 3.47-2.95 3.92-5.19.66-5.88.9-11.8.72-17.72v-31.84c-.25-6.36.68-12.71 2.74-18.73 2.07-4.82 5.46-8.96 9.79-11.94.64-.43 1.02-1.16 1.01-1.92 0-1.2-1.45-2.99-4.34-5.38-3.23-2.94-5.58-6.73-6.79-10.93-1.69-5.66-2.5-11.55-2.38-17.45Zm164.47-327.03 197.56 40.87-197.56 40.86-40.86 197.57-40.87-197.57-197.56-40.86 197.56-40.87 40.87-197.56 40.86 197.56z"/> <path d="m516.05 158.53 81.14 16.79-81.14 16.78-16.78 81.15-16.79-81.15-81.14-16.78 81.14-16.79 16.79-81.14 16.78 81.14zm43.7 281.88 41.02 8.48-41.02 8.48-8.48 41.02-8.49-41.02-41.01-8.48 41.01-8.48 8.49-41.02 8.48 41.02z"/> <path d="M698.87 563.96c16.22 26.17 25.29 55.26 25.29 85.9 0 117.09-105.49 205.38-245.39 205.38-3.01 0-6.03-.04-9.07-.12-13.15-.34-27.52-2.1-42.74-3.96-16.83-2.06-34.23-4.19-52.19-4.67l-8.81-.24-8.65 1.71-138.94 27.52 12.32-30.18 18.2-44.57-32.74-35.61c-22.03-23.96-48.3-63.4-48.3-115.27 0-113.76 124.78-206.3 278.15-206.3 10.26 0 20.38.43 30.35 1.23l-48.12-48.12C259.65 403.99 125.8 514.97 125.8 650.82c0 56.11 22.89 107.94 61.57 150.01l-59.5 145.77 252.16-49.95c26.34.7 55.86 6.99 85.42 7.76 3.35.09 6.69.13 10.01.13 171.44 0 290.73-115.81 290.73-253.72 0-42.53-13.14-82.62-36.34-117.86l-30.99 30.99Z"/> </svg>`, listView:{ title: function(aip){ return ` <joe-title>${aip.name}</joe-title> <joe-subtitle>${aip.info}</joe-subtitle><br/> <joe-subtext class="fright"><div><b>${aip.ai_model}</b></div>${aip.prompt_method}</joe-subtext> <joe-subtext>${aip.content_items.map(i=>{ return `<b>${i.itemtype}</b>: ${i.reference}`; }).join('')}</joe-subtext> ${_joe.schemas.tag.methods.renderTags(aip.tags,'fleft')} `; }, listWindowTitle: 'Ai Prompts' }, subsets:function(i){ return _joe.Filter.Options.status(); }, filters:function(i){ return _joe.Filter.Options.tags(); }, stripeColor: function(item) { //use the stripe color from ai_assistant status object if it has one if (item.status){ var status = _joe.Cache.get(item.status); if (status && status.color) { return {color:status.color,title:status.name}; } } }, onload:function(dataset){ //replace the blank instructions field with the populated template field && the blank instrctions format field with the populated template type field dataset.map(function(item){ if(item.template){ item.instructions = item.template; delete item.template; } if(item.template_type){ item.instructions_format = item.template_type; delete item.template_type; } }) }, fields:[ 'name', 'info', {name:"prompt_method",placeholder:"name of method to call in plugin", comment:'use executeJOEAiPrompt to use the JOE ui here for all smarts', default:"executeJOEAiPrompt",display:"Prompt Plugin Method",type:'text'}, {name:'content_items',type:'objectList', properties:['itemtype','reference'] }, {section_start:'Input'}, {name: 'functions', type: 'code', display: 'Helper Functions', language:'javascript',comment: ` <div>AI Prompt Helper Function <h4>Usage:</h4> <ul> <li>Must export an async function.</li> <li>Receives: { instructions, params, ai_prompt } as a single argument.</li> <li>Must return a final modified instructions string.</li> </ul> <h4>Example:</h4> <div class="pad10"> <pre> module.exports = async function({ instructions, params, ai_prompt }) // Your code here to modify the instructions based off params const object = $J.get(params.idToLookup); trackObject(params.idToLookup); // Tell parent we used this return { instructions: "Updated system-level instructions string", input: "Specific input text (URL, query, etc)" }; }; </pre> </div> </div>`}, {section_end:'Input'}, {section_start:'Instruct'}, {label:'Instructions'}, "instructions_format", "instructions", {name:"user_prompt",display:'User Prompt',type:'rendering',comment:'speciific input to the prompt if any, such as campaign intent'}, // 'template_type', // {extend:'template',specs:{comment:'legacy field, use instructions instead', // // comment:`<div>use $\\{this.AI_PROMPT.name\\} $\\{this.CONTENT\\} <br/></div><div>for <b>module</b>: export function(data) that returns an html string. // // data.request, data.REPORT, // // <br/>shorthand: $J.get(itemid) $J.schema(schemaname)</div>`, // language:function(item){ // switch(item.template_type){ // case 'module': // return 'javascript'; // break; // default: // return ''; // } // } // }}, {section_end:'Instruct'}, {section_start:'system',collapsed:true}, '_id','created','itemtype', {section_end:'system'}, {sidebar_start:'right',collapsed:true}, {section_start:'workflow'}, 'status', 'tags', // {name:'merge_status',comment:'status to add when this data is merged in', allowMultiple:false,type:"objectReference",display:'Merge Status',values:function(){ // return _joe.getDataset('status'); // }}, {section_end:'workflow'}, {section_start:'openAi',collapsed:true}, 'ai_model', {name:'temperature', type:'number',display:'Temperature', default:.7, step:"0.1",comment:'0-1, 0 is deterministic, 1 is random'}, //{name:'max_tokens', type:'number',display:'Max Tokens',comment:'max tokens to return',default:4096}, {section_end:'openAi'}, {section_start:'examples',collapsed:true}, {name:'examples', display:'prompt examples', comment:'runs the prompt to create a response',type:'content', reloadable:true,run:function(item){ return $J.schema('ai_prompt').methods.listExamples(item); } }, {section_end:'examples'}, {sidebar_end:'right'}, {sidebar_start:'left',collapsed:function(aip){ return aip.datasets.length != 0; }}, {section_start:'categorization',collapsed:false}, 'datasets', {section_end:'categorization'}, {sidebar_end:'left'}, ], idprop : "_id", sorter:['name','!joeUpdated'], methods:{ buildURL: function(prompt, items = []) { const method = prompt.prompt_method || ''; let url = `/API/plugin/chatgpt/${method}?ai_prompt=${prompt._id}`; if (!Array.isArray(items)) { console.warn('Expected items to be an array.'); return url; } if (prompt.content_items) { prompt.content_items.forEach(ci => { const matchingItem = items.find(it => it.itemtype === ci.itemtype ); if (matchingItem) { url += `&${ci.reference}=${matchingItem._id}`; } }); } return url; }, // listItemClickHandler:function(itemid,promptid){ // var item = $J.get(itemid); // var prompt; // if(promptid){ // prompt = $J.get(promptid); // }else{ // prompt = _jco(); // } // window.open(this.buildURL(prompt,[item])); // }, listItemClickHandler: function (itemMap, promptId) { const prompt = promptId ? $J.get(promptId,'ai_prompt') : _jco(); const items = []; for (const [itemtype, id] of Object.entries(itemMap)) { const obj = $J.get(id,itemtype); if (obj) { items.push(obj); } } window.open(this.buildURL(prompt, items)); }, listExamples:function(prompt){ var examples = []; var html =''; var ref0; var it0; if(!prompt.content_items){ return 'select content items to send with this prompt'; } prompt.content_items.map(function(ci){ if(_joe.Data[ci.itemtype]){ examples = examples.concat(_joe.Data[ci.itemtype]); it0 = ci.itemtype; ref0 = ci.reference; } }) var finalExamples = []; while(finalExamples.length < 5 && finalExamples.length < examples.length){ let ci = examples[Math.floor(Math.random()*examples.length)]; if(finalExamples.indexOf(ci) == -1){ finalExamples.push(ci); } } var rep_url; var method = finalExamples.map(function(ex){ //rep_url = '/API/plugin/chatgpt'+'?ai_prompt='+prompt._id+'&'+ref0+'='+ex._id; html += _joe.renderFieldListItem(ex, '<joe-subtext>'+it0+'</joe-subtext>'+ '<joe-title>${name} ${date}</joe-title>\ <joe-subtext>${website}</joe-subtext>', it0, { //action:'onclick="window.open(\''+rep_url+'\');"', action:`onclick="_joe.schemas.ai_prompt.methods.listItemClickHandler('${ex._id}');"`, icon:'ai_prompt' } ); }) return html; }, listPrompts: function (objectMap) { if (!objectMap || typeof objectMap !== 'object') return ''; const activeStatuses = _joe.getDataset('status') .filter(f => f.datasets.includes('ai_prompt') && f.active) .map(f => f._id); const prompts = _joe.getDataset('ai_prompt').filter(prompt => activeStatuses.includes(prompt.status) ); const context_items = {} // Inline helper: reduce objects to { itemtype: _id } const extractIds = map => { const idMap = {}; for (const [type, obj] of Object.entries(map)) { if (obj && obj._id) idMap[type] = obj._id; } return idMap; }; const objectIdMap = extractIds(objectMap); const paramStr = JSON.stringify(objectIdMap).replace(/"/g, '&quot;'); let html = ''; const temp = '<joe-title>${name}</joe-title>'; let itemtype = _joe.current.object.itemtype; const matchingPrompts = prompts.filter(prompt => (prompt.content_items || []).some(ci => ci.itemtype === itemtype) ); matchingPrompts.forEach(prompt => { html += _joe.renderFieldListItem(prompt, temp, 'ai_prompt', { icon: 'ai_prompt', action: `onclick="(function(){ _joe.schemas.ai_prompt.methods.listItemClickHandler(${paramStr}, '${prompt._id}'); })()"` //action: `onclick="_joe.schemas.ai_prompt.methods.listItemClickHandler(${paramStr}, "${prompt._id}");"` }); }); return html; } } }; module.exports = schema;