fuck-tiny-cloud/plugins/ai/plugin.min.js

10 lines
14 KiB
JavaScript

/*!
* Tiny AI plugin
*
* Copyright (c) 2023 Ephox Corporation DBA Tiny Technologies, Inc.
* Licensed under the Tiny commercial license. See https://www.tiny.cloud/legal/
*
* Version: 1.1.0-63
*/
!function(){"use strict";const e=e=>parseInt(e,10),t=(e,t)=>{const n=e-t;return 0===n?0:n>0?1:-1},n=(e,t,n)=>({major:e,minor:t,patch:n}),r=t=>{const r=/([0-9]+)\.([0-9]+)\.([0-9]+)(?:(\-.+)?)/.exec(t);return r?n(e(r[1]),e(r[2]),e(r[3])):n(0,0,0)},o=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,s=e=>t=>typeof t===e,a=o("string"),i=o("object"),l=o("array"),c=s("boolean"),p=e=>!(e=>null==e)(e),u=s("function"),m=()=>{};function g(e,...t){return(...n)=>{const r=t.concat(n);return e.apply(null,r)}}const d=e=>{e()},h=()=>!1;class y{constructor(e,t){this.tag=e,this.value=t}static some(e){return new y(!0,e)}static none(){return y.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?y.some(e(this.value)):y.none()}bind(e){return this.tag?e(this.value):y.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:y.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return p(e)?y.some(e):y.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}y.singletonNone=new y(!1);const f=(e,t)=>{for(let n=0,r=e.length;n<r;n++)t(e[n],n)},b=Object.hasOwnProperty,v=(e,t)=>b.call(e,t),w=(e,t)=>e?y.some(t):y.none(),A="generate",T="insert",I="discard",E="stop",S="regenerate",x="prompt",R="AI shortcuts",C="ai-prompt",k="Integration Error: {0}.",_="Response was not a string",O="respondWith was not used",D="An error occurred.",q=[{title:"Summarize content",prompt:"Provide the key points and concepts in this content in a succinct summary."},{title:"Improve writing",prompt:"Rewrite this content with no spelling mistakes, proper grammar, and with more descriptive language, using best writing practices without losing the original meaning."},{title:"Simplify language",prompt:"Rewrite this content with simplified language and reduce the complexity of the writing, so that the content is easier to understand."},{title:"Expand upon",prompt:"Expand upon this content with descriptive language and more detailed explanations, to make the writing easier to understand and increase the length of the content."},{title:"Trim content",prompt:"Remove any repetitive, redundant, or non-essential writing in this content without changing the meaning or losing any key information."},{title:"Change tone",subprompts:[{title:"Professional",prompt:"Rewrite this content using polished, formal, and respectful language to convey professional expertise and competence."},{title:"Casual",prompt:"Rewrite this content with casual, informal language to convey a casual conversation with a real person."},{title:"Direct",prompt:"Rewrite this content with direct language using only the essential information."},{title:"Confident",prompt:"Rewrite this content using compelling, optimistic language to convey confidence in the writing."},{title:"Friendly",prompt:"Rewrite this content using friendly, comforting language, to convey understanding and empathy."}]},{title:"Change style",subprompts:[{title:"Business",prompt:"Rewrite this content as a business professional with formal language."},{title:"Legal",prompt:"Rewrite this content as a legal professional using valid legal terminology."},{title:"Journalism",prompt:"Rewrite this content as a journalist using engaging language to convey the importance of the information."},{title:"Medical",prompt:"Rewrite this content as a medical professional using valid medical terminology."},{title:"Poetic",prompt:"Rewrite this content as a poem using poetic techniques without losing the original meaning."}]}],N=e=>t=>t.options.get(e),M=("ai_request",e=>(e=>y.from(N("ai_request")(e)).filter(u))(e).getOrDie("ai_request has not been implemented."));const j=e=>y.from(N("ai_shortcuts")(e)).filter((e=>e.length>0)),L=N("body_class"),$=N("content_style"),P=N("content_css_cors"),B=(e,t)=>t.parse(e,{insert:!0}),z=(e,t)=>{e.execCommand("mceAiDialog",!1,t)},U=(e,t)=>n=>{const r=e=>()=>n.setEnabled(e),o=r(!0),s=r(!1);return e.on("AIResponse AIError AIDialogClose",o),e.on("AIRequest",s),t.isInProgress()?s():o(),()=>{e.off("AIResponse AIError AIDialogClose",o),e.off("AIRequest",s)}},H=(e,t)=>((t,n)=>{const r=t.length,o=new Array(r);for(let n=0;n<r;n++){const r=t[n];o[n]=(e=>{return v(t=e,n="subprompts")&&void 0!==t[n]&&null!==t[n];var t,n})(s=r)?((e,t)=>({type:"nestedmenuitem",text:t.title,getSubmenuItems:()=>H(e,t.subprompts)}))(e,s):((e,t)=>({type:"menuitem",text:t.title,value:t.prompt,onAction:()=>z(e,{prompt:t.prompt,generate:!0,display:!1})}))(e,s)}var s;return o})(t),K=e=>(t,n)=>{const r=(o=a(n)?B(n,t.parser):n,s=t.schema,tinymce.html.Serializer({validate:!0},s).serialize(o));var o,s;const i=y.from($(t)).map((e=>`<style type="text/css">${e}</style>`)).getOr(""),l=y.from(P(t)).map((e=>e?' crossorigin="anonymous"':"")).getOr(""),c=(p=t.contentCSS,u=(e,n)=>`${e}<link type="text/css" rel="stylesheet" href="${t.documentBaseURI.toAbsolute(n)}"${l}>`,m="",f(p,((e,t)=>{m=u(m,e)})),m);var p,u,m;const g=t.dom.encode,d=`<body${y.from(L(t)).map((e=>` class="${g(e)}"`)).getOr("")}${y.from(t.getBody()).map((e=>g(e.dir))).bind((e=>w(""!==e,` dir="${e}"`))).getOr("")}>`,h=tinymce.Env.os,b='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !('+(h.isMacOS()||h.isiOS()?"e.metaKey":"e.ctrlKey && !e.altKey")+")) {e.preventDefault();}}}, false);<\/script> ",v=e?"<style>* { opacity: 80% }</style>":"";return`<!DOCTYPE html><html><head><base href="${g(t.documentBaseURI.getURI())}">`+c+i+"<style>table, table td, table th, table caption { border: 1px dashed #bbb }</style>"+v+b+"</head>"+d+r+"</body></html>"},W=K(!1),J=K(!0),F={prompt:"",generate:!1,display:!0},G=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},V=()=>{const e=(e=>{const t=G(y.none()),n=()=>t.get().each(e);return{clear:()=>{n(),t.set(y.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{n(),t.set(y.some(e))}}})(m);return{...e,on:t=>e.get().each(t)}},Q=(e,t)=>e.dispatch("AIResponse",{response:t}),Y=(e,t)=>e.dispatch("AIError",{error:t}),X=(e,t)=>{const n=tinymce.util.I18n,r=M(e),o=V(),s=o.isSet,i=e=>()=>o.get().exists((t=>t===e)),l=i("stream"),c=i("string"),u=V();return{isInProgress:s,isStream:l,isString:c,closeStream:()=>u.on(d),submitRequest:(s,i,l,c,m)=>{const g=new window.AbortController,d=g.signal;let h=!1;const y={string:r=>{(async r=>{const p="string";o.set(p),h=!0;try{const l=await r(d);if(!a(l)){const e=n.translate([k,_]);throw console.error(e,l),new TypeError(e)}const u={type:p,data:l};t.addNewThreadEvent(s,i,{response:u}),Q(e,u),c(u.data)}catch(n){const r=n;t.addNewThreadEvent(s,i,{error:{type:p,error:r}}),Y(e,r),l(r)}finally{o.clear()}})(r)},stream:r=>{(async r=>{const p="stream";o.set(p),h=!0;let y="";const f=()=>{d.removeEventListener("abort",b),u.clear()},b=()=>{const n={type:p,data:y};t.addNewThreadEvent(s,i,{response:n}),Q(e,n),c(y),f()};d.addEventListener("abort",b),u.set((()=>g.abort()));try{await r(d,(e=>{if(!a(e)){const t=n.translate([k,_]);throw console.error(t,e),new TypeError(t)}y+=e,m(y)})).then(b)}catch(n){u.on((e=>{f(),e()}));const r={type:p,data:y},o=n;t.addNewThreadEvent(s,i,{response:r,error:{type:p,error:o}}),Q(e,r),Y(e,o),l(o)}finally{o.clear()}})(r)}},f=r(((n,r)=>{const o=((e,n)=>({thread:t.getThread(n).getOr([]),...e}))(n,r);return((e,t)=>{e.dispatch("AIRequest",{request:t})})(e,o),o})(s,i),y);if(p(f)&&console.warn("Integration Warning: ai_request return type was not void."),!h){const r=n.translate([k,O]);console.error(r),t.addNewThreadEvent(s,i,{error:{type:"invalid",error:r}}),Y(e,r),l(r)}}}};let Z=0;const ee=e=>{const t=(new Date).getTime(),n=Math.floor(1e9*Math.random());return Z++,e+"_"+n+Z+String(t)},te=()=>{const e=G({}),t=e.get,n=e.set,r=e=>y.from(t()[e]),o=(e,r)=>{const o=t();return o[e]=r,n(o),r};return{getThreadLog:t,setThreadLog:n,createThread:(e=[])=>{const t=ee("mce-aithread");return o(t,e),t},getThread:r,setThread:o,getLatestThreadEvent:e=>r(e).bind((e=>((e,t,n)=>{for(let r=0,o=e.length;r<o;r++){const o=e[r];if(t(o,r))return y.some(o);if(n(o,r))break}return y.none()})(e,(e=>v(e,"response")),h))),addNewThreadEvent:(e,t,n)=>{((e,t)=>{r(e).map((n=>o(e,t.concat(n))))})(t,[{eventUid:ee("mce-aithreadevent"),timestamp:(new Date).toISOString(),request:e,...n}])}}},ne=["Answer the question based on the context below.","The response should be in HTML format.","The response should preserve any HTML formatting, links, and styles in the context."],re=(e,t)=>`${ne.join("\n")}\n\nContext:${t.map((e=>`"""${e}"""`)).getOr('""')}\n\nQuestion: """${e}"""\n\nAnswer:`,oe={type:"input",name:x,placeholder:"Ask AI to edit or generate...",maximized:!0},se=e=>({type:"button",name:A,text:"Generate",icon:"send",buttonType:e?"primary":"secondary"}),ae={type:"bar",items:[oe,se(!0)]},ie=[ae],le=e=>({type:"iframe",name:"preview",border:!0,sandboxed:!1,streamContent:e,transparent:!0}),ce={type:"button",name:T,text:"Insert",buttonType:"primary"},pe={type:"button",name:I,text:"Discard",buttonType:"secondary"},ue={...pe,name:E,text:"Stop"},me={type:"button",name:S,text:"Try again",buttonType:"secondary"},ge=e=>({type:"bar",items:[ce,me,e?ue:pe]}),de={type:"label",items:[],label:"AI responses can be inaccurate",align:"end"},he=e=>({type:"grid",columns:2,items:[ge(e),de]}),ye={type:"htmlpanel",html:""},fe={type:"bar",items:[oe,se(!1)]},be=e=>[le(e),he(e),ye,fe],ve=be(!0),we=be(!1),Ae=(e,t,n)=>{const r=V(),o=V(),s=V(),i=G(""),l=e=>t=>{t.setEnabled(E,!e),f([A,T,x,S],(n=>t.setEnabled(n,e)))},c=l(!1),p=l(!0),u=(e,t)=>{t.setEnabled(A,""!==e)},m=(t,r)=>{const o=G(!1),l=(e,t)=>({...r,prompt:e,preview:t}),m=(e,n)=>{t.unblock(),t.redial(k(e,n))},g=("error",n=>{const o=((e,t)=>({type:"label",label:"",items:[{type:"alertbanner",level:t,text:e,icon:"warning"}]}))(n,"error");s.get().map((t=>W(e,t))).fold((()=>m((e=>[e,ye,ae])(o),l(r.prompt))),(e=>m((e=>[le(!1),he(!1),e,ye,fe])(o),l(r.prompt,e)))),t.focus(x)});const d=e=>{const t=a(e)?e:e instanceof Error?e.message:D;g(t)},h=r=>{const o=n.isStream();s.set(r);const a=W(e,r);if(o)t.setData({preview:a}),p(t);else{const e=l("",a);m(we,e)}u("",t),t.focus(x)},y=n=>{s.set(n),o.get()?t.setData({preview:J(e,n)}):((e,t)=>{const n=((e,t)=>{const n=B(e,t);let r=n;do{8===(null==r?void 0:r.type)&&r.remove()}while(r=null==r?void 0:r.walk());return n})(t,e.parser);return w((r=n,o=e.schema,!r.isEmpty(o.getNonEmptyElements(),o.getWhitespaceElements())),J(e,n));var r,o})(e,n).each((e=>{const n=l("",e);m(ve,n),c(t),o.set(!0)}))};if(""!==r.prompt){t.block("Awaiting response");const e=(f=r.prompt,b=r.context,{prompt:re(f,b),query:f,context:b.getOr(""),system:ne});n.submitRequest(e,i.get(),d,h,y)}var f,b},d=(t,n=t.getData())=>{const r={...n,context:s.get().or((e=>w(!e.selection.isCollapsed(),e.selection.getContent()))(e))};o.set(r),m(t,r)},h=e=>{r.set(e),r.on(d)},y=(t,r)=>{switch(t.name){case A:d(r);break;case T:s.on((t=>{r.close(),((e,t)=>{e.insertContent(t)})(e,t)}));break;case E:n.closeStream();break;case I:r.close();break;case S:o.get().each((e=>m(r,e)))}},b=(e,t)=>{r.set(e),r.on(g(y,t))},v=(e,t)=>{const n=t.getData();e.name===x&&u(n.prompt,t)},R=(e,t)=>{r.set(e),r.on(g(v,t))},C=()=>{n.closeStream(),(e=>{e.dispatch("AIDialogClose")})(e),o.clear(),s.clear(),r.clear()},k=(e,t)=>({title:"AI Assistant",body:{type:"panel",items:e},size:"medium",initialData:t,onSubmit:h,onAction:b,onChange:R,onClose:C}),_=t=>{const n=t.display?ie:[],o=(e=>({prompt:e.prompt}))(t),s=k(n,o);r.set(e.windowManager.open(s,{inline:"bottom",persistent:!0})),r.on(g(u,t.prompt)),t.generate&&r.on((e=>d(e,o)))},O=()=>r.on((e=>e.close()));return{open:n=>{r.isSet()?(e=>!(e.generate&&e.prompt.length>0))(n)?r.on((e=>{e.focus(x)})):(e=>{r.on(O),_(e)})(n):(n=>{i.set(t.createThread()),(e=>{e.dispatch("AIDialogOpen")})(e),_(n)})(n)},close:O}};tinymce.PluginManager.requireLangPack("ai","ar,bg_BG,ca,cs,da,de,el,es,eu,fa,fi,fr_FR,he_IL,hi,hr,hu_HU,id,it,ja,kk,ko_KR,ms,nb_NO,nl,pl,pt_BR,pt_PT,ro,ru,sk,sl_SI,sv_SE,th_TH,tr,uk,vi,zh_CN,zh_TW"),tinymce.PluginManager.add("ai",(e=>{if(((e,n)=>!!e&&-1===((e,n)=>{const r=t(e.major,n.major);if(0!==r)return r;const o=t(e.minor,n.minor);if(0!==o)return o;const s=t(e.patch,n.patch);return 0!==s?s:0})((e=>r((e=>[e.majorVersion,e.minorVersion].join(".").split(".").slice(0,3).join("."))(e)))(e),r(n)))(tinymce,"6.6.0"))return console.error("The ai plugin requires at least version 6.6.0 of TinyMCE."),{};(e=>{const t=e.options.register;t("ai_request",{processor:"function"}),t("ai_shortcuts",{processor:e=>{if(c(e))return{valid:!0,value:!1===e?[]:q};{const t=((e,t)=>{if(l(e)){for(let n=0,r=e.length;n<r;++n)if(!t(e[n]))return!1;return!0}return!1})(e,i);return t?{value:e,valid:t}:{valid:!1,message:"Must be a boolean, empty array, or an array of objects."}}},default:q})})(e);const n=te(),o=X(e,n);return((e,t)=>{e.addCommand("mceAiDialog",((e,n)=>{const r={...F,...n};t.open(r)})),e.addCommand("mceAiDialogClose",t.close)})(e,Ae(e,n,o)),((e,t)=>{e.ui.registry.addMenuItem("aidialog",{icon:"ai",text:"Ask AI...",shortcut:"Meta+J",onSetup:U(e,t),onAction:()=>z(e)}),j(e).each((n=>{e.ui.registry.addNestedMenuItem("aishortcuts",{icon:C,text:R,onSetup:U(e,t),getSubmenuItems:()=>H(e,n)})}))})(e,o),((e,t)=>{e.ui.registry.addButton("aidialog",{icon:"ai",tooltip:"Ask AI",onSetup:U(e,t),onAction:()=>z(e)}),j(e).each((n=>{e.ui.registry.addMenuButton("aishortcuts",{icon:C,tooltip:R,onSetup:U(e,t),fetch:t=>t(H(e,n))})}))})(e,o),(e=>{e.ui.registry.addContextToolbar("ai",{predicate:t=>!e.selection.isCollapsed()&&e.dom.isEditable(t),items:"aidialog aishortcuts",position:"selection",scope:"editor"})})(e),(e=>{e.addShortcut("Meta+J","Open Ai Dialog",(()=>{e.execCommand("mceAiDialog")}))})(e),(e=>({getThreadLog:e.getThreadLog}))(n)}))}();