Spaces:
Sleeping
Sleeping
Upload 6 files
Browse files- Dockerfile +11 -0
- app.js +99 -0
- index.html +25 -0
- json_viewer.js +15 -0
- package.json +14 -0
- space.yaml +1 -0
Dockerfile
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM node:18
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
COPY . .
|
| 6 |
+
|
| 7 |
+
RUN npm install
|
| 8 |
+
|
| 9 |
+
EXPOSE 7860
|
| 10 |
+
|
| 11 |
+
CMD ["npm", "start"]
|
app.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import express from 'express';
|
| 2 |
+
import dotenv from 'dotenv';
|
| 3 |
+
import bodyParser from 'body-parser';
|
| 4 |
+
import { GoogleGenerativeAI } from '@google/generative-ai';
|
| 5 |
+
|
| 6 |
+
dotenv.config();
|
| 7 |
+
const app = express();
|
| 8 |
+
const port = process.env.PORT || 7860;
|
| 9 |
+
|
| 10 |
+
app.use(bodyParser.urlencoded({ extended: true }));
|
| 11 |
+
app.use(express.static('public'));
|
| 12 |
+
|
| 13 |
+
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
|
| 14 |
+
|
| 15 |
+
app.get('/', (req, res) => {
|
| 16 |
+
res.sendFile(process.cwd() + '/index.html');
|
| 17 |
+
});
|
| 18 |
+
|
| 19 |
+
app.post('/analyze', async (req, res) => {
|
| 20 |
+
const userContent = req.body.input_text;
|
| 21 |
+
const language = req.body.language;
|
| 22 |
+
|
| 23 |
+
const systemPrompt = `
|
| 24 |
+
You are an expert OSINT intelligence analyst with 20 years of experience in real-time analysis of social media platforms such as Twitter/X, Telegram, and Reddit. Your task is to analyze, interpret, and structure chaotic and multilingual data from these sources into actionable intelligence for use in journalistic investigations, NGO reports, or risk monitoring.
|
| 25 |
+
|
| 26 |
+
You always operate within the framework of journalistic ethics, digital safety, and compliance with privacy and legal norms (e.g., GDPR, UN Human Rights).
|
| 27 |
+
|
| 28 |
+
Your outputs are structured, neutral, evidence-based, and free from speculation or bias.
|
| 29 |
+
|
| 30 |
+
Summarize content:
|
| 31 |
+
- Extract key points, sentiments, and narratives from noisy data.
|
| 32 |
+
- Detect recurring keywords, hashtags, topics, or propaganda themes.
|
| 33 |
+
- Identify emerging or trending developments with timestamps.
|
| 34 |
+
|
| 35 |
+
Classify influence:
|
| 36 |
+
- Group sources by tone (e.g., neutral, hostile, supportive).
|
| 37 |
+
- Identify influential users, bots, or actors based on repetition, reach, and tone.
|
| 38 |
+
|
| 39 |
+
Geo-political & ethical context:
|
| 40 |
+
- Provide geopolitical framing if needed (e.g., warzones, protests).
|
| 41 |
+
- Detect hate speech, misinformation, or manipulated media.
|
| 42 |
+
|
| 43 |
+
Structure the report:
|
| 44 |
+
- Always return JSON objects in the following format:
|
| 45 |
+
|
| 46 |
+
{
|
| 47 |
+
"summary": "...",
|
| 48 |
+
"top_topics": ["...", "..."],
|
| 49 |
+
"notable_users": [
|
| 50 |
+
{
|
| 51 |
+
"username": "@example",
|
| 52 |
+
"type": "influencer | bot | journalist | unknown",
|
| 53 |
+
"activity_summary": "..."
|
| 54 |
+
}
|
| 55 |
+
],
|
| 56 |
+
"network_analysis": {
|
| 57 |
+
"clusters": [
|
| 58 |
+
{
|
| 59 |
+
"label": "Pro-X Sentiment",
|
| 60 |
+
"nodes": ["@a", "@b", "@c"],
|
| 61 |
+
"summary": "..."
|
| 62 |
+
}
|
| 63 |
+
]
|
| 64 |
+
},
|
| 65 |
+
"sentiment_overview": {
|
| 66 |
+
"positive": 33,
|
| 67 |
+
"neutral": 45,
|
| 68 |
+
"negative": 22
|
| 69 |
+
},
|
| 70 |
+
"risk_flags": ["misinformation", "calls for violence", "bot amplification"],
|
| 71 |
+
"timestamp_range": {
|
| 72 |
+
"from": "2025-05-19T10:00Z",
|
| 73 |
+
"to": "2025-05-19T14:00Z"
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
Analyze the following content in ${language} language:
|
| 78 |
+
`;
|
| 79 |
+
|
| 80 |
+
try {
|
| 81 |
+
const model = genAI.getGenerativeModel({ model: 'gemini-pro' });
|
| 82 |
+
const contents = [
|
| 83 |
+
{ role: 'user', parts: [{ text: systemPrompt }] },
|
| 84 |
+
{ role: 'user', parts: [{ text: userContent }] },
|
| 85 |
+
];
|
| 86 |
+
const result = await model.generateContent({ contents });
|
| 87 |
+
const output = result.response.text();
|
| 88 |
+
res.send(`<pre style="white-space: pre-wrap; font-family: monospace;">${output}</pre><a href="/">← Back</a>
|
| 89 |
+
<form method="POST" action="/download-pdf">
|
| 90 |
+
<input type="hidden" name="json_output" id="json_output">
|
| 91 |
+
<button onclick="document.getElementById('json_output').value=document.querySelector('pre').innerText"
|
| 92 |
+
class="mt-4 bg-green-600 text-white py-2 px-4 rounded hover:bg-green-700 transition">Download PDF</button>
|
| 93 |
+
</form>
|
| 94 |
+
<script src="json_viewer.js"></script>`);
|
| 95 |
+
} catch (err) {
|
| 96 |
+
console.error(err);
|
| 97 |
+
res.status(500).send('❌ Error: ' + err.message);
|
| 98 |
+
}
|
| 99 |
+
});
|
index.html
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
| 6 |
+
<title>OSINT Analyzer</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
</head>
|
| 9 |
+
<body class="bg-gray-100 font-sans">
|
| 10 |
+
<div class="max-w-3xl mx-auto mt-10 p-6 bg-white shadow-xl rounded-xl">
|
| 11 |
+
<h1 class="text-2xl font-bold mb-4 text-center">🔍 OSINT Analyzer</h1>
|
| 12 |
+
<form action="/analyze" method="POST">
|
| 13 |
+
<textarea name="input_text" rows="12" required class="w-full p-3 border rounded focus:outline-none focus:ring" placeholder="Paste tweets, Telegram messages, Reddit threads, or news articles..."></textarea>
|
| 14 |
+
<select name="language" class="mt-4 w-full p-2 border rounded focus:outline-none focus:ring">
|
| 15 |
+
<option value="en">English</option>
|
| 16 |
+
<option value="de">German</option>
|
| 17 |
+
<option value="es">Spanish</option>
|
| 18 |
+
<option value="fr">French</option>
|
| 19 |
+
<option value="ru">Russian</option>
|
| 20 |
+
</select>
|
| 21 |
+
<button type="submit" class="mt-4 w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 transition">Analyze</button>
|
| 22 |
+
</form>
|
| 23 |
+
</div>
|
| 24 |
+
</body>
|
| 25 |
+
</html>
|
json_viewer.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
function formatJSON() {
|
| 3 |
+
const pre = document.querySelector('pre');
|
| 4 |
+
try {
|
| 5 |
+
const rawText = pre.textContent;
|
| 6 |
+
const jsonStart = rawText.indexOf('{');
|
| 7 |
+
const jsonEnd = rawText.lastIndexOf('}');
|
| 8 |
+
const jsonText = rawText.slice(jsonStart, jsonEnd + 1);
|
| 9 |
+
const obj = JSON.parse(jsonText);
|
| 10 |
+
pre.innerHTML = '<code>' + JSON.stringify(obj, null, 2) + '</code>';
|
| 11 |
+
} catch (e) {
|
| 12 |
+
console.error("Invalid JSON output");
|
| 13 |
+
}
|
| 14 |
+
}
|
| 15 |
+
window.onload = formatJSON;
|
package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "module",
|
| 3 |
+
"name": "osint-analyzer",
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
+
"scripts": {
|
| 6 |
+
"start": "node app.js"
|
| 7 |
+
},
|
| 8 |
+
"dependencies": {
|
| 9 |
+
"express": "^4.18.2",
|
| 10 |
+
"dotenv": "^16.3.1",
|
| 11 |
+
"@google/generative-ai": "^0.4.0",
|
| 12 |
+
"body-parser": "^1.20.2"
|
| 13 |
+
}
|
| 14 |
+
}
|
space.yaml
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
sdk: docker
|