whatsapp-pi 1.0.51 → 1.0.52

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 CHANGED
@@ -27,7 +27,7 @@ Pi is a powerful agentic AI coding assistant that operates in your terminal. Thi
27
27
  - **Media Support**:
28
28
  - **Vision Analysis**: Automatically forwards WhatsApp images to Pi for analysis.
29
29
  - **Audio Transcription**: Transcribes voice notes when Whisper is installed.
30
- - **Document Handling**: Downloads and stores documents (PDF, text) for agent access.
30
+ - **Document Handling**: Downloads and stores documents (PDF, text) for agent access; PDFs include a bounded text preview when readable.
31
31
 
32
32
  ## Prerequisites
33
33
 
@@ -36,10 +36,8 @@ To enable audio transcription features:
36
36
  python -m pip install -U openai-whisper
37
37
  ```
38
38
 
39
- To enable PDF reading capabilities (required for the agent to process documents):
40
- - **Linux**: `sudo apt-get install poppler-utils`
41
- - **macOS**: `brew install poppler`
42
- - **Windows**: Install `poppler` (e.g., via Scoop) and add to PATH.
39
+ PDF documents are parsed locally and do not require extra system utilities.
40
+ If a PDF cannot be parsed automatically, it is still saved and forwarded with a clear fallback notice.
43
41
 
44
42
  ## Quick Start
45
43
 
@@ -164,7 +162,7 @@ npm test
164
162
  - **Group-Only Mode**: Use `--whatsapp-group <jid>` to bind Pi to a single WhatsApp group. The group must also be present in Allowed Groups.
165
163
  - **Recents Store**: Recent conversations and message history are persisted in `~/.pi/whatsapp-pi/recents/recents.json`.
166
164
  - **Message Detail / Reply**: Open a message from history to inspect full content and reply with `R`.
167
- - **Media Support**: Images are forwarded for vision analysis, audio is transcribed with Whisper, and documents are saved under `./.pi-data/whatsapp/documents/`.
165
+ - **Media Support**: Images are forwarded for vision analysis, audio is transcribed with Whisper, and PDFs are saved under `./.pi-data/whatsapp/documents/` with local text preview when available.
168
166
  - **Session Handling**: Saved state, allow list, and startup reconnects are restored automatically when available.
169
167
  - **Intelligent Message Filtering**: Messages ending with `π` are ignored to prevent bot loops.
170
168
  - **Storage Management**: Persistent data lives under `.pi-data/` plus the recents store in the user home directory.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whatsapp-pi",
3
- "version": "1.0.51",
3
+ "version": "1.0.52",
4
4
  "type": "module",
5
5
  "description": "WhatsApp integration extension for Pi",
6
6
  "main": "whatsapp-pi.ts",
@@ -32,6 +32,7 @@
32
32
  "typecheck": "tsc --noEmit"
33
33
  },
34
34
  "dependencies": {
35
+ "@llamaindex/liteparse": "^1.5.3",
35
36
  "baileys": "^6.7.21",
36
37
  "pino": "^10.3.1",
37
38
  "qrcode-terminal": "^0.12.0"
package/src/i18n.ts CHANGED
@@ -197,6 +197,8 @@ const fallback = {
197
197
  "incoming.media.documentSize": "Size: {size}",
198
198
  "incoming.media.documentLocation": "Location: {relativePath}",
199
199
  "incoming.media.documentDescription": "Description: {caption}",
200
+ "incoming.media.documentPdfPreviewHeading": "PDF text preview:",
201
+ "incoming.media.documentPdfFallbackNotice": "PDF text was not extracted automatically. The file is saved at the path above.",
200
202
  "incoming.media.documentDownloadFailed": "[WhatsApp-Pi] Failed to download document:",
201
203
  "incoming.media.documentDownloadFailedText": "[Document: {fileName} (download failed)]",
202
204
  "audio.emptyTranscription": "[Empty transcription]",
@@ -375,6 +377,8 @@ const translations: Record<Locale, Partial<Record<Key, string>>> = {
375
377
  "incoming.media.documentSize": "Tamanho: {size}",
376
378
  "incoming.media.documentLocation": "Local: {relativePath}",
377
379
  "incoming.media.documentDescription": "Descrição: {caption}",
380
+ "incoming.media.documentPdfPreviewHeading": "Prévia do texto do PDF:",
381
+ "incoming.media.documentPdfFallbackNotice": "O texto do PDF não pôde ser extraído automaticamente. O arquivo foi salvo no caminho acima.",
378
382
  "incoming.media.documentDownloadFailed": "[WhatsApp-Pi] Falha ao baixar documento:",
379
383
  "incoming.media.documentDownloadFailedText": "[Documento: {fileName} (download falhou)]",
380
384
  },
@@ -1,6 +1,7 @@
1
1
  import { downloadContentFromMessage } from 'baileys';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
+ import { LiteParse } from '@llamaindex/liteparse';
4
5
  import { AudioService } from './audio.service.js';
5
6
  import type { IncomingResolution } from './incoming-message.resolver.js';
6
7
  import { WhatsAppPiLogger } from './whatsapp-pi.logger.js';
@@ -12,7 +13,11 @@ export interface ProcessedIncomingContent {
12
13
  imageMimeType?: string;
13
14
  }
14
15
 
16
+ const PDF_PREVIEW_LIMIT = 1200;
17
+
15
18
  export class IncomingMediaService {
19
+ private readonly pdfParser = new LiteParse({ ocrEnabled: true });
20
+
16
21
  constructor(
17
22
  private readonly audioService: AudioService,
18
23
  private readonly logger = new WhatsAppPiLogger(false)
@@ -80,6 +85,15 @@ export class IncomingMediaService {
80
85
  + t('incoming.media.documentSize', { size: this.formatFileSize(fileSize) }) + '\n'
81
86
  + t('incoming.media.documentLocation', { relativePath });
82
87
 
88
+ if (this.isPdfDocument(fileName, mimeType)) {
89
+ const preview = await this.extractPdfPreview(buffer);
90
+ if (preview) {
91
+ text += `\n\n${t('incoming.media.documentPdfPreviewHeading')}\n${preview}`;
92
+ } else {
93
+ text += `\n\n${t('incoming.media.documentPdfFallbackNotice')}`;
94
+ }
95
+ }
96
+
83
97
  if (documentMessage.caption) {
84
98
  text += `\n\n${t('incoming.media.documentDescription', { caption: documentMessage.caption })}`;
85
99
  }
@@ -91,6 +105,34 @@ export class IncomingMediaService {
91
105
  }
92
106
  }
93
107
 
108
+ private async extractPdfPreview(buffer: Buffer): Promise<string | null> {
109
+ try {
110
+ const result = await this.pdfParser.parse(buffer);
111
+ return this.formatPdfPreview(result.text);
112
+ } catch (error) {
113
+ this.logger.warn('[WhatsApp-Pi] PDF parsing failed, falling back to storage-only behavior.', error);
114
+ return null;
115
+ }
116
+ }
117
+
118
+ private formatPdfPreview(text: string | undefined | null): string | null {
119
+ const normalized = (text || '').replace(/\r\n/g, '\n').trim();
120
+ if (!normalized) {
121
+ return null;
122
+ }
123
+
124
+ if (normalized.length <= PDF_PREVIEW_LIMIT) {
125
+ return normalized;
126
+ }
127
+
128
+ return `${normalized.slice(0, PDF_PREVIEW_LIMIT)}…`;
129
+ }
130
+
131
+ private isPdfDocument(fileName: string, mimeType: string): boolean {
132
+ const normalizedMimeType = mimeType.toLowerCase().split(';')[0].trim();
133
+ return normalizedMimeType === 'application/pdf' || fileName.toLowerCase().endsWith('.pdf');
134
+ }
135
+
94
136
  private async downloadMessage(message: any, type: 'image' | 'document'): Promise<Buffer> {
95
137
  const stream = await downloadContentFromMessage(message, type);
96
138
  let buffer = Buffer.from([]);
package/whatsapp-pi.ts CHANGED
@@ -183,17 +183,6 @@ export default function (pi: ExtensionAPI) {
183
183
  }
184
184
 
185
185
  ctx.ui.notify('WhatsApp: Session reset via /new is now fully supported.', 'info');
186
-
187
- // Verify pdftotext availability for document support
188
- try {
189
- const { code } = await pi.exec('pdftotext', ['-v']);
190
- if (code !== 0 && code !== 99) { // 99 is a common exit code for -v in some versions
191
- throw new Error(`pdftotext returned code ${code}`);
192
- }
193
- } catch {
194
- ctx.ui.notify('WhatsApp: pdftotext not found. PDF document support will be limited to storage only.', 'warning');
195
- logger.warn('[WhatsApp-Pi] Warning: pdftotext not found in system PATH.');
196
- }
197
186
  });
198
187
 
199
188
  // Track whether send_wa_message tool already sent a reply this turn