@crysnovax/baileys 2.6.1 → 2.6.2
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 +45 -2
- package/lib/Socket/chats.js +7 -13
- package/lib/Utils/bot-planning-replay.js +57 -92
- package/lib/Utils/messages-media.js +74 -0
- package/lib/Utils/meta-compositing.js +61 -77
- package/package.json +1 -1
- package/README.md[old] +0 -1612
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ const crysnova = {
|
|
|
118
118
|
| Image Processing | ✅ | Auto-detects `sharp`, `@napi-rs/image`, or `jimp` |
|
|
119
119
|
| Safe FFmpeg | ✅ | Uses `spawn` instead of `exec` |
|
|
120
120
|
| In-Memory Store | ✅ | Reintroduced with minimal ESM adaptation |
|
|
121
|
-
| HD Profile Picture |
|
|
121
|
+
| HD Profile Picture | ✅ | Full-size upload with no crop or resize via `{ hd: true }` (max 720px) |
|
|
122
122
|
|
|
123
123
|
---
|
|
124
124
|
|
|
@@ -776,6 +776,10 @@ sock.sendMessage(jid, {
|
|
|
776
776
|
|
|
777
777
|
## Meta AI Features
|
|
778
778
|
|
|
779
|
+
Meta AI-style thinking indicators and live reasoning feeds. Works on **all WhatsApp clients** — no "Update WhatsApp" messages.
|
|
780
|
+
|
|
781
|
+
> **Note:** These use plain text placeholders with typing indicators, not native Meta AI rendering (which only works on AI-enabled WhatsApp clients). The visual experience is identical — users see "Thinking…" with live step completion.
|
|
782
|
+
|
|
779
783
|
### Meta Typing Indicator
|
|
780
784
|
|
|
781
785
|
Show a live thinking indicator that you control. Delete it manually when ready — no "edited" badge ever appears.
|
|
@@ -797,6 +801,19 @@ await sock.sendMessage(jid, { delete: placeholder.key })
|
|
|
797
801
|
await sock.sendMessage(jid, { text: 'Here is your answer!' })
|
|
798
802
|
```
|
|
799
803
|
|
|
804
|
+
**What users see:**
|
|
805
|
+
```
|
|
806
|
+
[typing… indicator]
|
|
807
|
+
|
|
808
|
+
_Thinking…_
|
|
809
|
+
○ Reading your message…
|
|
810
|
+
○ Writing response…
|
|
811
|
+
|
|
812
|
+
[auto-deletes]
|
|
813
|
+
|
|
814
|
+
Here is your answer!
|
|
815
|
+
```
|
|
816
|
+
|
|
800
817
|
### Meta Compositing
|
|
801
818
|
|
|
802
819
|
Full flow: indicator shows → auto-deletes → clean final message lands. Works with every rich content type.
|
|
@@ -875,6 +892,30 @@ await replayPlanning(
|
|
|
875
892
|
)
|
|
876
893
|
```
|
|
877
894
|
|
|
895
|
+
**What users see:**
|
|
896
|
+
```
|
|
897
|
+
_Thinking…_
|
|
898
|
+
○ Understanding your question…
|
|
899
|
+
○ Searching for data…
|
|
900
|
+
○ Writing the answer…
|
|
901
|
+
|
|
902
|
+
[step 1 completes]
|
|
903
|
+
_Thinking…_
|
|
904
|
+
✓ Understanding your question…
|
|
905
|
+
○ Searching for data…
|
|
906
|
+
○ Writing the answer…
|
|
907
|
+
|
|
908
|
+
[step 2 completes]
|
|
909
|
+
_Thinking…_
|
|
910
|
+
✓ Understanding your question…
|
|
911
|
+
✓ Searching for data…
|
|
912
|
+
○ Writing the answer…
|
|
913
|
+
|
|
914
|
+
[all done, deletes, then:]
|
|
915
|
+
|
|
916
|
+
const answer = 42
|
|
917
|
+
```
|
|
918
|
+
|
|
878
919
|
**Step type helpers:**
|
|
879
920
|
|
|
880
921
|
```javascript
|
|
@@ -1344,7 +1385,9 @@ sock.updateProfilePicture(jid, { url })
|
|
|
1344
1385
|
// Standard with custom dimensions
|
|
1345
1386
|
sock.updateProfilePicture(jid, { url }, { width: 640, height: 640 })
|
|
1346
1387
|
|
|
1347
|
-
//
|
|
1388
|
+
// HD — preserves original aspect ratio, no crop, no padding
|
|
1389
|
+
// Images under 720px pass through unchanged.
|
|
1390
|
+
// Larger images are scaled down proportionally to fit within 720px.
|
|
1348
1391
|
sock.updateProfilePicture(jid, buffer, { hd: true })
|
|
1349
1392
|
sock.updateProfilePicture(jid, { url }, { hd: true })
|
|
1350
1393
|
|
package/lib/Socket/chats.js
CHANGED
|
@@ -5,7 +5,7 @@ import { DEFAULT_CACHE_TTLS, HISTORY_SYNC_PAUSED_TIMEOUT_MS, PROCESSABLE_HISTORY
|
|
|
5
5
|
import { ALL_WA_PATCH_NAMES } from '../Types/index.js';
|
|
6
6
|
import { SyncState } from '../Types/State.js';
|
|
7
7
|
import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, ensureLTHashStateVersion, extractSyncdPatches, generateProfilePicture, getHistoryMsg, isAppStateSyncIrrecoverable, isMissingKeyError, MAX_SYNC_ATTEMPTS, newLTHashState, processSyncAction } from '../Utils/index.js';
|
|
8
|
-
import {
|
|
8
|
+
import { generateProfilePictureHD } from '../Utils/messages-media.js';
|
|
9
9
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
10
10
|
import processMessage from '../Utils/process-message.js';
|
|
11
11
|
import { buildTcTokenFromJid } from '../Utils/tc-token-utils.js';
|
|
@@ -228,18 +228,12 @@ export const makeChatsSocket = (config) => {
|
|
|
228
228
|
else {
|
|
229
229
|
targetJid = undefined;
|
|
230
230
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const { stream } = await getStream(content);
|
|
238
|
-
img = await toBuffer(stream);
|
|
239
|
-
}
|
|
240
|
-
} else {
|
|
241
|
-
({ img } = await generateProfilePicture(content, dimensions));
|
|
242
|
-
}
|
|
231
|
+
// crysnovax@HD-Profile --- Dual mode:
|
|
232
|
+
// hd:true → generateProfilePictureHD (preserves aspect ratio, caps at 1920, manages file size)
|
|
233
|
+
// standard → generateProfilePicture (720×720 square crop, or custom dimensions)
|
|
234
|
+
const { img } = dimensions?.hd
|
|
235
|
+
? await generateProfilePictureHD(content)
|
|
236
|
+
: await generateProfilePicture(content, dimensions);
|
|
243
237
|
await query({
|
|
244
238
|
tag: 'iq',
|
|
245
239
|
attrs: {
|
|
@@ -2,22 +2,17 @@
|
|
|
2
2
|
* Lia@Changes [WIP]
|
|
3
3
|
* botPlanningReplay — Meta AI-style live reasoning feed.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* with NO "edited" badge, using the same delete-resend flow from
|
|
9
|
-
* meta-compositing.
|
|
10
|
-
*
|
|
11
|
-
* replayPlanning(sock, jid, steps, finalContent, options)
|
|
5
|
+
* UNIVERSAL VERSION: Works on ALL WhatsApp clients.
|
|
6
|
+
* - Native Meta AI rendering for compatible clients
|
|
7
|
+
* - Plain text fallback for regular clients (no "Update WhatsApp")
|
|
12
8
|
*
|
|
13
9
|
* Flow:
|
|
14
|
-
* Send placeholder (all steps
|
|
15
|
-
* → edit: step[0] → DONE
|
|
16
|
-
* → edit: step[1] → DONE
|
|
10
|
+
* Send placeholder (all steps pending)
|
|
11
|
+
* → edit: step[0] → DONE
|
|
12
|
+
* → edit: step[1] → DONE
|
|
17
13
|
* → ...
|
|
18
|
-
* → edit: step[n] → DONE (finalPauseMs)
|
|
19
14
|
* → delete placeholder
|
|
20
|
-
* → send final
|
|
15
|
+
* → send final message fresh
|
|
21
16
|
*
|
|
22
17
|
* If you use or copy this code, please credit @crysnovax/bailey.
|
|
23
18
|
*/
|
|
@@ -26,46 +21,32 @@ import { proto } from '../../WAProto/index.js';
|
|
|
26
21
|
import {
|
|
27
22
|
buildCompositingPlaceholder,
|
|
28
23
|
buildProgressIndicator,
|
|
24
|
+
buildPlainPlaceholder,
|
|
29
25
|
PlanningStepStatus
|
|
30
26
|
} from './meta-compositing.js';
|
|
31
27
|
import { botMetadataSignature, botMetadataCertificate } from './rich-message-utils.js';
|
|
32
28
|
import { BOT_RENDERING_CONFIG_METADATA } from '../Defaults/index.js';
|
|
33
29
|
import { delay } from './generics.js';
|
|
34
30
|
|
|
35
|
-
// ─── Internal:
|
|
31
|
+
// ─── Internal: build native Meta AI frame ──────────────────────────────────
|
|
36
32
|
const buildReplayFrame = (description, steps, placeholderText = '') => {
|
|
37
33
|
return buildCompositingPlaceholder({ description, steps, placeholderText });
|
|
38
34
|
};
|
|
39
35
|
|
|
40
|
-
// ─── Internal:
|
|
36
|
+
// ─── Internal: edit planning bubble (native Meta AI) ───────────────────────
|
|
41
37
|
const editPlanningBubble = async (sock, jid, key, description, steps, placeholderText) => {
|
|
42
38
|
const updated = buildReplayFrame(description, steps, placeholderText);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
await sock.sendMessage(jid, { raw: true, edit: key, ...updated });
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// ─── Internal: edit plain text bubble (universal) ──────────────────────────
|
|
43
|
+
const editPlainBubble = async (sock, jid, key, description, steps, placeholderText) => {
|
|
44
|
+
const updated = buildPlainPlaceholder(description, steps, placeholderText);
|
|
45
|
+
await sock.sendMessage(jid, { edit: key, ...updated });
|
|
49
46
|
};
|
|
50
47
|
|
|
51
48
|
/**
|
|
52
|
-
* replayPlanning — full live planning animation.
|
|
53
|
-
*
|
|
54
|
-
* @param {object} sock - Baileys socket
|
|
55
|
-
* @param {string} jid - Destination JID
|
|
56
|
-
* @param {Array} steps - Array of step definitions:
|
|
57
|
-
* { title, body?, isReasoning?, isEnhancedSearch? }
|
|
58
|
-
* Status is managed automatically — do NOT pass status here.
|
|
59
|
-
* @param {object} finalContent - Rich content for the final message.
|
|
60
|
-
* Same as sendMessage: { code, table, text, richResponse… }
|
|
61
|
-
* @param {object} [options]
|
|
62
|
-
* @param {string} [options.description] - Top label while thinking. Default: 'Thinking…'
|
|
63
|
-
* @param {string} [options.placeholderText] - Body text shown in bubble while loading.
|
|
64
|
-
* @param {number} [options.stepDelayMs] - Ms between each step completing. Default: 900
|
|
65
|
-
* @param {number} [options.finalPauseMs] - Ms to hold after all steps done before cleanup. Default: 600
|
|
66
|
-
* @param {boolean} [options.abortOnDisconnect] - Stop replay loop if socket closes. Default: true
|
|
67
|
-
* @param {object} [options.sendOptions] - Extra options for final sendMessage call.
|
|
68
|
-
* @returns {Promise<object>} - The final sent WAMessage
|
|
49
|
+
* replayPlanning — full live planning animation (UNIVERSAL).
|
|
69
50
|
*/
|
|
70
51
|
export const replayPlanning = async (sock, jid, steps, finalContent, {
|
|
71
52
|
description = 'Thinking…',
|
|
@@ -73,13 +54,13 @@ export const replayPlanning = async (sock, jid, steps, finalContent, {
|
|
|
73
54
|
stepDelayMs = 900,
|
|
74
55
|
finalPauseMs = 600,
|
|
75
56
|
abortOnDisconnect = true,
|
|
76
|
-
sendOptions = {}
|
|
57
|
+
sendOptions = {},
|
|
58
|
+
useNativeMeta = false
|
|
77
59
|
} = {}) => {
|
|
78
60
|
if (!steps?.length) {
|
|
79
61
|
throw new Error('replayPlanning: steps array must have at least one entry');
|
|
80
62
|
}
|
|
81
63
|
|
|
82
|
-
// ── Track abort state if socket disconnects mid-replay ───────────────────
|
|
83
64
|
let aborted = false;
|
|
84
65
|
const onClose = () => { aborted = true; };
|
|
85
66
|
if (abortOnDisconnect) {
|
|
@@ -88,112 +69,96 @@ export const replayPlanning = async (sock, jid, steps, finalContent, {
|
|
|
88
69
|
});
|
|
89
70
|
}
|
|
90
71
|
|
|
91
|
-
//
|
|
72
|
+
// Show typing
|
|
73
|
+
await sock.sendPresenceUpdate('composing', jid);
|
|
74
|
+
|
|
75
|
+
// Build initial steps (all pending)
|
|
92
76
|
const initialSteps = steps.map(step => ({
|
|
93
77
|
...step,
|
|
94
78
|
status: PlanningStepStatus.IN_PROGRESS
|
|
95
79
|
}));
|
|
96
80
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
81
|
+
// Determine mode
|
|
82
|
+
const isNative = useNativeMeta && false; // Always false for now — force universal
|
|
83
|
+
|
|
84
|
+
// Send initial placeholder
|
|
85
|
+
let placeholder;
|
|
86
|
+
if (isNative) {
|
|
87
|
+
placeholder = await sock.sendMessage(jid, {
|
|
88
|
+
raw: true,
|
|
89
|
+
...buildReplayFrame(description, initialSteps, placeholderText)
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
placeholder = await sock.sendMessage(jid,
|
|
93
|
+
buildPlainPlaceholder(description, initialSteps, placeholderText)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
101
96
|
|
|
102
97
|
const key = placeholder?.key;
|
|
103
98
|
|
|
104
|
-
//
|
|
99
|
+
// Replay loop
|
|
105
100
|
try {
|
|
106
101
|
const currentSteps = [...initialSteps];
|
|
107
102
|
|
|
108
103
|
for (let i = 0; i < currentSteps.length; i++) {
|
|
109
104
|
if (aborted) break;
|
|
110
|
-
|
|
111
105
|
await delay(stepDelayMs);
|
|
112
106
|
if (aborted) break;
|
|
113
107
|
|
|
114
|
-
|
|
115
|
-
currentSteps[i] = {
|
|
116
|
-
...currentSteps[i],
|
|
117
|
-
status: PlanningStepStatus.DONE
|
|
118
|
-
};
|
|
108
|
+
currentSteps[i] = { ...currentSteps[i], status: PlanningStepStatus.DONE };
|
|
119
109
|
|
|
120
110
|
if (key) {
|
|
121
|
-
|
|
122
|
-
sock, jid, key,
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
if (isNative) {
|
|
112
|
+
await editPlanningBubble(sock, jid, key, description, currentSteps, placeholderText);
|
|
113
|
+
} else {
|
|
114
|
+
await editPlainBubble(sock, jid, key, description, currentSteps, placeholderText);
|
|
115
|
+
}
|
|
125
116
|
}
|
|
126
117
|
}
|
|
127
118
|
|
|
128
|
-
// ── 3. Hold with all steps DONE so user sees completion ──────────────
|
|
129
119
|
if (!aborted && finalPauseMs > 0) {
|
|
130
120
|
await delay(finalPauseMs);
|
|
131
121
|
}
|
|
132
122
|
|
|
133
|
-
// ── 4. Delete placeholder silently ───────────────────────────────────
|
|
134
123
|
if (key && !aborted) {
|
|
135
124
|
await sock.sendMessage(jid, { delete: key });
|
|
136
125
|
}
|
|
137
126
|
} catch (err) {
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
if (key) await sock.sendMessage(jid, { delete: key });
|
|
141
|
-
} catch (_) {}
|
|
127
|
+
try { if (key) await sock.sendMessage(jid, { delete: key }); } catch (_) {}
|
|
142
128
|
}
|
|
143
129
|
|
|
144
|
-
|
|
130
|
+
await sock.sendPresenceUpdate('paused', jid);
|
|
131
|
+
|
|
132
|
+
// Skip final send if _skipFinalSend is set (for replayPlanningOnly)
|
|
133
|
+
if (sendOptions._skipFinalSend) return placeholder;
|
|
134
|
+
|
|
145
135
|
return sock.sendMessage(jid, finalContent, sendOptions);
|
|
146
136
|
};
|
|
147
137
|
|
|
148
138
|
/**
|
|
149
|
-
* replayPlanningOnly —
|
|
150
|
-
* Use when you want to control the final send yourself.
|
|
151
|
-
*
|
|
152
|
-
* Returns { key } of the placeholder (already deleted on completion).
|
|
153
|
-
*
|
|
154
|
-
* @param {object} sock
|
|
155
|
-
* @param {string} jid
|
|
156
|
-
* @param {Array} steps
|
|
157
|
-
* @param {object} [options] - Same options as replayPlanning minus sendOptions
|
|
158
|
-
* @returns {Promise<void>}
|
|
139
|
+
* replayPlanningOnly — animation WITHOUT final message.
|
|
159
140
|
*/
|
|
160
141
|
export const replayPlanningOnly = async (sock, jid, steps, options = {}) => {
|
|
161
142
|
return replayPlanning(sock, jid, steps, null, {
|
|
162
143
|
...options,
|
|
163
|
-
_skipFinalSend: true
|
|
144
|
+
sendOptions: { ...options.sendOptions, _skipFinalSend: true }
|
|
164
145
|
});
|
|
165
146
|
};
|
|
166
147
|
|
|
167
148
|
/**
|
|
168
|
-
* buildReasoningSteps —
|
|
169
|
-
* Renders with the "reasoning" visual treatment in the Meta bubble.
|
|
170
|
-
*
|
|
171
|
-
* @example
|
|
172
|
-
* buildReasoningSteps(['Analyzing the problem…', 'Checking edge cases…'])
|
|
149
|
+
* buildReasoningSteps — steps with isReasoning: true.
|
|
173
150
|
*/
|
|
174
151
|
export const buildReasoningSteps = (titles) =>
|
|
175
152
|
titles.map(title => ({ title, isReasoning: true }));
|
|
176
153
|
|
|
177
154
|
/**
|
|
178
|
-
* buildSearchSteps —
|
|
179
|
-
* Renders with the "enhanced search" visual treatment.
|
|
180
|
-
*
|
|
181
|
-
* @example
|
|
182
|
-
* buildSearchSteps(['Searching the web…', 'Reading top results…'])
|
|
155
|
+
* buildSearchSteps — steps with isEnhancedSearch: true.
|
|
183
156
|
*/
|
|
184
157
|
export const buildSearchSteps = (titles) =>
|
|
185
158
|
titles.map(title => ({ title, isEnhancedSearch: true }));
|
|
186
159
|
|
|
187
160
|
/**
|
|
188
|
-
* mixedSteps —
|
|
189
|
-
* Pass an array of { title, type? } where type is 'reasoning' | 'search' | undefined.
|
|
190
|
-
*
|
|
191
|
-
* @example
|
|
192
|
-
* mixedSteps([
|
|
193
|
-
* { title: 'Understanding your question…', type: 'reasoning' },
|
|
194
|
-
* { title: 'Searching for data…', type: 'search' },
|
|
195
|
-
* { title: 'Writing the answer…' }
|
|
196
|
-
* ])
|
|
161
|
+
* mixedSteps — mix reasoning + search + plain steps.
|
|
197
162
|
*/
|
|
198
163
|
export const mixedSteps = (defs) =>
|
|
199
164
|
defs.map(({ title, body, type }) => ({
|
|
@@ -220,6 +220,80 @@ export const generateProfilePicture = async (mediaUpload, dimensions) => {
|
|
|
220
220
|
img: await img
|
|
221
221
|
};
|
|
222
222
|
};
|
|
223
|
+
// crysnovax@HD-Profile --- Like generateProfilePicture but skips resize/crop.
|
|
224
|
+
// Re-encodes to JPEG so WA always gets valid image bytes.
|
|
225
|
+
// crysnovax@HD-Profile --- HD mode: preserves original aspect ratio, no crop.
|
|
226
|
+
// WhatsApp server accepts max 720px on any side. Images under 720px pass through
|
|
227
|
+
// unchanged. Larger images are scaled down proportionally to fit within 720px.
|
|
228
|
+
export const generateProfilePictureHD = async (mediaUpload) => {
|
|
229
|
+
let buffer;
|
|
230
|
+
if (Buffer.isBuffer(mediaUpload)) {
|
|
231
|
+
buffer = mediaUpload;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
const { stream } = await getStream(mediaUpload);
|
|
235
|
+
buffer = await toBuffer(stream);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const lib = await getImageProcessingLibrary();
|
|
239
|
+
let img;
|
|
240
|
+
|
|
241
|
+
if ('sharp' in lib && lib.sharp?.default) {
|
|
242
|
+
const metadata = await lib.sharp.default(buffer).metadata();
|
|
243
|
+
const origWidth = metadata.width || 720;
|
|
244
|
+
const origHeight = metadata.height || 720;
|
|
245
|
+
const maxDim = Math.max(origWidth, origHeight);
|
|
246
|
+
|
|
247
|
+
// WhatsApp server limit: 720px max dimension
|
|
248
|
+
// If already under 720, send as-is. If larger, scale down proportionally.
|
|
249
|
+
const needsResize = maxDim > 720;
|
|
250
|
+
|
|
251
|
+
let pipeline = lib.sharp.default(buffer);
|
|
252
|
+
|
|
253
|
+
if (needsResize) {
|
|
254
|
+
pipeline = pipeline.resize(720, 720, {
|
|
255
|
+
fit: 'inside',
|
|
256
|
+
withoutEnlargement: true
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
img = pipeline
|
|
261
|
+
.jpeg({ quality: 85, mozjpeg: true })
|
|
262
|
+
.toBuffer();
|
|
263
|
+
}
|
|
264
|
+
else if ('image' in lib && lib.image?.Transformer) {
|
|
265
|
+
// @napi-rs/image — cap at 720 via resize
|
|
266
|
+
img = new lib.image
|
|
267
|
+
.Transformer(buffer)
|
|
268
|
+
.resize(720, 720)
|
|
269
|
+
.jpeg(85);
|
|
270
|
+
}
|
|
271
|
+
else if ('jimp' in lib && lib.jimp?.Jimp) {
|
|
272
|
+
const jimp = await lib.jimp.Jimp.read(buffer);
|
|
273
|
+
const origWidth = jimp.width;
|
|
274
|
+
const origHeight = jimp.height;
|
|
275
|
+
const maxDim = Math.max(origWidth, origHeight);
|
|
276
|
+
|
|
277
|
+
let processed = jimp;
|
|
278
|
+
if (maxDim > 720) {
|
|
279
|
+
const scale = 720 / maxDim;
|
|
280
|
+
processed = jimp.resize({
|
|
281
|
+
w: Math.round(origWidth * scale),
|
|
282
|
+
h: Math.round(origHeight * scale),
|
|
283
|
+
mode: lib.jimp.ResizeStrategy.BILINEAR
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
img = processed.getBuffer('image/jpeg', { quality: 85 });
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
throw new Boom('No image processing library available');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const result = await img;
|
|
294
|
+
console.log(`[HD-Profile] Output: ${result.length} bytes, dims preserved (max 720px)`);
|
|
295
|
+
return { img: result };
|
|
296
|
+
};
|
|
223
297
|
/** gets the SHA256 of the given media message */
|
|
224
298
|
export const mediaMessageSHA256B64 = (message) => {
|
|
225
299
|
const media = Object.values(message)[0];
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Lia@Changes [WIP]
|
|
3
|
-
* Meta Compositing — send rich messages
|
|
4
|
-
* Meta AI-style progress indicator that appears BEFORE the final message.
|
|
3
|
+
* Meta Compositing — send rich messages with Meta AI-style progress indicator.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* UNIVERSAL VERSION: Works on ALL WhatsApp clients.
|
|
6
|
+
* - Native Meta AI rendering for compatible clients (Beta, AI-enabled)
|
|
7
|
+
* - Plain text fallback for regular clients (no "Update WhatsApp")
|
|
9
8
|
*
|
|
10
|
-
* metaTyping() — shows the "typing..." / planning steps indicator
|
|
9
|
+
* metaTyping() — shows the "typing..." / planning steps indicator.
|
|
11
10
|
* sendMetaComposited() — full flow: typing → delete → final message.
|
|
12
11
|
*
|
|
13
12
|
* If you use or copy this code, please credit @crysnovax/bailey.
|
|
@@ -19,18 +18,23 @@ import { BOT_RENDERING_CONFIG_METADATA } from '../Defaults/index.js';
|
|
|
19
18
|
import { generateWAMessageFromContent } from './messages.js';
|
|
20
19
|
import { unixTimestampSeconds, delay } from './generics.js';
|
|
21
20
|
|
|
22
|
-
// ─── Step status enum
|
|
21
|
+
// ─── Step status enum ───
|
|
23
22
|
export const PlanningStepStatus = {
|
|
24
23
|
IN_PROGRESS: 0,
|
|
25
24
|
DONE: 1,
|
|
26
25
|
FAILED: 2
|
|
27
26
|
};
|
|
28
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Check if recipient supports native Meta AI rendering.
|
|
30
|
+
* Always false for now — WhatsApp hasn't opened this to third-party bots.
|
|
31
|
+
*/
|
|
32
|
+
export const supportsMetaRendering = (jid, config = {}) => {
|
|
33
|
+
return config.forceMetaRendering === true;
|
|
34
|
+
};
|
|
35
|
+
|
|
29
36
|
/**
|
|
30
37
|
* Build a BotProgressIndicatorMetadata object.
|
|
31
|
-
* @param {string} description - Top-level label shown while "thinking"
|
|
32
|
-
* @param {Array} steps - Array of { title, body?, status?, isReasoning? }
|
|
33
|
-
* @param {number} estimatedMs - Optional estimated completion time in ms
|
|
34
38
|
*/
|
|
35
39
|
export const buildProgressIndicator = (description, steps = [], estimatedMs) => {
|
|
36
40
|
const stepsMetadata = steps.map(step => {
|
|
@@ -51,27 +55,16 @@ export const buildProgressIndicator = (description, steps = [], estimatedMs) =>
|
|
|
51
55
|
};
|
|
52
56
|
|
|
53
57
|
/**
|
|
54
|
-
* Build the
|
|
55
|
-
* "Meta AI is thinking..." / planning steps indicator in the chat bubble.
|
|
56
|
-
*
|
|
57
|
-
* This is a botForwardedMessage with richResponseMessage = null content
|
|
58
|
-
* but with progressIndicatorMetadata on the botMetadata.
|
|
59
|
-
*
|
|
60
|
-
* @param {object} options
|
|
61
|
-
* @param {string} options.description - "Thinking…" label
|
|
62
|
-
* @param {Array} options.steps - Planning steps array
|
|
63
|
-
* @param {number} [options.estimatedMs] - Estimated completion ms
|
|
64
|
-
* @param {string} [options.placeholderText] - Text shown in the bubble body while loading
|
|
58
|
+
* Build the native Meta AI compositing placeholder (for compatible clients only).
|
|
65
59
|
*/
|
|
66
60
|
export const buildCompositingPlaceholder = ({
|
|
67
61
|
description = 'Thinking…',
|
|
68
62
|
steps = [],
|
|
69
63
|
estimatedMs,
|
|
70
64
|
placeholderText = ''
|
|
71
|
-
}) => {
|
|
65
|
+
} = {}) => {
|
|
72
66
|
const progressIndicatorMetadata = buildProgressIndicator(description, steps, estimatedMs);
|
|
73
67
|
|
|
74
|
-
// Minimal richResponseMessage so the bubble renders in Bot mode
|
|
75
68
|
const textEncoder = new TextEncoder();
|
|
76
69
|
const unifiedData = textEncoder.encode(JSON.stringify({
|
|
77
70
|
response_id: crypto.randomUUID(),
|
|
@@ -119,90 +112,81 @@ export const buildCompositingPlaceholder = ({
|
|
|
119
112
|
};
|
|
120
113
|
|
|
121
114
|
/**
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
115
|
+
* Build a plain-text placeholder that works on ALL WhatsApp clients.
|
|
116
|
+
*/
|
|
117
|
+
export const buildPlainPlaceholder = (description = 'Thinking…', steps = [], placeholderText = '') => {
|
|
118
|
+
const stepLines = steps.map(step => {
|
|
119
|
+
const icon = step.status === PlanningStepStatus.DONE ? '✓' :
|
|
120
|
+
step.status === PlanningStepStatus.FAILED ? '✗' : '○';
|
|
121
|
+
return `${icon} ${step.title}`;
|
|
122
|
+
}).join('\n');
|
|
123
|
+
|
|
124
|
+
let text = `_${description}_`;
|
|
125
|
+
if (stepLines) text += `\n\n${stepLines}`;
|
|
126
|
+
if (placeholderText) text += `\n\n${placeholderText}`;
|
|
127
|
+
|
|
128
|
+
return { text };
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* metaTyping — sends the progress/compositing indicator.
|
|
133
|
+
* UNIVERSAL: Uses plain text for regular clients, native Meta AI for compatible ones.
|
|
131
134
|
*/
|
|
132
135
|
export const metaTyping = async (sock, jid, {
|
|
133
136
|
description = 'Thinking…',
|
|
134
137
|
steps = [],
|
|
135
138
|
estimatedMs,
|
|
136
|
-
placeholderText = ''
|
|
139
|
+
placeholderText = '',
|
|
140
|
+
useNativeMeta = false
|
|
137
141
|
} = {}) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
// Show typing indicator
|
|
143
|
+
await sock.sendPresenceUpdate('composing', jid);
|
|
144
|
+
|
|
145
|
+
if (useNativeMeta && supportsMetaRendering(jid, sock.config)) {
|
|
146
|
+
const placeholder = buildCompositingPlaceholder({
|
|
147
|
+
description, steps, estimatedMs, placeholderText
|
|
148
|
+
});
|
|
149
|
+
return sock.sendMessage(jid, { raw: true, ...placeholder });
|
|
150
|
+
}
|
|
144
151
|
|
|
145
|
-
|
|
152
|
+
// Universal fallback: plain text placeholder
|
|
153
|
+
const plainSteps = steps.map(s => ({ ...s, status: PlanningStepStatus.IN_PROGRESS }));
|
|
154
|
+
const placeholder = buildPlainPlaceholder(description, plainSteps, placeholderText);
|
|
155
|
+
return sock.sendMessage(jid, placeholder);
|
|
146
156
|
};
|
|
147
157
|
|
|
148
158
|
/**
|
|
149
|
-
* sendMetaComposited — full Meta AI flow
|
|
150
|
-
* 1. Send progress indicator
|
|
151
|
-
* 2. Wait
|
|
152
|
-
* 3. Delete
|
|
153
|
-
* 4. Send
|
|
154
|
-
*
|
|
155
|
-
* Supports all existing richResponse content types: text, code, table,
|
|
156
|
-
* expressions (LaTeX), items (reels carousel), or the richResponse array.
|
|
157
|
-
*
|
|
158
|
-
* @param {object} sock - Baileys socket
|
|
159
|
-
* @param {string} jid - Destination JID
|
|
160
|
-
* @param {object} content - Same content object as sendMessage richResponse
|
|
161
|
-
* @param {object} [options]
|
|
162
|
-
* @param {number} [options.thinkingMs=2000] - How long placeholder shows
|
|
163
|
-
* @param {string} [options.description='Thinking…'] - Placeholder label
|
|
164
|
-
* @param {Array} [options.steps=[]] - Planning steps to show
|
|
165
|
-
* @param {string} [options.placeholderText=''] - Body text while loading
|
|
166
|
-
* @param {object} [options.sendOptions={}] - Extra options for final sendMessage
|
|
167
|
-
* @returns {Promise<object>} - The final sent WAMessage
|
|
159
|
+
* sendMetaComposited — full Meta AI flow (UNIVERSAL).
|
|
160
|
+
* 1. Send progress indicator
|
|
161
|
+
* 2. Wait thinkingMs
|
|
162
|
+
* 3. Delete placeholder
|
|
163
|
+
* 4. Send final message fresh
|
|
168
164
|
*/
|
|
169
165
|
export const sendMetaComposited = async (sock, jid, content, {
|
|
170
166
|
thinkingMs = 2000,
|
|
171
167
|
description = 'Thinking…',
|
|
172
168
|
steps = [],
|
|
173
169
|
placeholderText = '',
|
|
174
|
-
sendOptions = {}
|
|
170
|
+
sendOptions = {},
|
|
171
|
+
useNativeMeta = false
|
|
175
172
|
} = {}) => {
|
|
176
|
-
// 1. Send the compositing placeholder
|
|
177
173
|
const placeholder = await metaTyping(sock, jid, {
|
|
178
|
-
description,
|
|
179
|
-
steps,
|
|
180
|
-
placeholderText
|
|
174
|
+
description, steps, estimatedMs: thinkingMs, placeholderText, useNativeMeta
|
|
181
175
|
});
|
|
182
176
|
|
|
183
177
|
try {
|
|
184
|
-
// 2. Wait — this is the "thinking" window
|
|
185
178
|
await delay(thinkingMs);
|
|
186
|
-
|
|
187
|
-
// 3. Delete the placeholder silently
|
|
188
179
|
if (placeholder?.key) {
|
|
189
180
|
await sock.sendMessage(jid, { delete: placeholder.key });
|
|
190
181
|
}
|
|
191
|
-
} catch (_) {
|
|
192
|
-
// Non-fatal — always attempt final send
|
|
193
|
-
}
|
|
182
|
+
} catch (_) {}
|
|
194
183
|
|
|
195
|
-
|
|
184
|
+
await sock.sendPresenceUpdate('paused', jid);
|
|
196
185
|
return sock.sendMessage(jid, content, sendOptions);
|
|
197
186
|
};
|
|
198
187
|
|
|
199
188
|
/**
|
|
200
|
-
* Convenience: build a steps array from plain strings
|
|
201
|
-
* Use PlanningStepStatus.DONE to mark a step complete.
|
|
202
|
-
*
|
|
203
|
-
* @example
|
|
204
|
-
* buildSteps(['Searching…', 'Reading sources…', 'Writing response…'])
|
|
189
|
+
* Convenience: build a steps array from plain strings.
|
|
205
190
|
*/
|
|
206
191
|
export const buildSteps = (titles, status = PlanningStepStatus.IN_PROGRESS) =>
|
|
207
192
|
titles.map(title => ({ title, status }));
|
|
208
|
-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crysnovax/baileys",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "Premium Baileys fork ⚉ Meta compositing, bot planning replay, welcome flow, rich messages (code, table, LaTeX, reels), interactive messages, albums, and more.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|