samarthya-bot 1.0.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.
Files changed (50) hide show
  1. package/README.md +92 -0
  2. package/backend/.env.example +23 -0
  3. package/backend/bin/samarthya.js +384 -0
  4. package/backend/config/constants.js +71 -0
  5. package/backend/config/db.js +13 -0
  6. package/backend/controllers/auditController.js +86 -0
  7. package/backend/controllers/authController.js +154 -0
  8. package/backend/controllers/chatController.js +158 -0
  9. package/backend/controllers/fileController.js +268 -0
  10. package/backend/controllers/platformController.js +54 -0
  11. package/backend/controllers/screenController.js +91 -0
  12. package/backend/controllers/telegramController.js +120 -0
  13. package/backend/controllers/toolsController.js +56 -0
  14. package/backend/controllers/whatsappController.js +214 -0
  15. package/backend/fix_toolRegistry.js +25 -0
  16. package/backend/middleware/auth.js +28 -0
  17. package/backend/models/AuditLog.js +28 -0
  18. package/backend/models/BackgroundJob.js +13 -0
  19. package/backend/models/Conversation.js +40 -0
  20. package/backend/models/Memory.js +17 -0
  21. package/backend/models/User.js +24 -0
  22. package/backend/package-lock.json +3766 -0
  23. package/backend/package.json +41 -0
  24. package/backend/public/assets/index-Ckf0GO1B.css +1 -0
  25. package/backend/public/assets/index-Do4jNsZS.js +19 -0
  26. package/backend/public/assets/index-Ui-pyZvK.js +25 -0
  27. package/backend/public/favicon.svg +17 -0
  28. package/backend/public/index.html +18 -0
  29. package/backend/public/manifest.json +16 -0
  30. package/backend/routes/audit.js +9 -0
  31. package/backend/routes/auth.js +11 -0
  32. package/backend/routes/chat.js +11 -0
  33. package/backend/routes/files.js +14 -0
  34. package/backend/routes/platform.js +18 -0
  35. package/backend/routes/screen.js +10 -0
  36. package/backend/routes/telegram.js +8 -0
  37. package/backend/routes/tools.js +9 -0
  38. package/backend/routes/whatsapp.js +11 -0
  39. package/backend/server.js +134 -0
  40. package/backend/services/background/backgroundService.js +81 -0
  41. package/backend/services/llm/llmService.js +444 -0
  42. package/backend/services/memory/memoryService.js +159 -0
  43. package/backend/services/planner/plannerService.js +182 -0
  44. package/backend/services/security/securityService.js +166 -0
  45. package/backend/services/telegram/telegramService.js +49 -0
  46. package/backend/services/tools/toolRegistry.js +879 -0
  47. package/backend/services/whatsapp/whatsappService.js +254 -0
  48. package/backend/test_email.js +29 -0
  49. package/backend/test_parser.js +10 -0
  50. package/package.json +49 -0
@@ -0,0 +1,254 @@
1
+ /**
2
+ * WhatsApp Business Cloud API Service
3
+ * Handles sending/receiving WhatsApp messages via Meta's API
4
+ *
5
+ * Setup: https://developers.facebook.com/docs/whatsapp/cloud-api/get-started
6
+ * 1. Create Meta Business account
7
+ * 2. Set up WhatsApp Business App
8
+ * 3. Get API token and phone number ID
9
+ * 4. Set webhook URL to: https://yourdomain.com/api/whatsapp/webhook
10
+ */
11
+
12
+ class WhatsAppService {
13
+ constructor() {
14
+ this.apiToken = process.env.WHATSAPP_API_TOKEN;
15
+ this.phoneNumberId = process.env.WHATSAPP_PHONE_NUMBER_ID;
16
+ this.verifyToken = process.env.WHATSAPP_VERIFY_TOKEN || 'samarthya_whatsapp_verify_2025';
17
+ this.apiUrl = 'https://graph.facebook.com/v18.0';
18
+ }
19
+
20
+ /**
21
+ * Send a text message via WhatsApp
22
+ */
23
+ async sendMessage(to, text) {
24
+ try {
25
+ const response = await fetch(
26
+ `${this.apiUrl}/${this.phoneNumberId}/messages`,
27
+ {
28
+ method: 'POST',
29
+ headers: {
30
+ 'Authorization': `Bearer ${this.apiToken}`,
31
+ 'Content-Type': 'application/json'
32
+ },
33
+ body: JSON.stringify({
34
+ messaging_product: 'whatsapp',
35
+ to: to,
36
+ type: 'text',
37
+ text: { body: text }
38
+ })
39
+ }
40
+ );
41
+
42
+ if (!response.ok) {
43
+ const error = await response.text();
44
+ console.error('WhatsApp send error:', error);
45
+ return { success: false, error };
46
+ }
47
+
48
+ const data = await response.json();
49
+ return { success: true, messageId: data.messages?.[0]?.id };
50
+ } catch (error) {
51
+ console.error('WhatsApp Service Error:', error);
52
+ return { success: false, error: error.message };
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Send interactive buttons
58
+ */
59
+ async sendButtons(to, bodyText, buttons) {
60
+ try {
61
+ const response = await fetch(
62
+ `${this.apiUrl}/${this.phoneNumberId}/messages`,
63
+ {
64
+ method: 'POST',
65
+ headers: {
66
+ 'Authorization': `Bearer ${this.apiToken}`,
67
+ 'Content-Type': 'application/json'
68
+ },
69
+ body: JSON.stringify({
70
+ messaging_product: 'whatsapp',
71
+ to: to,
72
+ type: 'interactive',
73
+ interactive: {
74
+ type: 'button',
75
+ body: { text: bodyText },
76
+ action: {
77
+ buttons: buttons.map((btn, i) => ({
78
+ type: 'reply',
79
+ reply: {
80
+ id: `btn_${i}`,
81
+ title: btn.substring(0, 20) // WhatsApp 20 char limit
82
+ }
83
+ }))
84
+ }
85
+ }
86
+ })
87
+ }
88
+ );
89
+
90
+ const data = await response.json();
91
+ return { success: response.ok, data };
92
+ } catch (error) {
93
+ console.error('WhatsApp buttons error:', error);
94
+ return { success: false, error: error.message };
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Send a template message (for notifications/reminders)
100
+ */
101
+ async sendTemplate(to, templateName, language = 'en', parameters = []) {
102
+ try {
103
+ const components = parameters.length > 0 ? [{
104
+ type: 'body',
105
+ parameters: parameters.map(p => ({
106
+ type: 'text',
107
+ text: String(p)
108
+ }))
109
+ }] : [];
110
+
111
+ const response = await fetch(
112
+ `${this.apiUrl}/${this.phoneNumberId}/messages`,
113
+ {
114
+ method: 'POST',
115
+ headers: {
116
+ 'Authorization': `Bearer ${this.apiToken}`,
117
+ 'Content-Type': 'application/json'
118
+ },
119
+ body: JSON.stringify({
120
+ messaging_product: 'whatsapp',
121
+ to: to,
122
+ type: 'template',
123
+ template: {
124
+ name: templateName,
125
+ language: { code: language },
126
+ components
127
+ }
128
+ })
129
+ }
130
+ );
131
+
132
+ const data = await response.json();
133
+ return { success: response.ok, data };
134
+ } catch (error) {
135
+ console.error('WhatsApp template error:', error);
136
+ return { success: false, error: error.message };
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Mark message as read
142
+ */
143
+ async markAsRead(messageId) {
144
+ try {
145
+ await fetch(
146
+ `${this.apiUrl}/${this.phoneNumberId}/messages`,
147
+ {
148
+ method: 'POST',
149
+ headers: {
150
+ 'Authorization': `Bearer ${this.apiToken}`,
151
+ 'Content-Type': 'application/json'
152
+ },
153
+ body: JSON.stringify({
154
+ messaging_product: 'whatsapp',
155
+ status: 'read',
156
+ message_id: messageId
157
+ })
158
+ }
159
+ );
160
+ } catch (error) {
161
+ console.error('Mark as read error:', error);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Download media (images, voice notes) from WhatsApp
167
+ * Returns buffer for processing
168
+ */
169
+ async downloadMedia(mediaId) {
170
+ try {
171
+ // Step 1: Get media URL
172
+ const urlRes = await fetch(
173
+ `${this.apiUrl}/${mediaId}`,
174
+ {
175
+ headers: { 'Authorization': `Bearer ${this.apiToken}` }
176
+ }
177
+ );
178
+ const urlData = await urlRes.json();
179
+
180
+ if (!urlData.url) return null;
181
+
182
+ // Step 2: Download actual media
183
+ const mediaRes = await fetch(urlData.url, {
184
+ headers: { 'Authorization': `Bearer ${this.apiToken}` }
185
+ });
186
+
187
+ const buffer = await mediaRes.arrayBuffer();
188
+ return {
189
+ buffer: Buffer.from(buffer),
190
+ mimeType: urlData.mime_type,
191
+ size: urlData.file_size
192
+ };
193
+ } catch (error) {
194
+ console.error('Media download error:', error);
195
+ return null;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Parse incoming webhook message
201
+ */
202
+ parseWebhookMessage(body) {
203
+ try {
204
+ const entry = body.entry?.[0];
205
+ const changes = entry?.changes?.[0];
206
+ const value = changes?.value;
207
+
208
+ if (!value?.messages?.[0]) return null;
209
+
210
+ const msg = value.messages[0];
211
+ const contact = value.contacts?.[0];
212
+
213
+ const parsed = {
214
+ messageId: msg.id,
215
+ from: msg.from, // phone number
216
+ timestamp: new Date(parseInt(msg.timestamp) * 1000),
217
+ contactName: contact?.profile?.name || 'Unknown',
218
+ type: msg.type, // text, image, audio, document, interactive
219
+ };
220
+
221
+ switch (msg.type) {
222
+ case 'text':
223
+ parsed.text = msg.text.body;
224
+ break;
225
+ case 'image':
226
+ parsed.mediaId = msg.image.id;
227
+ parsed.mimeType = msg.image.mime_type;
228
+ parsed.caption = msg.image.caption;
229
+ break;
230
+ case 'audio':
231
+ parsed.mediaId = msg.audio.id;
232
+ parsed.mimeType = msg.audio.mime_type;
233
+ break;
234
+ case 'document':
235
+ parsed.mediaId = msg.document.id;
236
+ parsed.mimeType = msg.document.mime_type;
237
+ parsed.filename = msg.document.filename;
238
+ break;
239
+ case 'interactive':
240
+ parsed.text = msg.interactive?.button_reply?.title ||
241
+ msg.interactive?.list_reply?.title || '';
242
+ parsed.buttonId = msg.interactive?.button_reply?.id;
243
+ break;
244
+ }
245
+
246
+ return parsed;
247
+ } catch (error) {
248
+ console.error('Webhook parse error:', error);
249
+ return null;
250
+ }
251
+ }
252
+ }
253
+
254
+ module.exports = new WhatsAppService();
@@ -0,0 +1,29 @@
1
+ const nodemailer = require('nodemailer');
2
+
3
+ const transporter = nodemailer.createTransport({
4
+ service: 'gmail',
5
+ auth: {
6
+ user: 'mebishnusahu0595@gmail.com',
7
+ pass: 'srdhoxxykgitcrph'
8
+ }
9
+ });
10
+
11
+ const mailOptions = {
12
+ from: 'mebishnusahu0595@gmail.com',
13
+ to: 'datascienceforus05@gmail.com',
14
+ subject: 'Direct SMTP Test',
15
+ text: 'If you see this, the terminal nodemailer is successful.'
16
+ };
17
+
18
+ async function send() {
19
+ try {
20
+ console.log("Attempting to send...");
21
+ const info = await transporter.sendMail(mailOptions);
22
+ console.log("✅ Success! ID: " + info.messageId);
23
+ } catch (err) {
24
+ console.error("❌ Failed!");
25
+ console.error(err);
26
+ }
27
+ }
28
+
29
+ send();
@@ -0,0 +1,10 @@
1
+ const llmService = require('./services/llm/llmService.js');
2
+ const response = `Here is the data:
3
+ \`\`\`tool_call
4
+ [
5
+ { "tool": "file_write", "args": { "filename": "test.txt", "content": "hello" } },
6
+ { "tool": "send_email", "args": { "to": "a@a.com", "subject": "a", "body": "a" } }
7
+ ]
8
+ \`\`\`
9
+ `;
10
+ console.log(llmService.parseToolCalls(response));
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "samarthya-bot",
3
+ "version": "1.0.2",
4
+ "description": "Privacy-First Local Agentic OS & Command Center",
5
+ "main": "backend/server.js",
6
+ "bin": {
7
+ "samarthya": "backend/bin/samarthya.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node backend/server.js"
11
+ },
12
+ "dependencies": {
13
+ "@google/genai": "^1.43.0",
14
+ "bcryptjs": "^3.0.3",
15
+ "cors": "^2.8.6",
16
+ "dotenv": "^17.3.1",
17
+ "express": "^5.2.1",
18
+ "helmet": "^8.1.0",
19
+ "jsonwebtoken": "^9.0.3",
20
+ "mongoose": "^9.2.3",
21
+ "morgan": "^1.10.1",
22
+ "node-cron": "^4.2.1",
23
+ "node-crypto": "^1.0.0",
24
+ "node-os-utils": "^2.0.1",
25
+ "nodemailer": "^8.0.1",
26
+ "os-utils": "^0.0.14",
27
+ "puppeteer-core": "^24.37.5",
28
+ "screenshot-desktop": "^1.15.3",
29
+ "socket.io": "^4.8.3",
30
+ "uuid": "^13.0.0"
31
+ },
32
+ "keywords": [
33
+ "ai",
34
+ "agent",
35
+ "os",
36
+ "local",
37
+ "samarthya-bot",
38
+ "ollama"
39
+ ],
40
+ "author": "Bishnu Sahu",
41
+ "license": "MIT",
42
+ "engines": {
43
+ "node": ">=20.0.0"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/mebishnusahu0595/SamarthyaBot.git"
48
+ }
49
+ }