ctod 0.6.2 → 0.7.0

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
@@ -15,15 +15,11 @@
15
15
 
16
16
  <br>
17
17
 
18
- ## Online Playground
19
-
20
- [Chat Of Requirement(織語)](https://cor.metalsheep.com/) 是為了 CtoD 建構的展示工具,你可以在這個工具中建構你與調適你的模板。
21
-
22
18
  ## 摘要
23
19
 
24
- 本工具是利用聊天機器人能夠讀懂自然語言的特性,將我們的需求與資料透過口語化的方式交付給他處理,並要求回應 JSON
20
+ 現在我們頻繁的有透過口語化的方式交付任務 LLM 處理並要求回應 JSON 的需求,透過 CtoD 你可以讓這個模式有架構化的進行。
25
21
 
26
- 在對話過程中,採用 [yup](https://github.com/jquense/yup) 來驗證請求與回復資料是否符合預期,以確保一致性,只要保持這個互動模式,就可以利用在 API 串接或是自動化系統上。
22
+ 在對話過程中,CtoD 採用 [yup](https://github.com/jquense/yup) 來驗證請求與回復資料是否符合預期,以確保一致性,只要保持這個互動模式,就可以利用在 API 串接或是自動化系統上。
27
23
 
28
24
  我們還附帶支援 `OpenAI` 與 `Llama3` 的相關服務。
29
25
 
@@ -45,43 +41,23 @@ yarn add ctod
45
41
 
46
42
  這個例子示範如何將藥物索引與客戶需求傳遞給聊天機器人,並返回最適合的結果,開發人員可以利用索引結果去資料庫搜尋最適合的藥物給消費者:
47
43
 
48
- > 關於型態定義,這裡有個有趣的議題,必須將 input 與 output 優先宣告才能讓型態正常運作。
49
-
50
44
  ```ts
51
- import { ChatBroker, OpenAI, templates } from 'ctod'
45
+ import { CtoD, OpenAI } from 'ctod'
52
46
 
53
- const broker = new ChatBroker({
54
- /** 驗證輸入資料 */
55
- input(yup) {
56
- return {
57
- indexs: yup.array(yup.string().required()).required(),
58
- question: yup.string().required()
59
- }
60
- },
61
- /** 驗證輸出資料 */
62
- output(yup) {
63
- const item = yup.object({
64
- name: yup.string().required().meta({
65
- jsonSchema: {
66
- description: '索引名稱'
67
- }
68
- }),
69
- score: yup.number().required().meta({
70
- jsonSchema: {
71
- description: '評比分數'
72
- }
73
- })
74
- }).required()
75
- return {
76
- indexs: yup.array(item).required().meta({
77
- jsonSchema: {
78
- description: '由高到低排序的索引'
79
- }
80
- })
47
+ const ctod = new CtoD({
48
+ request: OpenAI.createChatRequestWithJsonSchema({
49
+ apiKey: 'YOUR_API_KEY',
50
+ config: {
51
+ model: 'gpt-4o'
81
52
  }
82
- },
83
- /** 初始化系統,通常來植入或掛鉤生命週期 */
84
- install({ attach }) {
53
+ })
54
+ })
55
+
56
+ const brokerBuilder = ctod.createBrokerBuilder<{
57
+ indexes: string[]
58
+ question: string
59
+ }>({
60
+ install: ({ attach }) => {
85
61
  attach('start', async({ setPreMessages }) => {
86
62
  setPreMessages([
87
63
  {
@@ -90,30 +66,48 @@ const broker = new ChatBroker({
90
66
  }
91
67
  ])
92
68
  })
93
- },
94
- /** 定義發送請求的接口 */
95
- request: OpenAI.createChatRequestWithJsonSchema({
96
- apiKey: API_KEY,
97
- config: {
98
- model: 'gpt-4o-mini'
69
+ }
70
+ })
71
+
72
+ const broker = brokerBuilder.create(async({ yup, data, setMessages }) => {
73
+ const { indexes, question } = data
74
+ setMessages([
75
+ {
76
+ role: 'user',
77
+ content: [
78
+ '我有以下索引',
79
+ `${JSON.stringify(indexes)}`,
80
+ `請幫我解析"${question}"可能是哪個索引`,
81
+ '且相關性由高到低排序並給予分數,分數由 0 ~ 1'
82
+ ]
99
83
  }
100
- }),
101
- /** 組裝與定義我們要向機器人發出的請求 */
102
- question: async({ indexs, question }) => {
103
- return [
104
- '我有以下索引',
105
- `${JSON.stringify(indexs)}`,
106
- `請幫我解析"${question}"可能是哪個索引`,
107
- '且相關性由高到低排序並給予分數,分數由 0 ~ 1'
108
- ]
84
+ ])
85
+ const item = yup.object({
86
+ name: yup.string().required().meta({
87
+ jsonSchema: {
88
+ description: '索引名稱'
89
+ }
90
+ }),
91
+ score: yup.number().required().meta({
92
+ jsonSchema: {
93
+ description: '評比分數'
94
+ }
95
+ })
96
+ }).required()
97
+ return {
98
+ indexes: yup.array(item).required().meta({
99
+ jsonSchema: {
100
+ description: '由高到低排序的索引'
101
+ }
102
+ })
109
103
  }
110
104
  })
111
105
 
112
106
  broker.request({
113
- indexs: ['胃痛', '腰痛', '頭痛', '喉嚨痛', '四肢疼痛'],
107
+ indexes: ['胃痛', '腰痛', '頭痛', '喉嚨痛', '四肢疼痛'],
114
108
  question: '喝咖啡,吃甜食,胃食道逆流'
115
109
  }).then(e => {
116
- console.log('輸出結果:', e.indexs)
110
+ console.log('輸出結果:', e.indexes)
117
111
  /*
118
112
  [
119
113
  {
@@ -127,7 +121,10 @@ broker.request({
127
121
  ...
128
122
  ]
129
123
  */
124
+ }).catch(error => {
125
+ console.error('Error:', error)
130
126
  })
127
+
131
128
  ```
132
129
 
133
130
  ## Plugin
@@ -187,24 +184,26 @@ const broker = new ChatBroker({
187
184
  backup: backupPlugin.use({
188
185
  sendUrl: 'https://api/backup'
189
186
  })
190
- },
191
- // 以下方案也可以運行
192
- // plugins: () => {
193
- // return {
194
- // backup: backupPlugin.use({
195
- // sendUrl: 'https://api/backup'
196
- // })
197
- // }
198
- // },
187
+ }
188
+ })
189
+
190
+ const ctod = new CtoD({
199
191
  // ...
192
+ plugins: () => {
193
+ return {
194
+ backup: backupPlugin.use({
195
+ sendUrl: 'https://api/backup'
196
+ })
197
+ }
198
+ }
200
199
  })
201
200
  ```
202
201
 
203
202
  ## Examples
204
203
 
205
- [基礎用法 - 藥物查詢功能](./examples/chat-demo.ts)
204
+ [基礎用法 - 藥物查詢功能](./examples/basic.ts)
206
205
 
207
- [進階用法 - 請 AI COSPLAY](./examples//plugin-demo.ts)
206
+ [進階用法 - 請 AI COSPLAY](./examples/plugin.ts)
208
207
 
209
208
  ## Other
210
209
 
@@ -212,16 +211,23 @@ const broker = new ChatBroker({
212
211
 
213
212
  ## Version History
214
213
 
215
- ### 0.3.x
214
+ ### 0.7.x
216
215
 
217
- 為了支援更多平台與自建服務,我們捨棄了完全為了 ChatGPT 客制化的接口,這樣也能完整保持 Broker 與 Plugin 的一致性。
216
+ 感謝當今的模型對於json schema的支援,我們不再需要繁瑣的宣告,因此新增了透過註冊 CtoD 的方式來簡化流程。
218
217
 
219
- ### 0.4.x
218
+ ### 0.6.x
220
219
 
221
- 主要是支援 llama3.cpp 或者是其他自建服務上流程的調整。
220
+ `bindYupToJsonSchemaToYup` 有一些依賴問題已經被移除,改用以下方案取代:
222
221
 
223
- 1. 支援 llama3.cpp server service
224
- 2. 新增 yup to json scheme。
222
+ ```ts
223
+ yup.array(item).required().meta({
224
+ jsonSchema: {
225
+ description: '由高到低排序的索引'
226
+ }
227
+ })
228
+ ```
229
+
230
+ 1. 新增了 defineYupSchema 讓建立複雜的 Output 更加容易。
225
231
 
226
232
  ### 0.5.x
227
233
 
@@ -232,16 +238,13 @@ const broker = new ChatBroker({
232
238
  1. 可以在 question 中回應 array,會透過 join 進行合併。
233
239
  2. 可以省略 install 參數了。
234
240
 
235
- ### 0.6.x
241
+ ### 0.4.x
236
242
 
237
- `bindYupToJsonSchemaToYup` 有一些依賴問題已經被移除,改用以下方案取代:
243
+ 主要是支援 llama3.cpp 或者是其他自建服務上流程的調整。
238
244
 
239
- ```ts
240
- yup.array(item).required().meta({
241
- jsonSchema: {
242
- description: '由高到低排序的索引'
243
- }
244
- })
245
- ```
245
+ 1. 支援 llama3.cpp server service
246
+ 2. 新增 yup to json scheme。
246
247
 
247
- 1. 新增了 defineYupSchema 讓建立複雜的 Output 更加容易。
248
+ ### 0.3.x
249
+
250
+ 為了支援更多平台與自建服務,我們捨棄了完全為了 ChatGPT 客制化的接口,這樣也能完整保持 Broker 與 Plugin 的一致性。
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={177:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBroker=void 0;const r=n(306),a=n(572),o=n(235),s=n(165);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.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})}this.params.install?.(e)}}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,i=[this.event.on("cancel",(({requestId:e})=>{e===t&&c()})),this.event.on("cancelAll",(()=>{c()}))],l=()=>i.forEach((e=>e.off())),c=()=>{!1===r&&(o&&n&&n(),r=!0,l())},u=e=>{n=e},p=async()=>{let i=this.translator.getValidate(),l=null,c={},p=await this.translator.compile(e,{schema:i}),h=[{role:"user",content:p.prompt}];for(let e in this.plugins)c[e]={send:n=>this.plugins[e].send({id:t,data:n})};return await this.hook.notify("start",{id:t,data:e,schema:i,plugins:c,messages:h,setPreMessages:e=>{h=[...e,{role:"user",content:p.prompt}]},changeMessages:e=>{h=e}}),await a.flow.asyncWhile((async({count:a,doBreak:c})=>{if(a>=10)return c();let p="",d="",f=!1,m=h.filter((e=>"user"===e.role)).slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:h,lastUserMessage:m});const g=this.params.request(h,{count:a,schema:i,onCancel:u,isRetry:f});if(r)n&&n();else try{o=!0,p=await g,d=p}finally{o=!1}!1===r&&(await this.hook.notify("talkAfter",{id:t,data:e,response:p,messages:h,parseText:d,lastUserMessage:m,parseFail:e=>{throw new s.ParserError(e,[])},changeParseText:e=>{d=e}}),l=(await this.translator.parse(d)).output,await this.hook.notify("succeeded",{id:t,output:l})),await this.hook.notify("done",{id:t}),c()}catch(e){if(!(e instanceof s.ParserError))throw await this.hook.notify("done",{id:t}),e;if(await this.hook.notify("parseFailed",{id:t,error:e.error,count:a,response:p,messages:h,lastUserMessage:m,parserFails:e.parserFails,retry:()=>{f=!0},changeMessages:e=>{h=e}}),!1===f)throw await this.hook.notify("done",{id:t}),e}})),l};return{id:t,request:(async()=>{try{return await p()}finally{l()}})()}}async request(e){const{request:t}=this.requestWithId(e);return await t}}},306: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(865));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},198:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBrokerPlugin=void 0;const r=n(572);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}}}},235:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Translator=void 0;const r=n(357),a=n(165);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),a=await this.params.question(n,t);return{scheme:n,prompt:Array.isArray(a)?a.join("\n"):a}}getValidate(){return{input:this.params.input,output:this.params.output}}async parse(e){let t,n="",o=[];for(let r of this.params.parsers)try{t=await r.read(e),n=r.name}catch(e){t=void 0,o.push({name:r.name,error:e})}try{return{output:(0,r.validate)(t,this.params.output),parserName:n,parserFails:o}}catch(e){throw new a.ParserError(e,o)}}}},665: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.defineYupSchema=t.validateToJsonSchema=t.templates=t.plugins=void 0,t.plugins=o(n(374)),t.templates=o(n(854));var s=n(357);Object.defineProperty(t,"validateToJsonSchema",{enumerable:!0,get:function(){return s.validateToJsonSchema}}),Object.defineProperty(t,"defineYupSchema",{enumerable:!0,get:function(){return s.defineYupSchema}});var i=n(984);Object.defineProperty(t,"OpenAI",{enumerable:!0,get:function(){return i.OpenAI}});var l=n(887);Object.defineProperty(t,"Llama3Cpp",{enumerable:!0,get:function(){return l.Llama3Cpp}});var c=n(306);Object.defineProperty(t,"TextParser",{enumerable:!0,get:function(){return c.TextParser}});var u=n(177);Object.defineProperty(t,"ChatBroker",{enumerable:!0,get:function(){return u.ChatBroker}});var p=n(198);Object.defineProperty(t,"ChatBrokerPlugin",{enumerable:!0,get:function(){return p.ChatBrokerPlugin}});var h=n(235);Object.defineProperty(t,"Translator",{enumerable:!0,get:function(){return h.Translator}});const d=o(n(374)),f=o(n(854)),m=n(984),g=n(887),y=n(235),_=n(306),v=n(177),b=n(198),w=n(357);t.ctod={OpenAI:m.OpenAI,Llama3Cpp:g.Llama3Cpp,plugins:d,templates:f,ChatBroker:v.ChatBroker,Translator:y.Translator,TextParser:_.TextParser,ChatBrokerPlugin:b.ChatBrokerPlugin,defineYupSchema:w.defineYupSchema,validateToJsonSchema:w.validateToJsonSchema},e.exports=t.ctod,e.exports.ctod=t.ctod,t.default=t.ctod},374: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(92)),o=r(n(354)),s=r(n(270)),i=r(n(724));t.PrintLogPlugin=o.default,t.RetryPlugin=a.default,t.LimiterPlugin=s.default.plugin,t.LimiterPluginGlobState=s.default,t.RolePlugin=i.default},270:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(198),a=n(572),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())}))}))}))}})}},354:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(198);t.default=new r.ChatBrokerPlugin({name:"print-log",params:e=>({detail:e.boolean().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)}}))}})},92:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(198);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())}))}})},724:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(198);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])}))}})},129:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3CppCompletion=void 0;const r=n(572),a=n(4);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()}}},887: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(938)),o=n(4),s=n(357),i=n(129);class l{_axios=a.default.create();static createChatRequest(e){return async(t,{schema:n,onCancel:r})=>{const a=(new l).createCompletion(),i="function"==typeof e.config?await e.config():e.config;a.setConfig(i);let c=(0,s.validateToJsonSchema)(n.output);a.config.autoConvertTraditionalChinese&&(c=JSON.parse((0,o.sify)(JSON.stringify(c))));const{run:u,cancel:p}=a.talk({options:e.talkOptions,messages:t,response_format:{type:"json_object",schema:c}});r(p);const{message:h}=await u();return h}}setAxios(e){this._axios=e}createCompletion(){return new i.Llama3CppCompletion(this)}}t.Llama3Cpp=l},228:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIChat=void 0;const r=n(572);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)}}}},11:(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}}},984: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(938)),o=n(38),s=n(228),i=n(11),l=n(357);class c{_axios=a.default.create();_apiKey="";static createChatRequest(e,t={},n){return async(r,{onCancel:a})=>{const o=new c("string"==typeof e?e:await e()),s=o.createChat(),i=new AbortController;n&&n.axios&&o.setAxios(n.axios),s.setConfig("function"==typeof t?await t():t),a((()=>i.abort()));const{text:l}=await s.talk(r,{abortController:i});return l}}static createChatRequestWithJsonSchema(e){return async(t,{schema:n,onCancel:r})=>{const a=new c("string"==typeof e.apiKey?e.apiKey:await e.apiKey()),o=a.createChat(),s=new AbortController;e.config&&o.setConfig("function"==typeof e.config?await e.config():e.config),e.axios&&a.setAxios(e.axios),r((()=>s.abort()));const i=(0,l.validateToJsonSchema)(n.output),{text:u}=await o.talk(t,{abortController:s,jsonSchema:{name:"data",strict:!0,schema:i}});return u}}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},38:(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||[],r=n[0]?.message||{role:"assistant",content:""};return{id:t?.data.id,text:r.content,apiReseponse:t.data}}}},854: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(156)),o=n(572);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")},165:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserError=void 0,t.ParserError=class{isParserError=!0;parserFails=[];error;constructor(e,t){this.error=e,this.parserFails=t}}},357: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.defineYupSchema=t.validate=t.definedValidateSchema=void 0;const s=o(n(622)),i=n(250);t.definedValidateSchema=function(e){return e},t.validate=function(e,t){return s.object(t(s)).required().validateSync(e||{})},t.defineYupSchema=e=>e(s),t.validateToJsonSchema=e=>{const t=e=>{if(e.default&&delete e.default,e.properties)for(let n in e.properties)e.properties[n].default&&delete e.properties[n].default,t(e.properties[n]);e.items&&t(e.items)},n=e=>{if("object"===e.type){e.additionalProperties=!1;for(const t in e.properties)n(e.properties[t])}else"array"===e.type&&n(e.items)},r=(0,i.convertSchema)(s.object(e(s)));return t(r),n(r),r}},250:e=>{e.exports=require("@sodaru/yup-to-json-schema")},938:e=>{e.exports=require("axios")},4:e=>{e.exports=require("chinese-conv")},156:e=>{e.exports=require("handlebars")},865:e=>{e.exports=require("json5")},572:e=>{e.exports=require("power-helper")},622: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}(665)})()));
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={177:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBroker=void 0;const n=a(306),r=a(572),o=a(235),s=a(165);t.ChatBroker=class{__hookType;log;hook=new r.Hook;params;plugins={};installed=!1;translator;event=new r.Event;constructor(e){this.log=new r.Log(e.name??"no name"),this.params=e,this.translator=new o.Translator({...e,parsers:[n.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.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})}this.params.install?.(e)}}async cancel(e){e?this.event.emit("cancel",{requestId:e}):this.event.emit("cancelAll",{})}requestWithId(e){this._install();let t=r.flow.createUuid(),a=null,n=!1,o=!1,i=[this.event.on("cancel",(({requestId:e})=>{e===t&&c()})),this.event.on("cancelAll",(()=>{c()}))],l=()=>i.forEach((e=>e.off())),c=()=>{!1===n&&(o&&a&&a(),n=!0,l())},u=e=>{a=e},p=async()=>{let i=this.translator.getValidate(),l=null,c={},p=new Map,d=await this.translator.compile(e,{schema:i}),h=[],f=[];d.prompt&&f.push({role:"user",content:d.prompt});for(let e in this.plugins)c[e]={send:a=>this.plugins[e].send({id:t,data:a})};return await this.hook.notify("start",{id:t,data:e,schema:i,plugins:c,messages:f,metadata:p,setPreMessages:e=>{h=e.map((e=>({...e,content:Array.isArray(e.content)?e.content.join("\n"):e.content})))},changeMessages:e=>{f=e},changeOutputSchema:e=>{this.translator.changeOutputSchema(e),i=this.translator.getValidate()}}),f=[...h,...f],await r.flow.asyncWhile((async({count:r,doBreak:c})=>{if(r>=99)return c();let d="",h="",m=!1,g=f.filter((e=>"user"===e.role)).slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:f,metadata:p,lastUserMessage:g});const y=this.params.request(f,{id:t,count:r,schema:i,onCancel:u,metadata:p,isRetry:m});if(n)a&&a();else try{o=!0,d=await y,h=d}finally{o=!1}!1===n&&(await this.hook.notify("talkAfter",{id:t,data:e,response:d,messages:f,parseText:h,metadata:p,lastUserMessage:g,parseFail:e=>{throw new s.ParserError(e,[])},changeParseText:e=>{h=e}}),l=(await this.translator.parse(h)).output,await this.hook.notify("succeeded",{id:t,output:l,metadata:p})),await this.hook.notify("done",{id:t,metadata:p}),c()}catch(e){if(!(e instanceof s.ParserError))throw await this.hook.notify("done",{id:t,metadata:p}),e;if(await this.hook.notify("parseFailed",{id:t,error:e.error,count:r,response:d,messages:f,metadata:p,lastUserMessage:g,parserFails:e.parserFails,retry:()=>{m=!0},changeMessages:e=>{f=e}}),!1===m)throw await this.hook.notify("done",{id:t,metadata:p}),e}})),l};return{id:t,request:(async()=>{try{return await p()}finally{l()}})()}}async request(e){const{request:t}=this.requestWithId(e);return await t}}},306:function(e,t,a){var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.TextParser=void 0;const r=n(a(865));class o{params;static JsonMessage(){return new o({name:"JsonMessage",handler:async e=>{try{return JSON.parse(e)}catch(t){const a=/{(?:[^{}]|(?:{[^{}]*}))*}/,n=e.match(a)?.[0]||"";return r.default.parse(n)}}})}constructor(e){this.params=e}get name(){return this.params.name}async read(e){return await this.params.handler(e)}}t.TextParser=o},198:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBrokerPlugin=void 0;const n=a(572);t.ChatBrokerPlugin=class{_event=new n.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}}}},235:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Translator=void 0;const n=a(357),r=a(165);t.Translator=class{params;constructor(e){this.params=e}get __schemeType(){return null}get __outputType(){return null}async compile(e,t){const a=this.params.input?(0,n.validate)(e,this.params.input):e,r=this.params.question?await this.params.question(a,t):"";return{scheme:a,prompt:Array.isArray(r)?r.join("\n"):r}}getValidate(){return{input:this.params.input,output:this.params.output}}changeOutputSchema(e){this.params.output=e}async parse(e){let t,a="",o=[];for(let n of this.params.parsers)try{t=await n.read(e),a=n.name}catch(e){t=void 0,o.push({name:n.name,error:e})}try{return{output:(0,n.validate)(t,this.params.output),parserName:a,parserFails:o}}catch(e){throw new r.ParserError(e,o)}}}},697:function(e,t,a){var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){void 0===n&&(n=a);var r=Object.getOwnPropertyDescriptor(t,a);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[a]}}),Object.defineProperty(e,n,r)}:function(e,t,a,n){void 0===n&&(n=a),e[n]=t[a]}),r=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 a in e)"default"!==a&&Object.prototype.hasOwnProperty.call(e,a)&&n(t,e,a);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.CtoD=void 0;const s=a(177),i=o(a(622));t.CtoD=class{params;constructor(e){this.params=e}createBrokerBuilder(e){return{create:t=>new s.ChatBroker({output:()=>({}),install:a=>{e?.install?.(a),a.attach("start",(async({id:e,plugins:a,data:n,metadata:r,changeMessages:o,changeOutputSchema:s})=>{const l=await t({id:e,data:n,plugins:a,yup:i,setMessages:e=>{o(e.map((e=>({role:e.role,content:Array.isArray(e.content)?e.content.join("\n"):e.content}))))},metadata:r});s((()=>l))}))},plugins:this.params.plugins?.(),request:this.params.request})}}}},665:function(e,t,a){var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){void 0===n&&(n=a);var r=Object.getOwnPropertyDescriptor(t,a);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[a]}}),Object.defineProperty(e,n,r)}:function(e,t,a,n){void 0===n&&(n=a),e[n]=t[a]}),r=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 a in e)"default"!==a&&Object.prototype.hasOwnProperty.call(e,a)&&n(t,e,a);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.ctod=t.Translator=t.ChatBrokerPlugin=t.ChatBroker=t.TextParser=t.Llama3Cpp=t.OpenAI=t.defineYupSchema=t.validateToJsonSchema=t.CtoD=t.templates=t.plugins=void 0,t.plugins=o(a(374)),t.templates=o(a(854));var s=a(697);Object.defineProperty(t,"CtoD",{enumerable:!0,get:function(){return s.CtoD}});var i=a(357);Object.defineProperty(t,"validateToJsonSchema",{enumerable:!0,get:function(){return i.validateToJsonSchema}}),Object.defineProperty(t,"defineYupSchema",{enumerable:!0,get:function(){return i.defineYupSchema}});var l=a(984);Object.defineProperty(t,"OpenAI",{enumerable:!0,get:function(){return l.OpenAI}});var c=a(887);Object.defineProperty(t,"Llama3Cpp",{enumerable:!0,get:function(){return c.Llama3Cpp}});var u=a(306);Object.defineProperty(t,"TextParser",{enumerable:!0,get:function(){return u.TextParser}});var p=a(177);Object.defineProperty(t,"ChatBroker",{enumerable:!0,get:function(){return p.ChatBroker}});var d=a(198);Object.defineProperty(t,"ChatBrokerPlugin",{enumerable:!0,get:function(){return d.ChatBrokerPlugin}});var h=a(235);Object.defineProperty(t,"Translator",{enumerable:!0,get:function(){return h.Translator}});const f=o(a(374)),m=o(a(854)),g=a(984),y=a(697),_=a(887),v=a(235),b=a(306),w=a(177),C=a(198),O=a(357);t.ctod={CtoD:y.CtoD,OpenAI:g.OpenAI,Llama3Cpp:_.Llama3Cpp,plugins:f,templates:m,ChatBroker:w.ChatBroker,Translator:v.Translator,TextParser:b.TextParser,ChatBrokerPlugin:C.ChatBrokerPlugin,defineYupSchema:O.defineYupSchema,validateToJsonSchema:O.validateToJsonSchema},e.exports=t.ctod,e.exports.ctod=t.ctod,t.default=t.ctod},374:function(e,t,a){var n=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 r=n(a(92)),o=n(a(354)),s=n(a(270)),i=n(a(724));t.PrintLogPlugin=o.default,t.RetryPlugin=r.default,t.LimiterPlugin=s.default.plugin,t.LimiterPluginGlobState=s.default,t.RolePlugin=i.default},270:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0});const n=a(198),r=a(572),o={limit:3,interval:6e4},s={event:new r.Event,schedule:null,waitTimes:[],waitQueue:[]};t.default={event:s.event,config:o,closeSchedule:()=>{s.schedule&&(s.schedule.close(),s.schedule=null)},plugin:new n.ChatBrokerPlugin({name:"limiter",params:()=>({}),receiveData:()=>({}),onInstall({attach:e}){null==s.schedule&&(s.schedule=new r.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=r.flow.createUuid();return s.waitQueue.push(e),new Promise((t=>{s.event.on("run",(({id:a},{off:n})=>{a===e&&(n(),t())}))}))}))}})}},354:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0});const n=a(198);t.default=new n.ChatBrokerPlugin({name:"print-log",params:e=>({detail:e.boolean().default(!1)}),receiveData:()=>({}),onInstall({params:e,log:t,attach:a}){a("talkBefore",(async({lastUserMessage:a,messages:n})=>{t.print("Send:",{color:"green"}),e.detail?t.print("\n"+JSON.stringify(n,null,4)):t.print("\n"+a)})),a("talkAfter",(async({parseText:e})=>{t.print("Receive:",{color:"cyan"}),t.print("\n"+e)})),a("succeeded",(async({output:e})=>{t.print("Output:",{color:"yellow"});try{t.print("\n"+JSON.stringify(e,null,4))}catch(a){t.print("\n"+e)}}))}})},92:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0});const n=a(198);t.default=new n.ChatBrokerPlugin({name:"retry",params:e=>({retry:e.number().required().default(1),printWarn:e.boolean().required().default(!0)}),receiveData:()=>({}),onInstall({log:e,attach:t,params:a}){t("parseFailed",(async({count:t,retry:n,messages:r,changeMessages:o})=>{t<=a.retry&&(a.printWarn&&e.print(`Is Failed, Retry ${t} times.`),o(r),n())}))}})},724:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0});const n=a(198);t.default=new n.ChatBrokerPlugin({name:"role",params:e=>({role:e.string().required()}),receiveData:()=>({}),onInstall({attach:e,params:t}){e("start",(async({messages:e,changeMessages:a})=>{a([{role:"user",content:`你現在是${t.role}。`},{role:"assistant",content:`沒問題,我現在是${t.role},有什麼可以幫你的嗎?`},...e])}))}})},129:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3CppCompletion=void 0;const n=a(572),r=a(4);class o{core;streamAbortControllers=[];constructor(e){this.core=e}createAbortController(){const e=new AbortController,t=n.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:a}=this.createAbortController(),n=()=>{this.removeAbortController(a),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 a=t.body.getReader(),r=!1,o="";for(;!r;){const{value:t,done:n}=await a.read();if(t){o+=new TextDecoder("utf-8").decode(t);const a=o.split("\n\n");o=a.pop()||"",a.forEach((t=>{if(t.includes("[DONE]")&&(r=!0),t.startsWith("data:"))try{const a=JSON.parse(t.replace("data: ",""));e.onMessage(a)}catch(t){e.onWarn(t)}}))}n&&(r=!0)}n()}else e.onError(new Error("Body not found."))})).catch((t=>{t instanceof Error&&t.message.includes("The user aborted a request")?n():e.onError(t)}))}async fetch(e){const{signal:t,controllerId:a}=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(a)}}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:a,content:n}of e.messages)"system"===a&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${n}\n\n`),"user"===a&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${n?.replaceAll("\n","\\n")??""}`),"assistant"===a&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+n);const a=e.messages.at(-1)||"",n=new o(this);return{...n.export(),run:async()=>{const o=await n.fetch({path:"completion",data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,r.sify)(t.join("\n")):t.join("\n")}}),s=this.config.autoConvertTraditionalChinese?(0,r.tify)(o.data.content):o.data.content;return{message:s,fullMessage:`${a}${s}`}}}}completionStream(e){const t=[];for(let{role:a,content:n}of e.messages)"system"===a&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${n}\n\n`),"user"===a&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${n?.replaceAll("\n","\\n")??""}`),"assistant"===a&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+n);const a=new o(this);return a.stream({path:"completion",onEnd:e.onEnd||(()=>null),onMessage:t=>{e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,r.tify)(t.content):t.content})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,r.sify)(t.join("\n")):t.join("\n"),stream:!0}}),a.export()}talk(e){const t=new o(this);return{...t.export(),run:async()=>{const a=(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,r.sify)(e.content):e.content})))}})).data.choices[0].message.content||"";return{message:this.config.autoConvertTraditionalChinese?(0,r.tify)(a):a}}}}talkStream(e){const t=new o(this);return t.stream({path:"v1/chat/completions",onEnd:e.onEnd||(()=>null),onMessage:t=>{let a=t.choices[0].delta.content;a&&e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,r.tify)(a):a})},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,r.sify)(e.content):e.content})))}}),t.export()}}},887:function(e,t,a){var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3Cpp=void 0;const r=n(a(938)),o=a(4),s=a(357),i=a(129);class l{_axios=r.default.create();static createChatRequest(e){return async(t,{schema:a,onCancel:n})=>{const r=(new l).createCompletion(),i="function"==typeof e.config?await e.config():e.config;r.setConfig(i);let c=(0,s.validateToJsonSchema)(a.output);r.config.autoConvertTraditionalChinese&&(c=JSON.parse((0,o.sify)(JSON.stringify(c))));const{run:u,cancel:p}=r.talk({options:e.talkOptions,messages:t,response_format:{type:"json_object",schema:c}});n(p);const{message:d}=await u();return d}}setAxios(e){this._axios=e}createCompletion(){return new i.Llama3CppCompletion(this)}}t.Llama3Cpp=l},228:(e,t,a)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIChat=void 0;const n=a(572);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 a=n.json.jpjs(e),r=["gpt-4-turbo-preview","gpt-4-turbo","gpt-4o","gpt-4o-mini","gpt-3.5-turbo-1106"].includes(this.config.model);let o;r&&this.config.forceJsonFormat&&(o={type:"json_object"}),r&&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:a,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 a.push(l),{id:s?.data.id,text:l.content,newMessages:a,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 a=t.body?.pipeThrough(new TextDecoderStream).getReader();if(!a)throw new Error("Can not get reader");for(;;){const{value:t,done:n}=await a.read();if(n)break;const r=t.split("\n");for(let t of r)if(0!==t.length&&!t.startsWith(":")){if("data: [DONE]"===t){e.onEnd();break}try{const a=JSON.parse(t.substring(6)).choices[0].delta.content;e.onMessage(a)}catch(t){e.onWarn(t)}}}})).catch((t=>{"AbortError"===t.name?e.onEnd():e.onError(t)})),{cancel:()=>t.abort()}}async keepTalk(e,t=[]){const a=await this.talk([...t,{role:"user",content:Array.isArray(e)?e.join("\n"):e}]);return{result:a,nextTalk:e=>this.keepTalk(e,a.newMessages)}}}},11:(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}}},984:function(e,t,a){var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAI=void 0;const r=n(a(938)),o=a(38),s=a(228),i=a(11),l=a(357);class c{_axios=r.default.create();_apiKey="";static createChatRequest(e,t={},a){return async(n,{onCancel:r})=>{const o=new c("string"==typeof e?e:await e()),s=o.createChat(),i=new AbortController;a&&a.axios&&o.setAxios(a.axios),s.setConfig("function"==typeof t?await t():t),r((()=>i.abort()));const{text:l}=await s.talk(n,{abortController:i});return l}}static createChatRequestWithJsonSchema(e){return async(t,{schema:a,onCancel:n})=>{const r=new c("string"==typeof e.apiKey?e.apiKey:await e.apiKey()),o=r.createChat(),s=new AbortController;e.config&&o.setConfig("function"==typeof e.config?await e.config():e.config),e.axios&&r.setAxios(e.axios),n((()=>s.abort()));const i=(0,l.validateToJsonSchema)(a.output),{text:u}=await o.talk(t,{abortController:s,jsonSchema:{name:"data",strict:!0,schema:i}});return u}}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},38:(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}`}}),a=t.data.choices||[],n=a[0]?.message||{role:"assistant",content:""};return{id:t?.data.id,text:n.content,apiReseponse:t.data}}}},854:function(e,t,a){var n=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 r=n(a(156)),o=a(572);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,a,n)=>{const s=r.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)(a,n))(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")},165:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserError=void 0,t.ParserError=class{isParserError=!0;parserFails=[];error;constructor(e,t){this.error=e,this.parserFails=t}}},357:function(e,t,a){var n=this&&this.__createBinding||(Object.create?function(e,t,a,n){void 0===n&&(n=a);var r=Object.getOwnPropertyDescriptor(t,a);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[a]}}),Object.defineProperty(e,n,r)}:function(e,t,a,n){void 0===n&&(n=a),e[n]=t[a]}),r=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 a in e)"default"!==a&&Object.prototype.hasOwnProperty.call(e,a)&&n(t,e,a);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.validateToJsonSchema=t.defineYupSchema=t.validate=t.definedValidateSchema=void 0;const s=o(a(622)),i=a(250);t.definedValidateSchema=function(e){return e},t.validate=function(e,t){return s.object(t(s)).required().validateSync(e||{})},t.defineYupSchema=e=>e(s),t.validateToJsonSchema=e=>{const t=e=>{if(e.default&&delete e.default,e.properties)for(let a in e.properties)e.properties[a].default&&delete e.properties[a].default,t(e.properties[a]);e.items&&t(e.items)},a=e=>{if("object"===e.type){e.additionalProperties=!1;for(const t in e.properties)a(e.properties[t])}else"array"===e.type&&a(e.items)},n=(0,i.convertSchema)(s.object(e(s)));return t(n),a(n),n}},250:e=>{e.exports=require("@sodaru/yup-to-json-schema")},938:e=>{e.exports=require("axios")},4:e=>{e.exports=require("chinese-conv")},156:e=>{e.exports=require("handlebars")},865:e=>{e.exports=require("json5")},572:e=>{e.exports=require("power-helper")},622:e=>{e.exports=require("yup")}},t={};return function a(n){var r=t[n];if(void 0!==r)return r.exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,a),o.exports}(665)})()));
@@ -0,0 +1,89 @@
1
+ import fs from 'fs'
2
+ import { CtoD, OpenAI } from '../lib/index'
3
+
4
+ /**
5
+ * @test npx esno ./examples/basic.ts
6
+ */
7
+
8
+ const apiKey = fs.readFileSync('./.api-key', 'utf-8').trim()
9
+
10
+ const ctod = new CtoD({
11
+ request: OpenAI.createChatRequestWithJsonSchema({
12
+ apiKey,
13
+ config: {
14
+ model: 'gpt-4o'
15
+ }
16
+ })
17
+ })
18
+
19
+ const brokerBuilder = ctod.createBrokerBuilder<{
20
+ indexes: string[]
21
+ question: string
22
+ }>({
23
+ install: ({ attach }) => {
24
+ attach('start', async({ setPreMessages }) => {
25
+ setPreMessages([
26
+ {
27
+ role: 'system',
28
+ content: '你現在是一位擅長分類索引的藥師'
29
+ }
30
+ ])
31
+ })
32
+ }
33
+ })
34
+
35
+ const broker = brokerBuilder.create(async({ yup, data, setMessages }) => {
36
+ const { indexes, question } = data
37
+ setMessages([
38
+ {
39
+ role: 'user',
40
+ content: [
41
+ '我有以下索引',
42
+ `${JSON.stringify(indexes)}`,
43
+ `請幫我解析"${question}"可能是哪個索引`,
44
+ '且相關性由高到低排序並給予分數,分數由 0 ~ 1'
45
+ ]
46
+ }
47
+ ])
48
+ const item = yup.object({
49
+ name: yup.string().required().meta({
50
+ jsonSchema: {
51
+ description: '索引名稱'
52
+ }
53
+ }),
54
+ score: yup.number().required().meta({
55
+ jsonSchema: {
56
+ description: '評比分數'
57
+ }
58
+ })
59
+ }).required()
60
+ return {
61
+ indexes: yup.array(item).required().meta({
62
+ jsonSchema: {
63
+ description: '由高到低排序的索引'
64
+ }
65
+ })
66
+ }
67
+ })
68
+
69
+ broker.request({
70
+ indexes: ['胃痛', '腰痛', '頭痛', '喉嚨痛', '四肢疼痛'],
71
+ question: '喝咖啡,吃甜食,胃食道逆流'
72
+ }).then(e => {
73
+ console.log('輸出結果:', e.indexes)
74
+ /*
75
+ [
76
+ {
77
+ name: '胃痛',
78
+ score: 1
79
+ },
80
+ {
81
+ name: '喉嚨痛',
82
+ score: 0.7
83
+ },
84
+ ...
85
+ ]
86
+ */
87
+ }).catch(error => {
88
+ console.error('Error:', error)
89
+ })
@@ -1,23 +1,22 @@
1
1
  // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
2
  /// <reference path="../lib/shims.d.ts" />
3
- import { ChatBroker, Llama3Cpp, plugins } from '../lib/index'
3
+ import { CtoD, Llama3Cpp } from '../lib/index'
4
4
 
5
- const gameDesignerBroker = new ChatBroker({
6
- input: yup => {
7
- return {
8
- scene: yup.string()
9
- }
10
- },
11
- output: yup => {
12
- return {
13
- next: yup.array().of(yup.string().required()).required()
5
+ /**
6
+ * @test npx esno ./examples/llama.cpp.ts
7
+ */
8
+
9
+ const ctod = new CtoD({
10
+ request: Llama3Cpp.createChatRequest({
11
+ config: {
12
+ baseUrl: 'http://localhost:12333'
14
13
  }
15
- },
16
- plugins: {
17
- log: plugins.PrintLogPlugin.use({
18
- detail: true
19
- })
20
- },
14
+ })
15
+ })
16
+
17
+ const brokerBuilder = ctod.createBrokerBuilder<{
18
+ scene: string
19
+ }>({
21
20
  install: ({ attach }) => {
22
21
  attach('start', async({ setPreMessages }) => {
23
22
  setPreMessages([
@@ -35,23 +34,23 @@ const gameDesignerBroker = new ChatBroker({
35
34
  }
36
35
  ])
37
36
  })
38
- },
39
- /**
40
- * @zh createChatRequest 可以透過 output 自動推斷出要回傳的類型,不需要再額外提供型態
41
- * @en createChatRequest can infer the return type from output, no need to provide the type again
42
- */
43
- request: Llama3Cpp.createChatRequest({
44
- config: {
45
- baseUrl: 'http://localhost:12333'
37
+ }
38
+ })
39
+
40
+ const broker = brokerBuilder.create(async({ yup, data, setMessages }) => {
41
+ setMessages([
42
+ {
43
+ role: 'user',
44
+ content: data.scene || '任意發揮'
46
45
  }
47
- }),
48
- question: async({ scene }) => {
49
- return scene || '任意發揮'
46
+ ])
47
+ return {
48
+ next: yup.array().of(yup.string().required()).required()
50
49
  }
51
50
  })
52
51
 
53
- gameDesignerBroker.request({
52
+ broker.request({
54
53
  scene: '今天小紅帽遇到了大野狼,大野狼要吃掉小紅帽,小紅帽要怎麼辦?給我三個下一步要發生的事件'
55
54
  }).then(result => {
56
- console.log(result)
55
+ console.log(result.next)
57
56
  })
@@ -1,15 +1,17 @@
1
1
  // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
2
  /// <reference path="../lib/shims.d.ts" />
3
3
 
4
+ import fs from 'fs'
4
5
  import { flow } from 'power-helper'
5
6
  import { prompt } from 'inquirer'
6
- import { OpenAI, ChatBroker, plugins, ChatBrokerPlugin, templates } from '../lib'
7
+ import { CtoD, ChatBrokerPlugin, plugins, OpenAI } from '../lib/index'
7
8
 
8
9
  /**
9
- * @invoke npx ts-node ./examples/plugin-demo.ts
10
+ * @test npx esno ./examples/plugin.ts
10
11
  */
11
12
 
12
- const API_KEY = ''
13
+ const apiKey = fs.readFileSync('./.api-key', 'utf-8').trim()
14
+
13
15
  const characterPlugin = new ChatBrokerPlugin({
14
16
  name: 'character',
15
17
  params: () => {
@@ -20,12 +22,12 @@ const characterPlugin = new ChatBrokerPlugin({
20
22
  character: yup.string().required()
21
23
  }
22
24
  },
23
- onInstall: ({ receive, attach }) => {
25
+ onInstall: ({ receive, attachAfter }) => {
24
26
  const characters = new Map<string, string>()
25
27
  receive(({ id, data }) => {
26
28
  characters.set(id, data.character)
27
29
  })
28
- attach('start', async({ id, setPreMessages }) => {
30
+ attachAfter('start', async({ id, setPreMessages }) => {
29
31
  const character = characters.get(id)
30
32
  setPreMessages([
31
33
  {
@@ -38,7 +40,7 @@ const characterPlugin = new ChatBrokerPlugin({
38
40
  }
39
41
  ])
40
42
  })
41
- attach('done', async({ id }) => {
43
+ attachAfter('done', async({ id }) => {
42
44
  characters.delete(id)
43
45
  })
44
46
  }
@@ -59,24 +61,28 @@ flow.run(async () => {
59
61
  default: '你最好的朋友是誰?'
60
62
  }
61
63
  ])
62
- const broker = new ChatBroker({
63
- input: yup => {
64
+
65
+ const ctod = new CtoD({
66
+ plugins: () => {
64
67
  return {
65
- action: yup.string().required(),
66
- character: yup.string().required(),
68
+ character: characterPlugin.use({}),
69
+ log: plugins.PrintLogPlugin.use({
70
+ detail: true
71
+ })
67
72
  }
68
73
  },
69
- output: yup => {
70
- return {
71
- message: yup.string().required()
74
+ request: OpenAI.createChatRequestWithJsonSchema({
75
+ apiKey,
76
+ config: {
77
+ model: 'gpt-4o'
72
78
  }
73
- },
74
- plugins: {
75
- character: characterPlugin.use({}),
76
- print: plugins.PrintLogPlugin.use({
77
- detail: false
78
- })
79
- },
79
+ })
80
+ })
81
+
82
+ const brokerBuilder = ctod.createBrokerBuilder<{
83
+ action: string
84
+ character: string
85
+ }>({
80
86
  install: ({ attach }) => {
81
87
  attach('start', async({ data, plugins }) => {
82
88
  plugins.character.send({
@@ -84,26 +90,28 @@ flow.run(async () => {
84
90
  })
85
91
  })
86
92
  },
87
- request: OpenAI.createChatRequest(API_KEY, {
88
- model: 'gpt-4'
89
- }),
90
- question: async ({ action }) => {
91
- return templates.requireJsonResponse([
92
- '請基於你的角色個性,並依據以下指令進行回應:',
93
- action
94
- ], {
95
- message: {
96
- desc: '回應內容',
97
- example: 'string'
98
- }
99
- })
93
+ })
94
+
95
+ const broker = brokerBuilder.create(async({ yup, setMessages }) => {
96
+ setMessages([
97
+ {
98
+ role: 'user',
99
+ content: [
100
+ '請基於你的角色個性,並依據以下指令進行回應:',
101
+ action
102
+ ]
103
+ }
104
+ ])
105
+ return {
106
+ message: yup.string().required()
100
107
  }
101
108
  })
102
109
  try {
103
- await broker.request({
110
+ const { message } = await broker.request({
104
111
  action,
105
112
  character
106
113
  })
114
+ console.log(message)
107
115
  } catch (error: any) {
108
116
  console.error('Error:', error?.response?.data?.error?.message ?? error)
109
117
  }