Skip to content

Conversation

@Sutidon
Copy link

@Sutidon Sutidon commented Sep 29, 2025

#!/usr/bin/env python3

-- coding: utf-8 --

"""
guardian_ai_v3_complete.py

Single-file prototype: Guardian AI v3 - Defensive log scanner & alerting
Author: Assistant-generated for user (สุธิดล แซ่กั้ว)
Purpose: Passive parsing of honeypot/log files, signature detection, event storage,
optional LINE notify, optional FastAPI management endpoints, HTML/PDF report.

Usage:
python guardian_ai_v3_complete.py --scan
python guardian_ai_v3_complete.py --watch
python guardian_ai_v3_complete.py --report --output report_YYYYMMDD.html
python guardian_ai_v3_complete.py --api

Environment:
- GUARDIAN_BASE_DIR (optional)
- GUARDIAN_LINE_TOKEN (optional)
- If FastAPI & uvicorn installed, --api will run management endpoints

Security notes:
- Do not hardcode secrets here for production.
- This script is passive (parsing/logging only).
"""

from future import annotations
import os
import sys
import json
import time
import re
import sqlite3
import logging
import argparse
import tempfile
import hashlib
from datetime import datetime, timedelta
from pathlib import Path
from typing import List, Dict, Any, Optional

Optional imports

try:
import requests
except Exception:
requests = None

try:
import PyPDF2
except Exception:
PyPDF2 = None

try:
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas as reportlab_canvas
except Exception:
reportlab_canvas = None

FastAPI optional

FASTAPI_AVAILABLE = False
try:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, FileResponse
import uvicorn
FASTAPI_AVAILABLE = True
except Exception:
FASTAPI_AVAILABLE = False

----------------------------

Paths & defaults

----------------------------

BASE_DIR = Path(os.environ.get("GUARDIAN_BASE_DIR", os.getcwd()))
DB_PATH = BASE_DIR / os.environ.get("GUARDIAN_DB", "guardian_ai_v3.db")
LOG_DIR = BASE_DIR / os.environ.get("GUARDIAN_LOG_DIR", "logs")
REPORT_DIR = BASE_DIR / os.environ.get("GUARDIAN_REPORT_DIR", "reports")
EVENTS_JSON = BASE_DIR / os.environ.get("GUARDIAN_EVENTS_JSON", "events.json")
CONFIG_JSON = BASE_DIR / os.environ.get("GUARDIAN_CONFIG_JSON", "guardian_config.json")

LINE_TOKEN = os.environ.get("GUARDIAN_LINE_TOKEN") or os.environ.get("GUARDIAN_LINE_NOTIFY_TOKEN")
SCAN_POLL_INTERVAL = float(os.environ.get("GUARDIAN_SCAN_INTERVAL", "60"))
ALERT_THROTTLE_SECONDS = int(os.environ.get("GUARDIAN_ALERT_THROTTLE_SECONDS", "60"))

Ensure dirs

LOG_DIR.mkdir(parents=True, exist_ok=True)
REPORT_DIR.mkdir(parents=True, exist_ok=True)

----------------------------

Logging

----------------------------

logger = logging.getLogger("guardian_ai_v3_complete")
logger.setLevel(logging.INFO)
fmt = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(fmt)
logger.addHandler(ch)
fh = logging.FileHandler(LOG_DIR / f"guardian_{datetime.utcnow().date().isoformat()}.log", encoding='utf-8')
fh.setFormatter(fmt)
logger.addHandler(fh)

----------------------------

Utility helpers

----------------------------

def now_iso() -> str:
return datetime.utcnow().replace(microsecond=0).isoformat() + "Z"

def sha256_text(s: str) -> str:
return hashlib.sha256(s.encode("utf-8")).hexdigest()

def safe_load_json(path: Path, default):
try:
if path.exists():
return json.loads(path.read_text(encoding='utf-8'))
except Exception as e:
logger.warning("safe_load_json %s error: %s", path, e)
return default

def safe_save_

Summary

Changes

Closes:

Task list

  • For workflow changes, I have verified the Actions workflows function as expected.
  • For content changes, I have reviewed the style guide.
    .patch
    S.A.I. - Guardian AI — Full Repo Structure & Key Files

เอกสารนี้รวบรวมโครงสร้างรีโป (repo tree) และไฟล์สำคัญที่สามารถนำไปรันเป็นต้นแบบ (prototype) ของระบบ S.A.I. + Guardian AI ได้จริง — ครอบคลุม Backend, Worker, Frontend (Dashboard), Mobile App, Infra และสคริปต์ช่วยใช้


