@@ -0,0 +1,29 @@
|
||||
name: Deploy Node App
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Deploy to VPS
|
||||
uses: appleboy/ssh-action@master
|
||||
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.SSH_KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
|
||||
script: |
|
||||
cd /root/IR-Node-Setup
|
||||
|
||||
git pull origin main
|
||||
|
||||
npm install
|
||||
|
||||
pm2 restart IR-Node-Setup
|
||||
@@ -0,0 +1 @@
|
||||
/node_modules
|
||||
@@ -0,0 +1,87 @@
|
||||
const axios = require('axios');
|
||||
const { GoogleGenerativeAI } = require('@google/generative-ai');
|
||||
const ai = new GoogleGenerativeAI({ apiKey: process.env.GEMINI_API_KEY });
|
||||
|
||||
const fetchWrenData = async (prompt, tenantId) => {
|
||||
try {
|
||||
const url = process.env.WREN_AI_URL || 'http://localhost:5555/api/v1/text-to-sql';
|
||||
|
||||
const response = await axios.post(url,
|
||||
{ prompt: prompt },
|
||||
{
|
||||
headers: {
|
||||
|
||||
'X-Wren-Session-Properties': `@user_org_id=${tenantId}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Wren AI Integration Error:', error.message);
|
||||
throw new Error('Failed to fetch data payload from Wren AI endpoint');
|
||||
}
|
||||
};
|
||||
|
||||
const generateVegaSchema = async (question, dataArray) => {
|
||||
try {
|
||||
const model = ai.getGenerativeModel({
|
||||
model: 'gemini-2.5-flash',
|
||||
generationConfig: { responseMimeType: 'application/json' }
|
||||
});
|
||||
|
||||
const systemPrompt = `You are a data visualization expert. I will provide a user's question and a JSON array of data.
|
||||
Your task is to generate a strictly valid Vega-Lite JSON specification to visualize this data.
|
||||
The data array will be provided to the Vega spec internally. Map the JSON keys to the correct x, y, and color axes.
|
||||
Choose the best chart type (bar, line, arc) based on the question.`;
|
||||
|
||||
const userPrompt = `User Question: "${question}"\nData JSON: ${JSON.stringify(dataArray)}`;
|
||||
|
||||
const result = await model.generateContent({
|
||||
contents: [{ role: 'user', parts: [{ text: `${systemPrompt}\n\n${userPrompt}` }] }]
|
||||
});
|
||||
|
||||
return JSON.parse(result.response.text());
|
||||
} catch (error) {
|
||||
console.error('Gemini Engine Error:', error.message);
|
||||
throw new Error('Failed to transform data architecture into valid Vega-Lite spec');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleOrchestration = async (req, res) => {
|
||||
try {
|
||||
const { prompt } = req.body;
|
||||
|
||||
|
||||
const tenant_id = req.user ? req.user.client_id : null;
|
||||
return res.status(200).json("ok");
|
||||
|
||||
if (!prompt) {
|
||||
return res.status(400).json({ error: 'Prompt field is required in request body' });
|
||||
}
|
||||
if (!tenant_id) {
|
||||
return res.status(400).json({ error: 'Tenant context (client_id) missing from auth token' });
|
||||
}
|
||||
|
||||
|
||||
const wrenData = await fetchWrenData(prompt, tenant_id);
|
||||
|
||||
|
||||
const vegaSchema = await generateVegaSchema(prompt, wrenData);
|
||||
|
||||
|
||||
if (!vegaSchema || !vegaSchema.$schema) {
|
||||
return res.status(500).json({ error: 'Egress Pipeline Validation Failure: Output missing standard Vega $schema identifier' });
|
||||
}
|
||||
|
||||
|
||||
return res.status(200).json(vegaSchema);
|
||||
|
||||
} catch (error) {
|
||||
console.error('API Gateway Orchestrator Crash:', error.message);
|
||||
return res.status(500).json({ error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { handleOrchestration };
|
||||
@@ -0,0 +1,67 @@
|
||||
const clickhouse = require('../database/clickhouse');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = 'secretkey';
|
||||
|
||||
|
||||
const loginUser = async (req, res) => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "Username and password are required"
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const resultSet = await clickhouse.query({
|
||||
query: 'SELECT * FROM usertable WHERE username = {user: String} AND password = {pass: String}',
|
||||
query_params: {
|
||||
user: username,
|
||||
pass: password
|
||||
},
|
||||
format: 'JSONEachRow',
|
||||
});
|
||||
|
||||
const rows = await resultSet.json();
|
||||
|
||||
|
||||
if (rows.length === 0) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: "Invalid username or password"
|
||||
});
|
||||
}
|
||||
|
||||
const user = rows[0];
|
||||
|
||||
|
||||
const token = jwt.sign(
|
||||
{
|
||||
client_id: user.client_id,
|
||||
username: user.username
|
||||
},
|
||||
JWT_SECRET,
|
||||
{ expiresIn: '24h' }
|
||||
);
|
||||
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: "Login successful",
|
||||
token: token,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("Login Error:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "Internal server error",
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { loginUser };
|
||||
@@ -0,0 +1,10 @@
|
||||
const { createClient } = require('@clickhouse/client');
|
||||
|
||||
const clickhouse = createClient({
|
||||
url: 'http://172.188.12.194:8123',
|
||||
username: 'default',
|
||||
password: 'dipanshu_k',
|
||||
database: 'userdetails',
|
||||
});
|
||||
|
||||
module.exports = clickhouse;
|
||||
@@ -0,0 +1,15 @@
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
const route = require('./route/route.js');
|
||||
const cors = require('cors');
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.static('public'));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(route);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on http://localhost:${port}`);
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const authMiddleware = (req, res, next) => {
|
||||
const JWT_SECRET = 'secretkey';
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return res.status(401).json({ error: 'Unauthorized: Missing or invalid token format' });
|
||||
}
|
||||
const token = authHeader.split(' ')[1];
|
||||
try {
|
||||
const decoded = jwt.verify(token, JWT_SECRET);
|
||||
req.user = decoded;
|
||||
next();
|
||||
} catch (error) {
|
||||
|
||||
return res.status(401).json({ error: 'Unauthorized: Invalid token' });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = authMiddleware;
|
||||
Generated
+1505
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "ir-node-setup",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"license": "ISC",
|
||||
"author": "",
|
||||
"type": "commonjs",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "nodemon index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clickhouse/client": "^1.18.5",
|
||||
"@google/generative-ai": "^0.24.1",
|
||||
"axios": "^1.16.1",
|
||||
"cors": "^2.8.6",
|
||||
"express": "^5.2.1",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"nodemon": "^3.1.14"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const loginUser = require('../controller/loginUser.js');
|
||||
const authMiddleware = require('../middleware/authMiddleware.js');
|
||||
const handleOrchestration = require('../controller/handleOrchestration.js');
|
||||
|
||||
router.post('/loginUser', loginUser.loginUser);
|
||||
router.post('/handleOrchestration', authMiddleware, handleOrchestration.handleOrchestration);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user