Skip to content

مساعده #13

@ahmed734105204

Description

@ahmed734105204

app.py

-- coding: utf-8 --

"""
Shabwa OSINT Intelligence Dashboard (Legal & Anonymized)

  • يعمل بمعرّفات فقط (بدون أسماء/أرقام)
  • قاعدة بيانات SQLite
  • لوحة تحكم Streamlit: جداول، شبكة علاقات، تنبيهات، استيراد CSV، تصدير تقرير
    """

import os, io, sqlite3, base64
import pandas as pd
import streamlit as st
import networkx as nx
import matplotlib.pyplot as plt
from datetime import datetime

DB_NAME = "intelligence_shabwa.db"

---------- تهيئة قاعدة البيانات ----------

def init_db():
conn = sqlite3.connect(DB_NAME)
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS transfers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender_id TEXT,
receiver_id TEXT,
amount REAL,
location TEXT,
evidence TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)
""")
cur.execute("""
CREATE TABLE IF NOT EXISTS calls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender_id TEXT,
receiver_id TEXT,
duration INTEGER,
date TEXT,
evidence TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)
""")
conn.commit()
conn.close()

def seed_if_empty():
conn = sqlite3.connect(DB_NAME)
cur = conn.cursor()
cur.execute("SELECT COUNT() FROM transfers")
tcount = cur.fetchone()[0]
cur.execute("SELECT COUNT(
) FROM calls")
ccount = cur.fetchone()[0]

if tcount == 0:
    cur.executemany("""INSERT INTO transfers
        (sender_id,receiver_id,amount,location,evidence)
        VALUES (?,?,?,?,?)""", [
        ("ID1","ID4",2700000,"أبوظبي→شبوة","PDF1"),
        ("ID2","ID5",   4500,"الإمارات→شبوة","PDF2"),
        ("ID3","ID6",1800000,"الإمارات→شبوة","PDF3"),
    ])
if ccount == 0:
    cur.executemany("""INSERT INTO calls
        (sender_id,receiver_id,duration,date,evidence)
        VALUES (?,?,?,?,?)""", [
        ("ID1","ID4",9,"2025-08-19 02:15","Excel1"),
        ("ID2","ID5",12,"2025-08-19 03:30","Excel2"),
        ("ID3","ID6",7,"2025-08-19 04:45","Excel3"),
    ])
conn.commit()
conn.close()

---------- وظائف مساعدة ----------

def classify_risk(amount: float) -> str:
if amount is None:
return "غير معروف"
if amount > 2_000_000:
return "أحمر"
elif amount > 500_000:
return "أصفر"
else:
return "أخضر"

def fetch_dataframe(query: str, params=()):
conn = sqlite3.connect(DB_NAME)
df = pd.read_sql(query, conn, params=params)
conn.close()
return df

def upsert_csv_to_table(csv_file, table_name: str, expected_cols: list):
df = pd.read_csv(csv_file)
missing = [c for c in expected_cols if c not in df.columns]
if missing:
st.error(f"الأعمدة المطلوبة مفقودة في CSV: {missing}")
return False
conn = sqlite3.connect(DB_NAME)
df.to_sql(table_name, conn, if_exists="append", index=False)
conn.close()
return True

def build_merged():
conn = sqlite3.connect(DB_NAME)
q = """
SELECT t.sender_id, t.receiver_id, t.amount, t.location, t.evidence AS evidence_transfer,
c.duration, c.date, c.evidence AS evidence_call
FROM transfers t
LEFT JOIN calls c
ON t.sender_id = c.sender_id AND t.receiver_id = c.receiver_id
"""
df = pd.read_sql(q, conn)
conn.close()
if "amount" in df.columns:
df["المخاطر"] = df["amount"].apply(classify_risk)
return df

def df_to_excel_download(df: pd.DataFrame, filename: str = "تقرير_شبوة.xlsx"):
output = io.BytesIO()
with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
df.to_excel(writer, sheet_name="Report", index=False)
b64 = base64.b64encode(output.getvalue()).decode()
href = f'⬇️ تحميل {filename}'
return href

---------- واجهة Streamlit ----------

st.set_page_config(page_title="Shabwa OSINT Intelligence", page_icon="🛰️", layout="wide")

st.title("🛰️ Shabwa OSINT Intelligence Dashboard")
st.caption("لوحة قانونية تعمل بالمعرّفات فقط (بدون أسماء أو أرقام).")

إعداد قاعدة البيانات

if not os.path.exists(DB_NAME):
init_db()
seed_if_empty()
else:
init_db() # ضمان الجداول موجودة

with st.sidebar:
st.header("⚙️ إدارة البيانات")
st.write("استيراد CSV للحوالات والمكالمات (معرّفات فقط).")
st.markdown("- Transfers CSV الأعمدة: sender_id, receiver_id, amount, location, evidence")
st.markdown("- Calls CSV الأعمدة: sender_id, receiver_id, duration, date, evidence")

tr_csv = st.file_uploader("رفع Transfers CSV", type=["csv"], key="tr_csv")
if tr_csv and st.button("إضافة الحوالات", use_container_width=True):
    ok = upsert_csv_to_table(tr_csv, "transfers",
                             ["sender_id","receiver_id","amount","location","evidence"])
    if ok: st.success("تمت إضافة بيانات الحوالات.")

cl_csv = st.file_uploader("رفع Calls CSV", type=["csv"], key="cl_csv")
if cl_csv and st.button("إضافة المكالمات", use_container_width=True):
    ok = upsert_csv_to_table(cl_csv, "calls",
                             ["sender_id","receiver_id","duration","date","evidence"])
    if ok: st.success("تمت إضافة بيانات المكالمات.")

st.divider()
if st.button("تفريغ البيانات التجريبية وإعادة تعبئتها", type="secondary"):
    os.remove(DB_NAME) if os.path.exists(DB_NAME) else None
    init_db(); seed_if_empty()
    st.success("تمت إعادة التهيئة ببيانات تجريبية.")

st.subheader("📦 الحوالات")
transfers = fetch_dataframe("SELECT id, sender_id, receiver_id, amount, location, evidence, created_at FROM transfers ORDER BY id DESC")

تصنيف المخاطر داخل الجدول للعرض

if not transfers.empty:
transfers["المخاطر"] = transfers["amount"].apply(classify_risk)
st.dataframe(transfers, use_container_width=True)

st.subheader("📞 المكالمات")
calls = fetch_dataframe("SELECT id, sender_id, receiver_id, duration, date, evidence, created_at FROM calls ORDER BY id DESC")
st.dataframe(calls, use_container_width=True)

st.subheader("🧠 دمج/تحليل")
merged = build_merged()

col1, col2, col3 = st.columns(3)
with col1:
st.metric("عدد الحوالات", len(transfers))
with col2:
st.metric("عدد المكالمات", len(calls))
with col3:
high_count = int((merged["المخاطر"] == "أحمر").sum()) if not merged.empty else 0
st.metric("حالات عالية المخاطر", high_count)

فلاتر

st.markdown("### 🔎 عوامل تصفية")
risk_filter = st.multiselect("مستوى المخاطر", ["أحمر","أصفر","أخضر"], default=["أحمر","أصفر","أخضر"])
if risk_filter:
merged_view = merged[merged["المخاطر"].isin(risk_filter)]
else:
merged_view = merged.copy()

st.dataframe(merged_view, use_container_width=True)

شبكة العلاقات

st.markdown("### 🕸️ شبكة العلاقات")
if merged_view.empty:
st.info("لا توجد بيانات لعرض الشبكة.")
else:
G = nx.Graph()
for _, r in merged_view.iterrows():
s = r["sender_id"]; t = r["receiver_id"]
G.add_node(s); G.add_node(t)
G.add_edge(s, t, weight=r.get("amount", 0.0))
fig, ax = plt.subplots()
pos = nx.spring_layout(G, k=0.6, seed=42)
nx.draw(G, pos, with_labels=True, node_size=1200, ax=ax)
weights = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels=weights, ax=ax)
ax.set_title("شبكة الحوالات والمكالمات في شبوة (بدون أسماء/أرقام)")
st.pyplot(fig)

تنبيهات

st.markdown("### ⚠️ تنبيهات تلقائية")
alerts = []
if not merged.empty:
for _, r in merged.iterrows():
if r["المخاطر"] == "أحمر":
alerts.append(f"⚠️ حوالة عالية المخاطر: {r['sender_id']} → {r['receiver_id']} | مبلغ: {r['amount']} | موقع: {r['location']}")
if alerts:
for a in alerts:
st.error(a)
else:
st.success("لا توجد تنبيهات عالية المخاطر حاليًا.")

إنشاء تقرير للتنزيل

st.markdown("### 📄 تقرير Excel")
if not merged_view.empty:
href = df_to_excel_download(merged_view, filename=f"تقرير_شبوة_{datetime.now().strftime('%Y%m%d_%H%M')}.xlsx")
st.markdown(href, unsafe_allow_html=True)
else:
st.caption("أنشئ/استورد بيانات أولاً لتوليد التقرير.")

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions