@maiyunnet/kebab 3.2.28 → 3.2.30
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/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/core.d.ts +7 -0
- package/lib/core.js +19 -0
- package/lib/db.d.ts +3 -0
- package/lib/db.js +12 -7
- package/lib/kv.d.ts +6 -5
- package/lib/kv.js +7 -6
- package/lib/session.d.ts +1 -0
- package/lib/session.js +9 -2
- package/package.json +1 -1
- package/sys/child.js +2 -0
- package/sys/ctr.d.ts +2 -2
- package/sys/ctr.js +3 -3
- package/sys/route.js +1 -1
- package/www/example/ctr/test.d.ts +2 -0
- package/www/example/ctr/test.js +119 -6
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '3.2.
|
|
9
|
+
export const VER = '3.2.30';
|
|
10
10
|
// --- 服务端用的路径 ---
|
|
11
11
|
const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
|
|
12
12
|
/** --- /xxx/xxx --- */
|
package/lib/core.d.ts
CHANGED
|
@@ -249,3 +249,10 @@ export declare function display(message?: any, ...optionalParams: any[]): void;
|
|
|
249
249
|
* @param headers 头部
|
|
250
250
|
*/
|
|
251
251
|
export declare function writeHead(res: http2.Http2ServerResponse | http.ServerResponse, statusCode: number, headers?: http.OutgoingHttpHeaders): void;
|
|
252
|
+
export declare function writeEventStreamHead(res: http2.Http2ServerResponse | http.ServerResponse): void;
|
|
253
|
+
/**
|
|
254
|
+
* --- 向 res 发送数据 ---
|
|
255
|
+
* @param res 响应对象
|
|
256
|
+
* @param data 数据
|
|
257
|
+
*/
|
|
258
|
+
export declare function write(res: http2.Http2ServerResponse | http.ServerResponse, data: string | Buffer): void;
|
package/lib/core.js
CHANGED
|
@@ -806,3 +806,22 @@ export function writeHead(res, statusCode, headers) {
|
|
|
806
806
|
res.writeHead(statusCode, headers);
|
|
807
807
|
}
|
|
808
808
|
}
|
|
809
|
+
export function writeEventStreamHead(res) {
|
|
810
|
+
writeHead(res, 200, {
|
|
811
|
+
'content-type': 'text/event-stream; charset=utf-8',
|
|
812
|
+
'cache-control': 'no-store',
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* --- 向 res 发送数据 ---
|
|
817
|
+
* @param res 响应对象
|
|
818
|
+
* @param data 数据
|
|
819
|
+
*/
|
|
820
|
+
export function write(res, data) {
|
|
821
|
+
if (res instanceof http2.Http2ServerResponse) {
|
|
822
|
+
res.write(data);
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
res.write(data);
|
|
826
|
+
}
|
|
827
|
+
}
|
package/lib/db.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface IData {
|
|
|
15
15
|
'errno': number;
|
|
16
16
|
[key: string]: any;
|
|
17
17
|
} | null;
|
|
18
|
+
/** --- 1-正常,-500-服务器错误 --- */
|
|
19
|
+
'result': number;
|
|
18
20
|
}
|
|
19
21
|
/** --- exec 返回对象 --- */
|
|
20
22
|
export interface IPacket {
|
|
@@ -49,6 +51,7 @@ export declare class Pool {
|
|
|
49
51
|
* --- 执行一条 SQL,无视顺序和相同连接,随用随取 ---
|
|
50
52
|
* @param sql 执行的 SQL 字符串
|
|
51
53
|
* @param values 要替换的 data 数据
|
|
54
|
+
* @returns error.errno = -500 表示系统错误
|
|
52
55
|
*/
|
|
53
56
|
query(sql: string, values?: kebab.DbValue[]): Promise<IData>;
|
|
54
57
|
/**
|
package/lib/db.js
CHANGED
|
@@ -79,6 +79,7 @@ export class Pool {
|
|
|
79
79
|
* --- 执行一条 SQL,无视顺序和相同连接,随用随取 ---
|
|
80
80
|
* @param sql 执行的 SQL 字符串
|
|
81
81
|
* @param values 要替换的 data 数据
|
|
82
|
+
* @returns error.errno = -500 表示系统错误
|
|
82
83
|
*/
|
|
83
84
|
async query(sql, values) {
|
|
84
85
|
++this._queries;
|
|
@@ -89,9 +90,10 @@ export class Pool {
|
|
|
89
90
|
'rows': null,
|
|
90
91
|
'fields': [],
|
|
91
92
|
'error': {
|
|
92
|
-
'message': '
|
|
93
|
-
'errno': 0
|
|
94
|
-
}
|
|
93
|
+
'message': 'false',
|
|
94
|
+
'errno': 0,
|
|
95
|
+
},
|
|
96
|
+
'result': -500,
|
|
95
97
|
};
|
|
96
98
|
}
|
|
97
99
|
// --- 执行一次后自动解除 using ---
|
|
@@ -237,9 +239,10 @@ export class Transaction {
|
|
|
237
239
|
'rows': null,
|
|
238
240
|
'fields': [],
|
|
239
241
|
'error': {
|
|
240
|
-
'message': '
|
|
242
|
+
'message': 'false',
|
|
241
243
|
'errno': 0
|
|
242
|
-
}
|
|
244
|
+
},
|
|
245
|
+
'result': -500,
|
|
243
246
|
};
|
|
244
247
|
}
|
|
245
248
|
++this._queries;
|
|
@@ -439,7 +442,8 @@ export class Connection {
|
|
|
439
442
|
return {
|
|
440
443
|
'rows': null,
|
|
441
444
|
'fields': [],
|
|
442
|
-
'error': e
|
|
445
|
+
'error': e,
|
|
446
|
+
'result': -500,
|
|
443
447
|
};
|
|
444
448
|
}
|
|
445
449
|
if (!this._transaction) {
|
|
@@ -449,7 +453,8 @@ export class Connection {
|
|
|
449
453
|
return {
|
|
450
454
|
'rows': res[0],
|
|
451
455
|
'fields': res[1],
|
|
452
|
-
'error': null
|
|
456
|
+
'error': null,
|
|
457
|
+
'result': 1,
|
|
453
458
|
};
|
|
454
459
|
}
|
|
455
460
|
/**
|
package/lib/kv.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export declare class Pool {
|
|
|
62
62
|
* --- 获取字符串 ---
|
|
63
63
|
* @param key
|
|
64
64
|
*/
|
|
65
|
-
get(key: string): Promise<string | null>;
|
|
65
|
+
get(key: string): Promise<string | false | null>;
|
|
66
66
|
/**
|
|
67
67
|
* --- 获取相应的剩余有效期秒数 ---
|
|
68
68
|
* @param key
|
|
@@ -86,8 +86,9 @@ export declare class Pool {
|
|
|
86
86
|
/**
|
|
87
87
|
* --- 获取 json 对象 ---
|
|
88
88
|
* @param key
|
|
89
|
+
* @returns false 表示系统错误, null 表示不存在, 其他值为 json 对象
|
|
89
90
|
*/
|
|
90
|
-
getJson(key: string): Promise<any | null>;
|
|
91
|
+
getJson(key: string): Promise<any | false | null>;
|
|
91
92
|
/**
|
|
92
93
|
* --- 删除已存在的值 ---
|
|
93
94
|
* @param keys
|
|
@@ -301,9 +302,9 @@ export declare class Connection {
|
|
|
301
302
|
* --- 获取字符串 ---
|
|
302
303
|
* @param key
|
|
303
304
|
* @param etc
|
|
304
|
-
* @returns
|
|
305
|
+
* @returns 字符串 / false / null(即使存入时是 number,这个方法也只会返回字符串)
|
|
305
306
|
*/
|
|
306
|
-
get(key: string, etc: kebab.IConfigKv): Promise<string | null>;
|
|
307
|
+
get(key: string, etc: kebab.IConfigKv): Promise<string | false | null>;
|
|
307
308
|
/**
|
|
308
309
|
* --- 获取相应的剩余有效期秒数 ---
|
|
309
310
|
* @param key
|
|
@@ -334,7 +335,7 @@ export declare class Connection {
|
|
|
334
335
|
* @param key
|
|
335
336
|
* @param etc
|
|
336
337
|
*/
|
|
337
|
-
getJson(key: string, etc: kebab.IConfigKv): Promise<any | null>;
|
|
338
|
+
getJson(key: string, etc: kebab.IConfigKv): Promise<any | false | null>;
|
|
338
339
|
/**
|
|
339
340
|
* --- 删除已存在的值 ---
|
|
340
341
|
* @param keys
|
package/lib/kv.js
CHANGED
|
@@ -236,11 +236,12 @@ export class Pool {
|
|
|
236
236
|
/**
|
|
237
237
|
* --- 获取 json 对象 ---
|
|
238
238
|
* @param key
|
|
239
|
+
* @returns false 表示系统错误, null 表示不存在, 其他值为 json 对象
|
|
239
240
|
*/
|
|
240
241
|
async getJson(key) {
|
|
241
242
|
const conn = await this._getConnection();
|
|
242
243
|
if (!conn) {
|
|
243
|
-
return
|
|
244
|
+
return false;
|
|
244
245
|
}
|
|
245
246
|
const r = await conn.getJson(key, this._etc);
|
|
246
247
|
conn.used();
|
|
@@ -823,7 +824,7 @@ end`;
|
|
|
823
824
|
* --- 获取字符串 ---
|
|
824
825
|
* @param key
|
|
825
826
|
* @param etc
|
|
826
|
-
* @returns
|
|
827
|
+
* @returns 字符串 / false / null(即使存入时是 number,这个方法也只会返回字符串)
|
|
827
828
|
*/
|
|
828
829
|
async get(key, etc) {
|
|
829
830
|
this.refreshLast();
|
|
@@ -831,7 +832,7 @@ end`;
|
|
|
831
832
|
return await this._link.get(etc.pre + key);
|
|
832
833
|
}
|
|
833
834
|
catch {
|
|
834
|
-
return
|
|
835
|
+
return false;
|
|
835
836
|
}
|
|
836
837
|
}
|
|
837
838
|
/**
|
|
@@ -917,11 +918,11 @@ end`;
|
|
|
917
918
|
*/
|
|
918
919
|
async getJson(key, etc) {
|
|
919
920
|
const v = await this.get(key, etc);
|
|
920
|
-
if (v === null) {
|
|
921
|
-
return
|
|
921
|
+
if (v === null || v === false) {
|
|
922
|
+
return v;
|
|
922
923
|
}
|
|
923
924
|
const r = lText.parseJson(v);
|
|
924
|
-
return r
|
|
925
|
+
return r;
|
|
925
926
|
}
|
|
926
927
|
/**
|
|
927
928
|
* --- 删除已存在的值 ---
|
package/lib/session.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare class Session {
|
|
|
31
31
|
* @param link Kv 或 Db 实例
|
|
32
32
|
* @param auth 设为 true 则优先从头 Authorization 或 post _auth 值读取 token
|
|
33
33
|
* @param opt 选项
|
|
34
|
+
* @returns false 表示系统错误
|
|
34
35
|
*/
|
|
35
36
|
init(ctr: ctr.Ctr, link: db.Pool | kv.Pool, auth?: boolean, opt?: IOptions): Promise<boolean>;
|
|
36
37
|
/**
|
package/lib/session.js
CHANGED
|
@@ -36,6 +36,7 @@ export class Session {
|
|
|
36
36
|
* @param link Kv 或 Db 实例
|
|
37
37
|
* @param auth 设为 true 则优先从头 Authorization 或 post _auth 值读取 token
|
|
38
38
|
* @param opt 选项
|
|
39
|
+
* @returns false 表示系统错误
|
|
39
40
|
*/
|
|
40
41
|
async init(ctr, link, auth = false, opt = {}) {
|
|
41
42
|
const config = ctr.getPrototype('_config');
|
|
@@ -68,10 +69,13 @@ export class Session {
|
|
|
68
69
|
// --- 如果启用了内存加速则在内存找 ---
|
|
69
70
|
if (this._link instanceof kv.Pool) {
|
|
70
71
|
// --- Kv ---
|
|
71
|
-
|
|
72
|
-
if (
|
|
72
|
+
const data = await this._link.getJson(this._name + '_' + this._token);
|
|
73
|
+
if (data === null) {
|
|
73
74
|
needInsert = true;
|
|
74
75
|
}
|
|
76
|
+
else if (data === false) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
75
79
|
else {
|
|
76
80
|
session = data;
|
|
77
81
|
}
|
|
@@ -86,6 +90,9 @@ export class Session {
|
|
|
86
90
|
if (data.rows?.[0]) {
|
|
87
91
|
session = text.parseJson(data.rows[0].data);
|
|
88
92
|
}
|
|
93
|
+
else if (data.result === -500) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
89
96
|
else {
|
|
90
97
|
needInsert = true;
|
|
91
98
|
}
|
package/package.json
CHANGED
package/sys/child.js
CHANGED
package/sys/ctr.d.ts
CHANGED
|
@@ -58,7 +58,7 @@ export declare class Ctr {
|
|
|
58
58
|
protected _localeData: Record<string, Record<string, string>>;
|
|
59
59
|
constructor(config: kebab.IConfig, req: http2.Http2ServerRequest | http.IncomingMessage, res?: http2.Http2ServerResponse | http.ServerResponse);
|
|
60
60
|
/** --- 当前用户连接是否还在连接中 --- */
|
|
61
|
-
get
|
|
61
|
+
protected get _isAvail(): boolean;
|
|
62
62
|
/** --- timeout 的 timer --- */
|
|
63
63
|
protected _timer?: {
|
|
64
64
|
'timer': NodeJS.Timeout;
|
|
@@ -206,7 +206,7 @@ export declare class Ctr {
|
|
|
206
206
|
* @param auth 设为 true 则从头 Authorization 或 post _auth 值读取 token
|
|
207
207
|
* @param opt name, ttl, ssl, sqlPre
|
|
208
208
|
*/
|
|
209
|
-
protected _startSession(link: lDb.Pool | lKv.Pool, auth?: boolean, opt?: lSession.IOptions): Promise<
|
|
209
|
+
protected _startSession(link: lDb.Pool | lKv.Pool, auth?: boolean, opt?: lSession.IOptions): Promise<boolean>;
|
|
210
210
|
/**
|
|
211
211
|
* --- 设定语言并加载语言包 ---
|
|
212
212
|
* @param loc 要加载的目标语言
|
package/sys/ctr.js
CHANGED
|
@@ -78,7 +78,7 @@ export class Ctr {
|
|
|
78
78
|
this._cacheTTL = config.set.cacheTtl;
|
|
79
79
|
}
|
|
80
80
|
/** --- 当前用户连接是否还在连接中 --- */
|
|
81
|
-
get
|
|
81
|
+
get _isAvail() {
|
|
82
82
|
return this._req.socket.writable;
|
|
83
83
|
}
|
|
84
84
|
/** --- 获取当前过期时间 --- */
|
|
@@ -603,9 +603,9 @@ export class Ctr {
|
|
|
603
603
|
* @param auth 设为 true 则从头 Authorization 或 post _auth 值读取 token
|
|
604
604
|
* @param opt name, ttl, ssl, sqlPre
|
|
605
605
|
*/
|
|
606
|
-
|
|
606
|
+
_startSession(link, auth = false, opt = {}) {
|
|
607
607
|
this._sess = new lSession.Session();
|
|
608
|
-
|
|
608
|
+
return this._sess.init(this, link, auth, opt);
|
|
609
609
|
}
|
|
610
610
|
// --- 本地化 ---
|
|
611
611
|
/**
|
package/sys/route.js
CHANGED
|
@@ -505,7 +505,7 @@ export async function run(data) {
|
|
|
505
505
|
pathRight = pathRight.replace(/-([a-zA-Z0-9])/g, function (t, t1) {
|
|
506
506
|
return t1.toUpperCase();
|
|
507
507
|
});
|
|
508
|
-
if (cctr[pathRight] === undefined) {
|
|
508
|
+
if ((cctr[pathRight] === undefined) || (typeof cctr[pathRight] !== 'function')) {
|
|
509
509
|
if (config.route['#404']) {
|
|
510
510
|
data.res.setHeader('location', lText.urlResolve(config.const.urlBase, config.route['#404']));
|
|
511
511
|
lCore.writeHead(data.res, 302);
|
package/www/example/ctr/test.js
CHANGED
|
@@ -128,6 +128,7 @@ export default class extends sCtr.Ctr {
|
|
|
128
128
|
'<br><br><b>Library test:</b>',
|
|
129
129
|
`<br><br><b>Ai:</b>`,
|
|
130
130
|
`<br><br><a href="${this._config.const.urlBase}test/ai">View "test/ai"</a>`,
|
|
131
|
+
`<br><a href="${this._config.const.urlBase}test/ai-stream">View "test/ai-stream"</a>`,
|
|
131
132
|
'<br><br><b>Core:</b>',
|
|
132
133
|
`<br><br><a href="${this._config.const.urlBase}test/core-random">View "test/core-random"</a>`,
|
|
133
134
|
`<br><a href="${this._config.const.urlBase}test/core-rand">View "test/core-rand"</a>`,
|
|
@@ -2133,8 +2134,8 @@ function confirm() {
|
|
|
2133
2134
|
echo.push('link = lKv.get(this);\n');
|
|
2134
2135
|
}
|
|
2135
2136
|
if (this._get['auth'] === '') {
|
|
2136
|
-
await this._startSession(link, false, { 'ttl': 60 });
|
|
2137
|
-
echo.push(`await this._startSession(link, false, {'ttl': 60});
|
|
2137
|
+
const r = await this._startSession(link, false, { 'ttl': 60 });
|
|
2138
|
+
echo.push(`await this._startSession(link, false, {'ttl': 60}); // ${r}
|
|
2138
2139
|
JSON.stringify(this._session);</pre>` + lText.htmlescape(JSON.stringify(this._session)));
|
|
2139
2140
|
this._session['value'] = lText.logicalOr(this._get['value'], 'ok');
|
|
2140
2141
|
echo.push(`<pre>this._session['value'] = '${lText.logicalOr(this._get['value'], 'ok')}';
|
|
@@ -2146,7 +2147,7 @@ JSON.stringify(this._session);</pre>` + lText.htmlescape(JSON.stringify(this._se
|
|
|
2146
2147
|
}
|
|
2147
2148
|
else {
|
|
2148
2149
|
// --- AUTH 模式 ---
|
|
2149
|
-
await this._startSession(link, true, { 'ttl': 60 });
|
|
2150
|
+
const r = await this._startSession(link, true, { 'ttl': 60 });
|
|
2150
2151
|
if (Object.keys(this._post).length > 0) {
|
|
2151
2152
|
if (this._session['count'] === undefined) {
|
|
2152
2153
|
this._session['count'] = 1;
|
|
@@ -2157,7 +2158,7 @@ JSON.stringify(this._session);</pre>` + lText.htmlescape(JSON.stringify(this._se
|
|
|
2157
2158
|
return [1, { 'txt': 'this._session: ' + JSON.stringify(this._session) + '\nToken: ' + this._sess.getToken(), 'token': this._sess?.getToken(), '_auth': this._getBasicAuth('token', this._sess.getToken()) }];
|
|
2158
2159
|
}
|
|
2159
2160
|
else {
|
|
2160
|
-
echo.push(`await this._startSession(link, true, {'ttl': 60});
|
|
2161
|
+
echo.push(`await this._startSession(link, true, {'ttl': 60}); // ${r}
|
|
2161
2162
|
JSON.stringify(this._session));</pre>` + lText.htmlescape(JSON.stringify(this._session)));
|
|
2162
2163
|
this._session['value'] = lTime.format(this, 'H:i:s');
|
|
2163
2164
|
echo.push(`<pre>this._session['value'] = '${lTime.format(this, 'H:i:s')}';
|
|
@@ -3128,18 +3129,130 @@ rtn.push(reader.readBCDString());</pre>${JSON.stringify(rtn)}`);
|
|
|
3128
3129
|
'model': 'qwen-plus',
|
|
3129
3130
|
'messages': [
|
|
3130
3131
|
{ 'role': 'system', 'content': 'You are Kebab, a friendly and knowledgeable assistant based on an open-source Node framework. You do not mention any model names or AI identity. You can chat casually, answer questions, and provide guidance naturally. Respond in a human-like, approachable manner, as if you are a helpful companion rather than a traditional AI assistant.' },
|
|
3131
|
-
{ 'role': 'user', 'content': '你是谁?' }
|
|
3132
|
+
{ 'role': 'user', 'content': '你是谁?' },
|
|
3132
3133
|
],
|
|
3133
3134
|
});
|
|
3134
3135
|
echo.push(`<pre>await ai.link.chat.completions.create({
|
|
3135
3136
|
'model': 'qwen-plus',
|
|
3136
3137
|
'messages': [
|
|
3137
3138
|
{ 'role': 'system', 'content': 'You are Kebab, a friendly and knowledgeable assistant based on an open-source Node framework. You do not mention any model names or AI identity. You can chat casually, answer questions, and provide guidance naturally. Respond in a human-like, approachable manner, as if you are a helpful companion rather than a traditional AI assistant.' },
|
|
3138
|
-
{ 'role': 'user', 'content': '你是谁?' }
|
|
3139
|
+
{ 'role': 'user', 'content': '你是谁?' },
|
|
3139
3140
|
],
|
|
3140
3141
|
});</pre>` + JSON.stringify(completion.choices[0].message.content));
|
|
3141
3142
|
return echo.join('') + '<br><br>' + this._getEnd();
|
|
3142
3143
|
}
|
|
3144
|
+
aiStream() {
|
|
3145
|
+
const echo = `<input id="text" type="text"><button id="send">Send</button>
|
|
3146
|
+
<hr>
|
|
3147
|
+
<div id="content"></div>
|
|
3148
|
+
<script>
|
|
3149
|
+
let controller;
|
|
3150
|
+
const text = document.getElementById('text');
|
|
3151
|
+
const send = document.getElementById('send');
|
|
3152
|
+
const content = document.getElementById('content');
|
|
3153
|
+
send.addEventListener('click', async () => {
|
|
3154
|
+
if (send.innerHTML === 'Stop') {
|
|
3155
|
+
controller.abort();
|
|
3156
|
+
return;
|
|
3157
|
+
}
|
|
3158
|
+
if (!text.value) {
|
|
3159
|
+
alert('Please input content');
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
3162
|
+
send.innerHTML = 'Stop';
|
|
3163
|
+
send.disabled = true;
|
|
3164
|
+
controller = new AbortController();
|
|
3165
|
+
const res = await fetch('http${this._config.const.https ? 's' : ''}://${this._config.const.host}/test/ai-stream1', {
|
|
3166
|
+
'method': 'POST',
|
|
3167
|
+
'headers': { 'content-type': 'application/json' },
|
|
3168
|
+
'body': JSON.stringify({ 'content': text.value, }),
|
|
3169
|
+
'signal': controller.signal,
|
|
3170
|
+
});
|
|
3171
|
+
send.disabled = false;
|
|
3172
|
+
text.value = '';
|
|
3173
|
+
content.textContent = '';
|
|
3174
|
+
const reader = res.body.getReader();
|
|
3175
|
+
const decoder = new TextDecoder('utf8');
|
|
3176
|
+
let buf = '';
|
|
3177
|
+
while (true) {
|
|
3178
|
+
try {
|
|
3179
|
+
const { value, done } = await reader.read();
|
|
3180
|
+
if (done) {
|
|
3181
|
+
break;
|
|
3182
|
+
}
|
|
3183
|
+
buf += decoder.decode(value, { 'stream': true, });
|
|
3184
|
+
if (!buf.includes('\\n\\n')) {
|
|
3185
|
+
// --- 还没接收完 ---
|
|
3186
|
+
continue;
|
|
3187
|
+
}
|
|
3188
|
+
const events = buf.split('\\n\\n');
|
|
3189
|
+
buf = events.pop(); // --- 最后一个可能不完整 ---
|
|
3190
|
+
for (const ev of events) {
|
|
3191
|
+
content.textContent += JSON.parse(ev.slice(5).trim());
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
catch {
|
|
3195
|
+
break;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
send.innerHTML = 'Send';
|
|
3199
|
+
});
|
|
3200
|
+
</script>`;
|
|
3201
|
+
return echo + '<br>' + this._getEnd();
|
|
3202
|
+
}
|
|
3203
|
+
async aiStream1() {
|
|
3204
|
+
if (!this._cross()) {
|
|
3205
|
+
return '';
|
|
3206
|
+
}
|
|
3207
|
+
if (!this._post['content']) {
|
|
3208
|
+
return '';
|
|
3209
|
+
}
|
|
3210
|
+
const ai = lAi.get(this, {
|
|
3211
|
+
'service': lAi.ESERVICE.ALICN,
|
|
3212
|
+
});
|
|
3213
|
+
const stream = await ai.link.chat.completions.create({
|
|
3214
|
+
'model': 'qwen-plus',
|
|
3215
|
+
'stream': true,
|
|
3216
|
+
'messages': [
|
|
3217
|
+
{ 'role': 'system', 'content': 'You are Kebab, a friendly and knowledgeable assistant based on an open-source Node framework. You do not mention any model names or AI identity. You can chat casually, answer questions, and provide guidance naturally. Respond in a human-like, approachable manner, as if you are a helpful companion rather than a traditional AI assistant.' },
|
|
3218
|
+
{ 'role': 'user', 'content': this._post['content'] },
|
|
3219
|
+
],
|
|
3220
|
+
'stream_options': {
|
|
3221
|
+
'include_usage': true,
|
|
3222
|
+
},
|
|
3223
|
+
});
|
|
3224
|
+
lCore.writeEventStreamHead(this._res);
|
|
3225
|
+
for await (const chunk of stream) {
|
|
3226
|
+
if (!this._isAvail) {
|
|
3227
|
+
lCore.debug('Client disconnect');
|
|
3228
|
+
stream.controller.abort();
|
|
3229
|
+
break;
|
|
3230
|
+
}
|
|
3231
|
+
if (chunk.choices.length) {
|
|
3232
|
+
const content = chunk.choices[0].delta.content;
|
|
3233
|
+
if (!content) {
|
|
3234
|
+
continue;
|
|
3235
|
+
}
|
|
3236
|
+
if (!this._isAvail) {
|
|
3237
|
+
// --- 测试上面 abort 后不 break 的话还会执行到这里吗 ---
|
|
3238
|
+
// --- 测试结果:可能会,大概率只有一次,就证明连接确实断开了只不过有延迟 ---
|
|
3239
|
+
// --- 但上面 break 的话就肯定不会执行到这里了 ---
|
|
3240
|
+
lCore.debug('Client has been closed', content);
|
|
3241
|
+
continue;
|
|
3242
|
+
}
|
|
3243
|
+
lCore.write(this._res, 'data: ' + JSON.stringify(content) + '\n\n');
|
|
3244
|
+
continue;
|
|
3245
|
+
}
|
|
3246
|
+
if (!chunk.usage) {
|
|
3247
|
+
continue;
|
|
3248
|
+
}
|
|
3249
|
+
lCore.debug('--- All over ---');
|
|
3250
|
+
lCore.debug(`Input Tokens: ${chunk.usage.prompt_tokens}`);
|
|
3251
|
+
lCore.debug(`Output Tokens: ${chunk.usage.completion_tokens}`);
|
|
3252
|
+
lCore.debug(`Total Tokens: ${chunk.usage.total_tokens}`);
|
|
3253
|
+
}
|
|
3254
|
+
lCore.debug('AI DONE');
|
|
3255
|
+
}
|
|
3143
3256
|
/**
|
|
3144
3257
|
* --- END ---
|
|
3145
3258
|
*/
|