wechaty-web-panel 1.6.112 → 1.6.113
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/dist/bot/chatgpt/index.js +235 -0
- package/dist/bot/coze/sdk/index.js +110 -0
- package/dist/bot/dify/sdk/index.js +461 -0
- package/dist/bot/dify/sdk/office.js +319 -0
- package/dist/bot/fastgpt/index.js +98 -0
- package/dist/bot/qanything/index.js +136 -0
- package/dist/botInstance/coze.js +167 -0
- package/dist/botInstance/cozev3.js +157 -0
- package/dist/botInstance/dify.js +160 -0
- package/dist/botInstance/fastgpt.js +130 -0
- package/dist/botInstance/gpt4v.js +95 -0
- package/dist/botInstance/officialOpenAi.js +186 -0
- package/dist/botInstance/qany.js +144 -0
- package/dist/botInstance/sdk/chatGPT4V.js +89 -0
- package/dist/botInstance/sdk/coze.js +200 -0
- package/dist/botInstance/sdk/difyClient.js +354 -0
- package/dist/botInstance/sdk/pTimeout.js +97 -0
- package/dist/botInstance/sdk/qanything.js +137 -0
- package/dist/botInstance/sdk/quick-lru.js +237 -0
- package/dist/common/hook.js +66 -0
- package/dist/common/index.js +513 -0
- package/dist/common/multiReply.js +158 -0
- package/dist/common/reply.js +23 -0
- package/dist/const/puppet-type.js +71 -0
- package/dist/db/aiDb.js +27 -0
- package/dist/db/aichatDb.js +84 -0
- package/dist/db/chatHistory.js +137 -0
- package/dist/db/configDb.js +97 -0
- package/dist/db/global.js +62 -0
- package/dist/db/gptConfig.js +85 -0
- package/dist/db/nedb.js +88 -0
- package/dist/db/puppetDb.js +58 -0
- package/dist/db/roomDb.js +83 -0
- package/dist/db/rssConfig.js +82 -0
- package/dist/db/rssHistory.js +88 -0
- package/dist/db/userDb.js +27 -0
- package/dist/handlers/on-callback-message.js +183 -0
- package/dist/handlers/on-error.js +5 -0
- package/dist/handlers/on-friend.js +62 -0
- package/dist/handlers/on-heartbeat.js +20 -0
- package/dist/handlers/on-login.js +58 -0
- package/dist/handlers/on-logout.js +17 -0
- package/dist/handlers/on-message.js +644 -0
- package/dist/handlers/on-ready.js +36 -0
- package/dist/handlers/on-record-message.js +56 -0
- package/dist/handlers/on-roomjoin.js +42 -0
- package/dist/handlers/on-roomleave.js +12 -0
- package/dist/handlers/on-roomtopic.js +16 -0
- package/dist/handlers/on-scan.js +64 -0
- package/dist/handlers/on-verifycode.js +42 -0
- package/dist/index.js +81 -69306
- package/dist/lib/contentCensor.js +23 -0
- package/dist/lib/index.js +562 -0
- package/dist/lib/oss.js +43 -0
- package/dist/lib/s3oss.js +33 -0
- package/dist/mcp/mcp-server.js +26 -0
- package/dist/mcp/src/config/database.js +51 -0
- package/dist/mcp/src/index.js +238 -0
- package/dist/mcp/src/mcp/schemas.js +178 -0
- package/dist/mcp/src/mcp/server.js +421 -0
- package/dist/mcp/src/mcp/streamable-server.js +690 -0
- package/dist/mcp/src/models/ChatMessage.js +151 -0
- package/dist/mcp/src/models/Friend.js +64 -0
- package/dist/mcp/src/models/Group.js +55 -0
- package/dist/mcp/src/models/GroupMember.js +67 -0
- package/dist/mcp/src/models/index.js +27 -0
- package/dist/mcp/src/scripts/migrate.js +21 -0
- package/dist/mcp/src/services/ChatDataService.js +284 -0
- package/dist/mcp/src/services/McpService.js +521 -0
- package/dist/mcp/src/services/McpTools.js +504 -0
- package/dist/mcp/streamable-examples.js +283 -0
- package/dist/mcp/streamable-server.js +79 -0
- package/dist/mcp/test-mcp.js +64 -0
- package/dist/mcp/test-streamable-server.js +86 -0
- package/dist/package-json.js +89 -0
- package/dist/proxy/aibotk.js +829 -0
- package/dist/proxy/api.js +431 -0
- package/dist/proxy/apib.js +587 -0
- package/dist/proxy/bot/chatgpt.js +38 -0
- package/dist/proxy/bot/coze.js +38 -0
- package/dist/proxy/bot/cozev3.js +38 -0
- package/dist/proxy/bot/dify.js +38 -0
- package/dist/proxy/bot/dispatch.js +81 -0
- package/dist/proxy/bot/fastgpt.js +27 -0
- package/dist/proxy/bot/qany.js +27 -0
- package/dist/proxy/config.js +14 -0
- package/dist/proxy/cozeAi.js +60 -0
- package/dist/proxy/cozeV3Ai.js +60 -0
- package/dist/proxy/difyAi.js +58 -0
- package/dist/proxy/fastgpt.js +55 -0
- package/dist/proxy/mqtt.js +275 -0
- package/dist/proxy/multimodal.js +122 -0
- package/dist/proxy/openAi.js +63 -0
- package/dist/proxy/outapi.js +62 -0
- package/dist/proxy/qAnyAi.js +57 -0
- package/dist/proxy/superagent.js +200 -0
- package/dist/proxy/tencent-open.js +255 -0
- package/dist/service/event-dispatch-service.js +309 -0
- package/dist/service/gpt4vService.js +45 -0
- package/dist/service/msg-filter-service.js +121 -0
- package/dist/service/msg-filters.js +645 -0
- package/dist/service/room-async-service.js +455 -0
- package/dist/task/index.js +535 -0
- package/dist/task/rss.js +174 -0
- package/package.json +2 -2
- package/src/package-json.js +2 -2
- package/tsconfig.json +3 -12
- package/dist/index.d.ts +0 -9
- package/tsconfig.cjs.json +0 -12
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import Keyv from "keyv";
|
|
2
|
+
import pTimeout from "./pTimeout.js";
|
|
3
|
+
import QuickLRU from "./quick-lru.js";
|
|
4
|
+
import { v4 as uuidv4 } from "uuid";
|
|
5
|
+
const ChatCozeError = class extends Error {
|
|
6
|
+
};
|
|
7
|
+
const fetch = globalThis.fetch;
|
|
8
|
+
let CozeAPI = class {
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
const { apiKey, apiBaseUrl = "https://api.coze.com/open_api/v2", debug = false, messageStore, systemMessage, getMessageById, upsertMessage, botId, fetch: fetch2 = fetch } = opts;
|
|
11
|
+
this._apiKey = apiKey;
|
|
12
|
+
this._apiBaseUrl = apiBaseUrl || "https://api.coze.com/open_api/v2";
|
|
13
|
+
this._debug = !!debug;
|
|
14
|
+
this._fetch = fetch2;
|
|
15
|
+
this._completionParams = {
|
|
16
|
+
bot_id: botId
|
|
17
|
+
};
|
|
18
|
+
this._systemMessage = systemMessage;
|
|
19
|
+
if (this._systemMessage === void 0) {
|
|
20
|
+
const currentDate = new Date().toISOString().split("T")[0];
|
|
21
|
+
this._systemMessage = `You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible.
|
|
22
|
+
Knowledge cutoff: 2023-12-31
|
|
23
|
+
Current date: ${currentDate}`;
|
|
24
|
+
}
|
|
25
|
+
this._getMessageById = getMessageById ?? this._defaultGetMessageById;
|
|
26
|
+
this._upsertMessage = upsertMessage ?? this._defaultUpsertMessage;
|
|
27
|
+
if (messageStore) {
|
|
28
|
+
this._messageStore = messageStore;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
this._messageStore = new Keyv({
|
|
32
|
+
store: new QuickLRU({ maxSize: 1e4 })
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (!this._apiKey) {
|
|
36
|
+
throw new Error("Coze missing required PERSONAL_ACCESS_TOKEN");
|
|
37
|
+
}
|
|
38
|
+
if (!this._fetch) {
|
|
39
|
+
throw new Error("Invalid environment; fetch is not defined");
|
|
40
|
+
}
|
|
41
|
+
if (typeof this._fetch !== "function") {
|
|
42
|
+
throw new Error("Invalid \"fetch\" is not a function");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async sendMessage(text, opts = {}) {
|
|
46
|
+
const { parentMessageId, messageId = uuidv4(), timeoutMs, onProgress, stream = !!onProgress, user, conversationId, } = opts;
|
|
47
|
+
let { abortSignal } = opts;
|
|
48
|
+
let abortController = null;
|
|
49
|
+
if (timeoutMs && !abortSignal) {
|
|
50
|
+
abortController = new AbortController();
|
|
51
|
+
abortSignal = abortController.signal;
|
|
52
|
+
}
|
|
53
|
+
const latestQuestion = {
|
|
54
|
+
role: "user",
|
|
55
|
+
id: messageId,
|
|
56
|
+
conversationId,
|
|
57
|
+
parentMessageId,
|
|
58
|
+
text,
|
|
59
|
+
user
|
|
60
|
+
};
|
|
61
|
+
const { messages } = await this._buildMessages(text, opts);
|
|
62
|
+
const result = {
|
|
63
|
+
role: "assistant",
|
|
64
|
+
id: uuidv4(),
|
|
65
|
+
conversationId,
|
|
66
|
+
parentMessageId: messageId,
|
|
67
|
+
text: "",
|
|
68
|
+
suggestions: [],
|
|
69
|
+
user,
|
|
70
|
+
type: 'answer'
|
|
71
|
+
};
|
|
72
|
+
const responseP = new Promise(async (resolve, reject) => {
|
|
73
|
+
let _a, _b;
|
|
74
|
+
const url = `${this._apiBaseUrl}/chat`;
|
|
75
|
+
const headers = {
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
Authorization: `Bearer ${this._apiKey}`
|
|
78
|
+
};
|
|
79
|
+
const body = {
|
|
80
|
+
query: text,
|
|
81
|
+
stream,
|
|
82
|
+
conversation_id: conversationId,
|
|
83
|
+
...this._completionParams,
|
|
84
|
+
user,
|
|
85
|
+
chat_history: messages,
|
|
86
|
+
};
|
|
87
|
+
if (this._debug) {
|
|
88
|
+
console.log(`Coze send body`, body);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const res = await this._fetch(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers,
|
|
94
|
+
body: JSON.stringify(body),
|
|
95
|
+
signal: abortSignal
|
|
96
|
+
});
|
|
97
|
+
if (!res.ok) {
|
|
98
|
+
const reason = await res.text();
|
|
99
|
+
const msg = `Coze error ${res.status || res.statusText}: ${reason}`;
|
|
100
|
+
const error = new ChatCozeError(msg, { cause: res });
|
|
101
|
+
error.statusCode = res.status;
|
|
102
|
+
error.statusText = res.statusText;
|
|
103
|
+
return reject(error);
|
|
104
|
+
}
|
|
105
|
+
const response = await res.json();
|
|
106
|
+
if (this._debug) {
|
|
107
|
+
console.log('Coze response', response);
|
|
108
|
+
}
|
|
109
|
+
if (response.code === 0 && response.msg === "success") {
|
|
110
|
+
result.id = uuidv4();
|
|
111
|
+
result.conversationId = response.conversation_id;
|
|
112
|
+
const messages = response.messages;
|
|
113
|
+
const message2 = messages.find((message) => message.role === "assistant" && message.type === "answer");
|
|
114
|
+
result.text = message2.content;
|
|
115
|
+
result.type = message2.type;
|
|
116
|
+
if (message2.role) {
|
|
117
|
+
result.role = message2.role;
|
|
118
|
+
}
|
|
119
|
+
result.suggestions = messages.filter((message) => message.role === "assistant" && message.type === "follow_up") || [];
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
return reject(new Error(`Coze error: ${response.msg}`));
|
|
123
|
+
}
|
|
124
|
+
result.detail = response;
|
|
125
|
+
return resolve(result);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return reject(err);
|
|
129
|
+
}
|
|
130
|
+
}).then(async (message2) => {
|
|
131
|
+
return Promise.all([
|
|
132
|
+
this._upsertMessage(latestQuestion),
|
|
133
|
+
this._upsertMessage(message2)
|
|
134
|
+
]).then(() => message2);
|
|
135
|
+
});
|
|
136
|
+
if (timeoutMs) {
|
|
137
|
+
if (abortController) {
|
|
138
|
+
responseP.cancel = () => {
|
|
139
|
+
abortController.abort();
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return pTimeout(responseP, {
|
|
143
|
+
milliseconds: timeoutMs,
|
|
144
|
+
message: "Coze timed out waiting for response"
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
return responseP;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
get apiKey() {
|
|
152
|
+
return this._apiKey;
|
|
153
|
+
}
|
|
154
|
+
set apiKey(apiKey) {
|
|
155
|
+
this._apiKey = apiKey;
|
|
156
|
+
}
|
|
157
|
+
async _buildMessages(msg, opts) {
|
|
158
|
+
const { systemMessage = this._systemMessage } = opts;
|
|
159
|
+
let { parentMessageId } = opts;
|
|
160
|
+
let messages = [];
|
|
161
|
+
if (systemMessage) {
|
|
162
|
+
messages.push({
|
|
163
|
+
role: "system",
|
|
164
|
+
content: systemMessage,
|
|
165
|
+
content_type: "text"
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const systemMessageOffset = messages.length;
|
|
169
|
+
let nextMessages = messages;
|
|
170
|
+
do {
|
|
171
|
+
messages = nextMessages;
|
|
172
|
+
if (!parentMessageId) {
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
const parentMessage = await this._getMessageById(parentMessageId);
|
|
176
|
+
if (!parentMessage) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
const parentMessageRole = parentMessage.role || "user";
|
|
180
|
+
nextMessages = nextMessages.slice(0, systemMessageOffset).concat([
|
|
181
|
+
{
|
|
182
|
+
role: parentMessageRole,
|
|
183
|
+
content: parentMessage.text,
|
|
184
|
+
type: parentMessage.type,
|
|
185
|
+
},
|
|
186
|
+
...nextMessages.slice(systemMessageOffset)
|
|
187
|
+
]);
|
|
188
|
+
parentMessageId = parentMessage.parentMessageId;
|
|
189
|
+
} while (true);
|
|
190
|
+
return { messages };
|
|
191
|
+
}
|
|
192
|
+
async _defaultGetMessageById(id) {
|
|
193
|
+
return await this._messageStore.get(id);
|
|
194
|
+
}
|
|
195
|
+
async _defaultUpsertMessage(message) {
|
|
196
|
+
await this._messageStore.set(message.id, message);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
export { CozeAPI };
|
|
200
|
+
//# sourceMappingURL=coze.js.map
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
export const BASE_URL = 'https://api.dify.ai/v1';
|
|
3
|
+
export const routes = {
|
|
4
|
+
application: {
|
|
5
|
+
method: 'GET',
|
|
6
|
+
url: () => `/parameters`,
|
|
7
|
+
},
|
|
8
|
+
feedback: {
|
|
9
|
+
method: 'POST',
|
|
10
|
+
url: (messageId) => `/messages/${messageId}/feedbacks`,
|
|
11
|
+
},
|
|
12
|
+
createCompletionMessage: {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
url: () => `/completion-messages`,
|
|
15
|
+
},
|
|
16
|
+
createChatMessage: {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
url: () => `/chat-messages`,
|
|
19
|
+
},
|
|
20
|
+
getConversationMessages: {
|
|
21
|
+
method: 'GET',
|
|
22
|
+
url: () => '/messages',
|
|
23
|
+
},
|
|
24
|
+
getConversations: {
|
|
25
|
+
method: 'GET',
|
|
26
|
+
url: () => '/conversations',
|
|
27
|
+
},
|
|
28
|
+
renameConversation: {
|
|
29
|
+
method: 'PATCH',
|
|
30
|
+
url: (conversationId) => `/conversations/${conversationId}`,
|
|
31
|
+
},
|
|
32
|
+
deleteConversation: {
|
|
33
|
+
method: 'DELETE',
|
|
34
|
+
url: (conversation_id) => `/conversations/${conversation_id}`,
|
|
35
|
+
},
|
|
36
|
+
fileUpload: {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
url: () => `/files/upload`,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
export class DifyClient {
|
|
42
|
+
constructor({ apiKey, baseUrl = BASE_URL, debug = false, systemMessage = null, stream = false }) {
|
|
43
|
+
this.apiKey = apiKey;
|
|
44
|
+
this.baseUrl = baseUrl;
|
|
45
|
+
this.debug = debug;
|
|
46
|
+
this.stream = stream;
|
|
47
|
+
this.systemMessage = systemMessage;
|
|
48
|
+
}
|
|
49
|
+
updateApiKey(apiKey) {
|
|
50
|
+
this.apiKey = apiKey;
|
|
51
|
+
}
|
|
52
|
+
async sendUploadRequest(method, endpoint, data = null, params = null, stream = false, headerParams = {}) {
|
|
53
|
+
const headers = {
|
|
54
|
+
...{
|
|
55
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
56
|
+
'Content-Type': 'application/json',
|
|
57
|
+
},
|
|
58
|
+
...headerParams,
|
|
59
|
+
};
|
|
60
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
61
|
+
let response = await axios({
|
|
62
|
+
method,
|
|
63
|
+
url,
|
|
64
|
+
data,
|
|
65
|
+
params,
|
|
66
|
+
headers,
|
|
67
|
+
responseType: 'json',
|
|
68
|
+
});
|
|
69
|
+
return response;
|
|
70
|
+
}
|
|
71
|
+
async streamToString(stream) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
let data = '';
|
|
74
|
+
stream.on('data', (chunk) => (data += chunk.toString()));
|
|
75
|
+
stream.on('end', () => resolve(data));
|
|
76
|
+
stream.on('error', reject);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async sendRequest({ method, endpoint, data, params, stream = false, headerParams = {}, timeoutMs = 100 * 1000 }) {
|
|
80
|
+
try {
|
|
81
|
+
const headers = {
|
|
82
|
+
...{
|
|
83
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
84
|
+
'Content-Type': 'application/json',
|
|
85
|
+
},
|
|
86
|
+
...headerParams,
|
|
87
|
+
};
|
|
88
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
89
|
+
let response;
|
|
90
|
+
if (this.debug) {
|
|
91
|
+
console.log('dify request', url, { data, headers, params });
|
|
92
|
+
}
|
|
93
|
+
if (!stream) {
|
|
94
|
+
response = await axios({
|
|
95
|
+
method,
|
|
96
|
+
url,
|
|
97
|
+
data: data || null,
|
|
98
|
+
params: params || null,
|
|
99
|
+
headers,
|
|
100
|
+
timeout: timeoutMs,
|
|
101
|
+
responseType: 'json',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
response = await axios.request({
|
|
106
|
+
method,
|
|
107
|
+
url,
|
|
108
|
+
data,
|
|
109
|
+
params,
|
|
110
|
+
headers,
|
|
111
|
+
responseType: 'stream',
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return response;
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
if (stream && e.response) {
|
|
118
|
+
const errorText = await this.streamToString(e.response.data);
|
|
119
|
+
return Promise.reject(errorText);
|
|
120
|
+
}
|
|
121
|
+
console.log('error', e.response.data);
|
|
122
|
+
return Promise.reject(e);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
messageFeedback(messageId, rating, user) {
|
|
126
|
+
const data = {
|
|
127
|
+
rating,
|
|
128
|
+
user,
|
|
129
|
+
};
|
|
130
|
+
return this.sendRequest({ method: routes.feedback.method, endpoint: routes.feedback.url(messageId), data });
|
|
131
|
+
}
|
|
132
|
+
getApplicationParameters(user) {
|
|
133
|
+
const params = { user };
|
|
134
|
+
return this.sendRequest({ method: routes.application.method, endpoint: routes.application.url(), params });
|
|
135
|
+
}
|
|
136
|
+
fileUpload(data) {
|
|
137
|
+
return this.sendUploadRequest(routes.fileUpload.method, routes.fileUpload.url(), data, null, false, {
|
|
138
|
+
'Content-Type': 'multipart/form-data',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export class CompletionClient extends DifyClient {
|
|
143
|
+
createCompletionMessage(inputs, user, stream = false, files = null) {
|
|
144
|
+
const data = {
|
|
145
|
+
inputs,
|
|
146
|
+
user,
|
|
147
|
+
response_mode: stream ? 'streaming' : 'blocking',
|
|
148
|
+
files,
|
|
149
|
+
};
|
|
150
|
+
return this.sendRequest({
|
|
151
|
+
method: routes.createCompletionMessage.method,
|
|
152
|
+
endpoint: routes.createCompletionMessage.url(),
|
|
153
|
+
data,
|
|
154
|
+
stream,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function checkFileType(fileExtname) {
|
|
159
|
+
// 移除扩展名前的点号并转换为大写
|
|
160
|
+
const ext = fileExtname.replace('.', '').toUpperCase();
|
|
161
|
+
// 文档类型
|
|
162
|
+
const documentTypes = ['TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB'];
|
|
163
|
+
if (documentTypes.includes(ext)) {
|
|
164
|
+
return 'document';
|
|
165
|
+
}
|
|
166
|
+
// 图片类型
|
|
167
|
+
const imageTypes = ['JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG'];
|
|
168
|
+
if (imageTypes.includes(ext)) {
|
|
169
|
+
return 'image';
|
|
170
|
+
}
|
|
171
|
+
// 音频类型
|
|
172
|
+
const audioTypes = ['MP3', 'M4A', 'WAV', 'WEBM', 'AMR'];
|
|
173
|
+
if (audioTypes.includes(ext)) {
|
|
174
|
+
return 'audio';
|
|
175
|
+
}
|
|
176
|
+
// 视频类型
|
|
177
|
+
const videoTypes = ['MP4', 'MOV', 'MPEG', 'MPGA'];
|
|
178
|
+
if (videoTypes.includes(ext)) {
|
|
179
|
+
return 'video';
|
|
180
|
+
}
|
|
181
|
+
// 其他类型返回 custom
|
|
182
|
+
return 'custom';
|
|
183
|
+
}
|
|
184
|
+
export class ChatClient extends DifyClient {
|
|
185
|
+
async sendMessage({ query, file }, { systemMessage, user, conversationId = null, timeoutMs = 100 * 1000, inputs }) {
|
|
186
|
+
const data = {
|
|
187
|
+
inputs: {
|
|
188
|
+
...inputs,
|
|
189
|
+
},
|
|
190
|
+
query,
|
|
191
|
+
user,
|
|
192
|
+
response_mode: this.stream ? 'streaming' : 'blocking',
|
|
193
|
+
};
|
|
194
|
+
if (file) {
|
|
195
|
+
data['files'] = [
|
|
196
|
+
{
|
|
197
|
+
type: file.fileType === '图片' ? 'image' : checkFileType(file.fileExtname),
|
|
198
|
+
transfer_method: 'remote_url',
|
|
199
|
+
url: file.fileUrl,
|
|
200
|
+
},
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
if (systemMessage || this.systemMessage) {
|
|
204
|
+
data.inputs['systemMessage'] = systemMessage || this.systemMessage;
|
|
205
|
+
}
|
|
206
|
+
if (conversationId)
|
|
207
|
+
data.conversation_id = conversationId;
|
|
208
|
+
if (this.debug) {
|
|
209
|
+
console.log('request data', JSON.stringify(data));
|
|
210
|
+
}
|
|
211
|
+
const res = await this.sendRequest({
|
|
212
|
+
method: routes.createChatMessage.method,
|
|
213
|
+
endpoint: routes.createChatMessage.url(),
|
|
214
|
+
data,
|
|
215
|
+
stream: this.stream,
|
|
216
|
+
timeoutMs,
|
|
217
|
+
});
|
|
218
|
+
function unicodeToChar(text) {
|
|
219
|
+
if (!text)
|
|
220
|
+
return '';
|
|
221
|
+
return text.replace(/\\u[0-9a-f]{4}/g, (_match, p1) => {
|
|
222
|
+
return String.fromCharCode(parseInt(p1, 16));
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
const asyncSSE = (stream) => {
|
|
226
|
+
return new Promise((resolve, reject) => {
|
|
227
|
+
const answers = [];
|
|
228
|
+
const thought = [];
|
|
229
|
+
const files = [];
|
|
230
|
+
let conversation_id = '';
|
|
231
|
+
let id = '';
|
|
232
|
+
try {
|
|
233
|
+
stream.on('data', (data) => {
|
|
234
|
+
const streams = new TextDecoder('utf-8').decode(data, { stream: true }).split('\n');
|
|
235
|
+
streams.forEach((stream) => {
|
|
236
|
+
if (stream && stream.startsWith('data: ')) {
|
|
237
|
+
let res = {};
|
|
238
|
+
try {
|
|
239
|
+
res = JSON.parse(stream.substring(6)) || {};
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
// console.log('json 解析错误,不影响输出', e)
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (!res.event || res.event === 'error' || res.status === 400) {
|
|
246
|
+
console.log(`流式输出错误code:${res.code}`, res.message);
|
|
247
|
+
answers.push(res.message);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if ((res.event === 'agent_message' && res.answer) || (res.event === 'message' && res.answer)) {
|
|
251
|
+
conversation_id = res.conversation_id;
|
|
252
|
+
answers.push(unicodeToChar(res.answer));
|
|
253
|
+
}
|
|
254
|
+
if (res.event === 'message_file') {
|
|
255
|
+
console.log('收到一个需要展示的文件,稍后发送');
|
|
256
|
+
files.push(res.url);
|
|
257
|
+
}
|
|
258
|
+
if (res.event === 'agent_thought' && res.thought) {
|
|
259
|
+
console.log('Dify Agent 正在思考...');
|
|
260
|
+
thought.push(res.thought);
|
|
261
|
+
}
|
|
262
|
+
if (res.event === 'message_end') {
|
|
263
|
+
console.log('流数据接收完毕,正在组装数据进行发送');
|
|
264
|
+
conversation_id = res.conversation_id;
|
|
265
|
+
id = res.id;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
stream.on('end', async () => {
|
|
271
|
+
const { data } = conversation_id ? await this.getConversationMessages(user, conversation_id, null, 2) : { data: { data: [] } };
|
|
272
|
+
const lastMessage = data.data[data.data.length - 1] || {};
|
|
273
|
+
if (this.debug) {
|
|
274
|
+
console.log('获取最后一条对话记录', lastMessage);
|
|
275
|
+
}
|
|
276
|
+
let answer = '';
|
|
277
|
+
let finalFiles = [];
|
|
278
|
+
if (lastMessage.answer) {
|
|
279
|
+
answer = lastMessage.answer;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
answer = thought[thought.length - 1] ? thought[thought.length - 1] : answers.join('');
|
|
283
|
+
}
|
|
284
|
+
if (lastMessage.message_files && lastMessage.message_files.length) {
|
|
285
|
+
lastMessage.message_files.forEach((item) => {
|
|
286
|
+
if (item.belongs_to !== 'user') {
|
|
287
|
+
finalFiles.push(item.url);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
finalFiles = files;
|
|
293
|
+
}
|
|
294
|
+
resolve({ text: answer, conversationId: conversation_id, id, files: finalFiles });
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
catch (e) {
|
|
298
|
+
resolve({ text: `AI agent 出错,${e}`, conversationId: '', files: [] });
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
if (!this.stream) {
|
|
303
|
+
if (res.data.code) {
|
|
304
|
+
if (this.debug) {
|
|
305
|
+
console.log('dify request error', res.data.code, res.data.message);
|
|
306
|
+
}
|
|
307
|
+
return Promise.reject(res.message);
|
|
308
|
+
}
|
|
309
|
+
const response = res.data;
|
|
310
|
+
return {
|
|
311
|
+
text: response.answer,
|
|
312
|
+
conversationId: response.conversation_id,
|
|
313
|
+
files: [],
|
|
314
|
+
id: response.id,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
console.log('进入Dify Agent 智能助手输出模式,请耐心等待模型的思考');
|
|
319
|
+
const result = await asyncSSE(res.data);
|
|
320
|
+
return result;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
getConversationMessages(user, conversationId = '', firstId = null, limit = null) {
|
|
324
|
+
const params = { user };
|
|
325
|
+
if (conversationId)
|
|
326
|
+
params.conversation_id = conversationId;
|
|
327
|
+
if (firstId)
|
|
328
|
+
params.first_id = firstId;
|
|
329
|
+
if (limit)
|
|
330
|
+
params.limit = limit;
|
|
331
|
+
return this.sendRequest({
|
|
332
|
+
method: routes.getConversationMessages.method,
|
|
333
|
+
endpoint: routes.getConversationMessages.url(),
|
|
334
|
+
params,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
getConversations(user, firstId = null, limit = null, pinned = null) {
|
|
338
|
+
const params = { user, first_id: firstId, limit, pinned };
|
|
339
|
+
return this.sendRequest({
|
|
340
|
+
method: routes.getConversations.method,
|
|
341
|
+
endpoint: routes.getConversations.url(),
|
|
342
|
+
params,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
renameConversation(conversationId, name, user) {
|
|
346
|
+
const data = { name, user };
|
|
347
|
+
return this.sendRequest({
|
|
348
|
+
method: routes.renameConversation.method,
|
|
349
|
+
endpoint: routes.renameConversation.url(conversationId),
|
|
350
|
+
data,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
//# sourceMappingURL=difyClient.js.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export class TimeoutError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'TimeoutError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
An error to be thrown when the request is aborted by AbortController.
|
|
9
|
+
DOMException is thrown instead of this Error when DOMException is available.
|
|
10
|
+
*/
|
|
11
|
+
export class AbortError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super();
|
|
14
|
+
this.name = 'AbortError';
|
|
15
|
+
this.message = message;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
TODO: Remove AbortError and just throw DOMException when targeting Node 18.
|
|
20
|
+
*/
|
|
21
|
+
const getDOMException = errorMessage => globalThis.DOMException === undefined
|
|
22
|
+
? new AbortError(errorMessage)
|
|
23
|
+
: new DOMException(errorMessage);
|
|
24
|
+
/**
|
|
25
|
+
TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18.
|
|
26
|
+
*/
|
|
27
|
+
const getAbortedReason = signal => {
|
|
28
|
+
const reason = signal.reason === undefined
|
|
29
|
+
? getDOMException('This operation was aborted.')
|
|
30
|
+
: signal.reason;
|
|
31
|
+
return reason instanceof Error ? reason : getDOMException(reason);
|
|
32
|
+
};
|
|
33
|
+
export default function pTimeout(promise, options) {
|
|
34
|
+
const { milliseconds, fallback, message, customTimers = { setTimeout, clearTimeout }, } = options;
|
|
35
|
+
let timer;
|
|
36
|
+
const cancelablePromise = new Promise((resolve, reject) => {
|
|
37
|
+
if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {
|
|
38
|
+
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
39
|
+
}
|
|
40
|
+
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
41
|
+
resolve(promise);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (options.signal) {
|
|
45
|
+
const { signal } = options;
|
|
46
|
+
if (signal.aborted) {
|
|
47
|
+
reject(getAbortedReason(signal));
|
|
48
|
+
}
|
|
49
|
+
signal.addEventListener('abort', () => {
|
|
50
|
+
reject(getAbortedReason(signal));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// We create the error outside of `setTimeout` to preserve the stack trace.
|
|
54
|
+
const timeoutError = new TimeoutError();
|
|
55
|
+
timer = customTimers.setTimeout.call(undefined, () => {
|
|
56
|
+
if (fallback) {
|
|
57
|
+
try {
|
|
58
|
+
resolve(fallback());
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
reject(error);
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (typeof promise.cancel === 'function') {
|
|
66
|
+
promise.cancel();
|
|
67
|
+
}
|
|
68
|
+
if (message === false) {
|
|
69
|
+
resolve();
|
|
70
|
+
}
|
|
71
|
+
else if (message instanceof Error) {
|
|
72
|
+
reject(message);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
timeoutError.message = message ?? `Promise timed out after ${milliseconds} milliseconds`;
|
|
76
|
+
reject(timeoutError);
|
|
77
|
+
}
|
|
78
|
+
}, milliseconds);
|
|
79
|
+
(async () => {
|
|
80
|
+
try {
|
|
81
|
+
resolve(await promise);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
reject(error);
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
customTimers.clearTimeout.call(undefined, timer);
|
|
88
|
+
}
|
|
89
|
+
})();
|
|
90
|
+
});
|
|
91
|
+
cancelablePromise.clear = () => {
|
|
92
|
+
customTimers.clearTimeout.call(undefined, timer);
|
|
93
|
+
timer = undefined;
|
|
94
|
+
};
|
|
95
|
+
return cancelablePromise;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=pTimeout.js.map
|