Overview

Backend: FastAPI (Python) + Redis (state & pub/sub) + Postgres (option) + Celery/async workers

AI Integrations: pluggable adapters (OpenAI, Google Gemini, Meta) ผ่าน app/services/ai_adapter.py

Notifications: LINE Notify, Firebase Push, Email

Anti-Drone Prototype: โมดูลสำหรับรับข้อมูลจากกล้อง/เซ็นเซอร์ (stub) และส่งเหตุการณ์เข้าสู่ pipeline

Frontend Dashboard: React + Tailwind (display nodes, map, alerts)

Mobile App: React Native (Expo) ติดตั้งได้ง่าย และเรียก API

Deployment: Docker + docker-compose (local), templates สำหรับ Kubernetes / Terraform (cloud)


Repo Tree (high-level)

sai-guardian/
├── README.md
├── .env.example
├── docker-compose.yml
├── infra/
│ ├── docker/
│ │ ├── backend.Dockerfile
│ │ └── frontend.Dockerfile
│ └── k8s/
│ └── deployment.yaml
├── backend/
│ ├── requirements.txt
│ ├── Dockerfile
│ ├── app/
│ │ ├── main.py
│ │ ├── api.py
│ │ ├── core/
│ │ │ └── config.py
│ │ ├── models.py
│ │ ├── schemas.py
│ │ ├── services/
│ │ │ ├── ai_adapter.py
│ │ │ ├── detection_pipeline.py
│ │ │ └── anti_drone.py
│ │ ├── workers/
│ │ │ └── worker.py
│ │ ├── utils/
│ │ │ ├── notifications.py
│ │ │ └── geo.py
│ │ └── tests/
│ │ └── test_api.py
│ └── scripts/
│ └── init_db.py
├── frontend/
│ ├── package.json
│ ├── tailwind.config.js
│ └── src/
│ ├── App.jsx
│ ├── pages/
│ │ └── Dashboard.jsx
│ └── components/
│ └── AlertCard.jsx
├── mobile/
│ ├── package.json
│ └── App.js # expo react-native
└── .github/
└── workflows/
└── ci.yml


Key files (selected, ready-to-use stubs)

NOTE: ไฟล์ด้านล่างเป็นตัวอย่างโค้ดต้นแบบ — ปรับค่า ENV และ API keys ใน .env ก่อนรัน

README.md

S.A.I. - Guardian AI

Prototype system: FastAPI backend, React dashboard, React Native mobile

Quickstart (local)

  1. Copy .env.example to .env and set keys
  2. docker-compose up --build
  3. Backend: http://localhost:8000
  4. Frontend: http://localhost:3000

Services

  • /api/v1/alerts
  • /api/v1/nodes
  • /api/v1/ai/respond

.env.example

FastAPI

FASTAPI_HOST=0.0.0.0 FASTAPI_PORT=8000 SECRET_KEY=replace_me

Redis

REDIS_URL=redis://redis:6379/0

AI keys

OPENAI_API_KEY= GEMINI_API_KEY=

Notifications

LINE_NOTIFY_TOKEN= FIREBASE_SERVER_KEY=

Database

DATABASE_URL=postgresql://postgres:postgres@postgres:5432/sai_db

docker-compose.yml

version: '3.8'
services:
  redis:
    image: redis:7-alpine
    ports:
      - '6379:6379'
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: sai_db
    ports:
      - '5432:5432'

  backend:
    build: ./backend
    env_file: .env
    ports:
      - '8000:8000'
    depends_on:
      - redis
      - postgres

  frontend:
    build: ./infra/docker/frontend.Dockerfile
    ports:
      - '3000:3000'
    depends_on:
      - backend

---

## Backend (FastAPI)

### `backend/requirements.txt`

fastapi uvicorn[standard] httpx pydantic aioredis asyncpg sqlalchemy[aio] python-dotenv python-jose[cryptography] requests pytest

### `backend/Dockerfile`
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY ./app /app/app
COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

backend/app/main.py

from fastapi import FastAPI
from .api import router as api_router

app = FastAPI(title="S.A.I. Guardian API")
app.include_router(api_router, prefix="/api/v1")

@app.get("/health")
async def health():
    return {"status": "ok"}

backend/app/api.py

from fastapi import APIRouter, Depends
from .schemas import AIRequest, AIResponse
from .services.ai_adapter import AIAdapter

router = APIRouter()

