ctod 0.4.0 → 0.4.1

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.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ctod=t():e.ctod=t()}(this||("undefined"!=typeof window?window:global),(()=>(()=>{"use strict";var e={37:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBroker=void 0;const r=n(15),a=n(470),o=n(87);t.ChatBroker=class{__hookType;log;hook=new a.Hook;params;plugins={};installed=!1;translator;event=new a.Event;constructor(e){this.log=new a.Log(e.name??"no name"),this.params=e,this.translator=new o.Translator({...e,parsers:[r.TextParser.JsonMessage()]})}_install(){if(!1===this.installed){this.installed=!0;const e={log:this.log,attach:this.hook.attach.bind(this.hook),attachAfter:this.hook.attachAfter.bind(this.hook),translator:this.translator};if(this.params.install(e),this.params.plugins){this.plugins="function"==typeof this.params.plugins?this.params.plugins():this.params.plugins;for(let t in this.plugins)this.plugins[t].instance._params.onInstall({...e,params:this.plugins[t].params,receive:this.plugins[t].receive})}}}async cancel(e){e?this.event.emit("cancel",{requestId:e}):this.event.emit("cancelAll",{})}requestWithId(e){this._install();let t=a.flow.createUuid(),n=null,r=!1,o=!1,s=[this.event.on("cancel",(({requestId:e})=>{e===t&&l()})),this.event.on("cancelAll",(()=>{l()}))],i=()=>s.forEach((e=>e.off())),l=()=>{!1===r&&(o&&n&&n(),r=!0,i())},c=e=>{n=e},u=async()=>{let s=this.translator.getValidate(),i=null,l={},u=await this.translator.compile(e,{schema:s}),p=[{role:"user",content:u.prompt}];for(let e in this.plugins)l[e]={send:n=>this.plugins[e].send({id:t,data:n})};return await this.hook.notify("start",{id:t,data:e,schema:s,plugins:l,messages:p,setPreMessages:e=>{p=[...e,{role:"user",content:u.prompt}]},changeMessages:e=>{p=e}}),await a.flow.asyncWhile((async({count:a,doBreak:l})=>{if(a>=10)return l();let u="",d="",h=!1,f=p.filter((e=>"user"===e.role)).slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:p,lastUserMessage:f});const m=this.params.request(p,{count:a,schema:s,onCancel:c,isRetry:h});if(r)n&&n();else try{o=!0,u=await m,d=u}finally{o=!1}!1===r&&(await this.hook.notify("talkAfter",{id:t,data:e,response:u,messages:p,parseText:d,lastUserMessage:f,changeParseText:e=>{d=e}}),i=(await this.translator.parse(d)).output,await this.hook.notify("succeeded",{id:t,output:i})),await this.hook.notify("done",{id:t}),l()}catch(e){if(!e.isParserError)throw await this.hook.notify("done",{id:t}),e;if(await this.hook.notify("parseFailed",{id:t,error:e.error,count:a,response:u,messages:p,lastUserMessage:f,parserFails:e.parserFails,retry:()=>{h=!0},changeMessages:e=>{p=e}}),!1===h)throw await this.hook.notify("done",{id:t}),e}})),i};return{id:t,request:(async()=>{try{return await u()}finally{i()}})()}}async request(e){const{request:t}=this.requestWithId(e);return await t}}},15:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.TextParser=void 0;const a=r(n(959));class o{params;static JsonMessage(){return new o({name:"JsonMessage",handler:async e=>{try{return JSON.parse(e)}catch(t){const n=/{(?:[^{}]|(?:{[^{}]*}))*}/,r=e.match(n)?.[0]||"";return a.default.parse(r)}}})}constructor(e){this.params=e}get name(){return this.params.name}async read(e){return await this.params.handler(e)}}t.TextParser=o},241:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBrokerPlugin=void 0;const r=n(470);t.ChatBrokerPlugin=class{_event=new r.Event;_params;constructor(e){this._params=e}use(e){return{instance:this,params:e,send:e=>{this._event.emit("receive",e)},receive:e=>{this._event.on("receive",e)},__receiveData:null}}}},87:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Translator=void 0;const r=n(293);t.Translator=class{params;constructor(e){this.params=e}get __schemeType(){return null}get __outputType(){return null}async compile(e,t){const n=(0,r.validate)(e,this.params.input);return{scheme:n,prompt:await this.params.question(n,t)}}getValidate(){return{input:this.params.input,output:this.params.output}}async parse(e){let t,n="",a=[];for(let r of this.params.parsers)try{t=await r.read(e),n=r.name}catch(e){t=void 0,a.push({name:r.name,error:e})}try{return{output:(0,r.validate)(t,this.params.output),parserName:n,parserFails:a}}catch(e){throw{isParserError:!0,error:e,parserFails:a}}}}},620:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return a(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.ctod=t.Translator=t.ChatBrokerPlugin=t.ChatBroker=t.TextParser=t.Llama3Cpp=t.OpenAI=t.validateToJsonSchema=t.templates=t.plugins=void 0,t.plugins=o(n(218)),t.templates=o(n(298));var s=n(293);Object.defineProperty(t,"validateToJsonSchema",{enumerable:!0,get:function(){return s.validateToJsonSchema}});var i=n(616);Object.defineProperty(t,"OpenAI",{enumerable:!0,get:function(){return i.OpenAI}});var l=n(643);Object.defineProperty(t,"Llama3Cpp",{enumerable:!0,get:function(){return l.Llama3Cpp}});var c=n(15);Object.defineProperty(t,"TextParser",{enumerable:!0,get:function(){return c.TextParser}});var u=n(37);Object.defineProperty(t,"ChatBroker",{enumerable:!0,get:function(){return u.ChatBroker}});var p=n(241);Object.defineProperty(t,"ChatBrokerPlugin",{enumerable:!0,get:function(){return p.ChatBrokerPlugin}});var d=n(87);Object.defineProperty(t,"Translator",{enumerable:!0,get:function(){return d.Translator}});const h=o(n(218)),f=o(n(298)),m=n(616),g=n(643),y=n(87),_=n(15),v=n(37),b=n(241),w=n(293);t.ctod={OpenAI:m.OpenAI,Llama3Cpp:g.Llama3Cpp,plugins:h,templates:f,ChatBroker:v.ChatBroker,Translator:y.Translator,TextParser:_.TextParser,ChatBrokerPlugin:b.ChatBrokerPlugin,validateToJsonSchema:w.validateToJsonSchema},e.exports=t.ctod,e.exports.ctod=t.ctod,t.default=t.ctod},218:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.RolePlugin=t.LimiterPluginGlobState=t.LimiterPlugin=t.RetryPlugin=t.PrintLogPlugin=void 0;const a=r(n(894)),o=r(n(829)),s=r(n(626)),i=r(n(1));t.PrintLogPlugin=o.default,t.RetryPlugin=a.default,t.LimiterPlugin=s.default.plugin,t.LimiterPluginGlobState=s.default,t.RolePlugin=i.default},626:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241),a=n(470),o={limit:3,interval:6e4},s={event:new a.Event,schedule:null,waitTimes:[],waitQueue:[]};t.default={event:s.event,config:o,closeSchedule:()=>{s.schedule&&(s.schedule.close(),s.schedule=null)},plugin:new r.ChatBrokerPlugin({name:"limiter",params:()=>({}),receiveData:()=>({}),onInstall({attach:e}){null==s.schedule&&(s.schedule=new a.Schedule,s.schedule.add("calc queue",1e3,(async()=>{const e=Date.now();if(s.waitTimes=s.waitTimes.filter((t=>e-t<o.interval)),s.waitTimes.length!==o.limit){let e=s.waitQueue.shift();e&&(s.waitTimes.push(Date.now()),s.event.emit("run",{id:e}))}else s.waitTimes[0]&&s.event.emit("waitTimeChange",{waitTime:Math.floor(60-(e-s.waitTimes[0])/1e3)})})),s.schedule.play()),e("talkBefore",(async()=>{const e=a.flow.createUuid();return s.waitQueue.push(e),new Promise((t=>{s.event.on("run",(({id:n},{off:r})=>{n===e&&(r(),t())}))}))}))}})}},829:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"print-log",params:e=>({detail:e.boolean().required().default(!1)}),receiveData:()=>({}),onInstall({params:e,log:t,attach:n}){n("talkBefore",(async({lastUserMessage:n,messages:r})=>{t.print("Send:",{color:"green"}),e.detail?t.print("\n"+JSON.stringify(r,null,4)):t.print("\n"+n)})),n("talkAfter",(async({parseText:e})=>{t.print("Receive:",{color:"cyan"}),t.print("\n"+e)})),n("succeeded",(async({output:e})=>{t.print("Output:",{color:"yellow"});try{t.print("\n"+JSON.stringify(e,null,4))}catch(n){t.print("\n"+e)}}))}})},894:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"retry",params:e=>({retry:e.number().required().default(1),printWarn:e.boolean().required().default(!0)}),receiveData:()=>({}),onInstall({log:e,attach:t,params:n}){t("parseFailed",(async({count:t,retry:r,messages:a,changeMessages:o})=>{t<=n.retry&&(n.printWarn&&e.print(`Is Failed, Retry ${t} times.`),o(a),r())}))}})},1:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"role",params:e=>({role:e.string().required()}),receiveData:()=>({}),onInstall({attach:e,params:t}){e("start",(async({messages:e,changeMessages:n})=>{n([{role:"user",content:`你現在是${t.role}。`},{role:"assistant",content:`沒問題,我現在是${t.role},有什麼可以幫你的嗎?`},...e])}))}})},358:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3CppCompletion=void 0;const r=n(470),a=n(511);class o{core;streamAbortControllers=[];constructor(e){this.core=e}createAbortController(){const e=new AbortController,t=r.flow.createUuid();return this.streamAbortControllers.push({id:t,controller:e}),{signal:e.signal,controllerId:t}}removeAbortController(e){this.streamAbortControllers=this.streamAbortControllers.filter((t=>t.id!==e))}async stream(e){const{signal:t,controllerId:n}=this.createAbortController(),r=()=>{this.removeAbortController(n),e.onEnd()};fetch(`${this.core.config.baseUrl}/${e.path}`,{method:"POST",body:JSON.stringify(e.data),signal:t,headers:{"Content-Type":"application/json",...this.core.config.headers}}).then((async t=>{if(t.body){let n=t.body.getReader(),a=!1,o="";for(;!a;){const{value:t,done:r}=await n.read();if(t){o+=new TextDecoder("utf-8").decode(t);const n=o.split("\n\n");o=n.pop()||"",n.forEach((t=>{if(t.includes("[DONE]")&&(a=!0),t.startsWith("data:"))try{const n=JSON.parse(t.replace("data: ",""));e.onMessage(n)}catch(t){e.onWarn(t)}}))}r&&(a=!0)}r()}else e.onError(new Error("Body not found."))})).catch((t=>{t instanceof Error&&t.message.includes("The user aborted a request")?r():e.onError(t)}))}async fetch(e){const{signal:t,controllerId:n}=this.createAbortController();try{return{data:(await this.core.core._axios.post(`${this.core.config.baseUrl}/${e.path}`,e.data,{signal:t,headers:{"Content-Type":"application/json",...this.core.config.headers}})).data}}finally{this.removeAbortController(n)}}cancel(){this.streamAbortControllers.forEach((e=>e.controller.abort())),this.streamAbortControllers=[]}export(){return{cancel:this.cancel.bind(this)}}}t.Llama3CppCompletion=class{core;config={baseUrl:"",headers:{},autoConvertTraditionalChinese:!0};constructor(e){this.core=e}setConfig(e){this.config={...this.config,...e}}completion(e){const t=[];for(let{role:n,content:r}of e.messages)"system"===n&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${r}\n\n`),"user"===n&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${r?.replaceAll("\n","\\n")??""}`),"assistant"===n&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+r);const n=e.messages.at(-1)||"",r=new o(this);return{...r.export(),run:async()=>{const o=await r.fetch({path:"completion",data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,a.sify)(t.join("\n")):t.join("\n")}}),s=this.config.autoConvertTraditionalChinese?(0,a.tify)(o.data.content):o.data.content;return{message:s,fullMessage:`${n}${s}`}}}}completionStream(e){const t=[];for(let{role:n,content:r}of e.messages)"system"===n&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${r}\n\n`),"user"===n&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${r?.replaceAll("\n","\\n")??""}`),"assistant"===n&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+r);const n=new o(this);return n.stream({path:"completion",onEnd:e.onEnd||(()=>null),onMessage:t=>{e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,a.tify)(t.content):t.content})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,a.sify)(t.join("\n")):t.join("\n"),stream:!0}}),n.export()}talk(e){const t=new o(this);return{...t.export(),run:async()=>{const n=(await t.fetch({path:"v1/chat/completions",data:{...e.options||{},response_format:e.response_format,messages:e.messages.map((e=>({role:e.role,content:this.config.autoConvertTraditionalChinese?(0,a.sify)(e.content):e.content})))}})).data.choices[0].message.content||"";return{message:this.config.autoConvertTraditionalChinese?(0,a.tify)(n):n}}}}talkStream(e){const t=new o(this);return t.stream({path:"v1/chat/completions",onEnd:e.onEnd||(()=>null),onMessage:t=>{let n=t.choices[0].delta.content;n&&e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,a.tify)(n):n})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},stream:!0,messages:e.messages.map((e=>({role:e.role,content:this.config.autoConvertTraditionalChinese?(0,a.sify)(e.content):e.content})))}}),t.export()}}},643:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3Cpp=void 0;const a=r(n(167)),o=n(470),s=n(511),i=n(293),l=n(358);class c{_axios=a.default.create();static createChatRequest(e){return async(t,{schema:n,onCancel:r})=>{const a=(new c).createCompletion(),l="function"==typeof e.config?await e.config():e.config,u=e.jsonSchemaInfo?o.json.jpjs(e.jsonSchemaInfo):void 0;if(a.setConfig(l),a.config.autoConvertTraditionalChinese&&u)for(let e in u.desc){const t=u.desc[e];"object"==typeof t&&t.description&&(t.description=(0,s.sify)(t.description)),"string"==typeof t&&(u.desc[e]=(0,s.sify)(t))}const{run:p,cancel:d}=a.talk({options:e.talkOptions,messages:t,response_format:{type:"json_object",schema:(0,i.validateToJsonSchema)(n.output,u)}});r(d);const{message:h}=await p();return h}}setAxios(e){this._axios=e}createCompletion(){return new l.Llama3CppCompletion(this)}}t.Llama3Cpp=c},203:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIChat=void 0;const r=n(470);t.OpenAIChat=class{openai;config={n:1,model:"gpt-4o",temperature:1,maxTokens:void 0,forceJsonFormat:!0};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async moderations(e){const t=await this.openai._axios.post("https://api.openai.com/v1/moderations",{input:e},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}});return{isSafe:!1===t.data.results?.[0]?.flagged,result:t.data}}async talk(e=[],t){const n=r.json.jpjs(e),a=["gpt-4-turbo-preview","gpt-4-turbo","gpt-4o","gpt-4o-mini","gpt-3.5-turbo-1106"].includes(this.config.model),o=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:this.config.n,messages:n,response_format:!1===a||!1===this.config.forceJsonFormat?void 0:{type:"json_object"},temperature:this.config.temperature},{signal:t?.abortController?.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),s=o.data.choices||[],i=s[0]?.message||{role:"assistant",content:""};return n.push(i),{id:o?.data.id,text:i.content,newMessages:n,isDone:"stop"===s[0]?.finish_reason,apiReseponse:o.data}}talkStream(e){const t=new AbortController;return fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`},body:JSON.stringify({model:this.config.model,stream:!0,messages:e.messages}),signal:t.signal}).then((async t=>{const n=t.body?.pipeThrough(new TextDecoderStream).getReader();if(!n)throw new Error("Can not get reader");for(;;){const{value:t,done:r}=await n.read();if(r)break;const a=t.split("\n");for(let t of a)if(0!==t.length&&!t.startsWith(":")){if("data: [DONE]"===t){e.onEnd();break}try{const n=JSON.parse(t.substring(6)).choices[0].delta.content;e.onMessage(n)}catch(t){e.onWarn(t)}}}})).catch((t=>{"AbortError"===t.name?e.onEnd():e.onError(t)})),{cancel:()=>t.abort()}}async keepTalk(e,t=[]){const n=await this.talk([...t,{role:"user",content:Array.isArray(e)?e.join("\n"):e}]);return{result:n,nextTalk:e=>this.keepTalk(e,n.newMessages)}}}},725:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIImagesGeneration=void 0,t.OpenAIImagesGeneration=class{openai;config={model:"dall-e-2",size:"1024x1024"};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async create(e){return(await this.openai._axios.post("https://api.openai.com/v1/images/generations",{prompt:e,n:1,size:this.config.size,model:this.config.model,response_format:"b64_json"},{timeout:3e5,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}})).data}}},616:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAI=void 0;const a=n(710),o=n(203),s=n(725),i=r(n(167));class l{_axios=i.default.create();_apiKey="";static createChatRequest(e,t={}){return async(n,{onCancel:r})=>{const a=new l("string"==typeof e?e:await e()).createChat(),o=new AbortController;a.setConfig("function"==typeof t?await t():t),r((()=>o.abort()));const{text:s}=await a.talk(n,{abortController:o});return s}}constructor(e=""){this._apiKey=e}setAxios(e){this._axios=e}setConfiguration(e){this._apiKey=e}createChat(){return new o.OpenAIChat(this)}createVision(){return new a.OpenAIVision(this)}createImagesGeneration(){return new s.OpenAIImagesGeneration(this)}}t.OpenAI=l},710:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIVision=void 0,t.OpenAIVision=class{openai;config={model:"gpt-4-vision-preview",maxTokens:void 0,temperature:1};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async view(e){const t=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:1,messages:e,max_tokens:this.config.maxTokens,temperature:this.config.temperature},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),n=(t.data.choices||[])[0]?.message||{role:"assistant",content:""};return{id:t?.data.id,text:n.content,apiReseponse:t.data}}}},298:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.requireJsonResponseWithJsonSchema=t.requireJsonResponseWithHandlebars=t.requireJsonResponse=void 0;const a=r(n(97)),o=n(470);t.requireJsonResponse=(e,t)=>[...Array.isArray(e)?e:[e],"Please respond using the following JSON format and minify the JSON without including any explanation: ","{",Object.entries(t).map((([e,t])=>[`/* ${t.desc} */`,`"${e}": ${JSON.stringify(t.example)}`].join("\n"))).join(",\n"),"}"].join("\n"),t.requireJsonResponseWithHandlebars=(e,n,r)=>{const s=a.default.create();return s.registerHelper("DATA",(function(e){return JSON.stringify(e)})),s.registerHelper("ENV",(function(e){return this.__envs&&e?this.__envs[e]:""})),s.registerHelper("INPUT",(function(){return JSON.stringify(o.record.omit(this,["__envs"]))})),s.registerHelper("JOIN",(function(e){return Array.isArray(e)?e.join():JSON.stringify(e)})),s.compile((0,t.requireJsonResponse)(n,r))(e)},t.requireJsonResponseWithJsonSchema=(e,t)=>[...Array.isArray(e)?e:[e],"Please provide JSON data according to the following JSON Schema format:",JSON.stringify(t)].join("\n")},293:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return a(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.validateToJsonSchema=t.validate=t.definedValidateSchema=void 0;const s=o(n(609)),i=n(470),l=n(724);t.definedValidateSchema=function(e){return e},t.validate=function(e,t){return s.object(t(s)).required().validateSync(e||{})},t.validateToJsonSchema=(e,t)=>{const n=(0,l.convertSchema)(s.object(e(s)));return delete n.default,t?((e,t)=>{if(t&&t.desc)for(let n in t.desc)if(e.properties){let r=i.pick.peel(e.properties,n.replaceAll(".",".properties."));if(r&&!0!==r){let e=t.desc[n];"object"==typeof e?(e.description&&(r.description=e.description),e.examples&&(r.examples=e.examples)):"string"==typeof e&&(r.description=e)}}return e})(n,t):n}},724:e=>{e.exports=require("@sodaru/yup-to-json-schema")},167:e=>{e.exports=require("axios")},511:e=>{e.exports=require("chinese-conv")},97:e=>{e.exports=require("handlebars")},959:e=>{e.exports=require("json5")},470:e=>{e.exports=require("power-helper")},609:e=>{e.exports=require("yup")}},t={};return function n(r){var a=t[r];if(void 0!==a)return a.exports;var o=t[r]={exports:{}};return e[r].call(o.exports,o,o.exports,n),o.exports}(620)})()));
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ctod=t():e.ctod=t()}(this||("undefined"!=typeof window?window:global),(()=>(()=>{"use strict";var e={37:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBroker=void 0;const r=n(15),a=n(470),o=n(87);t.ChatBroker=class{__hookType;log;hook=new a.Hook;params;plugins={};installed=!1;translator;event=new a.Event;constructor(e){this.log=new a.Log(e.name??"no name"),this.params=e,this.translator=new o.Translator({...e,parsers:[r.TextParser.JsonMessage()]})}_install(){if(!1===this.installed){this.installed=!0;const e={log:this.log,attach:this.hook.attach.bind(this.hook),attachAfter:this.hook.attachAfter.bind(this.hook),translator:this.translator};if(this.params.install(e),this.params.plugins){this.plugins="function"==typeof this.params.plugins?this.params.plugins():this.params.plugins;for(let t in this.plugins)this.plugins[t].instance._params.onInstall({...e,params:this.plugins[t].params,receive:this.plugins[t].receive})}}}async cancel(e){e?this.event.emit("cancel",{requestId:e}):this.event.emit("cancelAll",{})}requestWithId(e){this._install();let t=a.flow.createUuid(),n=null,r=!1,o=!1,s=[this.event.on("cancel",(({requestId:e})=>{e===t&&l()})),this.event.on("cancelAll",(()=>{l()}))],i=()=>s.forEach((e=>e.off())),l=()=>{!1===r&&(o&&n&&n(),r=!0,i())},c=e=>{n=e},u=async()=>{let s=this.translator.getValidate(),i=null,l={},u=await this.translator.compile(e,{schema:s}),p=[{role:"user",content:u.prompt}];for(let e in this.plugins)l[e]={send:n=>this.plugins[e].send({id:t,data:n})};return await this.hook.notify("start",{id:t,data:e,schema:s,plugins:l,messages:p,setPreMessages:e=>{p=[...e,{role:"user",content:u.prompt}]},changeMessages:e=>{p=e}}),await a.flow.asyncWhile((async({count:a,doBreak:l})=>{if(a>=10)return l();let u="",d="",h=!1,f=p.filter((e=>"user"===e.role)).slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:p,lastUserMessage:f});const m=this.params.request(p,{count:a,schema:s,onCancel:c,isRetry:h});if(r)n&&n();else try{o=!0,u=await m,d=u}finally{o=!1}!1===r&&(await this.hook.notify("talkAfter",{id:t,data:e,response:u,messages:p,parseText:d,lastUserMessage:f,changeParseText:e=>{d=e}}),i=(await this.translator.parse(d)).output,await this.hook.notify("succeeded",{id:t,output:i})),await this.hook.notify("done",{id:t}),l()}catch(e){if(!e.isParserError)throw await this.hook.notify("done",{id:t}),e;if(await this.hook.notify("parseFailed",{id:t,error:e.error,count:a,response:u,messages:p,lastUserMessage:f,parserFails:e.parserFails,retry:()=>{h=!0},changeMessages:e=>{p=e}}),!1===h)throw await this.hook.notify("done",{id:t}),e}})),i};return{id:t,request:(async()=>{try{return await u()}finally{i()}})()}}async request(e){const{request:t}=this.requestWithId(e);return await t}}},15:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.TextParser=void 0;const a=r(n(959));class o{params;static JsonMessage(){return new o({name:"JsonMessage",handler:async e=>{try{return JSON.parse(e)}catch(t){const n=/{(?:[^{}]|(?:{[^{}]*}))*}/,r=e.match(n)?.[0]||"";return a.default.parse(r)}}})}constructor(e){this.params=e}get name(){return this.params.name}async read(e){return await this.params.handler(e)}}t.TextParser=o},241:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBrokerPlugin=void 0;const r=n(470);t.ChatBrokerPlugin=class{_event=new r.Event;_params;constructor(e){this._params=e}use(e){return{instance:this,params:e,send:e=>{this._event.emit("receive",e)},receive:e=>{this._event.on("receive",e)},__receiveData:null}}}},87:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Translator=void 0;const r=n(293);t.Translator=class{params;constructor(e){this.params=e}get __schemeType(){return null}get __outputType(){return null}async compile(e,t){const n=(0,r.validate)(e,this.params.input);return{scheme:n,prompt:await this.params.question(n,t)}}getValidate(){return{input:this.params.input,output:this.params.output}}async parse(e){let t,n="",a=[];for(let r of this.params.parsers)try{t=await r.read(e),n=r.name}catch(e){t=void 0,a.push({name:r.name,error:e})}try{return{output:(0,r.validate)(t,this.params.output),parserName:n,parserFails:a}}catch(e){throw{isParserError:!0,error:e,parserFails:a}}}}},620:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return a(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.ctod=t.Translator=t.ChatBrokerPlugin=t.ChatBroker=t.TextParser=t.Llama3Cpp=t.OpenAI=t.validateToJsonSchema=t.templates=t.plugins=void 0,t.plugins=o(n(218)),t.templates=o(n(298));var s=n(293);Object.defineProperty(t,"validateToJsonSchema",{enumerable:!0,get:function(){return s.validateToJsonSchema}});var i=n(616);Object.defineProperty(t,"OpenAI",{enumerable:!0,get:function(){return i.OpenAI}});var l=n(643);Object.defineProperty(t,"Llama3Cpp",{enumerable:!0,get:function(){return l.Llama3Cpp}});var c=n(15);Object.defineProperty(t,"TextParser",{enumerable:!0,get:function(){return c.TextParser}});var u=n(37);Object.defineProperty(t,"ChatBroker",{enumerable:!0,get:function(){return u.ChatBroker}});var p=n(241);Object.defineProperty(t,"ChatBrokerPlugin",{enumerable:!0,get:function(){return p.ChatBrokerPlugin}});var d=n(87);Object.defineProperty(t,"Translator",{enumerable:!0,get:function(){return d.Translator}});const h=o(n(218)),f=o(n(298)),m=n(616),g=n(643),y=n(87),_=n(15),v=n(37),b=n(241),w=n(293);t.ctod={OpenAI:m.OpenAI,Llama3Cpp:g.Llama3Cpp,plugins:h,templates:f,ChatBroker:v.ChatBroker,Translator:y.Translator,TextParser:_.TextParser,ChatBrokerPlugin:b.ChatBrokerPlugin,validateToJsonSchema:w.validateToJsonSchema},e.exports=t.ctod,e.exports.ctod=t.ctod,t.default=t.ctod},218:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.RolePlugin=t.LimiterPluginGlobState=t.LimiterPlugin=t.RetryPlugin=t.PrintLogPlugin=void 0;const a=r(n(894)),o=r(n(829)),s=r(n(626)),i=r(n(1));t.PrintLogPlugin=o.default,t.RetryPlugin=a.default,t.LimiterPlugin=s.default.plugin,t.LimiterPluginGlobState=s.default,t.RolePlugin=i.default},626:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241),a=n(470),o={limit:3,interval:6e4},s={event:new a.Event,schedule:null,waitTimes:[],waitQueue:[]};t.default={event:s.event,config:o,closeSchedule:()=>{s.schedule&&(s.schedule.close(),s.schedule=null)},plugin:new r.ChatBrokerPlugin({name:"limiter",params:()=>({}),receiveData:()=>({}),onInstall({attach:e}){null==s.schedule&&(s.schedule=new a.Schedule,s.schedule.add("calc queue",1e3,(async()=>{const e=Date.now();if(s.waitTimes=s.waitTimes.filter((t=>e-t<o.interval)),s.waitTimes.length!==o.limit){let e=s.waitQueue.shift();e&&(s.waitTimes.push(Date.now()),s.event.emit("run",{id:e}))}else s.waitTimes[0]&&s.event.emit("waitTimeChange",{waitTime:Math.floor(60-(e-s.waitTimes[0])/1e3)})})),s.schedule.play()),e("talkBefore",(async()=>{const e=a.flow.createUuid();return s.waitQueue.push(e),new Promise((t=>{s.event.on("run",(({id:n},{off:r})=>{n===e&&(r(),t())}))}))}))}})}},829:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"print-log",params:e=>({detail:e.boolean().required().default(!1)}),receiveData:()=>({}),onInstall({params:e,log:t,attach:n}){n("talkBefore",(async({lastUserMessage:n,messages:r})=>{t.print("Send:",{color:"green"}),e.detail?t.print("\n"+JSON.stringify(r,null,4)):t.print("\n"+n)})),n("talkAfter",(async({parseText:e})=>{t.print("Receive:",{color:"cyan"}),t.print("\n"+e)})),n("succeeded",(async({output:e})=>{t.print("Output:",{color:"yellow"});try{t.print("\n"+JSON.stringify(e,null,4))}catch(n){t.print("\n"+e)}}))}})},894:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"retry",params:e=>({retry:e.number().required().default(1),printWarn:e.boolean().required().default(!0)}),receiveData:()=>({}),onInstall({log:e,attach:t,params:n}){t("parseFailed",(async({count:t,retry:r,messages:a,changeMessages:o})=>{t<=n.retry&&(n.printWarn&&e.print(`Is Failed, Retry ${t} times.`),o(a),r())}))}})},1:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"role",params:e=>({role:e.string().required()}),receiveData:()=>({}),onInstall({attach:e,params:t}){e("start",(async({messages:e,changeMessages:n})=>{n([{role:"user",content:`你現在是${t.role}。`},{role:"assistant",content:`沒問題,我現在是${t.role},有什麼可以幫你的嗎?`},...e])}))}})},358:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3CppCompletion=void 0;const r=n(470),a=n(511);class o{core;streamAbortControllers=[];constructor(e){this.core=e}createAbortController(){const e=new AbortController,t=r.flow.createUuid();return this.streamAbortControllers.push({id:t,controller:e}),{signal:e.signal,controllerId:t}}removeAbortController(e){this.streamAbortControllers=this.streamAbortControllers.filter((t=>t.id!==e))}async stream(e){const{signal:t,controllerId:n}=this.createAbortController(),r=()=>{this.removeAbortController(n),e.onEnd()};fetch(`${this.core.config.baseUrl}/${e.path}`,{method:"POST",body:JSON.stringify(e.data),signal:t,headers:{"Content-Type":"application/json",...this.core.config.headers}}).then((async t=>{if(t.body){let n=t.body.getReader(),a=!1,o="";for(;!a;){const{value:t,done:r}=await n.read();if(t){o+=new TextDecoder("utf-8").decode(t);const n=o.split("\n\n");o=n.pop()||"",n.forEach((t=>{if(t.includes("[DONE]")&&(a=!0),t.startsWith("data:"))try{const n=JSON.parse(t.replace("data: ",""));e.onMessage(n)}catch(t){e.onWarn(t)}}))}r&&(a=!0)}r()}else e.onError(new Error("Body not found."))})).catch((t=>{t instanceof Error&&t.message.includes("The user aborted a request")?r():e.onError(t)}))}async fetch(e){const{signal:t,controllerId:n}=this.createAbortController();try{return{data:(await this.core.core._axios.post(`${this.core.config.baseUrl}/${e.path}`,e.data,{signal:t,headers:{"Content-Type":"application/json",...this.core.config.headers}})).data}}finally{this.removeAbortController(n)}}cancel(){this.streamAbortControllers.forEach((e=>e.controller.abort())),this.streamAbortControllers=[]}export(){return{cancel:this.cancel.bind(this)}}}t.Llama3CppCompletion=class{core;config={baseUrl:"",headers:{},autoConvertTraditionalChinese:!0};constructor(e){this.core=e}setConfig(e){this.config={...this.config,...e}}completion(e){const t=[];for(let{role:n,content:r}of e.messages)"system"===n&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${r}\n\n`),"user"===n&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${r?.replaceAll("\n","\\n")??""}`),"assistant"===n&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+r);const n=e.messages.at(-1)||"",r=new o(this);return{...r.export(),run:async()=>{const o=await r.fetch({path:"completion",data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,a.sify)(t.join("\n")):t.join("\n")}}),s=this.config.autoConvertTraditionalChinese?(0,a.tify)(o.data.content):o.data.content;return{message:s,fullMessage:`${n}${s}`}}}}completionStream(e){const t=[];for(let{role:n,content:r}of e.messages)"system"===n&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${r}\n\n`),"user"===n&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${r?.replaceAll("\n","\\n")??""}`),"assistant"===n&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+r);const n=new o(this);return n.stream({path:"completion",onEnd:e.onEnd||(()=>null),onMessage:t=>{e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,a.tify)(t.content):t.content})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,a.sify)(t.join("\n")):t.join("\n"),stream:!0}}),n.export()}talk(e){const t=new o(this);return{...t.export(),run:async()=>{const n=(await t.fetch({path:"v1/chat/completions",data:{...e.options||{},response_format:e.response_format,messages:e.messages.map((e=>({role:e.role,content:this.config.autoConvertTraditionalChinese?(0,a.sify)(e.content):e.content})))}})).data.choices[0].message.content||"";return{message:this.config.autoConvertTraditionalChinese?(0,a.tify)(n):n}}}}talkStream(e){const t=new o(this);return t.stream({path:"v1/chat/completions",onEnd:e.onEnd||(()=>null),onMessage:t=>{let n=t.choices[0].delta.content;n&&e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,a.tify)(n):n})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},stream:!0,messages:e.messages.map((e=>({role:e.role,content:this.config.autoConvertTraditionalChinese?(0,a.sify)(e.content):e.content})))}}),t.export()}}},643:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3Cpp=void 0;const a=r(n(167)),o=n(470),s=n(511),i=n(293),l=n(358);class c{_axios=a.default.create();static createChatRequest(e){return async(t,{schema:n,onCancel:r})=>{const a=(new c).createCompletion(),l="function"==typeof e.config?await e.config():e.config,u=e.jsonSchemaInfo?o.json.jpjs(e.jsonSchemaInfo):void 0;if(a.setConfig(l),a.config.autoConvertTraditionalChinese&&u)for(let e in u.desc){const t=u.desc[e];"object"==typeof t&&t.description&&(t.description=(0,s.sify)(t.description)),"string"==typeof t&&(u.desc[e]=(0,s.sify)(t))}const{run:p,cancel:d}=a.talk({options:e.talkOptions,messages:t,response_format:{type:"json_object",schema:(0,i.validateToJsonSchema)(n.output,u)}});r(d);const{message:h}=await p();return h}}setAxios(e){this._axios=e}createCompletion(){return new l.Llama3CppCompletion(this)}}t.Llama3Cpp=c},203:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIChat=void 0;const r=n(470);t.OpenAIChat=class{openai;config={n:1,model:"gpt-4o",temperature:1,maxTokens:void 0,forceJsonFormat:!0};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async moderations(e){const t=await this.openai._axios.post("https://api.openai.com/v1/moderations",{input:e},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}});return{isSafe:!1===t.data.results?.[0]?.flagged,result:t.data}}async talk(e=[],t){const n=r.json.jpjs(e),a=["gpt-4-turbo-preview","gpt-4-turbo","gpt-4o","gpt-4o-mini","gpt-3.5-turbo-1106"].includes(this.config.model);let o;a&&this.config.forceJsonFormat&&(o={type:"json_object"}),a&&this.config.forceJsonFormat&&t?.jsonSchema&&(o={type:"json_schema",json_schema:t.jsonSchema});const s=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:this.config.n,messages:n,response_format:o,temperature:this.config.temperature},{signal:t?.abortController?.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),i=s.data.choices||[],l=i[0]?.message||{role:"assistant",content:""};return n.push(l),{id:s?.data.id,text:l.content,newMessages:n,isDone:"stop"===i[0]?.finish_reason,apiReseponse:s.data}}talkStream(e){const t=new AbortController;return fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`},body:JSON.stringify({model:this.config.model,stream:!0,messages:e.messages}),signal:t.signal}).then((async t=>{const n=t.body?.pipeThrough(new TextDecoderStream).getReader();if(!n)throw new Error("Can not get reader");for(;;){const{value:t,done:r}=await n.read();if(r)break;const a=t.split("\n");for(let t of a)if(0!==t.length&&!t.startsWith(":")){if("data: [DONE]"===t){e.onEnd();break}try{const n=JSON.parse(t.substring(6)).choices[0].delta.content;e.onMessage(n)}catch(t){e.onWarn(t)}}}})).catch((t=>{"AbortError"===t.name?e.onEnd():e.onError(t)})),{cancel:()=>t.abort()}}async keepTalk(e,t=[]){const n=await this.talk([...t,{role:"user",content:Array.isArray(e)?e.join("\n"):e}]);return{result:n,nextTalk:e=>this.keepTalk(e,n.newMessages)}}}},725:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIImagesGeneration=void 0,t.OpenAIImagesGeneration=class{openai;config={model:"dall-e-2",size:"1024x1024"};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async create(e){return(await this.openai._axios.post("https://api.openai.com/v1/images/generations",{prompt:e,n:1,size:this.config.size,model:this.config.model,response_format:"b64_json"},{timeout:3e5,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}})).data}}},616:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAI=void 0;const a=r(n(167)),o=n(710),s=n(203),i=n(725),l=n(293);class c{_axios=a.default.create();_apiKey="";static createChatRequest(e,t={}){return async(n,{onCancel:r})=>{const a=new c("string"==typeof e?e:await e()).createChat(),o=new AbortController;a.setConfig("function"==typeof t?await t():t),r((()=>o.abort()));const{text:s}=await a.talk(n,{abortController:o});return s}}static createChatRequestWithJsonSchema(e){return async(t,{schema:n,onCancel:r})=>{const a=new c("string"==typeof e.apiKey?e.apiKey:await e.apiKey()).createChat(),o=new AbortController;e.config&&a.setConfig("function"==typeof e.config?await e.config():e.config),r((()=>o.abort()));const s=(0,l.validateToJsonSchema)(n.output,e.jsonSchemaInfo),{text:i}=await a.talk(t,{abortController:o,jsonSchema:{name:"data",strict:!0,schema:s}});return i}}constructor(e=""){this._apiKey=e}setAxios(e){this._axios=e}setConfiguration(e){this._apiKey=e}createChat(){return new s.OpenAIChat(this)}createVision(){return new o.OpenAIVision(this)}createImagesGeneration(){return new i.OpenAIImagesGeneration(this)}}t.OpenAI=c},710:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIVision=void 0,t.OpenAIVision=class{openai;config={model:"gpt-4-vision-preview",maxTokens:void 0,temperature:1};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async view(e){const t=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:1,messages:e,max_tokens:this.config.maxTokens,temperature:this.config.temperature},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),n=(t.data.choices||[])[0]?.message||{role:"assistant",content:""};return{id:t?.data.id,text:n.content,apiReseponse:t.data}}}},298:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.requireJsonResponseWithJsonSchema=t.requireJsonResponseWithHandlebars=t.requireJsonResponse=void 0;const a=r(n(97)),o=n(470);t.requireJsonResponse=(e,t)=>[...Array.isArray(e)?e:[e],"Please respond using the following JSON format and minify the JSON without including any explanation: ","{",Object.entries(t).map((([e,t])=>[`/* ${t.desc} */`,`"${e}": ${JSON.stringify(t.example)}`].join("\n"))).join(",\n"),"}"].join("\n"),t.requireJsonResponseWithHandlebars=(e,n,r)=>{const s=a.default.create();return s.registerHelper("DATA",(function(e){return JSON.stringify(e)})),s.registerHelper("ENV",(function(e){return this.__envs&&e?this.__envs[e]:""})),s.registerHelper("INPUT",(function(){return JSON.stringify(o.record.omit(this,["__envs"]))})),s.registerHelper("JOIN",(function(e){return Array.isArray(e)?e.join():JSON.stringify(e)})),s.compile((0,t.requireJsonResponse)(n,r))(e)},t.requireJsonResponseWithJsonSchema=(e,t)=>[...Array.isArray(e)?e:[e],"Please provide JSON data according to the following JSON Schema format:",JSON.stringify(t)].join("\n")},293:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return a(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.validateToJsonSchema=t.validate=t.definedValidateSchema=void 0;const s=o(n(609)),i=n(470),l=n(724);t.definedValidateSchema=function(e){return e},t.validate=function(e,t){return s.object(t(s)).required().validateSync(e||{})},t.validateToJsonSchema=(e,t)=>{const n=e=>{if(e.default&&delete e.default,e.properties)for(let t in e.properties)e.properties[t].default&&delete e.properties[t].default,n(e.properties[t]);e.items&&n(e.items)},r=e=>{if("object"===e.type){e.additionalProperties=!1;for(const t in e.properties)r(e.properties[t])}else"array"===e.type&&r(e.items)},a=(0,l.convertSchema)(s.object(e(s)));return n(a),r(a),t?((e,t)=>{if(t&&t.desc)for(let n in t.desc)if(e.properties){let r=i.pick.peel(e.properties,n.replaceAll(".",".properties."));if(r&&!0!==r){let e=t.desc[n];"object"==typeof e?(e.description&&(r.description=e.description),e.examples&&(r.examples=e.examples)):"string"==typeof e&&(r.description=e)}}return e})(a,t):a}},724:e=>{e.exports=require("@sodaru/yup-to-json-schema")},167:e=>{e.exports=require("axios")},511:e=>{e.exports=require("chinese-conv")},97:e=>{e.exports=require("handlebars")},959:e=>{e.exports=require("json5")},470:e=>{e.exports=require("power-helper")},609:e=>{e.exports=require("yup")}},t={};return function n(r){var a=t[r];if(void 0!==a)return a.exports;var o=t[r]={exports:{}};return e[r].call(o.exports,o,o.exports,n),o.exports}(620)})()));
@@ -1,6 +1,6 @@
1
1
  // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
