alemonjs-aichat 1.0.13 → 1.0.15
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 +68 -12
- package/lib/api.js +234 -37
- package/lib/assets/main.css-CXQ9gyIo.css +1 -0
- package/lib/assets/main.css.js +1 -1
- package/lib/config.js +75 -28
- package/lib/data/help.json.js +47 -3
- package/lib/data/ttsmodels.json.js +4992 -0
- package/lib/image/conponent/help.js +3 -1
- package/lib/index.js +5 -2
- package/lib/middleware/mw.js +97 -3
- package/lib/response/affection/res.js +2 -2
- package/lib/response/config/res.js +12 -7
- package/lib/response/setting/res.js +40 -6
- package/lib/response/tools/res.js +287 -0
- package/lib/response/zreply/res.js +217 -122
- package/lib/s3.js +237 -51
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -1,39 +1,95 @@
|
|
|
1
1
|
|
|
2
2
|
## 1.安装
|
|
3
3
|
|
|
4
|
+
安装中遇到问题可访问alemonjs官网查询[https://alemonjs.com/docs](https://alemonjs.com/docs)
|
|
5
|
+
|
|
4
6
|
### yarn安装方式(推荐)
|
|
7
|
+
前置条件:
|
|
8
|
+
安装alemonjs: [alemonjs官网](https://alemonjs.com)
|
|
5
9
|
|
|
6
|
-
```
|
|
10
|
+
``` sh
|
|
7
11
|
yarn add alemonjs-aichat
|
|
8
12
|
```
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
https://gitee.com/suancaixianyu/alemonjs-aichat.git
|
|
14
|
+
```sh
|
|
15
|
+
## 运行
|
|
16
|
+
yarn start
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
### git拉取项目安装
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
git clone git@gitee.com:suancaixianyu/alemonjs-aichat.git
|
|
23
|
+
cd alemonjs-aichat
|
|
24
|
+
yarn
|
|
18
25
|
```
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
## 运行
|
|
29
|
+
yarn dev
|
|
30
|
+
|
|
31
|
+
## 打包
|
|
32
|
+
yarn build
|
|
20
33
|
```
|
|
21
34
|
|
|
22
|
-
## 2
|
|
23
|
-
|
|
35
|
+
## 2.配置
|
|
36
|
+
|
|
37
|
+
#### 配置app
|
|
38
|
+
在配置中添加该插件, 才能正常触发指令
|
|
39
|
+
|
|
40
|
+
如果使用的是git拉取项目的方式, 就不需要配置这个
|
|
24
41
|
``` yaml
|
|
25
42
|
app:
|
|
26
43
|
- 'alemonjs-aichat'
|
|
27
44
|
```
|
|
28
45
|
|
|
29
|
-
|
|
46
|
+
#### 配置redis
|
|
30
47
|
`alemon.config.yaml`
|
|
31
48
|
``` yaml
|
|
32
49
|
redis:
|
|
33
|
-
host
|
|
50
|
+
# host默认 127.0.0.1
|
|
51
|
+
host: '127.0.0.1'
|
|
52
|
+
# 端口号默认 6379
|
|
34
53
|
port: 6379
|
|
54
|
+
# 无密码则留空或者不写, 默认无密码
|
|
35
55
|
password: ''
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 配置AI修图
|
|
59
|
+
修图基于xai的grok接口实现, 该接口返回的图片也是xai的, 在特定平台中可能无法发送此图片,这时候可以用自己写个代理将图片转为可访问状态
|
|
60
|
+
|
|
61
|
+
已知无需转换的平台: `QQ`,`Bubble`
|
|
62
|
+
`alemon.config.yaml`
|
|
63
|
+
``` yaml
|
|
64
|
+
# 代理默认可不填
|
|
65
|
+
xaiImgProxy: 'http://127.0.0.1:3002/ximgen'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
ai修图依赖于xai, 需要使用该功能必须添加一个grok模型, 在启动机器人后, 使用以下指令添加
|
|
69
|
+
```
|
|
70
|
+
#添加ai grok https://api.x.ai/v1 <你的apiKey> grok-4-1-fast-non-reasoning
|
|
71
|
+
```
|
|
72
|
+
通常情况下nodejs不会使用本地的代理, 因此你可能需要自己解决一下无法访问ai的问题, 例如另写一个脚本, 脚本已经预备好了, 下载项目中的`daili.js`然后运行它即可(Clash的默认端口一般是7890, 可能需要修改一下daili.js中的端口)
|
|
73
|
+
``` sh
|
|
74
|
+
node daili
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
如果你使用的是`daili.js`, 那么地址需要改为`http://127.0.0.1:3002/x/v1`
|
|
36
78
|
|
|
79
|
+
#### 配置搜索工具
|
|
80
|
+
网页搜索功能基于[https://serpapi.com](https://serpapi.com)的接口制作
|
|
81
|
+
需要前往他们的官网获取key
|
|
82
|
+
`alemon.config.yaml`
|
|
83
|
+
``` yaml
|
|
84
|
+
# 默认无, 可能无法使用网页搜索
|
|
85
|
+
searchApiKey: ''
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### 配置管理员
|
|
89
|
+
`alemon.config.yaml`
|
|
90
|
+
``` yaml
|
|
91
|
+
# 默认无, 小部分功能需要管理员权限才能使用
|
|
92
|
+
master_id: ['3501869534']
|
|
37
93
|
```
|
|
38
94
|
|
|
39
95
|
## 4.使用
|
package/lib/api.js
CHANGED
|
@@ -1,42 +1,10 @@
|
|
|
1
1
|
import { redis } from './redis.js';
|
|
2
2
|
import { getConfigValue } from 'alemonjs';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
+
import { uploadImageToR2 } from './s3.js';
|
|
5
|
+
import ttsmodels from './data/ttsmodels.json.js';
|
|
4
6
|
|
|
5
7
|
const value = getConfigValue();
|
|
6
|
-
const uploadImage = async (base64) => {
|
|
7
|
-
const apiUrl = "https://img.scdn.io/api/v1.php";
|
|
8
|
-
const uploadSingleImage = async (imageBase64) => {
|
|
9
|
-
const singleFormData = new FormData();
|
|
10
|
-
const blob = await (await fetch(imageBase64)).blob();
|
|
11
|
-
singleFormData.append("image", blob, "image.jpg");
|
|
12
|
-
const controller = new AbortController();
|
|
13
|
-
const timeoutId = setTimeout(() => controller.abort(), 30000);
|
|
14
|
-
const response = await fetch(apiUrl, {
|
|
15
|
-
method: "POST",
|
|
16
|
-
body: singleFormData,
|
|
17
|
-
signal: controller.signal,
|
|
18
|
-
});
|
|
19
|
-
clearTimeout(timeoutId);
|
|
20
|
-
if (!response.ok) {
|
|
21
|
-
return "";
|
|
22
|
-
}
|
|
23
|
-
const result = await response.json();
|
|
24
|
-
return result.url || "";
|
|
25
|
-
};
|
|
26
|
-
if (Array.isArray(base64)) {
|
|
27
|
-
const results = [];
|
|
28
|
-
for (const item of base64) {
|
|
29
|
-
const result = await uploadSingleImage(item);
|
|
30
|
-
if (result) {
|
|
31
|
-
results.push(result);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return results;
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
return [await uploadSingleImage(base64)];
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
8
|
const getTimeString = () => {
|
|
41
9
|
const now = new Date();
|
|
42
10
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
@@ -58,6 +26,41 @@ class TTSClient {
|
|
|
58
26
|
const data = await res.json();
|
|
59
27
|
return data.models;
|
|
60
28
|
}
|
|
29
|
+
async installModel(modelname) {
|
|
30
|
+
// 遍历ttsmodels,查找model对应的下载链接,模糊匹配
|
|
31
|
+
const matchedModel = ttsmodels.find((m) => {
|
|
32
|
+
return m.models.find((md) => md.modelname.includes(modelname));
|
|
33
|
+
});
|
|
34
|
+
if (!matchedModel) {
|
|
35
|
+
return { success: false, message: "未找到对应的模型" };
|
|
36
|
+
}
|
|
37
|
+
const modelInfo = matchedModel.models.find((md) => md.modelname.includes(modelname));
|
|
38
|
+
if (!modelInfo) {
|
|
39
|
+
return { success: false, message: "未找到对应的模型" };
|
|
40
|
+
}
|
|
41
|
+
// console.log("matchedModel", matchedModel);
|
|
42
|
+
console.log("modelInfo", modelInfo);
|
|
43
|
+
// 在这里实现模型安装逻辑
|
|
44
|
+
const res = await fetch(`${this.host}/install_model`, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
category: matchedModel.category,
|
|
51
|
+
dl_url: modelInfo.dl_link,
|
|
52
|
+
language: matchedModel.lang,
|
|
53
|
+
model_name: modelInfo.modelname,
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
const data = await res.json();
|
|
57
|
+
if (!res.ok) {
|
|
58
|
+
const err = await res.text();
|
|
59
|
+
console.log(err);
|
|
60
|
+
return { success: false, message: "模型安装失败: " + err };
|
|
61
|
+
}
|
|
62
|
+
return { success: true, message: data.msg };
|
|
63
|
+
}
|
|
61
64
|
async setModel(model, emotion) {
|
|
62
65
|
const models = await this.getModels("v4");
|
|
63
66
|
if (!models) {
|
|
@@ -175,9 +178,10 @@ const availableTools = {
|
|
|
175
178
|
* @param {string} prompt - 正向提示词
|
|
176
179
|
* @param {string} [bad_prompt] - 反向提示词
|
|
177
180
|
* @param {string} [direction] - 方向: landscape, portrait, square
|
|
181
|
+
* @param {boolean} [base64] - 是否返回base64格式的图片
|
|
178
182
|
* @returns {Promise<{type: "image", url: string}[]>} 图片列表
|
|
179
183
|
*/
|
|
180
|
-
StableDiffusionGenerateImage: async ({ prompt, bad_prompt = "(easynegative:1.1), (verybadimagenegative_v1.3:1), (low quality:1.2), (worst quality:1.2)", direction = "portrait", }) => {
|
|
184
|
+
StableDiffusionGenerateImage: async ({ prompt, bad_prompt = "(easynegative:1.1), (verybadimagenegative_v1.3:1), (low quality:1.2), (worst quality:1.2)", direction = "portrait", base64 = false, }) => {
|
|
181
185
|
const images = [];
|
|
182
186
|
const sizeMap = {
|
|
183
187
|
landscape: { width: 768, height: 512 },
|
|
@@ -222,6 +226,9 @@ const availableTools = {
|
|
|
222
226
|
const base64Data = data.images[0].replace(/^data:image\/\w+;base64,/, "");
|
|
223
227
|
const buffer = Buffer.from(base64Data, "base64");
|
|
224
228
|
fs.writeFileSync(path, buffer);
|
|
229
|
+
if (base64) {
|
|
230
|
+
return data.images;
|
|
231
|
+
}
|
|
225
232
|
images.push({ type: "image", url: path });
|
|
226
233
|
return images;
|
|
227
234
|
}
|
|
@@ -299,7 +306,21 @@ const availableTools = {
|
|
|
299
306
|
const data = await response.json();
|
|
300
307
|
return data.data.list.map((item) => ({
|
|
301
308
|
viewUrl: `https://test.suancaixianyu.cn/#/postDetails/${item.id}`,
|
|
302
|
-
|
|
309
|
+
title: item.title,
|
|
310
|
+
content: item.content,
|
|
311
|
+
userName: item.creator.nickname,
|
|
312
|
+
userPage: `https://test.suancaixianyu.cn/#/user/${item.creatorId}`,
|
|
313
|
+
createdAt: item.createdAt,
|
|
314
|
+
plate: item.plate.name,
|
|
315
|
+
postVersions: item.postVersions.map((version) => ({
|
|
316
|
+
version: version.version,
|
|
317
|
+
versionName: version.title,
|
|
318
|
+
createdAt: version.createdAt,
|
|
319
|
+
files: version.files.map((file) => ({
|
|
320
|
+
name: file.name,
|
|
321
|
+
url: file.url,
|
|
322
|
+
})),
|
|
323
|
+
})),
|
|
303
324
|
}));
|
|
304
325
|
}
|
|
305
326
|
catch (error) {
|
|
@@ -327,6 +348,182 @@ const availableTools = {
|
|
|
327
348
|
return [];
|
|
328
349
|
}
|
|
329
350
|
},
|
|
351
|
+
AIPS: async ({ image_url, instruction }) => {
|
|
352
|
+
// 从aiconfig中查询grok配置
|
|
353
|
+
const aiConfigStr = await redis.get(`ai:list:grok`);
|
|
354
|
+
if (!aiConfigStr) {
|
|
355
|
+
return "未找到AI配置";
|
|
356
|
+
}
|
|
357
|
+
const aiConfig = JSON.parse(aiConfigStr);
|
|
358
|
+
try {
|
|
359
|
+
// 处理单个或多个图片
|
|
360
|
+
const imageUrls = Array.isArray(image_url) ? image_url : [image_url];
|
|
361
|
+
const imgBase64Array = [];
|
|
362
|
+
for (const url of imageUrls) {
|
|
363
|
+
let imgBase64 = "";
|
|
364
|
+
if (url.startsWith("https://imgen.x.ai")) {
|
|
365
|
+
imgBase64 = url;
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
imgBase64 = await uploadImageToR2(url);
|
|
369
|
+
}
|
|
370
|
+
imgBase64Array.push(imgBase64);
|
|
371
|
+
}
|
|
372
|
+
const requestBody = Array.isArray(image_url)
|
|
373
|
+
? {
|
|
374
|
+
model: "grok-imagine-image",
|
|
375
|
+
images: imgBase64Array.map((base64) => ({
|
|
376
|
+
url: base64,
|
|
377
|
+
type: "image_url",
|
|
378
|
+
})),
|
|
379
|
+
prompt: instruction,
|
|
380
|
+
n: 1,
|
|
381
|
+
}
|
|
382
|
+
: {
|
|
383
|
+
model: "grok-imagine-image",
|
|
384
|
+
image: {
|
|
385
|
+
url: imgBase64Array[0],
|
|
386
|
+
type: "image_url",
|
|
387
|
+
},
|
|
388
|
+
prompt: instruction,
|
|
389
|
+
n: 1,
|
|
390
|
+
};
|
|
391
|
+
console.log("最终请求体", requestBody);
|
|
392
|
+
const res = await fetch(aiConfig.host + "/images/edits", {
|
|
393
|
+
method: "POST",
|
|
394
|
+
headers: {
|
|
395
|
+
"Content-Type": "application/json",
|
|
396
|
+
Authorization: `Bearer ${aiConfig.key}`,
|
|
397
|
+
},
|
|
398
|
+
body: JSON.stringify(requestBody),
|
|
399
|
+
});
|
|
400
|
+
if (!res.ok) {
|
|
401
|
+
const err = await res.text();
|
|
402
|
+
console.log(err);
|
|
403
|
+
return err;
|
|
404
|
+
}
|
|
405
|
+
const image = await res.json();
|
|
406
|
+
console.log("画好了", image);
|
|
407
|
+
return image.data;
|
|
408
|
+
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
console.error("Error calling AIPS:", error);
|
|
411
|
+
return "调用接口失败" + error;
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
AIVideos: async ({ image_url, instruction }) => {
|
|
415
|
+
// 从aiconfig中查询grok配置
|
|
416
|
+
const aiConfigStr = await redis.get(`ai:list:grok`);
|
|
417
|
+
if (!aiConfigStr) {
|
|
418
|
+
return "未找到AI配置";
|
|
419
|
+
}
|
|
420
|
+
const aiConfig = JSON.parse(aiConfigStr);
|
|
421
|
+
// 处理单个或多个图片
|
|
422
|
+
const imageUrls = Array.isArray(image_url) ? image_url : [image_url];
|
|
423
|
+
const imgBase64Array = [];
|
|
424
|
+
for (const url of imageUrls) {
|
|
425
|
+
let imgBase64 = "";
|
|
426
|
+
if (url) {
|
|
427
|
+
if (url.startsWith("https://imgen.x.ai")) {
|
|
428
|
+
imgBase64 = url;
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
imgBase64 = await uploadImageToR2(url);
|
|
432
|
+
}
|
|
433
|
+
imgBase64Array.push(imgBase64);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
try {
|
|
437
|
+
const requestBody = imgBase64Array.length === 0
|
|
438
|
+
? {
|
|
439
|
+
model: "grok-imagine-video",
|
|
440
|
+
prompt: instruction,
|
|
441
|
+
aspect_ratio: "16:9",
|
|
442
|
+
resolution: "720p",
|
|
443
|
+
}
|
|
444
|
+
: Array.isArray(image_url)
|
|
445
|
+
? {
|
|
446
|
+
model: "grok-imagine-video",
|
|
447
|
+
images: imgBase64Array.map((base64) => ({
|
|
448
|
+
url: base64,
|
|
449
|
+
type: "image_url",
|
|
450
|
+
})),
|
|
451
|
+
prompt: instruction,
|
|
452
|
+
resolution: "720p",
|
|
453
|
+
}
|
|
454
|
+
: {
|
|
455
|
+
model: "grok-imagine-video",
|
|
456
|
+
image: {
|
|
457
|
+
url: imgBase64Array[0],
|
|
458
|
+
type: "image_url",
|
|
459
|
+
},
|
|
460
|
+
prompt: instruction,
|
|
461
|
+
resolution: "720p",
|
|
462
|
+
};
|
|
463
|
+
console.log("最终请求体", requestBody);
|
|
464
|
+
const res = await fetch(aiConfig.host + "/videos/generations", {
|
|
465
|
+
method: "POST",
|
|
466
|
+
headers: {
|
|
467
|
+
"Content-Type": "application/json",
|
|
468
|
+
Authorization: `Bearer ${aiConfig.key}`,
|
|
469
|
+
},
|
|
470
|
+
body: JSON.stringify(requestBody),
|
|
471
|
+
});
|
|
472
|
+
if (!res.ok) {
|
|
473
|
+
const err = await res.text();
|
|
474
|
+
console.log(err);
|
|
475
|
+
return err;
|
|
476
|
+
}
|
|
477
|
+
const video = await res.json();
|
|
478
|
+
console.log("画好了", video);
|
|
479
|
+
return {
|
|
480
|
+
data: video,
|
|
481
|
+
msg: "生成任务已提交,稍后会自动发送生成结果,无需继续等待~,将request_id提供给用户,方便查询生成状态",
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
console.error("Error calling AIPS:", error);
|
|
486
|
+
return "调用接口失败" + error;
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
AIVideoResult: async ({ request_id }) => {
|
|
490
|
+
// 从aiconfig中查询grok配置
|
|
491
|
+
const aiConfigStr = await redis.get(`ai:list:grok`);
|
|
492
|
+
if (!aiConfigStr) {
|
|
493
|
+
return "未找到AI配置";
|
|
494
|
+
}
|
|
495
|
+
const aiConfig = JSON.parse(aiConfigStr);
|
|
496
|
+
try {
|
|
497
|
+
const res = await fetch(aiConfig.host + `/videos/${request_id}`, {
|
|
498
|
+
method: "GET",
|
|
499
|
+
headers: {
|
|
500
|
+
"Content-Type": "application/json",
|
|
501
|
+
Authorization: `Bearer ${aiConfig.key}`,
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
if (!res.ok) {
|
|
505
|
+
const err = await res.text();
|
|
506
|
+
console.log(err);
|
|
507
|
+
return err;
|
|
508
|
+
}
|
|
509
|
+
const video = await res.json();
|
|
510
|
+
console.log("视频生成结果", video);
|
|
511
|
+
return video;
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
console.error("Error calling AIVideoResult:", error);
|
|
515
|
+
return "调用接口失败" + error;
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
/**
|
|
519
|
+
* 获取TTS模型列表
|
|
520
|
+
* @returns TTS模型列表
|
|
521
|
+
*/
|
|
522
|
+
GetTTSModels: async () => {
|
|
523
|
+
const ttsClient = new TTSClient();
|
|
524
|
+
const models = await ttsClient.getModels("v4");
|
|
525
|
+
return models;
|
|
526
|
+
},
|
|
330
527
|
};
|
|
331
528
|
|
|
332
|
-
export { TTSClient, availableTools, getTimeString
|
|
529
|
+
export { TTSClient, availableTools, getTimeString };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-feature-settings:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]:where(:not([hidden=until-found])){display:none}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.box-border{box-sizing:border-box}.flex{display:flex}.w-1\/3{width:33.333333%}.flex-wrap{flex-wrap:wrap}.gap-2{gap:.5rem}.overflow-hidden{overflow:hidden}.rounded-lg{border-radius:.5rem}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-white\/20{border-color:hsla(0,0%,100%,.2)}.bg-black\/30{background-color:rgba(0,0,0,.3)}.bg-black\/60{background-color:rgba(0,0,0,.6)}.bg-cover{background-size:cover}.p-2{padding:.5rem}.p-4{padding:1rem}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.italic{font-style:italic}.text-\[\#B8AE8E\]{--tw-text-opacity:1;color:rgb(184 174 142/var(--tw-text-opacity,1))}.text-\[\#e8deba\]{--tw-text-opacity:1;color:rgb(232 222 186/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.drop-shadow-md{--tw-drop-shadow:drop-shadow(0 4px 3px rgba(0,0,0,.07)) drop-shadow(0 2px 2px rgba(0,0,0,.06));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}body{display:flex;flex-direction:column;margin:0;padding:0}.backdrop-blur-xs{backdrop-filter:blur(4px)}.last\:border-0:last-child{border-width:0}
|
package/lib/assets/main.css.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
const reg = ['win32'].includes(process.platform) ? /^file:\/\/\// : /^file:\/\// ;
|
|
2
|
-
const fileUrl = new URL('main.css-
|
|
2
|
+
const fileUrl = new URL('main.css-CXQ9gyIo.css', import.meta.url).href.replace(reg, '');
|
|
3
3
|
|
|
4
4
|
export { fileUrl as default };
|
package/lib/config.js
CHANGED
|
@@ -82,8 +82,8 @@ const getAIChatHistory = async (guid) => {
|
|
|
82
82
|
};
|
|
83
83
|
const addAIChatHistory = async (guid, data) => {
|
|
84
84
|
const history = await getAIChatHistory(guid);
|
|
85
|
-
// 处理messages, 不要超过
|
|
86
|
-
while (history.length >=
|
|
85
|
+
// 处理messages, 不要超过40条,超过就删除最早的
|
|
86
|
+
while (history.length >= 40) {
|
|
87
87
|
history.shift();
|
|
88
88
|
}
|
|
89
89
|
history.push(data);
|
|
@@ -105,8 +105,8 @@ const clearAIChatHistory = async (guid) => {
|
|
|
105
105
|
* @param userKey 用户标识
|
|
106
106
|
* @returns
|
|
107
107
|
*/
|
|
108
|
-
const getAffectionLevel = async (userKey) => {
|
|
109
|
-
const levelStr = await redis.get(`ai:affection:${userKey}`);
|
|
108
|
+
const getAffectionLevel = async (guid, userKey) => {
|
|
109
|
+
const levelStr = await redis.get(`ai:affection:${guid}:${userKey}`);
|
|
110
110
|
if (levelStr) {
|
|
111
111
|
return parseInt(levelStr, 10);
|
|
112
112
|
}
|
|
@@ -130,8 +130,8 @@ const getAffectionLevelAll = async (guid) => {
|
|
|
130
130
|
* @param level 好感度等级
|
|
131
131
|
* @returns
|
|
132
132
|
*/
|
|
133
|
-
const setAffectionLevel = async (userKey, level) => {
|
|
134
|
-
return await redis.set(`ai:affection:${userKey}`, level.toString());
|
|
133
|
+
const setAffectionLevel = async (guid, userKey, level) => {
|
|
134
|
+
return await redis.set(`ai:affection:${guid}:${userKey}`, level.toString());
|
|
135
135
|
};
|
|
136
136
|
/**
|
|
137
137
|
* 增加好感度等级
|
|
@@ -139,10 +139,10 @@ const setAffectionLevel = async (userKey, level) => {
|
|
|
139
139
|
* @param increment 增加的等级
|
|
140
140
|
* @returns
|
|
141
141
|
*/
|
|
142
|
-
const incrementAffectionLevel = async (userKey, increment) => {
|
|
143
|
-
const currentLevel = await getAffectionLevel(userKey);
|
|
142
|
+
const incrementAffectionLevel = async (guid, userKey, increment) => {
|
|
143
|
+
const currentLevel = await getAffectionLevel(guid, userKey);
|
|
144
144
|
const newLevel = currentLevel + increment;
|
|
145
|
-
await setAffectionLevel(userKey, newLevel);
|
|
145
|
+
await setAffectionLevel(guid, userKey, newLevel);
|
|
146
146
|
return newLevel;
|
|
147
147
|
};
|
|
148
148
|
/** * 重置好感度等级
|
|
@@ -180,12 +180,26 @@ const deleteAI = async (name) => {
|
|
|
180
180
|
const affectionSwitch = async (guid, enable) => {
|
|
181
181
|
return await redis.set(`ai:affection:switch:${guid}`, enable ? "1" : "0");
|
|
182
182
|
};
|
|
183
|
+
/**
|
|
184
|
+
* 获取好感度开关状态
|
|
185
|
+
*/
|
|
186
|
+
const getAffectionSwitch = async (guid) => {
|
|
187
|
+
const switchStr = (await redis.get(`ai:affection:switch:${guid}`)) || "1";
|
|
188
|
+
return switchStr;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* 获取tts回复开关状态
|
|
192
|
+
*/
|
|
193
|
+
const getTTSResponseSwitch = async (guid) => {
|
|
194
|
+
const switchStr = (await redis.get(`chat:tts:response:${guid}`)) || "0";
|
|
195
|
+
return switchStr;
|
|
196
|
+
};
|
|
183
197
|
const tools = [
|
|
184
198
|
{
|
|
185
199
|
type: "function",
|
|
186
200
|
function: {
|
|
187
201
|
name: "StableDiffusionGenerateImage",
|
|
188
|
-
description: "使用 Stable Diffusion
|
|
202
|
+
description: "使用 Stable Diffusion 模型生成图像, 该工具只擅长生成动漫风格的图片, 文本生成图像, 如需修改图像请使用AIPS工具",
|
|
189
203
|
parameters: {
|
|
190
204
|
type: "object",
|
|
191
205
|
properties: {
|
|
@@ -209,23 +223,24 @@ const tools = [
|
|
|
209
223
|
},
|
|
210
224
|
},
|
|
211
225
|
},
|
|
212
|
-
{
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
},
|
|
226
|
+
// {
|
|
227
|
+
// type: "function",
|
|
228
|
+
// function: {
|
|
229
|
+
// name: "StableDiffusionImageToPrompt",
|
|
230
|
+
// description:
|
|
231
|
+
// "使用 Stable Diffusion 将图片转换为提示词, 它只对动漫图片有效, 只能用来提取动漫图片的提示词",
|
|
232
|
+
// parameters: {
|
|
233
|
+
// type: "object",
|
|
234
|
+
// properties: {
|
|
235
|
+
// image_url: {
|
|
236
|
+
// type: "string",
|
|
237
|
+
// description: "图片的URL地址,必须是你所收到的图片地址",
|
|
238
|
+
// },
|
|
239
|
+
// },
|
|
240
|
+
// required: ["image_url"],
|
|
241
|
+
// },
|
|
242
|
+
// },
|
|
243
|
+
// },
|
|
229
244
|
{
|
|
230
245
|
type: "function",
|
|
231
246
|
function: {
|
|
@@ -277,6 +292,38 @@ const tools = [
|
|
|
277
292
|
},
|
|
278
293
|
},
|
|
279
294
|
},
|
|
295
|
+
{
|
|
296
|
+
type: "function",
|
|
297
|
+
function: {
|
|
298
|
+
name: "AIPS",
|
|
299
|
+
description: "AI修图工具, 可以对图片进行图像编辑, 无法用于图片分析. 使用时只需提供需要修改的图片url和修改需求即可. 当遇到审核拦截的问题时, 请不要再次尝试提交相同的修改需求, 这可能会导致账号被封禁. 请修改你的修改需求文本描述, 使其更具体和详细, 以避免触发审核拦截. ",
|
|
300
|
+
parameters: {
|
|
301
|
+
type: "object",
|
|
302
|
+
properties: {
|
|
303
|
+
image_url: {
|
|
304
|
+
type: "string",
|
|
305
|
+
description: "需要修改的图片URL地址,必须是你所收到的图片地址",
|
|
306
|
+
},
|
|
307
|
+
instruction: {
|
|
308
|
+
type: "string",
|
|
309
|
+
description: "修改需求的文本描述,尽量详细和具体,例如:'请将图片中的人物换成一个穿着宇航服的宇航员,背景改成月球表面,保持其他元素不变'",
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
required: ["image_url", "instruction"],
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
type: "function",
|
|
318
|
+
function: {
|
|
319
|
+
name: "GetTTSModels",
|
|
320
|
+
description: "获取可用的TTS模型列表, 可以用来选择不同的音色进行语音合成. 模型会不定期更新, 你可以定期调用这个工具来获取最新的模型列表. 当你想要使用TTS功能时, 可以先调用这个工具来获取可用的模型列表, 然后选择一个你喜欢的模型来进行语音合成. 例如, 你可以选择一个叫做'派蒙-默认'的模型来模仿派蒙的声音进行语音合成",
|
|
321
|
+
parameters: {
|
|
322
|
+
type: "object",
|
|
323
|
+
properties: {},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
280
327
|
];
|
|
281
328
|
|
|
282
|
-
export { addAI, addAIChatHistory, addPrompt, affectionSwitch, clearAIChatHistory, defaultAIConfig, deleteAI, deletePrompt, getAIChatHistory, getAIConfig, getAIList, getAffectionLevel, getAffectionLevelAll, getPromptList, incrementAffectionLevel, resetAffectionLevel, resetAllAffectionLevels, setAffectionLevel, setBotID, switchAI, switchPrompt, systemPrompt, tools };
|
|
329
|
+
export { addAI, addAIChatHistory, addPrompt, affectionSwitch, clearAIChatHistory, defaultAIConfig, deleteAI, deletePrompt, getAIChatHistory, getAIConfig, getAIList, getAffectionLevel, getAffectionLevelAll, getAffectionSwitch, getPromptList, getTTSResponseSwitch, incrementAffectionLevel, resetAffectionLevel, resetAllAffectionLevels, setAffectionLevel, setBotID, switchAI, switchPrompt, systemPrompt, tools };
|