json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
221 lines (209 loc) • 11.8 kB
JavaScript
var schema = {
title : 'Ai Response | ${name}',
info:"An ai response from openai etc",
summary:{
description:'Stored AI response objects generated from ai_prompt and the chatgpt plugin.',
purpose:'Use ai_response to persist responses, token usage, and referenced objects from OpenAI calls for auditing, reuse, and comparison back to JOE objects.',
labelField:'name',
defaultSort:{ field:'created', dir:'desc' },
searchableFields:['name','prompt_method','model_used','response_type','response_id','tags','_id'],
allowedSorts:['created','joeUpdated','name','model_used'],
relationships:{
outbound:[
{ field:'ai_prompt', targetSchema:'ai_prompt', cardinality:'one' },
{ field:'referenced_objects', targetSchema:'<schemaName>', cardinality:'many' },
{ field:'tags', targetSchema:'tag', 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_response' },
{ name:'name', type:'string', required:true },
{ name:'ai_prompt', type:'string', isReference:true, targetSchema:'ai_prompt' },
{ name:'referenced_objects', type:'string', isArray:true },
{ name:'generated_thoughts', type:'string', isArray:true, isReference:true, targetSchema:'thought' },
{ name:'user_prompt', type:'string' },
{ name:'prompt_method', type:'string' },
{ name:'model_used', type:'string' },
{ name:'response_type', type:'string' },
{ name:'response', type:'string' },
{ name:'response_keys', type:'string', isArray:true },
{ name:'response_id', type:'string' },
{ name:'usage', type:'object' },
{ name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
{ name:'joeUpdated', type:'string', format:'date-time' },
{ name:'created', type:'string', format:'date-time' }
]
},
menuicon:`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-150 -150 1324 1324">
<path d="M314.57 597.81h376.06v28.2H314.57zm0 75.21h376.06v28.2H314.57zm0 75.21h376.06v28.2H314.57zm239.99-498.47 151.31 31.3c12.23 2.53 12.23 20 0 22.53l-151.31 31.3-31.3 151.31c-2.53 12.23-20 12.23-22.53 0l-31.3-151.31-151.31-31.3c-12.23-2.53-12.23-20 0-22.53l151.31-31.3 31.3-151.31c2.53-12.23 20-12.23 22.53 0l31.3 151.31ZM388.55 102.88l65.55 13.56c5.3 1.1 5.3 8.66 0 9.76l-65.55 13.56-13.56 65.55c-1.1 5.3-8.66 5.3-9.76 0l-13.56-65.55-65.55-13.56c-5.3-1.1-5.3-8.66 0-9.76l65.55-13.56 13.56-65.55c1.1-5.3 8.66-5.3 9.76 0l13.56 65.55Zm20.9 365.17 63.07 13.04c5.1 1.05 5.1 8.33 0 9.39l-63.07 13.04-13.04 63.07c-1.05 5.1-8.33 5.1-9.39 0l-13.04-63.07-63.07-13.04c-5.1-1.05-5.1-8.33 0-9.39l63.07-13.04 13.04-63.07c1.05-5.1 8.33-5.1 9.39 0l13.04 63.07Z"/>
<path d="M689 155.94v37.61h67.44v676.9H267.56v-676.9H319v-37.61h-89.04v752.12h564.08V155.94H689z"/>
</svg>`,
listView:{
title: function(air){
var html = `<joe-subtext class="fright">${_joe.Utils.prettyPrintDTS(air.created)}</joe-subtext>
<joe-title>${air.name}</joe-title>
<joe-subtitle>${(air.response_keys?.length && `returns <b>${air.response_keys}</b>`) ||''}</joe-subtitle>
${air.prompt_method?`<joe-subtext class="fright">method ${air.prompt_method}</joe-subtext>`:''}
<div>${(air.referenced_objects||[]).map(function(ref){
var obj = $J.get(ref);
if(obj){
return `<joe-subtext>${obj.itemtype}:<b>${obj.name}</b> - ${obj._id}</joe-subtext>`;
}else{
return `<joe-subtext>${ref}</joe-subtext>`;
}
}).join('')}</div>`;
air.tags?.length && (html+=_joe.schemas.tag.methods.renderTags(air.tags,'fright'));
return html;
},
listWindowTitle: 'Ai Responses'
},
subsets: function(){
return _joe.Filter.Options.tags({group:true,collapsed:false}).concat(_joe.getDataset('ai_prompt').map(prompt => {
var color = prompt.status && $J.get(prompt.status,'status').color;
return {
name: prompt.name,
id: prompt._id,
filter: { ai_prompt: prompt._id },
stripecolor: color || null // optional
};
}))
},
sorter:['!created','name'],
checkChanges:false,
fields:[
'name',
//'info',
{name:'ai_prompt',type:'objectReference', values:'ai_prompt',display:'Ai Prompt',width:'50%',locked:true},
{name:'referenced_objects',type:'objectReference',width:'50%',values:function(air,orList){
return $J.search({_id:{$in:air.referenced_objects}});
},display:'Referenced Objects',locked:true},
{name:'generated_thoughts',type:'objectReference',width:'50%',values:function(air,orList){
return $J.search({_id:{$in:air.generated_thoughts||[]},itemtype:'thought'});
},display:'Generated Thoughts',locked:true},
{name:'user_prompt', display:'Sent User Prompt',comment:"The input sent by the user after all processing",locked:true,type:'rendering'},
{name:'prompt_method',locked:true,width:'50%'},
{name:'model_used',locked:true,width:'50%'},
// {name:'ai_prompt',type:'select', values:'ai_prompt',display:'Ai Prompt',width:'50%',template:function(resp,prompt){
// return prompt.name;
// }},
//{name:'business',type:'objectReference', values:'business',display:'Business',locked:true},
//{name:'params', type:'rendering', locked:true},
{section_start:'response',collapsed:false},
{name:'response_type',type:'text',display:'Response Type',
placeholder:'(a code for the responsetype)',locked:true,width:'50%',condition:function(v){
return v.length > 0;
}},
{name:'response', type:'rendering', locked:true,height:'500px'},
{name:'response_keys', type:'text', locked:true,display:'Response Keys'},
{name:'response_id', type:'text', display:'openAI response ID',locked:true},
{section_end:'response'},
{sidebar_start:'right', collapsed:false},
{section_start:'workflow'},
'tags',
{section_end:'workflow'},
{section_start:'tokens'},
{name:'usage',type:'content',display:'Tokens Used',run:function(air){
if(!air.usage || !air.usage.total_tokens){return '';}
var html=`<joe-text>input <b>${air.usage.input_tokens}</b></joe-text>
<joe-text>output <b>${air.usage.output_tokens}</b></joe-text>
<joe-text>total <b>${air.usage.total_tokens}</b></joe-text>`
return html;
}},
{section_end:'tokens'},
{sidebar_end:'right'},
//{name:'payload', type:'code', locked:true,height:'500px'},
//{name:'raw_response', type:'code', language:'json',locked:true},
{section_start:'system',collapsed:true},
'_id','created','itemtype',
{section_end:'system'},
],
methods:{
compareResponseToObject:function(response_id,object_id,do_alert){
let response =$J.get(response_id);
var object;
let object_keys;
if(_joe.current.object._id == object_id){
object = _jco(true);
object_keys = _joe.current.fields.map(f=>f.name)
}
else{
object = $J.get(object_id);
object_keys = Object.keys(object);
}
if(!response || !object){return false;}
//evaluate the response to see if it is valid json
try{
let parsed = JSON.parse(response.response);
//find the keys in the response that are in the object
let keys = Object.keys(parsed);
let match = keys.filter(k=>object_keys.includes(k));
//if there are no keys that match, return false
if(!match.length){
do_alert && alert('Response does not match any object keys: '+keys.join(','));
return false;}
//return an array of matching keys
do_alert && ( doit = confirm('Replace object values with responses for: '+match.join(',')));
if(doit){
_joe.schemas.ai_response.methods.updateObjectFromResponse(response_id,object_id,match);
}
return match;
}catch(e){
//if the response is not valid json, return false
return false;
}
},
updateObjectFromResponse:function(response_id,object_id,fields){
let response =$J.get(response_id);
let parsed = JSON.parse(response.response);
var object;
if(_joe.current.object._id == object_id){
object = _jco(true);
}
else{
object = $J.get(object_id);
}
//handle tags
if(response.tags && response.tags.length){
let newTags = (object.tags||[]).concat(response.tags);
//tags array to a set, then back to array
newTags = [...new Set(newTags)];
_joe.Fields.set('tags',newTags);
}
fields.map(function(field){
let newVal = object[field];
//update the object with the response
if(object[field].isArray()){
//append the response to the array
newVal = object[field].concat(parsed[field]);
}else if(typeof object[field] == 'string'){
//merge the response with the object
newVal = parsed[field]
}
_joe.Fields.set(field,newVal);
});
},
listResponses:function(obj){
let html ='';
let responses = _joe.getDataset('ai_response').filter(r=>{
return r.referenced_objects && r.referenced_objects.includes(obj._id);
})
$c.sortBy(responses,'!created');
responses.map(resp=>{
let temp = `<joe-subtitle>${resp.name}</joe-subtitle>
<joe-subtext>${_joe.Utils.prettyPrintDTS(resp.created)}</joe-subtext>
${resp.tags && _joe.schemas.tag.methods.renderTags(resp.tags) || ''}`;
resp.response_keys && (temp += `<joe-button-wrapper class="bottom"><joe-button class="joe-button joe-blue-button" onclick="_joe.Utils.stopPropagation(event);_joe.schemas.ai_response.methods.compareResponseToObject('${resp._id}','${obj._id}',true);">< merge ${resp.response_keys.length} fields</joe-button><joe-button-wrapper>`);
html+=_joe.renderFieldListItem(resp,temp,'ai_response',{icon:'ai_assistant',link:function(item){
return location.href.replace(location.hash,`#/${item.itemtype}/${item._id}`);
}});
})
return html;
}
},
idprop : "_id"
};
module.exports = schema;