2
  /// <reference path="../lib/shims.d.ts" />
3
- import { ChatBroker, OpenAI, templates, validateToJsonSchema } from '../lib/index'
3
+ import { ChatBroker, OpenAI } from '../lib/index'
4
4
 
5
5
  /**
6
6
  * @test npx ts-node ./examples/chat-demo.ts
@@ -23,18 +23,24 @@ const broker = new ChatBroker({
23
23
  }
24
24
  },
25
25
  install: () => null,
26
- request: OpenAI.createChatRequest(API_KEY),
27
- question: async({ indexs, question }, { schema }) => {
28
- return templates.requireJsonResponseWithJsonSchema([
26
+ request: OpenAI.createChatRequestWithJsonSchema({
27
+ apiKey: API_KEY,
28
+ config: {
29
+ model: 'gpt-4o-mini'
30
+ },
31
+ jsonSchemaInfo: {
32
+ desc: {
33
+ indexs: '由高到低排序的索引'
34
+ }
35
+ }
36
+ }),
37
+ question: async({ indexs, question }) => {
38
+ return [
29
39
  '我有以下索引',
30
40
  `${JSON.stringify(indexs)}`,
31
41
  `請幫我解析"${question}"可能是哪個索引`,
32
42
  '且相關性由高到低排序並給予分數,分數由 0 ~ 1'
33
- ], validateToJsonSchema(schema.output, {
34
- desc: {
35
- indexs: '由高到低排序的索引'
36
- }
37
- }))
43
+ ].join('\n')
38
44
  }
39
45
  })
40
46
 
@@ -105,6 +105,8 @@ export class OpenAIChat {
105
105
  */