@router.post('/ai/respond', response_model=AIResponse)
async def ai_respond(req: AIRequest):
    adapter = AIAdapter()
    resp = await adapter.respond(req.prompt, metadata=req.metadata)
    return {"reply": resp}

@router.get('/alerts')
async def list_alerts():
    return {"items": []}

backend/app/schemas.py

from pydantic import BaseModel
from typing import Dict, Any

class AIRequest(BaseModel):
    prompt: str
    metadata: Dict[str, Any] = {}

class AIResponse(BaseModel):
    reply: str

backend/app/core/config.py

import os
from pydantic import BaseSettings

class Settings(BaseSettings):
    redis_url: str = os.getenv('REDIS_URL', 'redis://localhost:6379/0')
    openai_key: str = os.getenv('OPENAI_API_KEY', '')
    gemini_key: str = os.getenv('GEMINI_API_KEY', '')

settings = Settings()

backend/app/services/ai_adapter.py

import os
import httpx
from ..core.config import settings

class AIAdapter:
    """Pluggable adapter. For now a simple wrapper that prefers OpenAI then Gemini.
    Replace httpx calls with official SDKs as needed.
    """
    def __init__(self):
        self.openai_key = settings.openai_key
        self.gemini_key = settings.gemini_key

    async def respond(self, prompt: str, metadata: dict = None) -> str:
        metadata = metadata or {}
        # If OPENAI key available, call OpenAI Chat Completion (stub)
        if self.openai_key:
            return await self._call_openai(prompt)
        if self.gemini_key:
            return await self._call_gemini(prompt)
        return "No AI key configured"

    async def _call_openai(self, prompt: str) -> str:
        # minimal httpx stub — replace with openai library or httpx calls to new API
        return f"[OpenAI echo] {prompt}"

    async def _call_gemini(self, prompt: str) -> str:
        return f"[Gemini echo] {prompt}"

backend/app/services/detection_pipeline.py

# Receives sensor/camera inputs, runs detection (placeholder), and pushes alerts to redis/pubsub
import asyncio

async def process_sensor_event(event: dict):
    # event contains: type, source, payload, timestamp
    # placeholder: simple rule-based detection
    severity = event.get('severity', 'low')
    if event.get('type') == 'drone' or 'vehicle' in event.get('payload', {}):
        severity = 'high'
    alert = {
        'message': f"Detected {event.get('type')}",
        'severity': severity,
        'raw': event
    }
    # publish to redis / push to db / send notifications
    return alert

backend/app/services/anti_drone.py

# Interface for Anti-Drone hardware integration (stubs)

class AntiDroneController:
    def __init__(self):
        pass
    def scan(self):
        # integrate with camera/DF system, return list of detections
        return []
    def trigger_mitigation(self, target_id):
        # e.g. jam radio, send alert (hardware-specific)
        return True

backend/app/workers/worker.py

import asyncio
from ..services.detection_pipeline import process_sensor_event
from ..utils.notifications import send_line_notify

async def worker_loop():
    # in production use Redis pubsub / Celery
    while True:
        # pop event from a queue (placeholder)
        await asyncio.sleep(1)
        # example event
        event = {'type': 'drone', 'payload': {}, 'timestamp': 0}
        alert = await process_sensor_event(event)
        if alert['severity'] in ('high', 'critical'):
            await send_line_notify(f"ALERT: {alert['message']} - severity {alert['severity']}")

if __name__ == '__main__':
    asyncio.run(worker_loop())

backend/app/utils/notifications.py

import os
import httpx

LINE_TOKEN = os.getenv('LINE_NOTIFY_TOKEN')

async def send_line_notify(message: str):
    if not LINE_TOKEN:
        print('LINE token missing, skipping notify')
        return
    async with httpx.AsyncClient() as client:
        await client.post(
            'https://notify-api.line.me/api/notify',
            headers={'Authorization': f'Bearer {LINE_TOKEN}'},
            data={'message': message}
        )


---

Frontend (React + Tailwind) — selected files

frontend/package.json

{
  "name": "sai-guardian-frontend",
  "private": true,
  "dependencies": {
    "react": "18.x",
    "react-dom": "18.x",
    "react-scripts": "5.x",
    "axios": "^1.0.0",
    "leaflet": "^1.9.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build"
  }
}

frontend/src/App.jsx

import React from 'react'
import Dashboard from './pages/Dashboard'

export default function App(){
  return (
    <div className="min-h-screen bg-slate-50">
      <Dashboard />
    </div>
  )
}

frontend/src/pages/Dashboard.jsx

import React, {useEffect, useState} from 'react'
import axios from 'axios'

