ctod 0.8.0 → 0.8.2

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/README.md CHANGED
@@ -21,7 +21,7 @@
21
21
 
22
22
  在對話過程中,CtoD 採用 [yup](https://github.com/jquense/yup) 來驗證請求與回復資料是否符合預期,以確保一致性,只要保持這個互動模式,就可以利用在 API 串接或是自動化系統上。
23
23
 
24
- 我們還附帶支援 `OpenAI` `Llama3` 的相關服務。
24
+ 我們還附帶支援 `OpenAI`, `Google`, `Llama3` 等相關 LLM 服務。
25
25
 
26
26
  ## 安裝
27
27
 
@@ -42,10 +42,10 @@ yarn add ctod
42
42
  這個例子示範如何將藥物索引與客戶需求傳遞給聊天機器人,並返回最適合的結果,開發人員可以利用索引結果去資料庫搜尋最適合的藥物給消費者:
43
43
 
44
44
  ```ts
45
- import { CtoD, OpenAI } from 'ctod'
45
+ import { CtoD, OpenAICtodService } from 'ctod'
46
46
 
47
47
  const ctod = new CtoD({
48
- request: OpenAI.createChatRequestWithJsonSchema({
48
+ request: OpenAICtodService.createChatRequestWithJsonSchema({
49
49
  apiKey: 'YOUR_API_KEY',
50
50
  config: {
51
51
  model: 'gpt-4o'
@@ -131,14 +131,14 @@ broker.request({
131
131
 
132
132
  雖然 Broker 本身已經能夠處理大部分的事務,但透過 Plugin 可以協助改善複雜的流程,幫助專案工程化。
133
133
 
134
- 每次發送請求時,Broker 會觸發一系列的生命週期,你可以從[原始碼](./lib/broker/chat.ts)中了解每個生命週期的參數與行為,並對其行為進行加工。
134
+ 每次發送請求時,Broker 會觸發一系列的生命週期,你可以從[原始碼](./lib/broker/openai.ts)中了解每個生命週期的參數與行為,並對其行為進行加工。
135
135
 
136
136
  現在,假設我們想要設計一個插件,它會在每次對話結束時將訊息備份到伺服器上:
137
137
 
138
138
  ```ts
139
139
  import axios from 'axios'
140
- import { ChatBroker, ChatBrokerPlugin } from 'ctod'
141
- const backupPlugin = new ChatBrokerPlugin({
140
+ import { CtoDPlugin } from 'ctod'
141
+ const backupPlugin = new CtoDPlugin({
142
142
  name: 'backup-plugin',
143
143
  // 定義參數為 sendUrl
144
144
  params: yup => {
@@ -178,15 +178,6 @@ const backupPlugin = new ChatBrokerPlugin({
178
178
  }
179
179
  })
180
180
 
181
- const broker = new ChatBroker({
182
- // ...
183
- plugins: {
184
- backup: backupPlugin.use({
185
- sendUrl: 'https://api/backup'
186
- })
187
- }
188
- })
189
-
190
181
  const ctod = new CtoD({
191
182
  // ...
192
183
  plugins: () => {
@@ -211,6 +202,11 @@ const ctod = new CtoD({
211
202
 
212
203
  ## Version History
213
204
 
205
+ ### 0.8.x
206
+
207
+ 1. 正規化 Service 的命名
208
+ 2. 新增 Google Service 的支援
209
+
214
210
  ### 0.7.x
215
211
 
216
212
  感謝當今的模型對於json schema的支援,我們不再需要繁瑣的宣告,因此新增了透過註冊 CtoD 的方式來簡化流程。
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
- var Y=Object.defineProperty;var se=(a,e,t)=>e in a?Y(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var Q=(a,e)=>{for(var t in e)Y(a,t,{get:e[t],enumerable:!0})};var o=(a,e,t)=>se(a,typeof e!="symbol"?e+"":e,t);var te={};Q(te,{LimiterPlugin:()=>me,LimiterPluginGlobState:()=>de,PrintLogPlugin:()=>pe,RetryPlugin:()=>ue,RolePlugin:()=>ge});import{Event as oe}from"power-helper";var h=class{constructor(e){o(this,"_event",new oe);o(this,"_params");this._params=e}use(e){return{instance:this,params:e,send:t=>{this._event.emit("receive",t)},receive:t=>{this._event.on("receive",t)},__receiveData:null}}};var X=new h({name:"retry",params:a=>({retry:a.number().required().default(1),printWarn:a.boolean().required().default(!0)}),receiveData:()=>({}),onInstall({log:a,attach:e,params:t}){e("parseFailed",async({count:r,retry:n,messages:s,changeMessages:i})=>{r<=t.retry&&(t.printWarn&&a.print(`Is Failed, Retry ${r} times.`),i(s),n())})}});var Z=new h({name:"print-log",params:a=>({detail:a.boolean().default(!1)}),receiveData:()=>({}),onInstall({params:a,log:e,attach:t}){t("talkBefore",async({lastUserMessage:r,messages:n})=>{e.print("Send:",{color:"green"}),a.detail?e.print(`
1
+ var Q=Object.defineProperty;var oe=(a,e,t)=>e in a?Q(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var X=(a,e)=>{for(var t in e)Q(a,t,{get:e[t],enumerable:!0})};var o=(a,e,t)=>oe(a,typeof e!="symbol"?e+"":e,t);var re={};X(re,{LimiterPlugin:()=>me,LimiterPluginGlobState:()=>de,PrintLogPlugin:()=>ue,RetryPlugin:()=>ge,RolePlugin:()=>he});import{Event as ie}from"power-helper";var d=class{constructor(e){o(this,"_event",new ie);o(this,"_params");this._params=e}use(e){return{instance:this,params:e,send:t=>{this._event.emit("receive",t)},receive:t=>{this._event.on("receive",t)},__receiveData:null}}};var Z=new d({name:"retry",params:a=>({retry:a.number().required().default(1),printWarn:a.boolean().required().default(!0)}),receiveData:()=>({}),onInstall({log:a,attach:e,params:t}){e("parseFailed",async({count:r,retry:n,messages:s,changeMessages:i})=>{r<=t.retry&&(t.printWarn&&a.print(`Is Failed, Retry ${r} times.`),i(s),n())})}});var ee=new d({name:"print-log",params:a=>({detail:a.boolean().default(!1)}),receiveData:()=>({}),onInstall({params:a,log:e,attach:t}){t("talkBefore",async({lastUserMessage:r,messages:n})=>{e.print("Send:",{color:"green"}),a.detail?e.print(`
2
2
  `+JSON.stringify(n,null,4)):e.print(`
3
3
  `+r)}),t("talkAfter",async({parseText:r})=>{e.print("Receive:",{color:"cyan"}),e.print(`
4
4
  `+r)}),t("succeeded",async({output:r})=>{e.print("Output:",{color:"yellow"});try{e.print(`
5
5
  `+JSON.stringify(r,null,4))}catch{e.print(`
6
- `+r)}})}});import{Event as ie,flow as le,Schedule as ce}from"power-helper";var F={limit:3,interval:6e4},u={event:new ie,schedule:null,waitTimes:[],waitQueue:[]},H={event:u.event,config:F,closeSchedule:()=>{u.schedule&&(u.schedule.close(),u.schedule=null)},plugin:new h({name:"limiter",params:()=>({}),receiveData:()=>({}),onInstall({attach:a}){u.schedule==null&&(u.schedule=new ce,u.schedule.add("calc queue",1e3,async()=>{let e=Date.now();if(u.waitTimes=u.waitTimes.filter(t=>e-t<F.interval),u.waitTimes.length!==F.limit){let t=u.waitQueue.shift();t&&(u.waitTimes.push(Date.now()),u.event.emit("run",{id:t}))}else u.waitTimes[0]&&u.event.emit("waitTimeChange",{waitTime:Math.floor(60-(e-u.waitTimes[0])/1e3)})}),u.schedule.play()),a("talkBefore",async()=>{let e=le.createUuid();return u.waitQueue.push(e),new Promise(t=>{u.event.on("run",({id:r},{off:n})=>{r===e&&(n(),t())})})})}})};var ee=new h({name:"role",params:a=>({role:a.string().required()}),receiveData:()=>({}),onInstall({attach:a,params:e}){a("start",async({messages:t,changeMessages:r})=>{r([{role:"user",content:`\u4F60\u73FE\u5728\u662F${e.role}\u3002`},{role:"assistant",content:`\u6C92\u554F\u984C\uFF0C\u6211\u73FE\u5728\u662F${e.role}\uFF0C\u6709\u4EC0\u9EBC\u53EF\u4EE5\u5E6B\u4F60\u7684\u55CE\uFF1F`},...t])})}});var pe=Z,ue=X,me=H.plugin,de=H,ge=ee;var ne={};Q(ne,{requireJsonResponse:()=>re,requireJsonResponseWithHandlebars:()=>ye,requireJsonResponseWithJsonSchema:()=>Ce});import he from"handlebars";import{record as fe}from"power-helper";var re=(a,e)=>[...Array.isArray(a)?a:[a],"Please respond using the following JSON format and minify the JSON without including any explanation: ","{",Object.entries(e).map(([t,r])=>[`/* ${r.desc} */`,`"${t}": ${JSON.stringify(r.example)}`].join(`
6
+ `+r)}})}});import{Event as le,flow as ce,Schedule as pe}from"power-helper";var F={limit:3,interval:6e4},u={event:new le,schedule:null,waitTimes:[],waitQueue:[]},H={event:u.event,config:F,closeSchedule:()=>{u.schedule&&(u.schedule.close(),u.schedule=null)},plugin:new d({name:"limiter",params:()=>({}),receiveData:()=>({}),onInstall({attach:a}){u.schedule==null&&(u.schedule=new pe,u.schedule.add("calc queue",1e3,async()=>{let e=Date.now();if(u.waitTimes=u.waitTimes.filter(t=>e-t<F.interval),u.waitTimes.length!==F.limit){let t=u.waitQueue.shift();t&&(u.waitTimes.push(Date.now()),u.event.emit("run",{id:t}))}else u.waitTimes[0]&&u.event.emit("waitTimeChange",{waitTime:Math.floor(60-(e-u.waitTimes[0])/1e3)})}),u.schedule.play()),a("talkBefore",async()=>{let e=ce.createUuid();return u.waitQueue.push(e),new Promise(t=>{u.event.on("run",({id:r},{off:n})=>{r===e&&(n(),t())})})})}})};var te=new d({name:"role",params:a=>({role:a.string().required()}),receiveData:()=>({}),onInstall({attach:a,params:e}){a("start",async({messages:t,changeMessages:r})=>{r([{role:"user",content:`\u4F60\u73FE\u5728\u662F${e.role}\u3002`},{role:"assistant",content:`\u6C92\u554F\u984C\uFF0C\u6211\u73FE\u5728\u662F${e.role}\uFF0C\u6709\u4EC0\u9EBC\u53EF\u4EE5\u5E6B\u4F60\u7684\u55CE\uFF1F`},...t])})}});var ue=ee,ge=Z,me=H.plugin,de=H,he=te;var ae={};X(ae,{requireJsonResponse:()=>ne,requireJsonResponseWithHandlebars:()=>Ce,requireJsonResponseWithJsonSchema:()=>xe});import fe from"handlebars";import{record as ye}from"power-helper";var ne=(a,e)=>[...Array.isArray(a)?a:[a],"Please respond using the following JSON format and minify the JSON without including any explanation: ","{",Object.entries(e).map(([t,r])=>[`/* ${r.desc} */`,`"${t}": ${JSON.stringify(r.example)}`].join(`
7
7
  `)).join(`,
8
8
  `),"}"].join(`
9
- `),ye=(a,e,t)=>{let r=he.create();return r.registerHelper("DATA",function(n){return JSON.stringify(n)}),r.registerHelper("ENV",function(n){return this.__envs&&n?this.__envs[n]:""}),r.registerHelper("INPUT",function(){return JSON.stringify(fe.omit(this,["__envs"]))}),r.registerHelper("JOIN",function(n){return Array.isArray(n)?n.join():JSON.stringify(n)}),r.compile(re(e,t))(a)},Ce=(a,e)=>[...Array.isArray(a)?a:[a],"Please provide JSON data according to the following JSON Schema format:",JSON.stringify(e)].join(`
10
- `);import xe from"json5";var S=class a{constructor(e){o(this,"params");this.params=e}static JsonMessage(){return new a({name:"JsonMessage",handler:async e=>{try{return JSON.parse(e)}catch{let r=/{(?:[^{}]|(?:{[^{}]*}))*}/,n=e.match(r)?.[0]||"";return xe.parse(n)}}})}get name(){return this.params.name}async read(e){return await this.params.handler(e)}};import{Event as Pe,flow as ae,Hook as Te,Log as ve}from"power-helper";import*as w from"yup";import{convertSchema as ke}from"@sodaru/yup-to-json-schema";function $(a,e){return w.object(e(w)).required().validateSync(a||{})}var be=a=>a(w),b=a=>{let e=n=>{if(n.default&&delete n.default,n.properties)for(let s in n.properties)n.properties[s].default&&delete n.properties[s].default,e(n.properties[s]);n.items&&e(n.items)},t=n=>{if(n.type==="object"){n.additionalProperties=!1;for(let s in n.properties)t(n.properties[s])}else n.type==="array"&&t(n.items)},r=ke(w.object(a(w)));return e(r),t(r),r};var P=class{constructor(e,t){o(this,"isParserError",!0);o(this,"parserFails",[]);o(this,"error");this.error=e,this.parserFails=t}};var A=class{constructor(e){o(this,"params");this.params=e}get __schemeType(){return null}get __outputType(){return null}async compile(e,t){let r=this.params.input?$(e,this.params.input):e,n=this.params.question?await this.params.question(r,t):"";return{scheme:r,prompt:Array.isArray(n)?n.join(`
11
- `):n}}getValidate(){return{input:this.params.input,output:this.params.output}}changeOutputSchema(e){this.params.output=e}async parse(e){let t,r="",n=[];for(let s of this.params.parsers)try{t=await s.read(e),r=s.name}catch(i){t=void 0,n.push({name:s.name,error:i})}try{return{output:$(t,this.params.output),parserName:r,parserFails:n}}catch(s){throw new P(s,n)}}};var R=class{constructor(e){o(this,"__hookType");o(this,"log");o(this,"hook",new Te);o(this,"params");o(this,"plugins",{});o(this,"installed",!1);o(this,"translator");o(this,"event",new Pe);this.log=new ve(e.name??"no name"),this.params=e,this.translator=new A({...e,parsers:[S.JsonMessage()]})}_install(){if(this.installed===!1){this.installed=!0;let e={log:this.log,attach:this.hook.attach.bind(this.hook),attachAfter:this.hook.attachAfter.bind(this.hook),translator:this.translator};if(this.params.plugins){this.plugins=typeof this.params.plugins=="function"?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})}this.params.install?.(e)}}async cancel(e){e?this.event.emit("cancel",{requestId:e}):this.event.emit("cancelAll",{})}requestWithId(e){this._install();let t=ae.createUuid(),r=null,n=!1,s=!1,i=[this.event.on("cancel",({requestId:p})=>{p===t&&l()}),this.event.on("cancelAll",()=>{l()})],c=()=>i.forEach(p=>p.off()),l=()=>{n===!1&&(s&&r&&r(),n=!0,c())},m=p=>{r=p},f=async()=>{let p=this.translator.getValidate(),k=null,v={},y=new Map,U=await this.translator.compile(e,{schema:p}),z=[],g=[];U.prompt&&g.push({role:"user",content:U.prompt});for(let d in this.plugins)v[d]={send:C=>this.plugins[d].send({id:t,data:C})};return await this.hook.notify("start",{id:t,data:e,schema:p,plugins:v,messages:g,metadata:y,setPreMessages:d=>{z=d.map(C=>({...C,content:Array.isArray(C.content)?C.content.join(`
12
- `):C.content}))},changeMessages:d=>{g=d},changeOutputSchema:d=>{this.translator.changeOutputSchema(d),p=this.translator.getValidate()}}),g=[...z,...g],await ae.asyncWhile(async({count:d,doBreak:C})=>{if(d>=99)return C();let M="",V="",N=!1,K=g.filter(x=>x.role==="user").slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:g,metadata:y,lastUserMessage:K});let x=this.params.request(g,{id:t,count:d,schema:p,onCancel:m,metadata:y,isRetry:N});if(n)r&&r();else try{s=!0,M=await x,V=M}finally{s=!1}n===!1&&(await this.hook.notify("talkAfter",{id:t,data:e,response:M,messages:g,parseText:V,metadata:y,lastUserMessage:K,parseFail:_=>{throw new P(_,[])},changeParseText:_=>{V=_}}),k=(await this.translator.parse(V)).output,await this.hook.notify("succeeded",{id:t,output:k,metadata:y})),await this.hook.notify("done",{id:t,metadata:y}),C()}catch(x){if(x instanceof P){if(await this.hook.notify("parseFailed",{id:t,error:x.error,count:d,response:M,messages:g,metadata:y,lastUserMessage:K,parserFails:x.parserFails,retry:()=>{N=!0},changeMessages:_=>{g=_}}),N===!1)throw await this.hook.notify("done",{id:t,metadata:y}),x}else throw await this.hook.notify("done",{id:t,metadata:y}),x}}),k};return{id:t,request:(async()=>{try{return await f()}finally{c()}})()}}async request(e){let{request:t}=this.requestWithId(e);return await t}};import*as we from"yup";var W=class{constructor(e){o(this,"params");this.params=e}createBrokerBuilder(e){return{create:t=>new R({output:()=>({}),install:r=>{e?.install?.(r),r.attach("start",async({id:n,plugins:s,data:i,metadata:c,changeMessages:l,changeOutputSchema:m})=>{let f=await t({id:n,data:i,plugins:s,yup:we,setMessages:T=>{l(T.map(p=>({role:p.role,content:Array.isArray(p.content)?p.content.join(`
13
- `):p.content})))},metadata:c});m(()=>f)})},plugins:this.params.plugins?()=>this.params.plugins():void 0,request:this.params.request})}}};import _e from"axios";var I=class{constructor(e){o(this,"openai");o(this,"config",{model:"gpt-4-vision-preview",maxTokens:void 0,temperature:1});this.openai=e}setConfig(e){Object.assign(this.config,e)}async view(e){let 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}}};import{json as Oe}from"power-helper";var j=class{constructor(e){o(this,"openai");o(this,"config",{n:1,model:"gpt-4o",temperature:1,maxTokens:void 0,forceJsonFormat:!0});this.openai=e}setConfig(e){Object.assign(this.config,e)}async moderations(e){let 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:t.data.results?.[0]?.flagged===!1,result:t.data}}async talk(e=[],t){let r=Oe.jpjs(e),n=["gpt-4-turbo-preview","gpt-4-turbo","gpt-4o","gpt-4o-mini","gpt-3.5-turbo-1106"].includes(this.config.model),s;n&&this.config.forceJsonFormat&&(s={type:"json_object"}),n&&this.config.forceJsonFormat&&t?.jsonSchema&&(s={type:"json_schema",json_schema:t.jsonSchema});let i=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:this.config.n,messages:r,response_format:s,temperature:this.config.temperature},{signal:t?.abortController?.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),c=i.data.choices||[],l=c[0]?.message||{role:"assistant",content:""};return r.push(l),{id:i?.data.id,text:l.content,newMessages:r,isDone:c[0]?.finish_reason==="stop",apiReseponse:i.data}}talkStream(e){let 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 r=>{let n=r.body?.pipeThrough(new TextDecoderStream).getReader();if(!n)throw new Error("Can not get reader");for(;;){let{value:s,done:i}=await n.read();if(i)break;let c=s.split(`
14
- `);for(let l of c)if(l.length!==0&&!l.startsWith(":")){if(l==="data: [DONE]"){e.onEnd();break}try{let f=JSON.parse(l.substring(6)).choices[0].delta.content;e.onMessage(f)}catch(m){e.onWarn(m)}}}}).catch(r=>{r.name==="AbortError"?e.onEnd():e.onError(r)}),{cancel:()=>t.abort()}}async keepTalk(e,t=[]){let r=await this.talk([...t,{role:"user",content:Array.isArray(e)?e.join(`
15
- `):e}]);return{result:r,nextTalk:n=>this.keepTalk(n,r.newMessages)}}};var J=class{constructor(e){o(this,"openai");o(this,"config",{model:"dall-e-2",size:"1024x1024"});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}};var D=class a{constructor(e=""){o(this,"_axios",_e.create());o(this,"_apiKey","");this._apiKey=e}static createChatRequest(e,t={},r){return async(n,{onCancel:s})=>{let i=new a(typeof e=="string"?e:await e()),c=i.createChat(),l=new AbortController;r&&r.axios&&i.setAxios(r.axios),c.setConfig(typeof t=="function"?await t():t),s(()=>l.abort());let{text:m}=await c.talk(n,{abortController:l});return m}}static createChatRequestWithJsonSchema(e){return async(t,{schema:r,onCancel:n})=>{let s=new a(typeof e.apiKey=="string"?e.apiKey:await e.apiKey()),i=s.createChat(),c=new AbortController;e.config&&i.setConfig(typeof e.config=="function"?await e.config():e.config),e.axios&&s.setAxios(e.axios),n(()=>c.abort());let l=b(r.output),{text:m}=await i.talk(t,{abortController:c,jsonSchema:{name:"data",strict:!0,schema:l}});return m}}setAxios(e){this._axios=e}setConfiguration(e){this._apiKey=e}createChat(){return new j(this)}createVision(){return new I(this)}createImagesGeneration(){return new J(this)}};import Ae from"axios";import{sify as Re}from"chinese-conv/dist";import{flow as Se}from"power-helper";import{tify as B,sify as E}from"chinese-conv/dist";var O=class{constructor(e){o(this,"core");o(this,"streamAbortControllers",[]);this.core=e}createAbortController(){let e=new AbortController,t=Se.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){let{signal:t,controllerId:r}=this.createAbortController(),n=()=>{this.removeAbortController(r),e.onEnd()},s=async i=>{if(i.body){let c=i.body.getReader(),l=!1,m="";for(;!l;){let{value:f,done:T}=await c.read();if(f){m+=new TextDecoder("utf-8").decode(f);let p=m.split(`
9
+ `),Ce=(a,e,t)=>{let r=fe.create();return r.registerHelper("DATA",function(n){return JSON.stringify(n)}),r.registerHelper("ENV",function(n){return this.__envs&&n?this.__envs[n]:""}),r.registerHelper("INPUT",function(){return JSON.stringify(ye.omit(this,["__envs"]))}),r.registerHelper("JOIN",function(n){return Array.isArray(n)?n.join():JSON.stringify(n)}),r.compile(ne(e,t))(a)},xe=(a,e)=>[...Array.isArray(a)?a:[a],"Please provide JSON data according to the following JSON Schema format:",JSON.stringify(e)].join(`
10
+ `);import ke from"json5";var O=class a{constructor(e){o(this,"params");this.params=e}static JsonMessage(){return new a({name:"JsonMessage",handler:async e=>{try{return JSON.parse(e)}catch{let r=/{(?:[^{}]|(?:{[^{}]*}))*}/,n=e.match(r)?.[0]||"";return ke.parse(n)}}})}get name(){return this.params.name}async read(e){return await this.params.handler(e)}};import{Event as Te,flow as se,Hook as be,Log as Se}from"power-helper";import*as S from"yup";import{convertSchema as ve}from"@sodaru/yup-to-json-schema";function $(a,e){return S.object(e(S)).required().validateSync(a||{})}var Pe=a=>a(S),v=a=>{let e=n=>{if(n.default&&delete n.default,n.properties)for(let s in n.properties)n.properties[s].default&&delete n.properties[s].default,e(n.properties[s]);n.items&&e(n.items)},t=n=>{if(n.type==="object"){n.additionalProperties=!1;for(let s in n.properties)t(n.properties[s])}else n.type==="array"&&t(n.items)},r=ve(S.object(a(S)));return e(r),t(r),r};var P=class{constructor(e,t){o(this,"isParserError",!0);o(this,"parserFails",[]);o(this,"error");this.error=e,this.parserFails=t}};var A=class{constructor(e){o(this,"params");this.params=e}get __schemeType(){return null}get __outputType(){return null}async compile(e,t){let r=this.params.input?$(e,this.params.input):e,n=this.params.question?await this.params.question(r,t):"";return{scheme:r,prompt:Array.isArray(n)?n.join(`
11
+ `):n}}getValidate(){return{input:this.params.input,output:this.params.output}}changeOutputSchema(e){this.params.output=e}async parse(e){let t,r="",n=[];for(let s of this.params.parsers)try{t=await s.read(e),r=s.name}catch(i){t=void 0,n.push({name:s.name,error:i})}try{return{output:$(t,this.params.output),parserName:r,parserFails:n}}catch(s){throw new P(s,n)}}};var M=class{constructor(e){o(this,"__hookType");o(this,"log");o(this,"hook",new be);o(this,"params");o(this,"plugins",{});o(this,"installed",!1);o(this,"translator");o(this,"event",new Te);this.log=new Se(e.name??"no name"),this.params=e,this.translator=new A({...e,parsers:[O.JsonMessage()]})}_install(){if(this.installed===!1){this.installed=!0;let e={log:this.log,attach:this.hook.attach.bind(this.hook),attachAfter:this.hook.attachAfter.bind(this.hook),translator:this.translator};if(this.params.plugins){this.plugins=typeof this.params.plugins=="function"?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})}this.params.install?.(e)}}async cancel(e){e?this.event.emit("cancel",{requestId:e}):this.event.emit("cancelAll",{})}requestWithId(e){this._install();let t=se.createUuid(),r=null,n=!1,s=!1,i=[this.event.on("cancel",({requestId:p})=>{p===t&&l()}),this.event.on("cancelAll",()=>{l()})],c=()=>i.forEach(p=>p.off()),l=()=>{n===!1&&(s&&r&&r(),n=!0,c())},g=p=>{r=p},f=async()=>{let p=this.translator.getValidate(),k=null,b={},y=new Map,z=await this.translator.compile(e,{schema:p}),Y=[],h=[];z.prompt&&h.push({role:"user",content:z.prompt});for(let m in this.plugins)b[m]={send:C=>this.plugins[m].send({id:t,data:C})};return await this.hook.notify("start",{id:t,data:e,schema:p,plugins:b,messages:h,metadata:y,setPreMessages:m=>{Y=m.map(C=>({...C,content:Array.isArray(C.content)?C.content.join(`
12
+ `):C.content}))},changeMessages:m=>{h=m},changeOutputSchema:m=>{this.translator.changeOutputSchema(m),p=this.translator.getValidate()}}),h=[...Y,...h],await se.asyncWhile(async({count:m,doBreak:C})=>{if(m>=99)return C();let R="",I="",N=!1,K=h.filter(x=>x.role==="user").slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:h,metadata:y,lastUserMessage:K});let x=this.params.request(h,{id:t,count:m,schema:p,onCancel:g,metadata:y,isRetry:N});if(n)r&&r();else try{s=!0,R=await x,I=R}finally{s=!1}n===!1&&(await this.hook.notify("talkAfter",{id:t,data:e,response:R,messages:h,parseText:I,metadata:y,lastUserMessage:K,parseFail:_=>{throw new P(_,[])},changeParseText:_=>{I=_}}),k=(await this.translator.parse(I)).output,await this.hook.notify("succeeded",{id:t,output:k,metadata:y})),await this.hook.notify("done",{id:t,metadata:y}),C()}catch(x){if(x instanceof P){if(await this.hook.notify("parseFailed",{id:t,error:x.error,count:m,response:R,messages:h,metadata:y,lastUserMessage:K,parserFails:x.parserFails,retry:()=>{N=!0},changeMessages:_=>{h=_}}),N===!1)throw await this.hook.notify("done",{id:t,metadata:y}),x}else throw await this.hook.notify("done",{id:t,metadata:y}),x}}),k};return{id:t,request:(async()=>{try{return await f()}finally{c()}})()}}async request(e){let{request:t}=this.requestWithId(e);return await t}};import*as we from"yup";var W=class{constructor(e){o(this,"params");this.params=e}createBrokerBuilder(e){return{create:t=>new M({output:()=>({}),install:r=>{e?.install?.(r),r.attach("start",async({id:n,plugins:s,data:i,metadata:c,changeMessages:l,changeOutputSchema:g})=>{let f=await t({id:n,data:i,plugins:s,yup:we,setMessages:T=>{l(T.map(p=>({role:p.role,content:Array.isArray(p.content)?p.content.join(`
13
+ `):p.content})))},metadata:c});g(()=>f)})},plugins:this.params.plugins?()=>this.params.plugins():void 0,request:this.params.request})}}};import Oe from"axios";var j=class{constructor(e){o(this,"openai");o(this,"config",{model:"gpt-4-vision-preview",maxTokens:void 0,temperature:1});this.openai=e}setConfig(e){Object.assign(this.config,e)}async view(e){let 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,apiResponse:t.data}}};import{json as _e}from"power-helper";var V=class{constructor(e){o(this,"openai");o(this,"config",{n:1,model:"gpt-4o",temperature:1,maxTokens:void 0,forceJsonFormat:!0});this.openai=e}setConfig(e){Object.assign(this.config,e)}async moderations(e){let 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:t.data.results?.[0]?.flagged===!1,result:t.data}}async talk(e=[],t){let r=_e.jpjs(e),n=["gpt-4-turbo-preview","gpt-4-turbo","gpt-4o","gpt-4o-mini","gpt-3.5-turbo-1106"].includes(this.config.model),s;n&&this.config.forceJsonFormat&&(s={type:"json_object"}),n&&this.config.forceJsonFormat&&t?.jsonSchema&&(s={type:"json_schema",json_schema:t.jsonSchema});let i=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:this.config.n,messages:r,response_format:s,temperature:this.config.temperature},{signal:t?.abortController?.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),c=i.data.choices||[],l=c[0]?.message||{role:"assistant",content:""};return r.push(l),{id:i?.data.id,text:l.content,newMessages:r,isDone:c[0]?.finish_reason==="stop",apiResponse:i.data}}talkStream(e){let 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 r=>{let n=r.body?.pipeThrough(new TextDecoderStream).getReader();if(!n)throw new Error("Can not get reader");for(;;){let{value:s,done:i}=await n.read();if(i)break;let c=s.split(`
14
+ `);for(let l of c)if(l.length!==0&&!l.startsWith(":")){if(l==="data: [DONE]"){e.onEnd();break}try{let f=JSON.parse(l.substring(6)).choices[0].delta.content;e.onMessage(f)}catch(g){e.onWarn(g)}}}}).catch(r=>{r.name==="AbortError"?e.onEnd():e.onError(r)}),{cancel:()=>t.abort()}}async keepTalk(e,t=[]){let r=await this.talk([...t,{role:"user",content:Array.isArray(e)?e.join(`
15
+ `):e}]);return{result:r,nextTalk:n=>this.keepTalk(n,r.newMessages)}}};var J=class{constructor(e){o(this,"openai");o(this,"config",{model:"dall-e-2",size:"1024x1024"});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}};var D=class a{constructor(e=""){o(this,"_axios",Oe.create());o(this,"_apiKey","");this._apiKey=e}static createChatRequest(e,t={},r){return async(n,{onCancel:s})=>{let i=new a(typeof e=="string"?e:await e()),c=i.createChat(),l=new AbortController;r&&r.axios&&i.setAxios(r.axios),c.setConfig(typeof t=="function"?await t():t),s(()=>l.abort());let{text:g}=await c.talk(n,{abortController:l});return g}}static createChatRequestWithJsonSchema(e){return async(t,{schema:r,onCancel:n})=>{let s=new a(typeof e.apiKey=="string"?e.apiKey:await e.apiKey()),i=s.createChat(),c=new AbortController;e.config&&i.setConfig(typeof e.config=="function"?await e.config():e.config),e.axios&&s.setAxios(e.axios),n(()=>c.abort());let l=v(r.output),{text:g}=await i.talk(t,{abortController:c,jsonSchema:{name:"data",strict:!0,schema:l}});return g}}setAxios(e){this._axios=e}setConfiguration(e){this._apiKey=e}createChat(){return new V(this)}createVision(){return new j(this)}createImagesGeneration(){return new J(this)}};import Me from"axios";import{sify as Re}from"chinese-conv/dist";import{flow as Ae}from"power-helper";import{tify as E,sify as G}from"chinese-conv/dist";var w=class{constructor(e){o(this,"core");o(this,"streamAbortControllers",[]);this.core=e}createAbortController(){let e=new AbortController,t=Ae.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){let{signal:t,controllerId:r}=this.createAbortController(),n=()=>{this.removeAbortController(r),e.onEnd()},s=async i=>{if(i.body){let c=i.body.getReader(),l=!1,g="";for(;!l;){let{value:f,done:T}=await c.read();if(f){g+=new TextDecoder("utf-8").decode(f);let p=g.split(`
16
16
 
17
- `);m=p.pop()||"",p.forEach(k=>{if(k.includes("[DONE]")&&(l=!0),k.startsWith("data:"))try{let v=JSON.parse(k.replace("data: ",""));e.onMessage(v)}catch(v){e.onWarn(v)}})}T&&(l=!0)}n()}else e.onError(new Error("Body not found."))};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(s).catch(i=>{i instanceof Error&&i.message.includes("The user aborted a request")?n():e.onError(i)})}async fetch(e){let{signal:t,controllerId:r}=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(r)}}cancel(){this.streamAbortControllers.forEach(e=>e.controller.abort()),this.streamAbortControllers=[]}export(){return{cancel:this.cancel.bind(this)}}},q=class{constructor(e){o(this,"core");o(this,"config",{baseUrl:"",headers:{},autoConvertTraditionalChinese:!0});this.core=e}setConfig(e){this.config={...this.config,...e}}completion(e){let t=[];for(let{role:s,content:i}of e.messages)s==="system"&&t.push(`<|start_header_id|>system<|end_header_id|>
17
+ `);g=p.pop()||"",p.forEach(k=>{if(k.includes("[DONE]")&&(l=!0),k.startsWith("data:"))try{let b=JSON.parse(k.replace("data: ",""));e.onMessage(b)}catch(b){e.onWarn(b)}})}T&&(l=!0)}n()}else e.onError(new Error("Body not found."))};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(s).catch(i=>{i instanceof Error&&i.message.includes("The user aborted a request")?n():e.onError(i)})}async fetch(e){let{signal:t,controllerId:r}=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(r)}}cancel(){this.streamAbortControllers.forEach(e=>e.controller.abort()),this.streamAbortControllers=[]}export(){return{cancel:this.cancel.bind(this)}}},B=class{constructor(e){o(this,"core");o(this,"config",{baseUrl:"",headers:{},autoConvertTraditionalChinese:!0});this.core=e}setConfig(e){this.config={...this.config,...e}}completion(e){let t=[];for(let{role:s,content:i}of e.messages)s==="system"&&t.push(`<|start_header_id|>system<|end_header_id|>
18
18
 
19
19
  ${i}
20
20
 
@@ -23,9 +23,9 @@ ${i}
23
23
  ${i?.replaceAll(`
24
24
  `,"\\n")??""}`),s==="assistant"&&t.push(`<|start_header_id|>assistant<|end_header_id|>
25
25
 
26
- `+i);let r=e.messages.at(-1)||"",n=new O(this);return{...n.export(),run:async()=>{let s=await n.fetch({path:"completion",data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?E(t.join(`
26
+ `+i);let r=e.messages.at(-1)||"",n=new w(this);return{...n.export(),run:async()=>{let s=await n.fetch({path:"completion",data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?G(t.join(`
27
27
  `)):t.join(`
28
- `)}}),i=this.config.autoConvertTraditionalChinese?B(s.data.content):s.data.content;return{message:i,fullMessage:`${r}${i}`}}}}completionStream(e){let t=[];for(let{role:n,content:s}of e.messages)n==="system"&&t.push(`<|start_header_id|>system<|end_header_id|>
28
+ `)}}),i=this.config.autoConvertTraditionalChinese?E(s.data.content):s.data.content;return{message:i,fullMessage:`${r}${i}`}}}}completionStream(e){let t=[];for(let{role:n,content:s}of e.messages)n==="system"&&t.push(`<|start_header_id|>system<|end_header_id|>
29
29
 
30
30
  ${s}
31
31
 
@@ -34,7 +34,7 @@ ${s}
34
34
  ${s?.replaceAll(`
35
35
  `,"\\n")??""}`),n==="assistant"&&t.push(`<|start_header_id|>assistant<|end_header_id|>
36
36
 
37
- `+s);let r=new O(this);return r.stream({path:"completion",onEnd:e.onEnd||(()=>null),onMessage:n=>{e.onMessage({message:this.config.autoConvertTraditionalChinese?B(n.content):n.content})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?E(t.join(`
37
+ `+s);let r=new w(this);return r.stream({path:"completion",onEnd:e.onEnd||(()=>null),onMessage:n=>{e.onMessage({message:this.config.autoConvertTraditionalChinese?E(n.content):n.content})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?G(t.join(`
38
38
  `)):t.join(`
39
- `),stream:!0}}),r.export()}talk(e){let t=new O(this);return{...t.export(),run:async()=>{let n=(await t.fetch({path:"v1/chat/completions",data:{...e.options||{},response_format:e.response_format,messages:e.messages.map(s=>({role:s.role,content:this.config.autoConvertTraditionalChinese?E(s.content):s.content}))}})).data.choices[0].message.content||"";return{message:this.config.autoConvertTraditionalChinese?B(n):n}}}}talkStream(e){let t=new O(this);return t.stream({path:"v1/chat/completions",onEnd:e.onEnd||(()=>null),onMessage:r=>{let n=r.choices[0].delta.content;n&&e.onMessage({message:this.config.autoConvertTraditionalChinese?B(n):n})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},stream:!0,messages:e.messages.map(r=>({role:r.role,content:this.config.autoConvertTraditionalChinese?E(r.content):r.content}))}}),t.export()}};var L=class a{constructor(){o(this,"_axios",Ae.create())}static createChatRequest(e){return async(t,{schema:r,onCancel:n})=>{let i=new a().createCompletion(),c=typeof e.config=="function"?await e.config():e.config;i.setConfig(c);let l=b(r.output);i.config.autoConvertTraditionalChinese&&(l=JSON.parse(Re(JSON.stringify(l))));let{run:m,cancel:f}=i.talk({options:e.talkOptions,messages:t,response_format:{type:"json_object",schema:l}});n(f);let{message:T}=await m();return T}}setAxios(e){this._axios=e}createCompletion(){return new q(this)}};var G=class{static createChatRequest(e){let t=r=>(r.type==="object"?(delete r.additionalProperties,Object.keys(r.properties).forEach(n=>{t(r.properties[n])})):r.type==="array"&&t(r.items),r);return async(r,{schema:n})=>{let s=t(b(n.output));return(await e.googleGenerativeAI.getGenerativeModel({model:e.model,generationConfig:{responseMimeType:"application/json",responseSchema:s}}).generateContent({contents:r.map(l=>l.role==="user"||l.role==="system"?{role:"user",parts:[{text:l.content}]}:{role:"model",parts:[{text:l.content}]})})).response.text()}}};export{R as ChatBroker,h as ChatBrokerPlugin,W as CtoD,G as Google,L as Llama3Cpp,D as OpenAI,S as TextParser,A as Translator,be as defineYupSchema,te as plugins,ne as templates,b as validateToJsonSchema};
39
+ `),stream:!0}}),r.export()}talk(e){let t=new w(this);return{...t.export(),run:async()=>{let n=(await t.fetch({path:"v1/chat/completions",data:{...e.options||{},response_format:e.response_format,messages:e.messages.map(s=>({role:s.role,content:this.config.autoConvertTraditionalChinese?G(s.content):s.content}))}})).data.choices[0].message.content||"";return{message:this.config.autoConvertTraditionalChinese?E(n):n}}}}talkStream(e){let t=new w(this);return t.stream({path:"v1/chat/completions",onEnd:e.onEnd||(()=>null),onMessage:r=>{let n=r.choices[0].delta.content;n&&e.onMessage({message:this.config.autoConvertTraditionalChinese?E(n):n})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},stream:!0,messages:e.messages.map(r=>({role:r.role,content:this.config.autoConvertTraditionalChinese?G(r.content):r.content}))}}),t.export()}};var L=class a{constructor(){o(this,"_axios",Me.create())}static createChatRequestWithJsonSchema(e){return async(t,{schema:r,onCancel:n})=>{let i=new a().createCompletion(),c=typeof e.config=="function"?await e.config():e.config;i.setConfig(c);let l=v(r.output);i.config.autoConvertTraditionalChinese&&(l=JSON.parse(Re(JSON.stringify(l))));let{run:g,cancel:f}=i.talk({options:e.talkOptions,messages:t,response_format:{type:"json_object",schema:l}});n(f);let{message:T}=await g();return T}}setAxios(e){this._axios=e}createCompletion(){return new B(this)}};import{json as Ie}from"power-helper";var q=class{constructor(e){o(this,"google");o(this,"config",{model:"gemini-1.5-flash"});this.google=e}setConfig(e){Object.assign(this.config,e)}async talk(e=[]){let t=Ie.jpjs(e),s=(await this.google.generativeAI.getGenerativeModel({model:this.config.model}).generateContent({contents:t})).response.text();return{text:s,newMessages:[...t,{role:"model",parts:[{text:s}]}]}}talkStream(e){let t=this.google.generativeAI.getGenerativeModel({model:this.config.model}),r={contents:e.messages};t.generateContentStream(r).then(async({stream:n})=>{for await(let s of n){let i=s.text();e.onMessage(i)}e.onEnd()}).catch(n=>{e.onError(n)})}};var U=class a{constructor(e){o(this,"generativeAI");this.generativeAI=e}static chatGPTMessageToGoogleChatMessage(e){let t=r=>typeof r=="string"?[{text:r}]:Array.isArray(r)?r.map(({type:n,image_url:s,text:i})=>{if(n==="image_url"){let c=s?.url||"",l=c.includes("data:image/png")?"image/png":"image/jpeg";return{inlineData:{data:c.split("base64,")[1]||"",mimeType:l}}}else return{text:i||""}}):[];return e.map(r=>r.role==="user"||r.role==="system"?{role:"user",parts:t(r.content)}:{role:"model",parts:t(r.content)})}static createChatRequestWithJsonSchema(e){let t=r=>(r.type==="object"?(delete r.additionalProperties,Object.keys(r.properties).forEach(n=>{t(r.properties[n])})):r.type==="array"&&t(r.items),r);return async(r,{schema:n})=>{let s=t(v(n.output));return(await e.googleGenerativeAI.getGenerativeModel({model:e.model,generationConfig:{responseMimeType:"application/json",responseSchema:s}}).generateContent({contents:a.chatGPTMessageToGoogleChatMessage(r)})).response.text()}}createChat(){return new q(this)}};export{M as ChatBroker,d as ChatBrokerPlugin,W as CtoD,d as CtoDPlugin,U as GoogleCtodService,L as Llama3CppCtodService,D as OpenAICtodService,O as TextParser,A as Translator,Pe as defineYupSchema,re as plugins,ae as templates,v as validateToJsonSchema};
40
40
  //# sourceMappingURL=index.js.map