106
106
 
107
107
  async talk(messages: ChatGPTMessage[] = [], options?: {
108
+ /** 要 forceJsonFormat 為 true 才會生效 */
109
+ jsonSchema?: any
108
110
  abortController?: AbortController
109
111
  }) {
110
112
  const newMessages = json.jpjs(messages)
@@ -115,13 +117,23 @@ export class OpenAIChat {
115
117
  'gpt-4o-mini',
116
118
  'gpt-3.5-turbo-1106'
117
119
  ].includes(this.config.model)
120
+ let response_format: any = undefined
121
+ if (isSupportJson && this.config.forceJsonFormat) {
122
+ response_format = {
123
+ type: 'json_object'
124
+ }
125
+ }
126
+ if (isSupportJson && this.config.forceJsonFormat && options?.jsonSchema) {
127
+ response_format = {
128
+ type: 'json_schema',
129
+ json_schema: options.jsonSchema
130
+ }
131
+ }
118
132
  const result = await this.openai._axios.post<ApiResponse>('https://api.openai.com/v1/chat/completions', {
119
133
  model: this.config.model,
120
134
  n: this.config.n,
121
135
  messages: newMessages,
122
- response_format: (isSupportJson === false || this.config.forceJsonFormat === false) ? undefined : {
123
- type: 'json_object'
124
- },
136
+ response_format,
125
137
  temperature: this.config.temperature
126
138
  }, {
127
139
  signal: options?.abortController?.signal,
@@ -1,7 +1,8 @@
1
+ import axios, { AxiosInstance } from 'axios'
1
2
  import { OpenAIVision } from './vision'
2
3
  import { OpenAIChat, Config } from './chat'
3
4
  import { OpenAIImagesGeneration } from './images-generation'
4
- import axios, { AxiosInstance } from 'axios'
5
+ import { validateToJsonSchema, JsonSchemaInfo } from '../../utils/validate'
5
6
 
6
7
  export class OpenAI {
7
8
  _axios = axios.create()
@@ -21,6 +22,33 @@ export class OpenAI {
21
22
  }
22
23
  }
23
24
 
25
+ static createChatRequestWithJsonSchema(params:{
26
+ apiKey: string | (() => Promise<string>),
27
+ config?: Partial<Config> | (() => Promise<Partial<Config>>)
28
+ jsonSchemaInfo?: JsonSchemaInfo
29
+ }) {
30
+ return async(messages: any[], { schema, onCancel }: any) => {
31
+ const openai = new OpenAI(typeof params.apiKey === 'string' ? params.apiKey : await params.apiKey())
32
+ const chat = openai.createChat()
33
+ const abortController = new AbortController()
34
+ if (params.config) {
35
+ chat.setConfig(typeof params.config === 'function' ? await params.config() : params.config)
36
+ }
37
+ onCancel(() => abortController.abort())
38
+ const jsonSchema = validateToJsonSchema(schema.output, params.jsonSchemaInfo)
39
+ const { text } = await chat.talk(messages, {
40
+ abortController,
41
+ jsonSchema: {
42
+ name: 'data',
43
+ strict: true,
44
+ schema: jsonSchema
45
+ }
46
+ })
47
+ return text
48
+ }
49
+ }
50
+
51
+
24
52
  constructor(apiKey = '') {
25
53
  this._apiKey = apiKey
26
54
  }
@@ -63,7 +63,34 @@ export const validateToJsonSchema = <T extends ValidateCallback<any>>(cb: T, inf
63
63
  }
64
64
  return schema
65
65
  }
66
+ const removeAllDefault = (schema: any) => {
67
+ if (schema.default) {
68
+ delete schema.default
69
+ }
70
+ if (schema.properties) {
71
+ for (let key in schema.properties) {
72
+ if (schema.properties[key].default) {
73
+ delete schema.properties[key].default
74
+ }
75
+ removeAllDefault(schema.properties[key])
76
+ }
77
+ }
78
+ if (schema.items) {
79
+ removeAllDefault(schema.items)
80
+ }
81
+ }
82
+ const addAllAdditionalProperties = (jsonSchema: any) => {
83
+ if (jsonSchema.type === 'object') {
84
+ jsonSchema.additionalProperties = false
85
+ for (const key in jsonSchema.properties) {
86
+ addAllAdditionalProperties(jsonSchema.properties[key])
87
+ }
88
+ } else if (jsonSchema.type === 'array') {
89
+ addAllAdditionalProperties(jsonSchema.items)
90
+ }
91
+ }
66
92
  const jsonSchema = convertSchema(Yup.object(cb(Yup)))
67
- delete jsonSchema.default
93
+ removeAllDefault(jsonSchema)
94
+ addAllAdditionalProperties(jsonSchema)
68
95
  return info ? bodySchemaBindDoc(jsonSchema, info) : jsonSchema
69
96
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctod",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "CtoD Is Chat To Data Utils.",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -73,6 +73,8 @@ export declare class OpenAIChat {
73
73
  * @en Talk to the AI
74
74
  */
75
75
  talk(messages?: ChatGPTMessage[], options?: {
76
+ /** 要 forceJsonFormat 為 true 才會生效 */
77
+ jsonSchema?: any;
76
78
  abortController?: AbortController;
77
79
  }): Promise<{
78
80
  id: string;
@@ -1,11 +1,17 @@
1
+ import { AxiosInstance } from 'axios';
1
2
  import { OpenAIVision } from './vision';
2
3
  import { OpenAIChat, Config } from './chat';
3
4
  import { OpenAIImagesGeneration } from './images-generation';
4
- import { AxiosInstance } from 'axios';
5
+ import { JsonSchemaInfo } from '../../utils/validate';
5
6
  export declare class OpenAI {
6
7
  _axios: AxiosInstance;
7
8
  _apiKey: string;
8
9
  static createChatRequest(apiKey: string | (() => Promise<string>), config?: Partial<Config> | (() => Promise<Partial<Config>>)): (messages: any[], { onCancel }: any) => Promise<string>;
10
+ static createChatRequestWithJsonSchema(params: {
11
+ apiKey: string | (() => Promise<string>);
12
+ config?: Partial<Config> | (() => Promise<Partial<Config>>);
13
+ jsonSchemaInfo?: JsonSchemaInfo;
14
+ }): (messages: any[], { schema, onCancel }: any) => Promise<string>;
9
15
  constructor(apiKey?: string);
10
16
  /**
11
17
  * @zh 如果你有需要特別設定 axios,請使用這方法。