export default function Dashboard(){
  const [alerts, setAlerts] = useState([])
  useEffect(()=>{
    axios.get('/api/v1/alerts').then(r=>setAlerts(r.data.items||[]))
  },[])
  return (
    <div className="p-6">
      <h1 className="text-2xl font-bold">Guardian AI Dashboard</h1>
      <div className="mt-4 grid gap-4">
        {alerts.map((a,i)=>(<div key={i} className="p-4 bg-white rounded shadow">{a.message||JSON.stringify(a)}</div>))}
      </div>
    </div>
  )
}


---

Mobile (React Native - Expo)

mobile/package.json (minimal)

{
  "name": "sai-guardian-mobile",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start"
  },
  "dependencies": {
    "expo": "~48.0.0",
    "react": "18.2.0",
    "react-native": "0.71.8",
    "axios": "^1.0.0"
  }
}

mobile/App.js (stub)

import React, {useEffect, useState} from 'react'
import { Text, View, FlatList } from 'react-native'
import axios from 'axios'

export default function App(){
  const [alerts, setAlerts] = useState([])
  useEffect(()=>{
    axios.get('http://YOUR_BACKEND_HOST:8000/api/v1/alerts').then(r=>setAlerts(r.data.items||[])).catch(()=>{})
  },[])
  return (
    <View style={{flex:1, padding:20}}>
      <Text style={{fontSize:20, fontWeight:'bold'}}>Guardian AI Mobile</Text>
      <FlatList data={alerts} keyExtractor={(i)=>String(i.id||i.message)} renderItem={({item})=> <Text>{item.message}</Text>} />
    </View>
  )
}


---

CI (GitHub Actions) — .github/workflows/ci.yml

name: CI
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install deps
        run: |
          pip install -r backend/requirements.txt
      - name: Run tests
        run: |
          pytest -q


---

Deployment notes

Local dev: docker-compose up --build

For Cloud: provide Kubernetes manifests (infra/k8s/) and Terraform snippets to provision Redis (Managed), Postgres (Managed), and object store

Use a reverse proxy (Traefik / Nginx) with TLS termination



---
sai-guardian/
├── README.md                  # คำอธิบายโปรเจกต์และ quickstart
├── .env.example               # ตัวอย่างไฟล์ environment variables
├── docker-compose.yml         # สำหรับรัน services ทั้งหมด local
├── infra/                     # Infrastructure templates
│   ├── docker/                # Dockerfiles สำหรับ backend/frontend
│   │   ├── backend.Dockerfile
│   │   └── frontend.Dockerfile
│   └── k8s/                   # Kubernetes manifests
│       └── deployment.yaml
├── backend/                   # Backend FastAPI
│   ├── requirements.txt       # Dependencies Python
│   ├── Dockerfile
│   ├── app/                   # Core application
│   │   ├── main.py            # Entry point FastAPI
│   │   ├── api.py             # API routes
│   │   ├── core/config.py     # Settings จาก ENV
│   │   ├── models.py          # Database models (SQLAlchemy)
│   │   ├── schemas.py         # Pydantic schemas
│   │   ├── services/          # Business logic
│   │   │   ├── ai_adapter.py  # Adapter สำหรับ AI providers
│   │   │   ├── detection_pipeline.py  # Pipeline ตรวจจับเหตุการณ์
│   │   │   └── anti_drone.py  # Controller สำหรับ anti-drone
│   │   ├── workers/           # Background tasks
│   │   │   └── worker.py      # Worker loop สำหรับ process events
│   │   ├── utils/             # Utilities
│   │   │   ├── notifications.py  # ส่งแจ้งเตือน
│   │   │   └── geo.py         # Geo-related functions (แผนที่)
│   │   └── tests/             # Unit tests
│   │       └── test_api.py
│   └── scripts/               # Helper scripts
│       └── init_db.py         # Initialize database
├── frontend/                  # React Dashboard
│   ├── package.json           # Dependencies JS
│   ├── tailwind.config.js     # Tailwind config
│   └── src/
│       ├── App.jsx            # Main app component
│       ├── pages/Dashboard.jsx  # Dashboard page
│       └── components/        # Re

@Sutidon Sutidon marked this pull request as ready for review September 29, 2025 16:31
@Sutidon
Copy link
Author

Sutidon commented Sep 29, 2025

Suthidon

@Sutidon Sutidon marked this pull request as draft September 29, 2025 16:32
@Sutidon Sutidon marked this pull request as ready for review September 29, 2025 16:32
@Sutidon
Copy link
Author

Sutidon commented Oct 7, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant