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.
- package/README.md +92 -0
- package/backend/.env.example +23 -0
- package/backend/bin/samarthya.js +384 -0
- package/backend/config/constants.js +71 -0
- package/backend/config/db.js +13 -0
- package/backend/controllers/auditController.js +86 -0
- package/backend/controllers/authController.js +154 -0
- package/backend/controllers/chatController.js +158 -0
- package/backend/controllers/fileController.js +268 -0
- package/backend/controllers/platformController.js +54 -0
- package/backend/controllers/screenController.js +91 -0
- package/backend/controllers/telegramController.js +120 -0
- package/backend/controllers/toolsController.js +56 -0
- package/backend/controllers/whatsappController.js +214 -0
- package/backend/fix_toolRegistry.js +25 -0
- package/backend/middleware/auth.js +28 -0
- package/backend/models/AuditLog.js +28 -0
- package/backend/models/BackgroundJob.js +13 -0
- package/backend/models/Conversation.js +40 -0
- package/backend/models/Memory.js +17 -0
- package/backend/models/User.js +24 -0
- package/backend/package-lock.json +3766 -0
- package/backend/package.json +41 -0
- package/backend/public/assets/index-Ckf0GO1B.css +1 -0
- package/backend/public/assets/index-Do4jNsZS.js +19 -0
- package/backend/public/assets/index-Ui-pyZvK.js +25 -0
- package/backend/public/favicon.svg +17 -0
- package/backend/public/index.html +18 -0
- package/backend/public/manifest.json +16 -0
- package/backend/routes/audit.js +9 -0
- package/backend/routes/auth.js +11 -0
- package/backend/routes/chat.js +11 -0
- package/backend/routes/files.js +14 -0
- package/backend/routes/platform.js +18 -0
- package/backend/routes/screen.js +10 -0
- package/backend/routes/telegram.js +8 -0
- package/backend/routes/tools.js +9 -0
- package/backend/routes/whatsapp.js +11 -0
- package/backend/server.js +134 -0
- package/backend/services/background/backgroundService.js +81 -0
- package/backend/services/llm/llmService.js +444 -0
- package/backend/services/memory/memoryService.js +159 -0
- package/backend/services/planner/plannerService.js +182 -0
- package/backend/services/security/securityService.js +166 -0
- package/backend/services/telegram/telegramService.js +49 -0
- package/backend/services/tools/toolRegistry.js +879 -0
- package/backend/services/whatsapp/whatsappService.js +254 -0
- package/backend/test_email.js +29 -0
- package/backend/test_parser.js +10 -0
- package/package.json +49 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#FF9933"/>
|
|
5
|
+
<stop offset="50%" style="stop-color:#FFFFFF"/>
|
|
6
|
+
<stop offset="100%" style="stop-color:#138808"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
9
|
+
<stop offset="0%" style="stop-color:#0D0D0D"/>
|
|
10
|
+
<stop offset="100%" style="stop-color:#1a1a2e"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
</defs>
|
|
13
|
+
<rect width="64" height="64" rx="14" fill="url(#bg)"/>
|
|
14
|
+
<text x="32" y="44" text-anchor="middle" font-size="30" font-family="sans-serif" font-weight="bold" fill="url(#grad)">स</text>
|
|
15
|
+
<circle cx="48" cy="14" r="4" fill="#FF9933" opacity="0.8"/>
|
|
16
|
+
<circle cx="14" cy="50" r="3" fill="#138808" opacity="0.6"/>
|
|
17
|
+
</svg>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<meta name="description" content="SamarthyaBot - Privacy-first Personal AI Operator built for Indian workflows. Hindi, Hinglish & English support." />
|
|
8
|
+
<meta name="theme-color" content="#0f0f23" />
|
|
9
|
+
<link rel="manifest" href="/manifest.json" />
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Noto+Sans+Devanagari:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
11
|
+
<title>SamarthyaBot - समर्थ्य बोट | Personal AI Operator</title>
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-Ui-pyZvK.js"></script>
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Ckf0GO1B.css">
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<div id="root"></div>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "SamarthyaBot",
|
|
3
|
+
"short_name": "SamarthyaBot",
|
|
4
|
+
"description": "Privacy-first Personal AI Operator for Indian workflows",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"display": "standalone",
|
|
7
|
+
"background_color": "#0f0f23",
|
|
8
|
+
"theme_color": "#6366f1",
|
|
9
|
+
"icons": [
|
|
10
|
+
{
|
|
11
|
+
"src": "/favicon.svg",
|
|
12
|
+
"sizes": "any",
|
|
13
|
+
"type": "image/svg+xml"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const router = require('express').Router();
|
|
2
|
+
const { getAuditLogs, getAuditStats, rollbackAction } = require('../controllers/auditController');
|
|
3
|
+
const auth = require('../middleware/auth');
|
|
4
|
+
|
|
5
|
+
router.get('/logs', auth, getAuditLogs);
|
|
6
|
+
router.get('/stats', auth, getAuditStats);
|
|
7
|
+
router.post('/rollback/:id', auth, rollbackAction);
|
|
8
|
+
|
|
9
|
+
module.exports = router;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const router = require('express').Router();
|
|
2
|
+
const { register, login, getProfile, updateProfile, demoLogin } = require('../controllers/authController');
|
|
3
|
+
const auth = require('../middleware/auth');
|
|
4
|
+
|
|
5
|
+
router.post('/register', register);
|
|
6
|
+
router.post('/login', login);
|
|
7
|
+
router.post('/demo', demoLogin);
|
|
8
|
+
router.get('/profile', auth, getProfile);
|
|
9
|
+
router.put('/profile', auth, updateProfile);
|
|
10
|
+
|
|
11
|
+
module.exports = router;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const router = require('express').Router();
|
|
2
|
+
const { sendMessage, getConversations, getConversation, deleteConversation, togglePin } = require('../controllers/chatController');
|
|
3
|
+
const auth = require('../middleware/auth');
|
|
4
|
+
|
|
5
|
+
router.post('/message', auth, sendMessage);
|
|
6
|
+
router.get('/conversations', auth, getConversations);
|
|
7
|
+
router.get('/conversations/:id', auth, getConversation);
|
|
8
|
+
router.delete('/conversations/:id', auth, deleteConversation);
|
|
9
|
+
router.patch('/conversations/:id/pin', auth, togglePin);
|
|
10
|
+
|
|
11
|
+
module.exports = router;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const auth = require('../middleware/auth');
|
|
4
|
+
const fileController = require('../controllers/fileController');
|
|
5
|
+
|
|
6
|
+
router.get('/list', auth, fileController.listFiles);
|
|
7
|
+
router.get('/read', auth, fileController.readFile);
|
|
8
|
+
router.get('/download', auth, fileController.downloadFile);
|
|
9
|
+
router.get('/stats', auth, fileController.getStats);
|
|
10
|
+
router.post('/mkdir', auth, fileController.createFolder);
|
|
11
|
+
router.post('/upload', auth, fileController.uploadFile);
|
|
12
|
+
router.delete('/delete', auth, fileController.deleteFile);
|
|
13
|
+
|
|
14
|
+
module.exports = router;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const auth = require('../middleware/auth');
|
|
4
|
+
const platformController = require('../controllers/platformController');
|
|
5
|
+
|
|
6
|
+
// All platform routes require authentication
|
|
7
|
+
router.use(auth);
|
|
8
|
+
|
|
9
|
+
// Get platform real-time status
|
|
10
|
+
router.get('/status', platformController.getPlatformStatus);
|
|
11
|
+
|
|
12
|
+
// Get background jobs
|
|
13
|
+
router.get('/jobs', platformController.getBackgroundJobs);
|
|
14
|
+
|
|
15
|
+
// Emergency Kill Switch
|
|
16
|
+
router.post('/emergency-stop', platformController.emergencyStop);
|
|
17
|
+
|
|
18
|
+
module.exports = router;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const auth = require('../middleware/auth');
|
|
4
|
+
const screenController = require('../controllers/screenController');
|
|
5
|
+
|
|
6
|
+
// Screen Understanding routes
|
|
7
|
+
router.post('/analyze', auth, screenController.analyzeScreen);
|
|
8
|
+
router.get('/supported', auth, screenController.getSupportedScreens);
|
|
9
|
+
|
|
10
|
+
module.exports = router;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const telegramController = require('../controllers/telegramController');
|
|
4
|
+
|
|
5
|
+
// Telegram Incoming Webhook (POST request)
|
|
6
|
+
router.post('/webhook', telegramController.handleMessage);
|
|
7
|
+
|
|
8
|
+
module.exports = router;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const router = require('express').Router();
|
|
2
|
+
const { getTools, getToolPacks, getPackTools } = require('../controllers/toolsController');
|
|
3
|
+
const auth = require('../middleware/auth');
|
|
4
|
+
|
|
5
|
+
router.get('/', auth, getTools);
|
|
6
|
+
router.get('/packs', auth, getToolPacks);
|
|
7
|
+
router.get('/packs/:packId', auth, getPackTools);
|
|
8
|
+
|
|
9
|
+
module.exports = router;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const whatsappController = require('../controllers/whatsappController');
|
|
4
|
+
|
|
5
|
+
// WhatsApp Webhook Verification (Meta sends GET request)
|
|
6
|
+
router.get('/webhook', whatsappController.verifyWebhook);
|
|
7
|
+
|
|
8
|
+
// WhatsApp Incoming Messages (Meta sends POST request)
|
|
9
|
+
router.post('/webhook', whatsappController.handleMessage);
|
|
10
|
+
|
|
11
|
+
module.exports = router;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require('dotenv').config();
|
|
2
|
+
const express = require('express');
|
|
3
|
+
const cors = require('cors');
|
|
4
|
+
const helmet = require('helmet');
|
|
5
|
+
const morgan = require('morgan');
|
|
6
|
+
const http = require('http');
|
|
7
|
+
const { Server } = require('socket.io');
|
|
8
|
+
const connectDB = require('./config/db');
|
|
9
|
+
|
|
10
|
+
// Import Routes
|
|
11
|
+
const authRoutes = require('./routes/auth');
|
|
12
|
+
const chatRoutes = require('./routes/chat');
|
|
13
|
+
const auditRoutes = require('./routes/audit');
|
|
14
|
+
const toolsRoutes = require('./routes/tools');
|
|
15
|
+
const whatsappRoutes = require('./routes/whatsapp');
|
|
16
|
+
const telegramRoutes = require('./routes/telegram');
|
|
17
|
+
const screenRoutes = require('./routes/screen');
|
|
18
|
+
const fileRoutes = require('./routes/files');
|
|
19
|
+
const platformRoutes = require('./routes/platform');
|
|
20
|
+
const backgroundService = require('./services/background/backgroundService');
|
|
21
|
+
|
|
22
|
+
const app = express();
|
|
23
|
+
const server = http.createServer(app);
|
|
24
|
+
|
|
25
|
+
// Socket.IO setup
|
|
26
|
+
const io = new Server(server, {
|
|
27
|
+
cors: {
|
|
28
|
+
origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
|
|
29
|
+
methods: ['GET', 'POST']
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Middleware
|
|
34
|
+
app.use(helmet());
|
|
35
|
+
app.use(cors({ origin: process.env.CORS_ORIGIN || 'http://localhost:5173' }));
|
|
36
|
+
app.use(express.json({ limit: '15mb' }));
|
|
37
|
+
app.use(morgan('dev'));
|
|
38
|
+
|
|
39
|
+
// Inject io into requests
|
|
40
|
+
app.use((req, res, next) => {
|
|
41
|
+
req.io = io;
|
|
42
|
+
next();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const path = require('path');
|
|
46
|
+
|
|
47
|
+
// Routes
|
|
48
|
+
app.use('/api/auth', authRoutes);
|
|
49
|
+
app.use('/api/chat', chatRoutes);
|
|
50
|
+
app.use('/api/audit', auditRoutes);
|
|
51
|
+
app.use('/api/tools', toolsRoutes);
|
|
52
|
+
app.use('/api/whatsapp', whatsappRoutes);
|
|
53
|
+
app.use('/api/telegram', telegramRoutes);
|
|
54
|
+
app.use('/api/screen', screenRoutes);
|
|
55
|
+
app.use('/api/files', fileRoutes);
|
|
56
|
+
app.use('/api/platform', platformRoutes);
|
|
57
|
+
|
|
58
|
+
// Serve static frontend UI (SamarthyaBot Dashboard)
|
|
59
|
+
app.use(express.static(path.join(__dirname, 'public')));
|
|
60
|
+
|
|
61
|
+
// Health check
|
|
62
|
+
app.get('/api/health', (req, res) => {
|
|
63
|
+
res.json({
|
|
64
|
+
status: 'ok',
|
|
65
|
+
name: 'SamarthyaBot Server',
|
|
66
|
+
version: '1.0.0',
|
|
67
|
+
uptime: process.uptime(),
|
|
68
|
+
timestamp: new Date().toISOString()
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Socket.IO connection
|
|
73
|
+
io.on('connection', (socket) => {
|
|
74
|
+
console.log('🔌 Client connected:', socket.id);
|
|
75
|
+
|
|
76
|
+
socket.on('join', (userId) => {
|
|
77
|
+
socket.join(userId);
|
|
78
|
+
console.log(`👤 User ${userId} joined room`);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
socket.on('typing', (data) => {
|
|
82
|
+
socket.to(data.userId).emit('typing', data);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
socket.on('disconnect', () => {
|
|
86
|
+
console.log('❌ Client disconnected:', socket.id);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// SPA Catch-all Middleware for Express 5
|
|
91
|
+
app.use((req, res, next) => {
|
|
92
|
+
if (req.path.startsWith('/api/')) return next();
|
|
93
|
+
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Connect DB & Start Server
|
|
97
|
+
const PORT = process.env.PORT || 5000;
|
|
98
|
+
|
|
99
|
+
connectDB().then(() => {
|
|
100
|
+
server.listen(PORT, () => {
|
|
101
|
+
const activeProvider = process.env.ACTIVE_PROVIDER ? process.env.ACTIVE_PROVIDER.toUpperCase() : 'GEMINI';
|
|
102
|
+
const activeModel = process.env.ACTIVE_MODEL || 'gemini-2.5-flash';
|
|
103
|
+
const aiString = `🧠 Active AI: ${activeProvider} (${activeModel})`.padEnd(49, ' ');
|
|
104
|
+
|
|
105
|
+
console.log(`
|
|
106
|
+
╔══════════════════════════════════════════════════════╗
|
|
107
|
+
║ ║
|
|
108
|
+
║ 🧠 SamarthyaBot Server v1.1.0 ║
|
|
109
|
+
║ Privacy-first Personal AI Operator ║
|
|
110
|
+
║ ║
|
|
111
|
+
║ 🌐 Server: http://localhost:${PORT} ║
|
|
112
|
+
║ 📡 Socket: ws://localhost:${PORT} ║
|
|
113
|
+
║ 🔗 Health: http://localhost:${PORT}/api/health ║
|
|
114
|
+
║ 📱 WhatsApp: /api/whatsapp/webhook ║
|
|
115
|
+
║ 🤖 Telegram: /api/telegram/webhook ║
|
|
116
|
+
║ 👁️ Vision: /api/screen/analyze ║
|
|
117
|
+
║ ║
|
|
118
|
+
║ 🇮🇳 Built for Indian Workflows ║
|
|
119
|
+
║ 📦 Ollama: ${process.env.USE_OLLAMA === 'true' ? '✅ Enabled'.padEnd(35) : '❌ Disabled'.padEnd(35)}║
|
|
120
|
+
║ 🔄 Autonomous Background Engine: ✅ Active ║
|
|
121
|
+
║ 🔌 Dynamic Plugin Engine: ✅ Active ║
|
|
122
|
+
║ ${aiString} ║
|
|
123
|
+
║ ║
|
|
124
|
+
╚══════════════════════════════════════════════════════╝
|
|
125
|
+
`);
|
|
126
|
+
backgroundService.start();
|
|
127
|
+
});
|
|
128
|
+
}).catch(err => {
|
|
129
|
+
console.error('Failed to connect to database:', err);
|
|
130
|
+
// Start server even without DB for demo
|
|
131
|
+
server.listen(PORT, () => {
|
|
132
|
+
console.log(`⚠️ Server running without DB on port ${PORT}`);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const BackgroundJob = require('../../models/BackgroundJob');
|
|
2
|
+
const User = require('../../models/User');
|
|
3
|
+
const plannerService = require('../planner/plannerService');
|
|
4
|
+
const telegramService = require('../telegram/telegramService');
|
|
5
|
+
const Conversation = require('../../models/Conversation');
|
|
6
|
+
|
|
7
|
+
class BackgroundService {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.isRunning = false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
start() {
|
|
13
|
+
if (this.isRunning) return;
|
|
14
|
+
this.isRunning = true;
|
|
15
|
+
console.log('🔄 Background Autonomous Mode Started (Checking every 1 minute)');
|
|
16
|
+
|
|
17
|
+
// Check every minute
|
|
18
|
+
setInterval(() => this.checkJobs(), 60 * 1000);
|
|
19
|
+
// Do an initial check
|
|
20
|
+
this.checkJobs();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async checkJobs() {
|
|
24
|
+
try {
|
|
25
|
+
const now = new Date();
|
|
26
|
+
// Find jobs where nextRunAt <= now and is active
|
|
27
|
+
const jobs = await BackgroundJob.find({
|
|
28
|
+
isActive: true,
|
|
29
|
+
nextRunAt: { $lte: now }
|
|
30
|
+
}).populate('userId');
|
|
31
|
+
|
|
32
|
+
for (const job of jobs) {
|
|
33
|
+
if (!job.userId) continue;
|
|
34
|
+
console.log(`⏱️ Executing Background Job: ${job.taskName} for ${job.userId.email}`);
|
|
35
|
+
|
|
36
|
+
// 1. Prepare conversation (create a temporary memory block for context)
|
|
37
|
+
const previousMessages = [{
|
|
38
|
+
role: 'system',
|
|
39
|
+
content: `[CRITICAL INSTRUCTION] You are running in AUTONOMOUS BACKGROUND MODE.
|
|
40
|
+
You must execute the following scheduled background job: "${job.taskName}".
|
|
41
|
+
Context/Prompt: ${job.prompt}
|
|
42
|
+
You must perform the necessary actions using tools. If you find something noteworthy, or if the user asked to be alerted, output a final message. The final message will be sent to the user on Telegram.`
|
|
43
|
+
}];
|
|
44
|
+
|
|
45
|
+
// 2. Execute via planner
|
|
46
|
+
const result = await plannerService.processMessage(
|
|
47
|
+
job.userId,
|
|
48
|
+
previousMessages,
|
|
49
|
+
`[BACKGROUND TRIGGER]: Run job "${job.taskName}" now.`,
|
|
50
|
+
null // no onProgress for background
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// 3. Send result to Telegram if there's a meaningful response
|
|
54
|
+
// Since this runs silent, only send if there's content and the agent didn't just say "done"
|
|
55
|
+
if (result.response && result.response.length > 5) {
|
|
56
|
+
const chatIdMatch = job.userId.email.match(/^tg_(\d+)@samarthya\.local$/);
|
|
57
|
+
if (chatIdMatch) {
|
|
58
|
+
const chatId = chatIdMatch[1];
|
|
59
|
+
await telegramService.sendMessage(
|
|
60
|
+
chatId,
|
|
61
|
+
`🤖 *Background Task Completed: ${job.taskName}*\n\n${result.response}`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 4. Update job schedule
|
|
67
|
+
job.lastRunAt = now;
|
|
68
|
+
if (job.intervalMinutes > 0) {
|
|
69
|
+
job.nextRunAt = new Date(now.getTime() + job.intervalMinutes * 60000);
|
|
70
|
+
} else {
|
|
71
|
+
job.isActive = false; // Run once
|
|
72
|
+
}
|
|
73
|
+
await job.save();
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('Background job error:', error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = new BackgroundService();
|