ctod 0.4.1 → 0.6.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 +67 -32
- package/dist/index.js +1 -1
- package/examples/chat-demo.ts +42 -20
- package/lib/broker/chat.ts +12 -3
- package/lib/core/translator.ts +4 -7
- package/lib/index.ts +3 -2
- package/lib/plugins/print-log.ts +1 -1
- package/lib/service/llama3.cpp/index.ts +5 -15
- package/lib/service/openai/index.ts +2 -3
- package/lib/utils/error.ts +14 -0
- package/lib/utils/validate.ts +5 -37
- package/package.json +3 -3
- package/types/lib/broker/chat.d.ts +10 -5
- package/types/lib/core/parser.d.ts +1 -1
- package/types/lib/core/plugin.d.ts +2 -2
- package/types/lib/core/translator.d.ts +2 -2
- package/types/lib/index.d.ts +5 -2
- package/types/lib/plugins/index.d.ts +2 -2
- package/types/lib/plugins/limiter.d.ts +1 -1
- package/types/lib/plugins/print-log.d.ts +1 -1
- package/types/lib/plugins/retry.d.ts +1 -1
- package/types/lib/service/llama3.cpp/completion.d.ts +4 -4
- package/types/lib/service/llama3.cpp/index.d.ts +0 -2
- package/types/lib/service/openai/chat.d.ts +4 -4
- package/types/lib/service/openai/images-generation.d.ts +2 -2
- package/types/lib/service/openai/index.d.ts +0 -2
- package/types/lib/service/openai/vision.d.ts +5 -5
- package/types/lib/templates.d.ts +1 -1
- package/types/lib/types.d.ts +1 -1
- package/types/lib/utils/error.d.ts +11 -0
- package/types/lib/utils/validate.d.ts +6 -13
- package/webpack.config.ts +3 -1
- package/examples/chat-with-json-schema-demo.ts +0 -67
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<h1 align="center">CtoD</h1>
|
|
4
4
|
<h3 align="center">Chat To Data</h3>
|
|
5
5
|
|
|
6
|
-
<
|
|
6
|
+
<h6 align="center">
|
|
7
7
|
<a href="https://www.npmjs.com/package/ctod">
|
|
8
8
|
<img src="https://img.shields.io/npm/v/ctod.svg">
|
|
9
9
|
</a>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<img src="https://img.shields.io/github/stars/KHC-ZhiHao/ctod.svg?style=social">
|
|
12
12
|
</a>
|
|
13
13
|
<br>
|
|
14
|
-
</
|
|
14
|
+
</h6>
|
|
15
15
|
|
|
16
16
|
<br>
|
|
17
17
|
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
|
|
22
22
|
## 摘要
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
本工具是利用聊天機器人能夠讀懂自然語言的特性,將我們的需求與資料透過口語化的方式交付給他處理,並要求回應 JSON。
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
在對話過程中,採用 [yup](https://github.com/jquense/yup) 來驗證請求與回復資料是否符合預期,以確保一致性,只要保持這個互動模式,就可以利用在 API 串接或是自動化系統上。
|
|
27
27
|
|
|
28
|
-
我們還附帶支援 `OpenAI` 的相關服務。
|
|
28
|
+
我們還附帶支援 `OpenAI` 與 `Llama3` 的相關服務。
|
|
29
29
|
|
|
30
30
|
## 安裝
|
|
31
31
|
|
|
@@ -49,51 +49,63 @@ yarn add ctod
|
|
|
49
49
|
|
|
50
50
|
```ts
|
|
51
51
|
import { ChatBroker, OpenAI, templates } from 'ctod'
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
const broker = new ChatBroker({
|
|
54
54
|
/** 驗證輸入資料 */
|
|
55
|
-
input
|
|
55
|
+
input(yup) {
|
|
56
56
|
return {
|
|
57
|
-
indexs: yup.array(yup.string()).required(),
|
|
57
|
+
indexs: yup.array(yup.string().required()).required(),
|
|
58
58
|
question: yup.string().required()
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
/** 驗證輸出資料 */
|
|
62
|
-
output
|
|
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()
|
|
63
75
|
return {
|
|
64
|
-
indexs: yup.array(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
indexs: yup.array(item).required().meta({
|
|
77
|
+
jsonSchema: {
|
|
78
|
+
description: '由高到低排序的索引'
|
|
79
|
+
}
|
|
80
|
+
})
|
|
68
81
|
}
|
|
69
82
|
},
|
|
70
83
|
/** 初始化系統,通常來植入或掛鉤生命週期 */
|
|
71
|
-
install
|
|
84
|
+
install({ attach }) {
|
|
85
|
+
attach('start', async({ setPreMessages }) => {
|
|
86
|
+
setPreMessages([
|
|
87
|
+
{
|
|
88
|
+
role: 'system',
|
|
89
|
+
content: '你現在是一位擅長分類索引的藥師'
|
|
90
|
+
}
|
|
91
|
+
])
|
|
92
|
+
})
|
|
93
|
+
},
|
|
72
94
|
/** 定義發送請求的接口 */
|
|
73
|
-
request:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
95
|
+
request: OpenAI.createChatRequestWithJsonSchema({
|
|
96
|
+
apiKey: API_KEY,
|
|
97
|
+
config: {
|
|
98
|
+
model: 'gpt-4o-mini'
|
|
99
|
+
}
|
|
100
|
+
}),
|
|
79
101
|
/** 組裝與定義我們要向機器人發出的請求 */
|
|
80
102
|
question: async({ indexs, question }) => {
|
|
81
|
-
return
|
|
103
|
+
return [
|
|
82
104
|
'我有以下索引',
|
|
83
105
|
`${JSON.stringify(indexs)}`,
|
|
84
106
|
`請幫我解析"${question}"可能是哪個索引`,
|
|
85
107
|
'且相關性由高到低排序並給予分數,分數由 0 ~ 1'
|
|
86
|
-
]
|
|
87
|
-
indexs: {
|
|
88
|
-
desc: '由高到低排序的索引',
|
|
89
|
-
example: [
|
|
90
|
-
{
|
|
91
|
-
name: '索引名稱',
|
|
92
|
-
score: '評比分數,數字顯示'
|
|
93
|
-
}
|
|
94
|
-
]
|
|
95
|
-
}
|
|
96
|
-
})
|
|
108
|
+
]
|
|
97
109
|
}
|
|
98
110
|
})
|
|
99
111
|
|
|
@@ -210,3 +222,26 @@ const broker = new ChatBroker({
|
|
|
210
222
|
|
|
211
223
|
1. 支援 llama3.cpp server service
|
|
212
224
|
2. 新增 yup to json scheme。
|
|
225
|
+
|
|
226
|
+
### 0.5.x
|
|
227
|
+
|
|
228
|
+
移除了 JSON Schema Info 的支援,而是透過 [yup-to-json-schema](https://github.com/sodaru/yup-to-json-schema) 進行生成資料格式。
|
|
229
|
+
|
|
230
|
+
由於 `yup-to-json-schema` 的延伸套件要使用 `yup.string().description()` 方法需要進行全域註冊,在此我們提供了 `bindYupToJsonSchemaToYup` 這個方法,讓使用者可以自行決定是否要進行註冊。
|
|
231
|
+
|
|
232
|
+
1. 可以在 question 中回應 array,會透過 join 進行合併。
|
|
233
|
+
2. 可以省略 install 參數了。
|
|
234
|
+
|
|
235
|
+
### 0.6.x
|
|
236
|
+
|
|
237
|
+
`bindYupToJsonSchemaToYup` 有一些依賴問題已經被移除,改用以下方案取代:
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
yup.array(item).required().meta({
|
|
241
|
+
jsonSchema: {
|
|
242
|
+
description: '由高到低排序的索引'
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
1. 新增了 definedYupSchema 讓建立複雜的 Output 更加容易。
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ctod=t():e.ctod=t()}(this||("undefined"!=typeof window?window:global),(()=>(()=>{"use strict";var e={37:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBroker=void 0;const r=n(15),a=n(470),o=n(87);t.ChatBroker=class{__hookType;log;hook=new a.Hook;params;plugins={};installed=!1;translator;event=new a.Event;constructor(e){this.log=new a.Log(e.name??"no name"),this.params=e,this.translator=new o.Translator({...e,parsers:[r.TextParser.JsonMessage()]})}_install(){if(!1===this.installed){this.installed=!0;const e={log:this.log,attach:this.hook.attach.bind(this.hook),attachAfter:this.hook.attachAfter.bind(this.hook),translator:this.translator};if(this.params.install(e),this.params.plugins){this.plugins="function"==typeof this.params.plugins?this.params.plugins():this.params.plugins;for(let t in this.plugins)this.plugins[t].instance._params.onInstall({...e,params:this.plugins[t].params,receive:this.plugins[t].receive})}}}async cancel(e){e?this.event.emit("cancel",{requestId:e}):this.event.emit("cancelAll",{})}requestWithId(e){this._install();let t=a.flow.createUuid(),n=null,r=!1,o=!1,s=[this.event.on("cancel",(({requestId:e})=>{e===t&&l()})),this.event.on("cancelAll",(()=>{l()}))],i=()=>s.forEach((e=>e.off())),l=()=>{!1===r&&(o&&n&&n(),r=!0,i())},c=e=>{n=e},u=async()=>{let s=this.translator.getValidate(),i=null,l={},u=await this.translator.compile(e,{schema:s}),p=[{role:"user",content:u.prompt}];for(let e in this.plugins)l[e]={send:n=>this.plugins[e].send({id:t,data:n})};return await this.hook.notify("start",{id:t,data:e,schema:s,plugins:l,messages:p,setPreMessages:e=>{p=[...e,{role:"user",content:u.prompt}]},changeMessages:e=>{p=e}}),await a.flow.asyncWhile((async({count:a,doBreak:l})=>{if(a>=10)return l();let u="",d="",h=!1,f=p.filter((e=>"user"===e.role)).slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:p,lastUserMessage:f});const m=this.params.request(p,{count:a,schema:s,onCancel:c,isRetry:h});if(r)n&&n();else try{o=!0,u=await m,d=u}finally{o=!1}!1===r&&(await this.hook.notify("talkAfter",{id:t,data:e,response:u,messages:p,parseText:d,lastUserMessage:f,changeParseText:e=>{d=e}}),i=(await this.translator.parse(d)).output,await this.hook.notify("succeeded",{id:t,output:i})),await this.hook.notify("done",{id:t}),l()}catch(e){if(!e.isParserError)throw await this.hook.notify("done",{id:t}),e;if(await this.hook.notify("parseFailed",{id:t,error:e.error,count:a,response:u,messages:p,lastUserMessage:f,parserFails:e.parserFails,retry:()=>{h=!0},changeMessages:e=>{p=e}}),!1===h)throw await this.hook.notify("done",{id:t}),e}})),i};return{id:t,request:(async()=>{try{return await u()}finally{i()}})()}}async request(e){const{request:t}=this.requestWithId(e);return await t}}},15:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.TextParser=void 0;const a=r(n(959));class o{params;static JsonMessage(){return new o({name:"JsonMessage",handler:async e=>{try{return JSON.parse(e)}catch(t){const n=/{(?:[^{}]|(?:{[^{}]*}))*}/,r=e.match(n)?.[0]||"";return a.default.parse(r)}}})}constructor(e){this.params=e}get name(){return this.params.name}async read(e){return await this.params.handler(e)}}t.TextParser=o},241:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChatBrokerPlugin=void 0;const r=n(470);t.ChatBrokerPlugin=class{_event=new r.Event;_params;constructor(e){this._params=e}use(e){return{instance:this,params:e,send:e=>{this._event.emit("receive",e)},receive:e=>{this._event.on("receive",e)},__receiveData:null}}}},87:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Translator=void 0;const r=n(293);t.Translator=class{params;constructor(e){this.params=e}get __schemeType(){return null}get __outputType(){return null}async compile(e,t){const n=(0,r.validate)(e,this.params.input);return{scheme:n,prompt:await this.params.question(n,t)}}getValidate(){return{input:this.params.input,output:this.params.output}}async parse(e){let t,n="",a=[];for(let r of this.params.parsers)try{t=await r.read(e),n=r.name}catch(e){t=void 0,a.push({name:r.name,error:e})}try{return{output:(0,r.validate)(t,this.params.output),parserName:n,parserFails:a}}catch(e){throw{isParserError:!0,error:e,parserFails:a}}}}},620:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return a(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.ctod=t.Translator=t.ChatBrokerPlugin=t.ChatBroker=t.TextParser=t.Llama3Cpp=t.OpenAI=t.validateToJsonSchema=t.templates=t.plugins=void 0,t.plugins=o(n(218)),t.templates=o(n(298));var s=n(293);Object.defineProperty(t,"validateToJsonSchema",{enumerable:!0,get:function(){return s.validateToJsonSchema}});var i=n(616);Object.defineProperty(t,"OpenAI",{enumerable:!0,get:function(){return i.OpenAI}});var l=n(643);Object.defineProperty(t,"Llama3Cpp",{enumerable:!0,get:function(){return l.Llama3Cpp}});var c=n(15);Object.defineProperty(t,"TextParser",{enumerable:!0,get:function(){return c.TextParser}});var u=n(37);Object.defineProperty(t,"ChatBroker",{enumerable:!0,get:function(){return u.ChatBroker}});var p=n(241);Object.defineProperty(t,"ChatBrokerPlugin",{enumerable:!0,get:function(){return p.ChatBrokerPlugin}});var d=n(87);Object.defineProperty(t,"Translator",{enumerable:!0,get:function(){return d.Translator}});const h=o(n(218)),f=o(n(298)),m=n(616),g=n(643),y=n(87),_=n(15),v=n(37),b=n(241),w=n(293);t.ctod={OpenAI:m.OpenAI,Llama3Cpp:g.Llama3Cpp,plugins:h,templates:f,ChatBroker:v.ChatBroker,Translator:y.Translator,TextParser:_.TextParser,ChatBrokerPlugin:b.ChatBrokerPlugin,validateToJsonSchema:w.validateToJsonSchema},e.exports=t.ctod,e.exports.ctod=t.ctod,t.default=t.ctod},218:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.RolePlugin=t.LimiterPluginGlobState=t.LimiterPlugin=t.RetryPlugin=t.PrintLogPlugin=void 0;const a=r(n(894)),o=r(n(829)),s=r(n(626)),i=r(n(1));t.PrintLogPlugin=o.default,t.RetryPlugin=a.default,t.LimiterPlugin=s.default.plugin,t.LimiterPluginGlobState=s.default,t.RolePlugin=i.default},626:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241),a=n(470),o={limit:3,interval:6e4},s={event:new a.Event,schedule:null,waitTimes:[],waitQueue:[]};t.default={event:s.event,config:o,closeSchedule:()=>{s.schedule&&(s.schedule.close(),s.schedule=null)},plugin:new r.ChatBrokerPlugin({name:"limiter",params:()=>({}),receiveData:()=>({}),onInstall({attach:e}){null==s.schedule&&(s.schedule=new a.Schedule,s.schedule.add("calc queue",1e3,(async()=>{const e=Date.now();if(s.waitTimes=s.waitTimes.filter((t=>e-t<o.interval)),s.waitTimes.length!==o.limit){let e=s.waitQueue.shift();e&&(s.waitTimes.push(Date.now()),s.event.emit("run",{id:e}))}else s.waitTimes[0]&&s.event.emit("waitTimeChange",{waitTime:Math.floor(60-(e-s.waitTimes[0])/1e3)})})),s.schedule.play()),e("talkBefore",(async()=>{const e=a.flow.createUuid();return s.waitQueue.push(e),new Promise((t=>{s.event.on("run",(({id:n},{off:r})=>{n===e&&(r(),t())}))}))}))}})}},829:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"print-log",params:e=>({detail:e.boolean().required().default(!1)}),receiveData:()=>({}),onInstall({params:e,log:t,attach:n}){n("talkBefore",(async({lastUserMessage:n,messages:r})=>{t.print("Send:",{color:"green"}),e.detail?t.print("\n"+JSON.stringify(r,null,4)):t.print("\n"+n)})),n("talkAfter",(async({parseText:e})=>{t.print("Receive:",{color:"cyan"}),t.print("\n"+e)})),n("succeeded",(async({output:e})=>{t.print("Output:",{color:"yellow"});try{t.print("\n"+JSON.stringify(e,null,4))}catch(n){t.print("\n"+e)}}))}})},894:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"retry",params:e=>({retry:e.number().required().default(1),printWarn:e.boolean().required().default(!0)}),receiveData:()=>({}),onInstall({log:e,attach:t,params:n}){t("parseFailed",(async({count:t,retry:r,messages:a,changeMessages:o})=>{t<=n.retry&&(n.printWarn&&e.print(`Is Failed, Retry ${t} times.`),o(a),r())}))}})},1:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0});const r=n(241);t.default=new r.ChatBrokerPlugin({name:"role",params:e=>({role:e.string().required()}),receiveData:()=>({}),onInstall({attach:e,params:t}){e("start",(async({messages:e,changeMessages:n})=>{n([{role:"user",content:`你現在是${t.role}。`},{role:"assistant",content:`沒問題,我現在是${t.role},有什麼可以幫你的嗎?`},...e])}))}})},358:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3CppCompletion=void 0;const r=n(470),a=n(511);class o{core;streamAbortControllers=[];constructor(e){this.core=e}createAbortController(){const e=new AbortController,t=r.flow.createUuid();return this.streamAbortControllers.push({id:t,controller:e}),{signal:e.signal,controllerId:t}}removeAbortController(e){this.streamAbortControllers=this.streamAbortControllers.filter((t=>t.id!==e))}async stream(e){const{signal:t,controllerId:n}=this.createAbortController(),r=()=>{this.removeAbortController(n),e.onEnd()};fetch(`${this.core.config.baseUrl}/${e.path}`,{method:"POST",body:JSON.stringify(e.data),signal:t,headers:{"Content-Type":"application/json",...this.core.config.headers}}).then((async t=>{if(t.body){let n=t.body.getReader(),a=!1,o="";for(;!a;){const{value:t,done:r}=await n.read();if(t){o+=new TextDecoder("utf-8").decode(t);const n=o.split("\n\n");o=n.pop()||"",n.forEach((t=>{if(t.includes("[DONE]")&&(a=!0),t.startsWith("data:"))try{const n=JSON.parse(t.replace("data: ",""));e.onMessage(n)}catch(t){e.onWarn(t)}}))}r&&(a=!0)}r()}else e.onError(new Error("Body not found."))})).catch((t=>{t instanceof Error&&t.message.includes("The user aborted a request")?r():e.onError(t)}))}async fetch(e){const{signal:t,controllerId:n}=this.createAbortController();try{return{data:(await this.core.core._axios.post(`${this.core.config.baseUrl}/${e.path}`,e.data,{signal:t,headers:{"Content-Type":"application/json",...this.core.config.headers}})).data}}finally{this.removeAbortController(n)}}cancel(){this.streamAbortControllers.forEach((e=>e.controller.abort())),this.streamAbortControllers=[]}export(){return{cancel:this.cancel.bind(this)}}}t.Llama3CppCompletion=class{core;config={baseUrl:"",headers:{},autoConvertTraditionalChinese:!0};constructor(e){this.core=e}setConfig(e){this.config={...this.config,...e}}completion(e){const t=[];for(let{role:n,content:r}of e.messages)"system"===n&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${r}\n\n`),"user"===n&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${r?.replaceAll("\n","\\n")??""}`),"assistant"===n&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+r);const n=e.messages.at(-1)||"",r=new o(this);return{...r.export(),run:async()=>{const o=await r.fetch({path:"completion",data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,a.sify)(t.join("\n")):t.join("\n")}}),s=this.config.autoConvertTraditionalChinese?(0,a.tify)(o.data.content):o.data.content;return{message:s,fullMessage:`${n}${s}`}}}}completionStream(e){const t=[];for(let{role:n,content:r}of e.messages)"system"===n&&t.push(`<|start_header_id|>system<|end_header_id|>\n\n${r}\n\n`),"user"===n&&t.push(`<|start_header_id|>user<|end_header_id|>\n\n${r?.replaceAll("\n","\\n")??""}`),"assistant"===n&&t.push("<|start_header_id|>assistant<|end_header_id|>\n\n"+r);const n=new o(this);return n.stream({path:"completion",onEnd:e.onEnd||(()=>null),onMessage:t=>{e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,a.tify)(t.content):t.content})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},prompt:this.config.autoConvertTraditionalChinese?(0,a.sify)(t.join("\n")):t.join("\n"),stream:!0}}),n.export()}talk(e){const t=new o(this);return{...t.export(),run:async()=>{const n=(await t.fetch({path:"v1/chat/completions",data:{...e.options||{},response_format:e.response_format,messages:e.messages.map((e=>({role:e.role,content:this.config.autoConvertTraditionalChinese?(0,a.sify)(e.content):e.content})))}})).data.choices[0].message.content||"";return{message:this.config.autoConvertTraditionalChinese?(0,a.tify)(n):n}}}}talkStream(e){const t=new o(this);return t.stream({path:"v1/chat/completions",onEnd:e.onEnd||(()=>null),onMessage:t=>{let n=t.choices[0].delta.content;n&&e.onMessage({message:this.config.autoConvertTraditionalChinese?(0,a.tify)(n):n})},onWarn:e.onWarn||(()=>null),onError:e.onError||(()=>null),data:{...e.options||{},stream:!0,messages:e.messages.map((e=>({role:e.role,content:this.config.autoConvertTraditionalChinese?(0,a.sify)(e.content):e.content})))}}),t.export()}}},643:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Llama3Cpp=void 0;const a=r(n(167)),o=n(470),s=n(511),i=n(293),l=n(358);class c{_axios=a.default.create();static createChatRequest(e){return async(t,{schema:n,onCancel:r})=>{const a=(new c).createCompletion(),l="function"==typeof e.config?await e.config():e.config,u=e.jsonSchemaInfo?o.json.jpjs(e.jsonSchemaInfo):void 0;if(a.setConfig(l),a.config.autoConvertTraditionalChinese&&u)for(let e in u.desc){const t=u.desc[e];"object"==typeof t&&t.description&&(t.description=(0,s.sify)(t.description)),"string"==typeof t&&(u.desc[e]=(0,s.sify)(t))}const{run:p,cancel:d}=a.talk({options:e.talkOptions,messages:t,response_format:{type:"json_object",schema:(0,i.validateToJsonSchema)(n.output,u)}});r(d);const{message:h}=await p();return h}}setAxios(e){this._axios=e}createCompletion(){return new l.Llama3CppCompletion(this)}}t.Llama3Cpp=c},203:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIChat=void 0;const r=n(470);t.OpenAIChat=class{openai;config={n:1,model:"gpt-4o",temperature:1,maxTokens:void 0,forceJsonFormat:!0};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async moderations(e){const t=await this.openai._axios.post("https://api.openai.com/v1/moderations",{input:e},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}});return{isSafe:!1===t.data.results?.[0]?.flagged,result:t.data}}async talk(e=[],t){const n=r.json.jpjs(e),a=["gpt-4-turbo-preview","gpt-4-turbo","gpt-4o","gpt-4o-mini","gpt-3.5-turbo-1106"].includes(this.config.model);let o;a&&this.config.forceJsonFormat&&(o={type:"json_object"}),a&&this.config.forceJsonFormat&&t?.jsonSchema&&(o={type:"json_schema",json_schema:t.jsonSchema});const s=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:this.config.n,messages:n,response_format:o,temperature:this.config.temperature},{signal:t?.abortController?.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),i=s.data.choices||[],l=i[0]?.message||{role:"assistant",content:""};return n.push(l),{id:s?.data.id,text:l.content,newMessages:n,isDone:"stop"===i[0]?.finish_reason,apiReseponse:s.data}}talkStream(e){const t=new AbortController;return fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`},body:JSON.stringify({model:this.config.model,stream:!0,messages:e.messages}),signal:t.signal}).then((async t=>{const n=t.body?.pipeThrough(new TextDecoderStream).getReader();if(!n)throw new Error("Can not get reader");for(;;){const{value:t,done:r}=await n.read();if(r)break;const a=t.split("\n");for(let t of a)if(0!==t.length&&!t.startsWith(":")){if("data: [DONE]"===t){e.onEnd();break}try{const n=JSON.parse(t.substring(6)).choices[0].delta.content;e.onMessage(n)}catch(t){e.onWarn(t)}}}})).catch((t=>{"AbortError"===t.name?e.onEnd():e.onError(t)})),{cancel:()=>t.abort()}}async keepTalk(e,t=[]){const n=await this.talk([...t,{role:"user",content:Array.isArray(e)?e.join("\n"):e}]);return{result:n,nextTalk:e=>this.keepTalk(e,n.newMessages)}}}},725:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIImagesGeneration=void 0,t.OpenAIImagesGeneration=class{openai;config={model:"dall-e-2",size:"1024x1024"};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async create(e){return(await this.openai._axios.post("https://api.openai.com/v1/images/generations",{prompt:e,n:1,size:this.config.size,model:this.config.model,response_format:"b64_json"},{timeout:3e5,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}})).data}}},616:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAI=void 0;const a=r(n(167)),o=n(710),s=n(203),i=n(725),l=n(293);class c{_axios=a.default.create();_apiKey="";static createChatRequest(e,t={}){return async(n,{onCancel:r})=>{const a=new c("string"==typeof e?e:await e()).createChat(),o=new AbortController;a.setConfig("function"==typeof t?await t():t),r((()=>o.abort()));const{text:s}=await a.talk(n,{abortController:o});return s}}static createChatRequestWithJsonSchema(e){return async(t,{schema:n,onCancel:r})=>{const a=new c("string"==typeof e.apiKey?e.apiKey:await e.apiKey()).createChat(),o=new AbortController;e.config&&a.setConfig("function"==typeof e.config?await e.config():e.config),r((()=>o.abort()));const s=(0,l.validateToJsonSchema)(n.output,e.jsonSchemaInfo),{text:i}=await a.talk(t,{abortController:o,jsonSchema:{name:"data",strict:!0,schema:s}});return i}}constructor(e=""){this._apiKey=e}setAxios(e){this._axios=e}setConfiguration(e){this._apiKey=e}createChat(){return new s.OpenAIChat(this)}createVision(){return new o.OpenAIVision(this)}createImagesGeneration(){return new i.OpenAIImagesGeneration(this)}}t.OpenAI=c},710:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OpenAIVision=void 0,t.OpenAIVision=class{openai;config={model:"gpt-4-vision-preview",maxTokens:void 0,temperature:1};constructor(e){this.openai=e}setConfig(e){Object.assign(this.config,e)}async view(e){const t=await this.openai._axios.post("https://api.openai.com/v1/chat/completions",{model:this.config.model,n:1,messages:e,max_tokens:this.config.maxTokens,temperature:this.config.temperature},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.openai._apiKey}`}}),n=(t.data.choices||[])[0]?.message||{role:"assistant",content:""};return{id:t?.data.id,text:n.content,apiReseponse:t.data}}}},298:function(e,t,n){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.requireJsonResponseWithJsonSchema=t.requireJsonResponseWithHandlebars=t.requireJsonResponse=void 0;const a=r(n(97)),o=n(470);t.requireJsonResponse=(e,t)=>[...Array.isArray(e)?e:[e],"Please respond using the following JSON format and minify the JSON without including any explanation: ","{",Object.entries(t).map((([e,t])=>[`/* ${t.desc} */`,`"${e}": ${JSON.stringify(t.example)}`].join("\n"))).join(",\n"),"}"].join("\n"),t.requireJsonResponseWithHandlebars=(e,n,r)=>{const s=a.default.create();return s.registerHelper("DATA",(function(e){return JSON.stringify(e)})),s.registerHelper("ENV",(function(e){return this.__envs&&e?this.__envs[e]:""})),s.registerHelper("INPUT",(function(){return JSON.stringify(o.record.omit(this,["__envs"]))})),s.registerHelper("JOIN",(function(e){return Array.isArray(e)?e.join():JSON.stringify(e)})),s.compile((0,t.requireJsonResponse)(n,r))(e)},t.requireJsonResponseWithJsonSchema=(e,t)=>[...Array.isArray(e)?e:[e],"Please provide JSON data according to the following JSON Schema format:",JSON.stringify(t)].join("\n")},293:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),a=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&r(t,e,n);return a(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.validateToJsonSchema=t.validate=t.definedValidateSchema=void 0;const s=o(n(609)),i=n(470),l=n(724);t.definedValidateSchema=function(e){return e},t.validate=function(e,t){return s.object(t(s)).required().validateSync(e||{})},t.validateToJsonSchema=(e,t)=>{const n=e=>{if(e.default&&delete e.default,e.properties)for(let t in e.properties)e.properties[t].default&&delete e.properties[t].default,n(e.properties[t]);e.items&&n(e.items)},r=e=>{if("object"===e.type){e.additionalProperties=!1;for(const t in e.properties)r(e.properties[t])}else"array"===e.type&&r(e.items)},a=(0,l.convertSchema)(s.object(e(s)));return n(a),r(a),t?((e,t)=>{if(t&&t.desc)for(let n in t.desc)if(e.properties){let r=i.pick.peel(e.properties,n.replaceAll(".",".properties."));if(r&&!0!==r){let e=t.desc[n];"object"==typeof e?(e.description&&(r.description=e.description),e.examples&&(r.examples=e.examples)):"string"==typeof e&&(r.description=e)}}return e})(a,t):a}},724:e=>{e.exports=require("@sodaru/yup-to-json-schema")},167:e=>{e.exports=require("axios")},511:e=>{e.exports=require("chinese-conv")},97:e=>{e.exports=require("handlebars")},959:e=>{e.exports=require("json5")},470:e=>{e.exports=require("power-helper")},609:e=>{e.exports=require("yup")}},t={};return function n(r){var a=t[r];if(void 0!==a)return a.exports;var o=t[r]={exports:{}};return e[r].call(o.exports,o,o.exports,n),o.exports}(620)})()));
|
|
1
|
+
!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}),d=[{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:d,setPreMessages:e=>{d=[...e,{role:"user",content:p.prompt}]},changeMessages:e=>{d=e}}),await a.flow.asyncWhile((async({count:a,doBreak:c})=>{if(a>=10)return c();let p="",h="",f=!1,m=d.filter((e=>"user"===e.role)).slice(-1)[0]?.content||"";try{await this.hook.notify("talkBefore",{id:t,data:e,messages:d,lastUserMessage:m});const g=this.params.request(d,{count:a,schema:i,onCancel:u,isRetry:f});if(r)n&&n();else try{o=!0,p=await g,h=p}finally{o=!1}!1===r&&(await this.hook.notify("talkAfter",{id:t,data:e,response:p,messages:d,parseText:h,lastUserMessage:m,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})),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:d,lastUserMessage:m,parserFails:e.parserFails,retry:()=>{f=!0},changeMessages:e=>{d=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.definedYupSchema=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,"definedYupSchema",{enumerable:!0,get:function(){return s.definedYupSchema}});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 d=n(235);Object.defineProperty(t,"Translator",{enumerable:!0,get:function(){return d.Translator}});const h=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:h,templates:f,ChatBroker:v.ChatBroker,Translator:y.Translator,TextParser:_.TextParser,ChatBrokerPlugin:b.ChatBrokerPlugin,definedYupSchema:w.definedYupSchema,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:d}=await u();return d}}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={}){return async(n,{onCancel:r})=>{const a=new c("string"==typeof e?e:await e()).createChat(),o=new AbortController;a.setConfig("function"==typeof t?await t():t),r((()=>o.abort()));const{text:s}=await a.talk(n,{abortController:o});return s}}static createChatRequestWithJsonSchema(e){return async(t,{schema:n,onCancel:r})=>{const a=new c("string"==typeof e.apiKey?e.apiKey:await e.apiKey()).createChat(),o=new AbortController;e.config&&a.setConfig("function"==typeof e.config?await e.config():e.config),r((()=>o.abort()));const s=(0,l.validateToJsonSchema)(n.output),{text:i}=await a.talk(t,{abortController:o,jsonSchema:{name:"data",strict:!0,schema:s}});return i}}constructor(e=""){this._apiKey=e}setAxios(e){this._axios=e}setConfiguration(e){this._apiKey=e}createChat(){return new s.OpenAIChat(this)}createVision(){return new o.OpenAIVision(this)}createImagesGeneration(){return new i.OpenAIImagesGeneration(this)}}t.OpenAI=c},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.definedYupSchema=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.definedYupSchema=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)})()));
|
package/examples/chat-demo.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
2
2
|
/// <reference path="../lib/shims.d.ts" />
|
|
3
|
-
import { ChatBroker, OpenAI,
|
|
3
|
+
import { ChatBroker, OpenAI, plugins } from '../lib/index'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @test npx ts-node ./examples/chat-demo.ts
|
|
@@ -10,37 +10,59 @@ const API_KEY = ''
|
|
|
10
10
|
const broker = new ChatBroker({
|
|
11
11
|
input: yup => {
|
|
12
12
|
return {
|
|
13
|
-
indexs: yup.array(yup.string()).required(),
|
|
13
|
+
indexs: yup.array(yup.string().required()).required(),
|
|
14
14
|
question: yup.string().required()
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
output: yup => {
|
|
18
|
+
const item = yup.object({
|
|
19
|
+
name: yup.string().required().meta({
|
|
20
|
+
jsonSchema: {
|
|
21
|
+
description: '索引名稱'
|
|
22
|
+
}
|
|
23
|
+
}),
|
|
24
|
+
score: yup.number().required().meta({
|
|
25
|
+
jsonSchema: {
|
|
26
|
+
description: '評比分數'
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}).required()
|
|
18
30
|
return {
|
|
19
|
-
indexs: yup.array(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
indexs: yup.array(item).required().meta({
|
|
32
|
+
jsonSchema: {
|
|
33
|
+
description: '由高到低排序的索引'
|
|
34
|
+
}
|
|
35
|
+
})
|
|
23
36
|
}
|
|
24
37
|
},
|
|
25
|
-
|
|
26
|
-
|
|
38
|
+
plugins: {
|
|
39
|
+
log: plugins.PrintLogPlugin.use({
|
|
40
|
+
detail: true
|
|
41
|
+
})
|
|
42
|
+
},
|
|
43
|
+
install({ attach }) {
|
|
44
|
+
attach('start', async({ setPreMessages }) => {
|
|
45
|
+
setPreMessages([
|
|
46
|
+
{
|
|
47
|
+
role: 'system',
|
|
48
|
+
content: '你現在是一位擅長分類索引的藥師'
|
|
49
|
+
}
|
|
50
|
+
])
|
|
51
|
+
})
|
|
52
|
+
},
|
|
53
|
+
request: OpenAI.createChatRequestWithJsonSchema({
|
|
54
|
+
apiKey: API_KEY,
|
|
55
|
+
config: {
|
|
56
|
+
model: 'gpt-4o-mini'
|
|
57
|
+
}
|
|
58
|
+
}),
|
|
27
59
|
question: async({ indexs, question }) => {
|
|
28
|
-
return
|
|
60
|
+
return [
|
|
29
61
|
'我有以下索引',
|
|
30
62
|
`${JSON.stringify(indexs)}`,
|
|
31
63
|
`請幫我解析"${question}"可能是哪個索引`,
|
|
32
64
|
'且相關性由高到低排序並給予分數,分數由 0 ~ 1'
|
|
33
|
-
]
|
|
34
|
-
indexs: {
|
|
35
|
-
desc: '由高到低排序的索引',
|
|
36
|
-
example: [
|
|
37
|
-
{
|
|
38
|
-
name: '索引名稱',
|
|
39
|
-
score: '評比分數,數字顯示'
|
|
40
|
-
}
|
|
41
|
-
]
|
|
42
|
-
}
|
|
43
|
-
})
|
|
65
|
+
]
|
|
44
66
|
}
|
|
45
67
|
})
|
|
46
68
|
|
package/lib/broker/chat.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ChatBrokerPlugin } from '../core/plugin'
|
|
|
3
3
|
import { Event, flow, Hook, Log } from 'power-helper'
|
|
4
4
|
import { Translator, TranslatorParams } from '../core/translator'
|
|
5
5
|
import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate'
|
|
6
|
+
import { ParserError } from '../utils/error'
|
|
6
7
|
|
|
7
8
|
type Message = {
|
|
8
9
|
role: 'system' | 'user' | 'assistant'
|
|
@@ -63,6 +64,11 @@ export type ChatBrokerHooks<
|
|
|
63
64
|
messages: Message[]
|
|
64
65
|
parseText: string
|
|
65
66
|
lastUserMessage: string
|
|
67
|
+
/**
|
|
68
|
+
* @zh 宣告解析失敗
|
|
69
|
+
* @en Declare parsing failure
|
|
70
|
+
*/
|
|
71
|
+
parseFail: (error: any) => void
|
|
66
72
|
changeParseText: (text: string) => void
|
|
67
73
|
}
|
|
68
74
|
|
|
@@ -123,7 +129,7 @@ export type Params<
|
|
|
123
129
|
name?: string
|
|
124
130
|
plugins?: PS | (() => PS)
|
|
125
131
|
request: (messages: Message[], context: RequestContext) => Promise<string>
|
|
126
|
-
install
|
|
132
|
+
install?: (context: {
|
|
127
133
|
log: Log
|
|
128
134
|
attach: Hook<C>['attach']
|
|
129
135
|
attachAfter: Hook<C>['attachAfter']
|
|
@@ -172,7 +178,6 @@ export class ChatBroker<
|
|
|
172
178
|
attachAfter: this.hook.attachAfter.bind(this.hook),
|
|
173
179
|
translator: this.translator
|
|
174
180
|
}
|
|
175
|
-
this.params.install(context)
|
|
176
181
|
if (this.params.plugins) {
|
|
177
182
|
this.plugins = typeof this.params.plugins === 'function' ? this.params.plugins() : this.params.plugins
|
|
178
183
|
for (let key in this.plugins) {
|
|
@@ -183,6 +188,7 @@ export class ChatBroker<
|
|
|
183
188
|
})
|
|
184
189
|
}
|
|
185
190
|
}
|
|
191
|
+
this.params.install?.(context)
|
|
186
192
|
}
|
|
187
193
|
}
|
|
188
194
|
|
|
@@ -322,6 +328,9 @@ export class ChatBroker<
|
|
|
322
328
|
messages,
|
|
323
329
|
parseText,
|
|
324
330
|
lastUserMessage,
|
|
331
|
+
parseFail: (error) => {
|
|
332
|
+
throw new ParserError(error, [])
|
|
333
|
+
},
|
|
325
334
|
changeParseText: text => {
|
|
326
335
|
parseText = text
|
|
327
336
|
}
|
|
@@ -336,7 +345,7 @@ export class ChatBroker<
|
|
|
336
345
|
doBreak()
|
|
337
346
|
} catch (error: any) {
|
|
338
347
|
// 如果解析錯誤,可以選擇是否重新解讀
|
|
339
|
-
if (error
|
|
348
|
+
if (error instanceof ParserError) {
|
|
340
349
|
await this.hook.notify('parseFailed', {
|
|
341
350
|
id,
|
|
342
351
|
error: error.error,
|
package/lib/core/translator.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TextParser } from './parser'
|
|
2
2
|
import { validate, ValidateCallback, ValidateCallbackOutputs } from '../utils/validate'
|
|
3
|
+
import { ParserError } from '../utils/error'
|
|
3
4
|
|
|
4
5
|
export type TranslatorParams<
|
|
5
6
|
S extends ValidateCallback<any>,
|
|
@@ -29,7 +30,7 @@ export type TranslatorParams<
|
|
|
29
30
|
input: S
|
|
30
31
|
output: O
|
|
31
32
|
}
|
|
32
|
-
}) => Promise<string>
|
|
33
|
+
}) => Promise<string | string[]>
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export class Translator<
|
|
@@ -64,7 +65,7 @@ export class Translator<
|
|
|
64
65
|
const prompt = await this.params.question(scheme, context)
|
|
65
66
|
return {
|
|
66
67
|
scheme,
|
|
67
|
-
prompt
|
|
68
|
+
prompt: Array.isArray(prompt) ? prompt.join('\n') : prompt
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -104,11 +105,7 @@ export class Translator<
|
|
|
104
105
|
parserFails
|
|
105
106
|
}
|
|
106
107
|
} catch (error) {
|
|
107
|
-
throw
|
|
108
|
-
isParserError: true,
|
|
109
|
-
error,
|
|
110
|
-
parserFails
|
|
111
|
-
}
|
|
108
|
+
throw new ParserError(error, parserFails)
|
|
112
109
|
}
|
|
113
110
|
}
|
|
114
111
|
}
|
package/lib/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * as plugins from './plugins'
|
|
2
2
|
export * as templates from './templates'
|
|
3
|
-
export { validateToJsonSchema,
|
|
3
|
+
export { validateToJsonSchema, definedYupSchema } from './utils/validate'
|
|
4
4
|
export { OpenAI } from './service/openai'
|
|
5
5
|
export { Llama3Cpp } from './service/llama3.cpp'
|
|
6
6
|
export { TextParser } from './core/parser'
|
|
@@ -17,7 +17,7 @@ import { Translator } from './core/translator'
|
|
|
17
17
|
import { TextParser } from './core/parser'
|
|
18
18
|
import { ChatBroker } from './broker/chat'
|
|
19
19
|
import { ChatBrokerPlugin } from './core/plugin'
|
|
20
|
-
import { validateToJsonSchema } from './utils/validate'
|
|
20
|
+
import { validateToJsonSchema, definedYupSchema } from './utils/validate'
|
|
21
21
|
|
|
22
22
|
export const ctod = {
|
|
23
23
|
OpenAI,
|
|
@@ -28,6 +28,7 @@ export const ctod = {
|
|
|
28
28
|
Translator,
|
|
29
29
|
TextParser,
|
|
30
30
|
ChatBrokerPlugin,
|
|
31
|
+
definedYupSchema,
|
|
31
32
|
validateToJsonSchema
|
|
32
33
|
}
|
|
33
34
|
|
package/lib/plugins/print-log.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import axios, { AxiosInstance } from 'axios'
|
|
2
|
-
import { json } from 'power-helper'
|
|
3
2
|
import { sify } from 'chinese-conv'
|
|
4
|
-
import { validateToJsonSchema
|
|
3
|
+
import { validateToJsonSchema } from '../../utils/validate'
|
|
5
4
|
import { Llama3CppCompletion, Config } from './completion'
|
|
6
5
|
|
|
7
6
|
export class Llama3Cpp {
|
|
@@ -10,31 +9,22 @@ export class Llama3Cpp {
|
|
|
10
9
|
static createChatRequest(params: {
|
|
11
10
|
config: Partial<Config> | (() => Promise<Partial<Config>>)
|
|
12
11
|
talkOptions?: any
|
|
13
|
-
jsonSchemaInfo?: JsonSchemaInfo
|
|
14
12
|
}) {
|
|
15
13
|
return async(messages: any[], { schema, onCancel }: any) => {
|
|
16
14
|
const ll3cpp = new Llama3Cpp()
|
|
17
15
|
const chat = ll3cpp.createCompletion()
|
|
18
16
|
const config = typeof params.config === 'function' ? await params.config() : params.config
|
|
19
|
-
const info = params.jsonSchemaInfo ? json.jpjs(params.jsonSchemaInfo) : undefined
|
|
20
17
|
chat.setConfig(config)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (typeof d === 'object' && d.description) {
|
|
25
|
-
d.description = sify(d.description)
|
|
26
|
-
}
|
|
27
|
-
if (typeof d === 'string') {
|
|
28
|
-
info.desc[key] = sify(d)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
18
|
+
let formatSchema = validateToJsonSchema(schema.output)
|
|
19
|
+
if (chat.config.autoConvertTraditionalChinese) {
|
|
20
|
+
formatSchema = JSON.parse(sify(JSON.stringify(formatSchema)))
|
|
31
21
|
}
|
|
32
22
|
const { run, cancel } = chat.talk({
|
|
33
23
|
options: params.talkOptions,
|
|
34
24
|
messages: messages,
|
|
35
25
|
response_format: {
|
|
36
26
|
type: 'json_object',
|
|
37
|
-
schema:
|
|
27
|
+
schema: formatSchema
|
|
38
28
|
}
|
|
39
29
|
})
|
|
40
30
|
onCancel(cancel)
|
|
@@ -2,7 +2,7 @@ import axios, { AxiosInstance } from 'axios'
|
|
|
2
2
|
import { OpenAIVision } from './vision'
|
|
3
3
|
import { OpenAIChat, Config } from './chat'
|
|
4
4
|
import { OpenAIImagesGeneration } from './images-generation'
|
|
5
|
-
import { validateToJsonSchema
|
|
5
|
+
import { validateToJsonSchema } from '../../utils/validate'
|
|
6
6
|
|
|
7
7
|
export class OpenAI {
|
|
8
8
|
_axios = axios.create()
|
|
@@ -25,7 +25,6 @@ export class OpenAI {
|
|
|
25
25
|
static createChatRequestWithJsonSchema(params:{
|
|
26
26
|
apiKey: string | (() => Promise<string>),
|
|
27
27
|
config?: Partial<Config> | (() => Promise<Partial<Config>>)
|
|
28
|
-
jsonSchemaInfo?: JsonSchemaInfo
|
|
29
28
|
}) {
|
|
30
29
|
return async(messages: any[], { schema, onCancel }: any) => {
|
|
31
30
|
const openai = new OpenAI(typeof params.apiKey === 'string' ? params.apiKey : await params.apiKey())
|
|
@@ -35,7 +34,7 @@ export class OpenAI {
|
|
|
35
34
|
chat.setConfig(typeof params.config === 'function' ? await params.config() : params.config)
|
|
36
35
|
}
|
|
37
36
|
onCancel(() => abortController.abort())
|
|
38
|
-
const jsonSchema = validateToJsonSchema(schema.output
|
|
37
|
+
const jsonSchema = validateToJsonSchema(schema.output)
|
|
39
38
|
const { text } = await chat.talk(messages, {
|
|
40
39
|
abortController,
|
|
41
40
|
jsonSchema: {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type ParserFail = {
|
|
2
|
+
name: string
|
|
3
|
+
error: any
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export class ParserError {
|
|
7
|
+
isParserError = true
|
|
8
|
+
parserFails: ParserFail[] = []
|
|
9
|
+
error: any
|
|
10
|
+
constructor(error: any, parserFails: ParserFail[]) {
|
|
11
|
+
this.error = error
|
|
12
|
+
this.parserFails = parserFails
|
|
13
|
+
}
|
|
14
|
+
}
|
package/lib/utils/validate.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as Yup from 'yup'
|
|
2
|
-
import { pick } from 'power-helper'
|
|
3
2
|
import { convertSchema } from '@sodaru/yup-to-json-schema'
|
|
4
|
-
import
|
|
3
|
+
import { Schema } from 'yup'
|
|
5
4
|
|
|
6
5
|
export type ValidateCallback<T extends Record<string, Schema>> = (_yup: typeof Yup) => {
|
|
7
6
|
[K in keyof T]: T[K]
|
|
@@ -27,42 +26,11 @@ export function validate<
|
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* @en Set the JSON Schema description, you can specify deep structures, such as user.name, user.level, etc.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
export type JsonSchemaInfo = {
|
|
36
|
-
desc?: Record<string, string | {
|
|
37
|
-
description?: string
|
|
38
|
-
examples?: any
|
|
39
|
-
}>
|
|
29
|
+
export const definedYupSchema = <T extends ValidateCallback<any>>(cb: T) => {
|
|
30
|
+
return cb(Yup)
|
|
40
31
|
}
|
|
41
32
|
|
|
42
|
-
export const validateToJsonSchema = <T extends ValidateCallback<any>>(cb: T
|
|
43
|
-
const bodySchemaBindDoc = (schema: ReturnType<typeof convertSchema>, doc: JsonSchemaInfo) => {
|
|
44
|
-
if (doc && doc.desc) {
|
|
45
|
-
for (let key in doc.desc) {
|
|
46
|
-
if (schema.properties) {
|
|
47
|
-
let target = pick.peel(schema.properties, key.replaceAll('.', '.properties.'))
|
|
48
|
-
if (target && target !== true) {
|
|
49
|
-
let d = doc.desc[key]
|
|
50
|
-
if (typeof d === 'object') {
|
|
51
|
-
if (d.description) {
|
|
52
|
-
target.description = d.description
|
|
53
|
-
}
|
|
54
|
-
if (d.examples) {
|
|
55
|
-
target.examples = d.examples
|
|
56
|
-
}
|
|
57
|
-
} else if (typeof d === 'string') {
|
|
58
|
-
target.description = d
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return schema
|
|
65
|
-
}
|
|
33
|
+
export const validateToJsonSchema = <T extends ValidateCallback<any>>(cb: T) => {
|
|
66
34
|
const removeAllDefault = (schema: any) => {
|
|
67
35
|
if (schema.default) {
|
|
68
36
|
delete schema.default
|
|
@@ -92,5 +60,5 @@ export const validateToJsonSchema = <T extends ValidateCallback<any>>(cb: T, inf
|
|
|
92
60
|
const jsonSchema = convertSchema(Yup.object(cb(Yup)))
|
|
93
61
|
removeAllDefault(jsonSchema)
|
|
94
62
|
addAllAdditionalProperties(jsonSchema)
|
|
95
|
-
return
|
|
63
|
+
return jsonSchema
|
|
96
64
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctod",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "CtoD Is Chat To Data Utils.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"webpack-node-externals": "^3.0.0"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
+
"yup": "^1.4.0",
|
|
57
58
|
"@sodaru/yup-to-json-schema": "^2.0.1",
|
|
58
59
|
"axios": "^1.4.0",
|
|
59
60
|
"chinese-conv": "^1.1.0",
|
|
60
61
|
"handlebars": "^4.7.7",
|
|
61
62
|
"json5": "^2.2.3",
|
|
62
|
-
"power-helper": "^0.7.
|
|
63
|
-
"yup": "^1.1.1"
|
|
63
|
+
"power-helper": "^0.7.9"
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -2,12 +2,12 @@ import { ChatBrokerPlugin } from '../core/plugin';
|
|
|
2
2
|
import { Event, Hook, Log } from 'power-helper';
|
|
3
3
|
import { Translator, TranslatorParams } from '../core/translator';
|
|
4
4
|
import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate';
|
|
5
|
-
|
|
5
|
+
type Message = {
|
|
6
6
|
role: 'system' | 'user' | 'assistant';
|
|
7
7
|
name?: string;
|
|
8
8
|
content: string;
|
|
9
9
|
};
|
|
10
|
-
export
|
|
10
|
+
export type ChatBrokerHooks<S extends ValidateCallback<any>, O extends ValidateCallback<any>, P extends ChatBrokerPlugin<any, any>, PS extends Record<string, ReturnType<P['use']>>> = {
|
|
11
11
|
/**
|
|
12
12
|
* @zh 第一次聊天的時候觸發
|
|
13
13
|
* @en Triggered when chatting for the first time
|
|
@@ -49,6 +49,11 @@ export declare type ChatBrokerHooks<S extends ValidateCallback<any>, O extends V
|
|
|
49
49
|
messages: Message[];
|
|
50
50
|
parseText: string;
|
|
51
51
|
lastUserMessage: string;
|
|
52
|
+
/**
|
|
53
|
+
* @zh 宣告解析失敗
|
|
54
|
+
* @en Declare parsing failure
|
|
55
|
+
*/
|
|
56
|
+
parseFail: (error: any) => void;
|
|
52
57
|
changeParseText: (text: string) => void;
|
|
53
58
|
};
|
|
54
59
|
/**
|
|
@@ -85,7 +90,7 @@ export declare type ChatBrokerHooks<S extends ValidateCallback<any>, O extends V
|
|
|
85
90
|
id: string;
|
|
86
91
|
};
|
|
87
92
|
};
|
|
88
|
-
|
|
93
|
+
type RequestContext = {
|
|
89
94
|
count: number;
|
|
90
95
|
isRetry: boolean;
|
|
91
96
|
onCancel: (cb: () => void) => void;
|
|
@@ -94,11 +99,11 @@ declare type RequestContext = {
|
|
|
94
99
|
output: any;
|
|
95
100
|
};
|
|
96
101
|
};
|
|
97
|
-
export
|
|
102
|
+
export type Params<S extends ValidateCallback<any>, O extends ValidateCallback<any>, C extends Record<string, any>, P extends ChatBrokerPlugin<any, any>, PS extends Record<string, ReturnType<P['use']>>> = Omit<TranslatorParams<S, O>, 'parsers'> & {
|
|
98
103
|
name?: string;
|
|
99
104
|
plugins?: PS | (() => PS);
|
|
100
105
|
request: (messages: Message[], context: RequestContext) => Promise<string>;
|
|
101
|
-
install
|
|
106
|
+
install?: (context: {
|
|
102
107
|
log: Log;
|
|
103
108
|
attach: Hook<C>['attach'];
|
|
104
109
|
attachAfter: Hook<C>['attachAfter'];
|
|
@@ -2,8 +2,8 @@ import { Translator } from './translator';
|
|
|
2
2
|
import { ChatBrokerHooks } from '../broker/chat';
|
|
3
3
|
import { Log, Hook, Event } from 'power-helper';
|
|
4
4
|
import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
type BrokerHooks = ChatBrokerHooks<any, any, any, any>;
|
|
6
|
+
type BrokerPluginParams<T extends ValidateCallback<any>, R extends ValidateCallback<any>> = {
|
|
7
7
|
name: string;
|
|
8
8
|
params: T;
|
|
9
9
|
receiveData: R;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TextParser } from './parser';
|
|
2
2
|
import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate';
|
|
3
|
-
export
|
|
3
|
+
export type TranslatorParams<S extends ValidateCallback<any>, O extends ValidateCallback<any>> = {
|
|
4
4
|
/**
|
|
5
5
|
* @zh 輸入的資料格式。
|
|
6
6
|
* @en The input data format.
|
|
@@ -25,7 +25,7 @@ export declare type TranslatorParams<S extends ValidateCallback<any>, O extends
|
|
|
25
25
|
input: S;
|
|
26
26
|
output: O;
|
|
27
27
|
};
|
|
28
|
-
}) => Promise<string>;
|
|
28
|
+
}) => Promise<string | string[]>;
|
|
29
29
|
};
|
|
30
30
|
export declare class Translator<S extends ValidateCallback<any>, O extends ValidateCallback<any>> {
|
|
31
31
|
private params;
|
package/types/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * as plugins from './plugins';
|
|
2
2
|
export * as templates from './templates';
|
|
3
|
-
export { validateToJsonSchema,
|
|
3
|
+
export { validateToJsonSchema, definedYupSchema } from './utils/validate';
|
|
4
4
|
export { OpenAI } from './service/openai';
|
|
5
5
|
export { Llama3Cpp } from './service/llama3.cpp';
|
|
6
6
|
export { TextParser } from './core/parser';
|
|
@@ -25,6 +25,9 @@ export declare const ctod: {
|
|
|
25
25
|
Translator: typeof Translator;
|
|
26
26
|
TextParser: typeof TextParser;
|
|
27
27
|
ChatBrokerPlugin: typeof ChatBrokerPlugin;
|
|
28
|
-
|
|
28
|
+
definedYupSchema: <T extends import("./utils/validate").ValidateCallback<any>>(cb: T) => {
|
|
29
|
+
[x: string]: any;
|
|
30
|
+
};
|
|
31
|
+
validateToJsonSchema: <T_1 extends import("./utils/validate").ValidateCallback<any>>(cb: T_1) => import("json-schema").JSONSchema7;
|
|
29
32
|
};
|
|
30
33
|
export default ctod;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @en A plugin based on printing log.
|
|
4
4
|
*/
|
|
5
5
|
export declare const PrintLogPlugin: import("..").ChatBrokerPlugin<(yup: typeof import("yup")) => {
|
|
6
|
-
detail: import("yup").BooleanSchema<boolean, import("yup").AnyObject, false, "d">;
|
|
6
|
+
detail: import("yup").BooleanSchema<boolean | undefined, import("yup").AnyObject, false, "d">;
|
|
7
7
|
}, () => {}>;
|
|
8
8
|
/**
|
|
9
9
|
* @zh 當解析失敗時,會自動重試的對話。
|
|
@@ -11,7 +11,7 @@ export declare const PrintLogPlugin: import("..").ChatBrokerPlugin<(yup: typeof
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const RetryPlugin: import("..").ChatBrokerPlugin<(yup: typeof import("yup")) => {
|
|
13
13
|
retry: import("yup").NumberSchema<number, import("yup").AnyObject, 1, "d">;
|
|
14
|
-
printWarn: import("yup").BooleanSchema<boolean
|
|
14
|
+
printWarn: import("yup").BooleanSchema<NonNullable<boolean | undefined>, import("yup").AnyObject, true, "d">;
|
|
15
15
|
}, () => {}>;
|
|
16
16
|
/**
|
|
17
17
|
* @zh 限制使用流量,這個 plugin 可以有效讓所有對話不會再限制內同時發送,可用於在開發過程中遭遇伺服器因頻率過高而阻擋請求。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChatBrokerPlugin } from '../core/plugin';
|
|
2
2
|
declare const _default: ChatBrokerPlugin<(yup: typeof import("yup")) => {
|
|
3
|
-
detail: import("yup").BooleanSchema<boolean, import("yup").AnyObject, false, "d">;
|
|
3
|
+
detail: import("yup").BooleanSchema<boolean | undefined, import("yup").AnyObject, false, "d">;
|
|
4
4
|
}, () => {}>;
|
|
5
5
|
export default _default;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ChatBrokerPlugin } from '../core/plugin';
|
|
2
2
|
declare const _default: ChatBrokerPlugin<(yup: typeof import("yup")) => {
|
|
3
3
|
retry: import("yup").NumberSchema<number, import("yup").AnyObject, 1, "d">;
|
|
4
|
-
printWarn: import("yup").BooleanSchema<boolean
|
|
4
|
+
printWarn: import("yup").BooleanSchema<NonNullable<boolean | undefined>, import("yup").AnyObject, true, "d">;
|
|
5
5
|
}, () => {}>;
|
|
6
6
|
export default _default;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Llama3Cpp } from './index';
|
|
2
|
-
|
|
2
|
+
type Message = {
|
|
3
3
|
role: string;
|
|
4
4
|
content: string;
|
|
5
5
|
};
|
|
6
|
-
|
|
7
|
-
export
|
|
6
|
+
type Options = any;
|
|
7
|
+
export type Config = {
|
|
8
8
|
baseUrl: string;
|
|
9
9
|
headers: Record<string, string>;
|
|
10
10
|
autoConvertTraditionalChinese: boolean;
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
type Stream = {
|
|
13
13
|
onMessage: (data: {
|
|
14
14
|
message: string;
|
|
15
15
|
}) => void;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { AxiosInstance } from 'axios';
|
|
2
|
-
import { JsonSchemaInfo } from '../../utils/validate';
|
|
3
2
|
import { Llama3CppCompletion, Config } from './completion';
|
|
4
3
|
export declare class Llama3Cpp {
|
|
5
4
|
_axios: AxiosInstance;
|
|
6
5
|
static createChatRequest(params: {
|
|
7
6
|
config: Partial<Config> | (() => Promise<Partial<Config>>);
|
|
8
7
|
talkOptions?: any;
|
|
9
|
-
jsonSchemaInfo?: JsonSchemaInfo;
|
|
10
8
|
}): (messages: any[], { schema, onCancel }: any) => Promise<string>;
|
|
11
9
|
/**
|
|
12
10
|
* @zh 如果你有需要特別設定 axios,請使用這方法。
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { OpenAI } from './index';
|
|
2
2
|
import { PromiseResponseType } from '../../types';
|
|
3
|
-
export
|
|
3
|
+
export type ChatGPTMessage = {
|
|
4
4
|
role: 'system' | 'user' | 'assistant';
|
|
5
5
|
name?: string;
|
|
6
6
|
content: string;
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
type ApiResponse = {
|
|
9
9
|
id: string;
|
|
10
10
|
object: string;
|
|
11
11
|
created: number;
|
|
@@ -24,7 +24,7 @@ declare type ApiResponse = {
|
|
|
24
24
|
total_tokens: number;
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
|
-
export
|
|
27
|
+
export type Config = {
|
|
28
28
|
/**
|
|
29
29
|
* @zh 一次回應數量
|
|
30
30
|
* @en How many chat completion choices to generate for each input message.
|
|
@@ -106,5 +106,5 @@ export declare class OpenAIChat {
|
|
|
106
106
|
nextTalk: (prompt: string | string[]) => Promise<any>;
|
|
107
107
|
}>;
|
|
108
108
|
}
|
|
109
|
-
export
|
|
109
|
+
export type OpenAIChatTalkResponse = PromiseResponseType<OpenAIChat['talk']>;
|
|
110
110
|
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { OpenAI } from './index';
|
|
2
|
-
|
|
2
|
+
type ApiResponse = {
|
|
3
3
|
created: string;
|
|
4
4
|
data: {
|
|
5
5
|
b64_json: string;
|
|
6
6
|
}[];
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
type Config = {
|
|
9
9
|
/**
|
|
10
10
|
* @zh 模型,支援 dall-e-2 和 dall-e-3
|
|
11
11
|
* @en Model, support dall-e-2 and dall-e-3
|
|
@@ -2,7 +2,6 @@ import { AxiosInstance } from 'axios';
|
|
|
2
2
|
import { OpenAIVision } from './vision';
|
|
3
3
|
import { OpenAIChat, Config } from './chat';
|
|
4
4
|
import { OpenAIImagesGeneration } from './images-generation';
|
|
5
|
-
import { JsonSchemaInfo } from '../../utils/validate';
|
|
6
5
|
export declare class OpenAI {
|
|
7
6
|
_axios: AxiosInstance;
|
|
8
7
|
_apiKey: string;
|
|
@@ -10,7 +9,6 @@ export declare class OpenAI {
|
|
|
10
9
|
static createChatRequestWithJsonSchema(params: {
|
|
11
10
|
apiKey: string | (() => Promise<string>);
|
|
12
11
|
config?: Partial<Config> | (() => Promise<Partial<Config>>);
|
|
13
|
-
jsonSchemaInfo?: JsonSchemaInfo;
|
|
14
12
|
}): (messages: any[], { schema, onCancel }: any) => Promise<string>;
|
|
15
13
|
constructor(apiKey?: string);
|
|
16
14
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OpenAI } from './index';
|
|
2
2
|
import { PromiseResponseType } from '../../types';
|
|
3
|
-
|
|
3
|
+
type ImageContent = {
|
|
4
4
|
type: 'image_url' | 'text';
|
|
5
5
|
text?: string;
|
|
6
6
|
image_url?: {
|
|
@@ -8,12 +8,12 @@ declare type ImageContent = {
|
|
|
8
8
|
detail?: string;
|
|
9
9
|
};
|
|
10
10
|
};
|
|
11
|
-
|
|
11
|
+
type VisionMessage = {
|
|
12
12
|
role: 'system' | 'user' | 'assistant';
|
|
13
13
|
name?: string;
|
|
14
14
|
content: string | ImageContent[];
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
type ApiResponse = {
|
|
17
17
|
id: string;
|
|
18
18
|
object: string;
|
|
19
19
|
created: number;
|
|
@@ -34,7 +34,7 @@ declare type ApiResponse = {
|
|
|
34
34
|
index: number;
|
|
35
35
|
}>;
|
|
36
36
|
};
|
|
37
|
-
export
|
|
37
|
+
export type Config = {
|
|
38
38
|
/**
|
|
39
39
|
* @zh 選擇運行的模型。
|
|
40
40
|
* @en How many chat completion choices to generate for each input message.
|
|
@@ -70,5 +70,5 @@ export declare class OpenAIVision {
|
|
|
70
70
|
apiReseponse: ApiResponse;
|
|
71
71
|
}>;
|
|
72
72
|
}
|
|
73
|
-
export
|
|
73
|
+
export type OpenAIChatVisionResponse = PromiseResponseType<OpenAIVision['view']>;
|
|
74
74
|
export {};
|
package/types/lib/templates.d.ts
CHANGED
package/types/lib/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type PromiseResponseType<T extends (...args: any) => Promise<any>, R = Parameters<ReturnType<T>['then']>[0]> = R extends (value: infer P) => any ? P : never;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as Yup from 'yup';
|
|
2
|
-
import
|
|
3
|
-
export
|
|
2
|
+
import { Schema } from 'yup';
|
|
3
|
+
export type ValidateCallback<T extends Record<string, Schema>> = (_yup: typeof Yup) => {
|
|
4
4
|
[K in keyof T]: T[K];
|
|
5
5
|
};
|
|
6
|
-
export
|
|
6
|
+
export type ValidateCallbackOutputs<T extends ValidateCallback<any>, R = ReturnType<T>> = {
|
|
7
7
|
[K in keyof R]: R[K] extends {
|
|
8
8
|
'__outputType': any;
|
|
9
9
|
} ? R[K]['__outputType'] : unknown;
|
|
@@ -12,14 +12,7 @@ export declare function definedValidateSchema<T extends ValidateCallback<any>>(c
|
|
|
12
12
|
export declare function validate<T extends ValidateCallback<any>, R = ReturnType<T>>(target: any, schemaCallback: T): { [K in keyof R]: R[K] extends {
|
|
13
13
|
__outputType: any;
|
|
14
14
|
} ? R[K]["__outputType"] : unknown; };
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* @en Set the JSON Schema description, you can specify deep structures, such as user.name, user.level, etc.
|
|
18
|
-
*/
|
|
19
|
-
export declare type JsonSchemaInfo = {
|
|
20
|
-
desc?: Record<string, string | {
|
|
21
|
-
description?: string;
|
|
22
|
-
examples?: any;
|
|
23
|
-
}>;
|
|
15
|
+
export declare const definedYupSchema: <T extends ValidateCallback<any>>(cb: T) => {
|
|
16
|
+
[x: string]: any;
|
|
24
17
|
};
|
|
25
|
-
export declare const validateToJsonSchema: <T extends ValidateCallback<any>>(cb: T
|
|
18
|
+
export declare const validateToJsonSchema: <T extends ValidateCallback<any>>(cb: T) => import("json-schema").JSONSchema7;
|
package/webpack.config.ts
CHANGED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
2
|
-
/// <reference path="../lib/shims.d.ts" />
|
|
3
|
-
import { ChatBroker, OpenAI } from '../lib/index'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @test npx ts-node ./examples/chat-demo.ts
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const API_KEY = ''
|
|
10
|
-
const broker = new ChatBroker({
|
|
11
|
-
input: yup => {
|
|
12
|
-
return {
|
|
13
|
-
indexs: yup.array(yup.string()).required(),
|
|
14
|
-
question: yup.string().required()
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
output: yup => {
|
|
18
|
-
return {
|
|
19
|
-
indexs: yup.array(yup.object({
|
|
20
|
-
name: yup.string().required(),
|
|
21
|
-
score: yup.number().required()
|
|
22
|
-
})).required()
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
install: () => null,
|
|
26
|
-
request: OpenAI.createChatRequestWithJsonSchema({
|
|
27
|
-
apiKey: API_KEY,
|
|
28
|
-
config: {
|
|
29
|
-
model: 'gpt-4o-mini'
|
|
30
|
-
},
|
|
31
|
-
jsonSchemaInfo: {
|
|
32
|
-
desc: {
|
|
33
|
-
indexs: '由高到低排序的索引'
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}),
|
|
37
|
-
question: async({ indexs, question }) => {
|
|
38
|
-
return [
|
|
39
|
-
'我有以下索引',
|
|
40
|
-
`${JSON.stringify(indexs)}`,
|
|
41
|
-
`請幫我解析"${question}"可能是哪個索引`,
|
|
42
|
-
'且相關性由高到低排序並給予分數,分數由 0 ~ 1'
|
|
43
|
-
].join('\n')
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
broker.request({
|
|
48
|
-
indexs: ['胃痛', '腰痛', '頭痛', '喉嚨痛', '四肢疼痛'],
|
|
49
|
-
question: '喝咖啡,吃甜食,胃食道逆流'
|
|
50
|
-
}).then(e => {
|
|
51
|
-
console.log('輸出結果:', e.indexs)
|
|
52
|
-
/*
|
|
53
|
-
[
|
|
54
|
-
{
|
|
55
|
-
name: '胃痛',
|
|
56
|
-
score: 1
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: '喉嚨痛',
|
|
60
|
-
score: 0.7
|
|
61
|
-
},
|
|
62
|
-
...
|
|
63
|
-
]
|
|
64
|
-
*/
|
|
65
|
-
}).catch(error => {
|
|
66
|
-
console.error('Error:', error?.response?.data?.error?.message ?? error)
|
|
67
|
-
})
|