alemonjs-aichat 1.0.4 → 1.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alemonjs-aichat",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "alemonjs-aichat",
5
5
  "author": "suancaixianyu",
6
6
  "license": "MIT",
package/lib/api.js DELETED
@@ -1,292 +0,0 @@
1
- import { redis } from './redis.js';
2
- import { getConfigValue } from 'alemonjs';
3
- import fs from 'fs';
4
-
5
- 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
- const getTimeString = () => {
41
- const now = new Date();
42
- const month = String(now.getMonth() + 1).padStart(2, "0");
43
- const day = String(now.getDate()).padStart(2, "0");
44
- const hours = String(now.getHours()).padStart(2, "0");
45
- const minutes = String(now.getMinutes()).padStart(2, "0");
46
- return `${month}-${day} ${hours}:${minutes}`;
47
- };
48
- class TTSClient {
49
- host;
50
- constructor() {
51
- this.host = value.ttsServer?.host || "http://localhost:8000";
52
- }
53
- async getModels(version = "v4") {
54
- const res = await fetch(`${this.host}/models/${version}`);
55
- if (!res.ok) {
56
- return null;
57
- }
58
- const data = await res.json();
59
- return data.models;
60
- }
61
- async setModel(model, emotion) {
62
- const models = await this.getModels("v4");
63
- if (!models) {
64
- return null;
65
- }
66
- let modelInfo = await redis.get("chat:tts:modelInfo");
67
- if (!modelInfo) {
68
- modelInfo = {
69
- version: "v4",
70
- model_name: "",
71
- prompt_text_lang: "中文",
72
- emotion: emotion ?? "默认",
73
- text_lang: "中文",
74
- };
75
- }
76
- else {
77
- modelInfo = JSON.parse(modelInfo);
78
- }
79
- // model可能只包含模型名称的一部分,需要模糊匹配
80
- const matchedModel = Object.keys(models).find((m) => m.includes(model));
81
- if (!matchedModel) {
82
- return null;
83
- }
84
- if (!modelInfo || typeof modelInfo === "string") {
85
- return null;
86
- }
87
- modelInfo.model_name = matchedModel;
88
- modelInfo.prompt_text_lang = Object.keys(models[matchedModel])[0];
89
- modelInfo.emotion =
90
- emotion || models[matchedModel][modelInfo.prompt_text_lang][0];
91
- modelInfo.text_lang = modelInfo.prompt_text_lang;
92
- await redis.set("chat:tts:modelInfo", JSON.stringify(modelInfo));
93
- return matchedModel;
94
- }
95
- async getAudio(text) {
96
- let modelInfo = await redis.get("chat:tts:modelInfo");
97
- if (!modelInfo) {
98
- modelInfo = {
99
- version: "v4",
100
- model_name: "原神-中文-芙宁娜_ZH",
101
- prompt_text_lang: "中文",
102
- emotion: "默认",
103
- text_lang: "中文",
104
- };
105
- }
106
- else {
107
- modelInfo = JSON.parse(modelInfo);
108
- }
109
- if (!modelInfo || typeof modelInfo === "string") {
110
- return null;
111
- }
112
- console.log("modelInfo", modelInfo);
113
- const res = await fetch(`${this.host}/infer_single`, {
114
- method: "POST",
115
- headers: {
116
- "Content-Type": "application/json",
117
- },
118
- body: JSON.stringify({
119
- dl_url: this.host,
120
- version: modelInfo.version,
121
- model_name: modelInfo.model_name,
122
- prompt_text_lang: modelInfo.prompt_text_lang,
123
- emotion: modelInfo.emotion,
124
- text: text,
125
- text_lang: modelInfo.text_lang,
126
- top_k: 10,
127
- top_p: 1,
128
- temperature: 1,
129
- text_split_method: "按标点符号切",
130
- batch_size: 1,
131
- batch_threshold: 0.75,
132
- split_bucket: true,
133
- speed_facter: 1,
134
- fragment_interval: 0.3,
135
- media_type: "wav",
136
- parallel_infer: true,
137
- repetition_penalty: 1.35,
138
- seed: -1,
139
- sample_steps: 16,
140
- if_sr: false,
141
- }),
142
- });
143
- if (!res.ok) {
144
- return null;
145
- }
146
- const data = await res.json();
147
- return data;
148
- }
149
- }
150
- const getPrompt = async (text) => {
151
- // 检查中文
152
- const hasChinese = /[\u4e00-\u9fa5]/g.test(text);
153
- const fanyiApi = "https://api.52vmy.cn/api/query/fanyi/youdao?msg=";
154
- if (hasChinese) {
155
- try {
156
- // 调用后端的 send_get_request 函数
157
- const responseText = await fetch(fanyiApi + encodeURIComponent(text)).then((res) => res.text());
158
- // 将返回的 JSON 字符串解析为对象
159
- const data = JSON.parse(responseText);
160
- console.log("提示词翻译:", data.data.target);
161
- return data.data.target;
162
- }
163
- catch (error) {
164
- console.error("Error fetching translation:", error);
165
- return text; // 如果翻译失败,返回原始文本
166
- }
167
- }
168
- else {
169
- return text;
170
- }
171
- };
172
- const availableTools = {
173
- /**
174
- * 使用 Stable Diffusion 生成图片
175
- * @param {string} prompt - 正向提示词
176
- * @param {string} [bad_prompt] - 反向提示词
177
- * @param {string} [direction] - 方向: landscape, portrait, square
178
- * @returns {Promise<{type: "image", url: string}[]>} 图片列表
179
- */
180
- StableDiffusionGenerateImage: async ({ prompt, bad_prompt = "(easynegative:1.1), (verybadimagenegative_v1.3:1), (low quality:1.2), (worst quality:1.2)", direction = "portrait", }) => {
181
- const images = [];
182
- const sizeMap = {
183
- landscape: { width: 768, height: 512 },
184
- portrait: { width: 512, height: 768 },
185
- square: { width: 640, height: 640 },
186
- };
187
- const { width, height } = sizeMap[direction] || sizeMap["portrait"];
188
- // 检查是否有中文
189
- const body = {
190
- enable_hr: true,
191
- denoising_strength: 0.8,
192
- hr_scale: 2,
193
- hr_upscaler: "R-ESRGAN 4x+ Anime6B",
194
- hr_second_pass_steps: 10,
195
- prompt: await getPrompt(prompt),
196
- seed: -1,
197
- sampler_name: "DPM++ 2M",
198
- steps: 20,
199
- cfg_scale: 10,
200
- width: width,
201
- height: height,
202
- negative_prompt: bad_prompt,
203
- };
204
- try {
205
- const response = await fetch("http://datukuai.top:1450/ht2.php", {
206
- method: "POST",
207
- headers: {
208
- "Content-Type": "application/json",
209
- },
210
- body: JSON.stringify(body),
211
- });
212
- if (!response.ok) {
213
- return images;
214
- }
215
- const data = await response.json();
216
- // 将图片保存到本地,然后返回本地路径
217
- const dir = "./public/image_out";
218
- if (!fs.existsSync(dir)) {
219
- fs.mkdirSync(dir, { recursive: true });
220
- }
221
- const path = `${dir}/${Date.now()}.jpg`;
222
- const base64Data = data.images[0].replace(/^data:image\/\w+;base64,/, "");
223
- const buffer = Buffer.from(base64Data, "base64");
224
- fs.writeFileSync(path, buffer);
225
- images.push({ type: "image", url: path });
226
- return images;
227
- }
228
- catch (error) {
229
- console.error("Error generating images:", error);
230
- return images;
231
- }
232
- },
233
- StableDiffusionImageToPrompt: async ({ image_url }) => {
234
- // 先查看redis中是否有这张图的缓存
235
- const cacheKey = `image:caption:${image_url}`;
236
- const cachedCaption = await redis.get(cacheKey);
237
- let imgBase64 = "";
238
- if (cachedCaption) {
239
- // 如果有, 它是本地路径, 获取base64
240
- const data = fs.readFileSync(cachedCaption, { encoding: "base64" });
241
- imgBase64 = data;
242
- }
243
- else {
244
- // 如果没有, 下载图片并转换为base64
245
- const response = await fetch(image_url);
246
- const arrayBuffer = await response.arrayBuffer();
247
- const buffer = Buffer.from(arrayBuffer);
248
- imgBase64 = buffer.toString("base64");
249
- }
250
- const api = "http://datukuai.top:1450//ckmf.php";
251
- const body = {
252
- fn_index: 280,
253
- data: [
254
- "data:image/png;base64," + imgBase64,
255
- "",
256
- false,
257
- "",
258
- "[name].[output_extension]",
259
- "ignore",
260
- false,
261
- "wd14-vit",
262
- 0.35,
263
- "",
264
- "",
265
- false,
266
- false,
267
- true,
268
- "0_0, (o)_(o), +_+, +_-, ._., <o>_<o>, <|>_<|>, =_=, >_<, 3_3, 6_9, >_o, @_@, ^_^, o_o, u_u, x_x, |_|, ||_||",
269
- false,
270
- false,
271
- ],
272
- session_hash: "0yzsdmhe9br9",
273
- };
274
- const res = await fetch(api, {
275
- method: "POST",
276
- headers: {
277
- "Content-Type": "application/json",
278
- "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36",
279
- },
280
- body: JSON.stringify(body),
281
- });
282
- if (!res.ok) {
283
- return "无法转为提示词";
284
- }
285
- const data = await res.json();
286
- const prompt = data.data[0];
287
- console.log("图片提示词:", prompt);
288
- return prompt;
289
- },
290
- };
291
-
292
- export { TTSClient, availableTools, getTimeString, uploadImage };
@@ -1,4 +0,0 @@
1
- const reg = ['win32'].includes(process.platform) ? /^file:\/\/\// : /^file:\/\// ;
2
- const fileUrl = new URL('113574575_p0_master1200-BncvWC99.jpg', import.meta.url).href.replace(reg, '');
3
-
4
- export { fileUrl as default };
@@ -1 +0,0 @@
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}.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}
@@ -1,4 +0,0 @@
1
- const reg = ['win32'].includes(process.platform) ? /^file:\/\/\// : /^file:\/\// ;
2
- const fileUrl = new URL('main.css-DlHMK5k-.css', import.meta.url).href.replace(reg, '');
3
-
4
- export { fileUrl as default };
package/lib/config.js DELETED
@@ -1,231 +0,0 @@
1
- import { redis } from './redis.js';
2
-
3
- const systemPrompt = ``;
4
- const defaultAIConfig = {
5
- host: "",
6
- key: "",
7
- model: "",
8
- temperature: 0.7,
9
- max_tokens: 150,
10
- systemPrompt: systemPrompt,
11
- };
12
- const getAIConfig = async (guid) => {
13
- let id = guid ?? "global";
14
- const userConfigStr = await redis.get(`ai:config:${id}`);
15
- if (userConfigStr) {
16
- const userConfig = JSON.parse(userConfigStr);
17
- return userConfig;
18
- }
19
- redis.set(`ai:config:${id}`, JSON.stringify(defaultAIConfig));
20
- return defaultAIConfig;
21
- };
22
- const getAIList = async () => {
23
- const keys = await redis.keys("ai:list:*");
24
- return keys.map((key) => key.replace("ai:list:", ""));
25
- };
26
- const addAI = async (guid, name, host, key, model) => {
27
- const defaultConfig = await getAIConfig();
28
- defaultConfig.host = host;
29
- defaultConfig.key = key;
30
- defaultConfig.model = model;
31
- await redis.set(`ai:list:${name}`, JSON.stringify(defaultConfig));
32
- await switchAI(guid, name);
33
- };
34
- const switchAI = async (guid, name) => {
35
- const aiConfigStr = await redis.get(`ai:list:${name}`);
36
- if (!aiConfigStr) {
37
- console.log("切换失败, 无此模型");
38
- // 清空当前配置
39
- await redis.set(`ai:config:${guid}`, JSON.stringify(defaultAIConfig));
40
- return null;
41
- }
42
- const aiConfig = JSON.parse(aiConfigStr);
43
- // 保留当前系统提示词
44
- const currentConfig = await getAIConfig(guid);
45
- aiConfig.systemPrompt = currentConfig.systemPrompt;
46
- await redis.set(`ai:config:${guid}`, JSON.stringify(aiConfig));
47
- return aiConfig;
48
- };
49
- const getPromptList = async () => {
50
- const keys = await redis.keys("ai:prompt:*");
51
- return keys.map((key) => key.replace("ai:prompt:", ""));
52
- };
53
- const addPrompt = async (name, content) => {
54
- return await redis.set(`ai:prompt:${name}`, content);
55
- };
56
- const deletePrompt = async (name) => {
57
- return await redis.del(`ai:prompt:${name}`);
58
- };
59
- const switchPrompt = async (guid, name) => {
60
- if (name === "") {
61
- const config = await getAIConfig(guid);
62
- config.systemPrompt = "";
63
- await redis.set(`ai:config:${guid}`, JSON.stringify(config));
64
- return systemPrompt;
65
- }
66
- const prompt = await redis.get(`ai:prompt:${name}`);
67
- if (!prompt) {
68
- console.log("切换提示词失败, 无此提示词");
69
- return null;
70
- }
71
- const config = await getAIConfig(guid);
72
- config.systemPrompt = prompt;
73
- await redis.set(`ai:config:${guid}`, JSON.stringify(config));
74
- return prompt;
75
- };
76
- const getAIChatHistory = async (guid) => {
77
- const historyStr = await redis.get(`ai:history:${guid}`);
78
- if (historyStr) {
79
- return JSON.parse(historyStr);
80
- }
81
- return [];
82
- };
83
- const addAIChatHistory = async (guid, data) => {
84
- const history = await getAIChatHistory(guid);
85
- // 处理messages, 不要超过15条,超过就删除最早的
86
- while (history.length >= 20) {
87
- history.shift();
88
- }
89
- history.push(data);
90
- await redis.set(`ai:history:${guid}`, JSON.stringify(history));
91
- return history;
92
- };
93
- const clearAIChatHistory = async (guid) => {
94
- if (!guid) {
95
- const keys = await redis.keys(`ai:history:*`);
96
- for (const key of keys) {
97
- await redis.del(key);
98
- }
99
- return;
100
- }
101
- return await redis.del(`ai:history:${guid}`);
102
- };
103
- /**
104
- * 获取好感度等级
105
- * @param userKey 用户标识
106
- * @returns
107
- */
108
- const getAffectionLevel = async (userKey) => {
109
- const levelStr = await redis.get(`ai:affection:${userKey}`);
110
- if (levelStr) {
111
- return parseInt(levelStr, 10);
112
- }
113
- return 0;
114
- };
115
- const getAffectionLevelAll = async (guid) => {
116
- const keys = await redis.keys(`ai:affection:${guid}:*`);
117
- const levels = {};
118
- for (const key of keys) {
119
- const levelStr = await redis.get(key);
120
- if (levelStr) {
121
- const userKey = key.replace(`ai:affection:${guid}:`, "");
122
- levels[userKey] = parseInt(levelStr, 10);
123
- }
124
- }
125
- return levels;
126
- };
127
- /**
128
- * 设置好感度等级
129
- * @param userKey 用户标识
130
- * @param level 好感度等级
131
- * @returns
132
- */
133
- const setAffectionLevel = async (userKey, level) => {
134
- return await redis.set(`ai:affection:${userKey}`, level.toString());
135
- };
136
- /**
137
- * 增加好感度等级
138
- * @param userKey 用户标识
139
- * @param increment 增加的等级
140
- * @returns
141
- */
142
- const incrementAffectionLevel = async (userKey, increment) => {
143
- const currentLevel = await getAffectionLevel(userKey);
144
- const newLevel = currentLevel + increment;
145
- await setAffectionLevel(userKey, newLevel);
146
- return newLevel;
147
- };
148
- /** * 重置好感度等级
149
- * @param userKey 用户标识
150
- * @returns
151
- */
152
- const resetAffectionLevel = async (userKey) => {
153
- return await redis.del(`ai:affection:${userKey}`);
154
- };
155
- /** 重置所有用户好感度等级
156
- * @param guid 频道标识
157
- * @returns
158
- */
159
- const resetAllAffectionLevels = async () => {
160
- const keys = await redis.keys(`ai:affection:*`);
161
- for (const key of keys) {
162
- await redis.del(key);
163
- }
164
- };
165
- const setBotID = async (id) => {
166
- return await redis.set("bot:id", id);
167
- };
168
- const deleteAI = async (name) => {
169
- const aiConfigStr = await redis.get(`ai:list:${name}`);
170
- if (!aiConfigStr) {
171
- console.log("删除失败, 无此模型");
172
- return false;
173
- }
174
- await redis.del(`ai:list:${name}`);
175
- return true;
176
- };
177
- /**
178
- * 设置好感度开关
179
- */
180
- const affectionSwitch = async (guid, enable) => {
181
- return await redis.set(`ai:affection:switch:${guid}`, enable ? "1" : "0");
182
- };
183
- const tools = [
184
- {
185
- type: "function",
186
- function: {
187
- name: "StableDiffusionGenerateImage",
188
- description: "使用 Stable Diffusion 模型生成图像",
189
- parameters: {
190
- type: "object",
191
- properties: {
192
- prompt: {
193
- type: "string",
194
- description: "正向提示词(prompt),越详细越好。建议包含:主体、动作、服装、场景、风格、光线、画质修饰词。\n推荐全英文且使用标签描述,当遇到动漫人物时,使用ta的英文名可以自动触发lora,不用额外lora标签\n括号的使用:[增强效果],(弱化效果), 示例:'[artist:ciloranko],artist:kazutake_hazano,[artist:kedama milk],smile, short_hair, open_mouth, bangs, multiple_girls, skirt, black_hair, hair_ornament, red_eyes, long_sleeves, 2girls, sitting, school_uniform, :d, grey_hair, multicolored_hair, pleated_skirt, shoes, serafuku, choker, socks, sailor_collar, neckerchief, orange_eyes, petals, siblings, black_choker, brown_footwear, blue sky, pointing, loafers, red_neckerchief, bench, falling_petals'",
195
- },
196
- bad_prompt: {
197
- type: "string",
198
- description: "反向提示词(negative prompt),用于排除不想要的元素。\n示例:'lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, deformed'",
199
- default: "(easynegative:1.1), (verybadimagenegative_v1.3:1), (low quality:1.2), (worst quality:1.2)",
200
- },
201
- direction: {
202
- type: "string",
203
- description: "图片方向, 横向: landscape, 纵向: portrait, 方形: square",
204
- enum: ["landscape", "portrait", "square"],
205
- default: "portrait",
206
- },
207
- },
208
- required: ["prompt"],
209
- },
210
- },
211
- },
212
- {
213
- type: "function",
214
- function: {
215
- name: "StableDiffusionImageToPrompt",
216
- description: "使用 Stable Diffusion 将图片转换为提示词",
217
- parameters: {
218
- type: "object",
219
- properties: {
220
- image_url: {
221
- type: "string",
222
- description: "图片的URL地址,必须是你所收到的图片地址",
223
- },
224
- },
225
- required: ["image_url"],
226
- },
227
- },
228
- },
229
- ];
230
-
231
- export { addAI, addAIChatHistory, addPrompt, affectionSwitch, clearAIChatHistory, defaultAIConfig, deleteAI, deletePrompt, getAIChatHistory, getAIConfig, getAIList, getAffectionLevel, getAffectionLevelAll, getPromptList, incrementAffectionLevel, resetAffectionLevel, resetAllAffectionLevels, setAffectionLevel, setBotID, switchAI, switchPrompt, systemPrompt, tools };
@@ -1,115 +0,0 @@
1
- var title = "IA聊天插件";
2
- var name = "aichat";
3
- var version = "v1.0.4";
4
- var by = "AlemonJS";
5
- var list = [
6
- {
7
- group: {
8
- title: "配置操作",
9
- items: [
10
- {
11
- cmd: "/添加ai",
12
- desc: "添加新的AI聊天配置。"
13
- },
14
- {
15
- cmd: "/删除ai [名称]",
16
- desc: "删除已有的AI聊天配置。"
17
- },
18
- {
19
- cmd: "/ai配置",
20
- desc: "查看当前的ai配置"
21
- },
22
- {
23
- cmd: "/ai列表",
24
- desc: "查看当前可用的ai配置列表"
25
- },
26
- {
27
- cmd: "/切换ai [名称]",
28
- desc: "切换到指定名称的ai配置。"
29
- }
30
- ]
31
- }
32
- },
33
- {
34
- group: {
35
- title: "提示词操作",
36
- items: [
37
- {
38
- cmd: "/添加提示词 [名称] [内容]",
39
- desc: "添加新的AI聊天配置。"
40
- },
41
- {
42
- cmd: "/删除提示词 [名称]",
43
- desc: "删除已有的AI聊天配置。"
44
- },
45
- {
46
- cmd: "/提示词列表",
47
- desc: "查看当前可用的提示词列表"
48
- },
49
- {
50
- cmd: "/查看提示词",
51
- desc: "查看当前的提示词设置"
52
- },
53
- {
54
- cmd: "/清空提示词",
55
- desc: "清空当前的提示词设置"
56
- }
57
- ]
58
- }
59
- },
60
- {
61
- group: {
62
- title: "聊天",
63
- items: [
64
- {
65
- cmd: "/[开启|关闭]聊天",
66
- desc: "开启或关闭AI聊天功能。"
67
- },
68
- {
69
- cmd: "/[开启|关闭]好感度",
70
- desc: "开启或关闭好感度功能。"
71
- },
72
- {
73
- cmd: "/[开启|关闭]语音回复",
74
- desc: "开启或关闭语音回复功能。"
75
- },
76
- {
77
- cmd: "/好感度",
78
- desc: "查看当前好感度状态。"
79
- },
80
- {
81
- cmd: "/清空好感度",
82
- desc: "清空当前用户的好感度数据。"
83
- },
84
- {
85
- cmd: "/清空对话",
86
- desc: "清空当前页面的对话记录。"
87
- }
88
- ]
89
- }
90
- },
91
- {
92
- group: {
93
- title: "管理员设置",
94
- items: [
95
- {
96
- cmd: "/清空所有对话",
97
- desc: "清空所有用户的对话记录。"
98
- },
99
- {
100
- cmd: "/清空所有好感度",
101
- desc: "清空所有用户的好感度数据。"
102
- }
103
- ]
104
- }
105
- }
106
- ];
107
- var help = {
108
- title: title,
109
- name: name,
110
- version: version,
111
- by: by,
112
- list: list
113
- };
114
-
115
- export { by, help as default, list, name, title, version };