initial commit
This commit is contained in:
24
.env
Normal file
24
.env
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# MikroTik Gemini Integration - Environment Variables
|
||||||
|
|
||||||
|
# Google Gemini API Key (required)
|
||||||
|
# Dapatkan dari: https://makersuite.google.com/app/apikey
|
||||||
|
GEMINI_API_KEY=AIzaSyC9RXt7VHVIlvxU_OuI7xONzwIuu56iS-g
|
||||||
|
|
||||||
|
# MikroTik Connection (optional, for data updates)
|
||||||
|
MIKROTIK_HOST=192.168.7.1
|
||||||
|
MIKROTIK_PORT=80
|
||||||
|
MIKROTIK_USER=admin11
|
||||||
|
MIKROTIK_PASSWORD=Dua75316__
|
||||||
|
|
||||||
|
# API Server Configuration
|
||||||
|
API_HOST=0.0.0.0
|
||||||
|
API_PORT=8010
|
||||||
|
API_DEBUG=true
|
||||||
|
API_KEY=mkmcp_secret_key_2026
|
||||||
|
|
||||||
|
# Data File Path
|
||||||
|
DATA_FILE=data/mikrotik_mcp_data.json
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
LOG_FILE=logs/app.log
|
||||||
23
.env.example
Normal file
23
.env.example
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# MikroTik Gemini Integration - Environment Variables
|
||||||
|
|
||||||
|
# Google Gemini API Key (required)
|
||||||
|
# Dapatkan dari: https://makersuite.google.com/app/apikey
|
||||||
|
GEMINI_API_KEY=your_gemini_api_key_here
|
||||||
|
|
||||||
|
# MikroTik Connection (optional, for data updates)
|
||||||
|
MIKROTIK_HOST=192.168.1.1
|
||||||
|
MIKROTIK_PORT=8728
|
||||||
|
MIKROTIK_USER=admin
|
||||||
|
MIKROTIK_PASSWORD=password
|
||||||
|
|
||||||
|
# API Server Configuration
|
||||||
|
API_HOST=0.0.0.0
|
||||||
|
API_PORT=8000
|
||||||
|
API_DEBUG=true
|
||||||
|
|
||||||
|
# Data File Path
|
||||||
|
DATA_FILE=../mikrotik_mcp_data.json
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
LOG_FILE=logs/app.log
|
||||||
164
README.md
Normal file
164
README.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
# 🚀 Integrasi MikroTik MCP dengan Gemini AI
|
||||||
|
|
||||||
|
## 📋 **Daftar Isi**
|
||||||
|
1. [Overview](#overview)
|
||||||
|
2. [Prerequisites](#prerequisites)
|
||||||
|
3. [Struktur File](#struktur-file)
|
||||||
|
4. [Instalasi Cepat](#instalasi-cepat)
|
||||||
|
5. [Penggunaan](#penggunaan)
|
||||||
|
6. [Deployment](#deployment)
|
||||||
|
7. [Contoh Penggunaan](#contoh-penggunaan)
|
||||||
|
8. [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## 🔍 **Overview**
|
||||||
|
|
||||||
|
Integrasi ini memungkinkan Anda bertanya tentang perangkat MikroTik menggunakan **Google Gemini AI** dengan konteks data real-time dari perangkat.
|
||||||
|
|
||||||
|
**Fitur Utama:**
|
||||||
|
- ✅ Query natural language tentang MikroTik
|
||||||
|
- ✅ Context-aware responses
|
||||||
|
- ✅ Real-time monitoring
|
||||||
|
- ✅ Web API interface
|
||||||
|
- ✅ Docker deployment
|
||||||
|
- ✅ Optimized token usage
|
||||||
|
|
||||||
|
## 📦 **Prerequisites**
|
||||||
|
|
||||||
|
### **1. Google Cloud Account**
|
||||||
|
- API Key Gemini dari [Google AI Studio](https://makersuite.google.com/app/apikey)
|
||||||
|
|
||||||
|
### **2. Python 3.11+**
|
||||||
|
```bash
|
||||||
|
python --version
|
||||||
|
```
|
||||||
|
|
||||||
|
### **3. MikroTik Data**
|
||||||
|
File: `mikrotik_mcp_data.json` (sudah ada di project)
|
||||||
|
|
||||||
|
## 📁 **Struktur File**
|
||||||
|
|
||||||
|
```
|
||||||
|
gemini_integration/
|
||||||
|
├── README.md # File ini
|
||||||
|
├── gemini_mikrotik_integration.py # Script utama
|
||||||
|
├── api_server.py # FastAPI server
|
||||||
|
├── realtime_monitor.py # Monitoring real-time
|
||||||
|
├── context_optimizer.py # Optimasi context
|
||||||
|
├── update_data.py # Script update data MikroTik
|
||||||
|
├── requirements.txt # Dependencies
|
||||||
|
├── docker-compose.yml # Docker deployment
|
||||||
|
├── config.yaml # Konfigurasi
|
||||||
|
├── example_prompts.md # Contoh prompt
|
||||||
|
├── .env.example # Template environment
|
||||||
|
└── logs/ # Log directory (auto-created)
|
||||||
|
```
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚡ **Instalasi Cepat**
|
||||||
|
|
||||||
|
### **Step 1: Setup Environment**
|
||||||
|
```bash
|
||||||
|
cd /a0/usr/projects/project_1/gemini_integration
|
||||||
|
|
||||||
|
# Copy environment template
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Edit .env dengan API key Anda
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Step 2: Install Dependencies**
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Step 3: Test Integration**
|
||||||
|
```bash
|
||||||
|
python gemini_mikrotik_integration.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 **Penggunaan**
|
||||||
|
|
||||||
|
### **1. Interactive Chat**
|
||||||
|
```bash
|
||||||
|
python gemini_mikrotik_integration.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### **2. Web API**
|
||||||
|
```bash
|
||||||
|
python api_server.py
|
||||||
|
# Akses: http://localhost:8000/docs
|
||||||
|
```
|
||||||
|
|
||||||
|
### **3. Real-time Monitoring**
|
||||||
|
```bash
|
||||||
|
python realtime_monitor.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐳 **Deployment dengan Docker**
|
||||||
|
|
||||||
|
### **Build dan Run**
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Check Status**
|
||||||
|
```bash
|
||||||
|
docker-compose ps
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 **Contoh Penggunaan**
|
||||||
|
|
||||||
|
### **Via Python Script**
|
||||||
|
```python
|
||||||
|
from gemini_mikrotik_integration import MikroTikGeminiAssistant
|
||||||
|
|
||||||
|
assistant = MikroTikGeminiAssistant()
|
||||||
|
answer = assistant.ask_question("Berapa CPU usage router?")
|
||||||
|
print(answer)
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Via API**
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8000/ask \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"question": "Ada berapa interface yang running?"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 **Troubleshooting**
|
||||||
|
|
||||||
|
### **Error: API Key Invalid**
|
||||||
|
```bash
|
||||||
|
# Periksa .env file
|
||||||
|
cat .env | grep GEMINI_API_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Error: MikroTik Data Not Found**
|
||||||
|
```bash
|
||||||
|
# Pastikan file data ada
|
||||||
|
ls -la ../mikrotik_mcp_data.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Error: Port Already in Use**
|
||||||
|
```bash
|
||||||
|
# Ganti port di api_server.py atau kill process
|
||||||
|
lsof -i :8000
|
||||||
|
kill -9 <PID>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📞 **Support**
|
||||||
|
|
||||||
|
- **Issues**: Check error logs
|
||||||
|
- **Questions**: Lihat example_prompts.md
|
||||||
|
- **Updates**: Pantau perubahan API Gemini
|
||||||
|
|
||||||
|
## 📄 **License**
|
||||||
|
|
||||||
|
MIT License - Bebas digunakan untuk keperluan apapun.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Dibuat oleh:** Agent Zero AI Assistant
|
||||||
|
**Tanggal:** 2026-01-20
|
||||||
|
**Versi:** 1.0.0
|
||||||
162
README.md.backup
Normal file
162
README.md.backup
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
# 🚀 Integrasi MikroTik MCP dengan Gemini AI
|
||||||
|
|
||||||
|
## 📋 **Daftar Isi**
|
||||||
|
1. [Overview](#overview)
|
||||||
|
2. [Prerequisites](#prerequisites)
|
||||||
|
3. [Struktur File](#struktur-file)
|
||||||
|
4. [Instalasi Cepat](#instalasi-cepat)
|
||||||
|
5. [Penggunaan](#penggunaan)
|
||||||
|
6. [Deployment](#deployment)
|
||||||
|
7. [Contoh Penggunaan](#contoh-penggunaan)
|
||||||
|
8. [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## 🔍 **Overview**
|
||||||
|
|
||||||
|
Integrasi ini memungkinkan Anda bertanya tentang perangkat MikroTik menggunakan **Google Gemini AI** dengan konteks data real-time dari perangkat.
|
||||||
|
|
||||||
|
**Fitur Utama:**
|
||||||
|
- ✅ Query natural language tentang MikroTik
|
||||||
|
- ✅ Context-aware responses
|
||||||
|
- ✅ Real-time monitoring
|
||||||
|
- ✅ Web API interface
|
||||||
|
- ✅ Docker deployment
|
||||||
|
- ✅ Optimized token usage
|
||||||
|
|
||||||
|
## 📦 **Prerequisites**
|
||||||
|
|
||||||
|
### **1. Google Cloud Account**
|
||||||
|
- API Key Gemini dari [Google AI Studio](https://makersuite.google.com/app/apikey)
|
||||||
|
|
||||||
|
### **2. Python 3.11+**
|
||||||
|
```bash
|
||||||
|
python --version
|
||||||
|
```
|
||||||
|
|
||||||
|
### **3. MikroTik Data**
|
||||||
|
File: `mikrotik_mcp_data.json` (sudah ada di project)
|
||||||
|
|
||||||
|
## 📁 **Struktur File**
|
||||||
|
|
||||||
|
```
|
||||||
|
gemini_integration/
|
||||||
|
├── README.md # File ini
|
||||||
|
├── gemini_mikrotik_integration.py # Script utama
|
||||||
|
├── api_server.py # FastAPI server
|
||||||
|
├── realtime_monitor.py # Monitoring real-time
|
||||||
|
├── context_optimizer.py # Optimasi context
|
||||||
|
├── requirements.txt # Dependencies
|
||||||
|
├── docker-compose.yml # Docker deployment
|
||||||
|
├── nginx.conf # Nginx config
|
||||||
|
├── example_prompts.md # Contoh prompt
|
||||||
|
├── .env.example # Template environment
|
||||||
|
└── config.yaml # Konfigurasi
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚡ **Instalasi Cepat**
|
||||||
|
|
||||||
|
### **Step 1: Setup Environment**
|
||||||
|
```bash
|
||||||
|
cd /a0/usr/projects/project_1/gemini_integration
|
||||||
|
|
||||||
|
# Copy environment template
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Edit .env dengan API key Anda
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Step 2: Install Dependencies**
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Step 3: Test Integration**
|
||||||
|
```bash
|
||||||
|
python gemini_mikrotik_integration.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 **Penggunaan**
|
||||||
|
|
||||||
|
### **1. Interactive Chat**
|
||||||
|
```bash
|
||||||
|
python gemini_mikrotik_integration.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### **2. Web API**
|
||||||
|
```bash
|
||||||
|
python api_server.py
|
||||||
|
# Akses: http://localhost:8000/docs
|
||||||
|
```
|
||||||
|
|
||||||
|
### **3. Real-time Monitoring**
|
||||||
|
```bash
|
||||||
|
python realtime_monitor.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐳 **Deployment dengan Docker**
|
||||||
|
|
||||||
|
### **Build dan Run**
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Check Status**
|
||||||
|
```bash
|
||||||
|
docker-compose ps
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 **Contoh Penggunaan**
|
||||||
|
|
||||||
|
### **Via Python Script**
|
||||||
|
```python
|
||||||
|
from gemini_mikrotik_integration import MikroTikGeminiAssistant
|
||||||
|
|
||||||
|
assistant = MikroTikGeminiAssistant()
|
||||||
|
answer = assistant.ask_question("Berapa CPU usage router?")
|
||||||
|
print(answer)
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Via API**
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8000/ask \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"question": "Ada berapa interface yang running?"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 **Troubleshooting**
|
||||||
|
|
||||||
|
### **Error: API Key Invalid**
|
||||||
|
```bash
|
||||||
|
# Periksa .env file
|
||||||
|
cat .env | grep GEMINI_API_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Error: MikroTik Data Not Found**
|
||||||
|
```bash
|
||||||
|
# Pastikan file data ada
|
||||||
|
ls -la ../mikrotik_mcp_data.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Error: Port Already in Use**
|
||||||
|
```bash
|
||||||
|
# Ganti port di api_server.py atau kill process
|
||||||
|
lsof -i :8000
|
||||||
|
kill -9 <PID>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📞 **Support**
|
||||||
|
|
||||||
|
- **Issues**: Check error logs
|
||||||
|
- **Questions**: Lihat example_prompts.md
|
||||||
|
- **Updates**: Pantau perubahan API Gemini
|
||||||
|
|
||||||
|
## 📄 **License**
|
||||||
|
|
||||||
|
MIT License - Bebas digunakan untuk keperluan apapun.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Dibuat oleh:** Agent Zero AI Assistant
|
||||||
|
**Tanggal:** 2026-01-20
|
||||||
|
**Versi:** 1.0.0
|
||||||
BIN
__pycache__/context_optimizer.cpython-313.pyc
Normal file
BIN
__pycache__/context_optimizer.cpython-313.pyc
Normal file
Binary file not shown.
BIN
__pycache__/gemini_mikrotik_integration.cpython-313.pyc
Normal file
BIN
__pycache__/gemini_mikrotik_integration.cpython-313.pyc
Normal file
Binary file not shown.
BIN
__pycache__/update_data.cpython-313.pyc
Normal file
BIN
__pycache__/update_data.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/context_optimizer.cpython-313.pyc
Normal file
BIN
app/__pycache__/context_optimizer.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/gemini_mikrotik_integration.cpython-313.pyc
Normal file
BIN
app/__pycache__/gemini_mikrotik_integration.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/update_data.cpython-313.pyc
Normal file
BIN
app/__pycache__/update_data.cpython-313.pyc
Normal file
Binary file not shown.
153
app/api_server.py
Normal file
153
app/api_server.py
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
FastAPI Server untuk MikroTik Gemini Integration
|
||||||
|
"""
|
||||||
|
|
||||||
|
from fastapi import FastAPI, HTTPException, Security, status, Depends
|
||||||
|
from fastapi.security import APIKeyHeader
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from datetime import datetime
|
||||||
|
import uvicorn
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Import our assistant
|
||||||
|
from gemini_mikrotik_integration import MikroTikGeminiAssistant
|
||||||
|
|
||||||
|
# Load environment
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Security
|
||||||
|
API_KEY = os.getenv("API_KEY", "mkmcp_secret_key_2026")
|
||||||
|
API_KEY_NAME = "X-API-Key"
|
||||||
|
api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False)
|
||||||
|
|
||||||
|
async def get_api_key(api_key: str = Security(api_key_header)):
|
||||||
|
if api_key == API_KEY:
|
||||||
|
return api_key
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="API Key tidak valid atau tidak ditemukan",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize FastAPI
|
||||||
|
app = FastAPI(
|
||||||
|
title="MikroTik Gemini API",
|
||||||
|
description="API untuk query MikroTik dengan Gemini AI",
|
||||||
|
version="1.0.0",
|
||||||
|
docs_url="/docs",
|
||||||
|
redoc_url="/redoc",
|
||||||
|
dependencies=[Depends(get_api_key)]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize assistant
|
||||||
|
assistant = None
|
||||||
|
try:
|
||||||
|
assistant = MikroTikGeminiAssistant()
|
||||||
|
print("✅ MikroTik Gemini Assistant initialized")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Assistant initialization failed: {e}")
|
||||||
|
assistant = None
|
||||||
|
|
||||||
|
# Request/Response models
|
||||||
|
class QuestionRequest(BaseModel):
|
||||||
|
question: str
|
||||||
|
detailed: bool = False
|
||||||
|
|
||||||
|
class AnswerResponse(BaseModel):
|
||||||
|
question: str
|
||||||
|
answer: str
|
||||||
|
timestamp: str
|
||||||
|
success: bool
|
||||||
|
|
||||||
|
class HealthResponse(BaseModel):
|
||||||
|
status: str
|
||||||
|
service: str
|
||||||
|
version: str
|
||||||
|
timestamp: str
|
||||||
|
mikrotik_device: str = "N/A"
|
||||||
|
data_age: str = "N/A"
|
||||||
|
|
||||||
|
# API Endpoints
|
||||||
|
@app.get("/")
|
||||||
|
def root():
|
||||||
|
return {
|
||||||
|
"service": "MikroTik Gemini API",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"endpoints": {
|
||||||
|
"docs": "/docs",
|
||||||
|
"health": "/health",
|
||||||
|
"ask": "/ask (POST)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@app.get("/health", response_model=HealthResponse)
|
||||||
|
def health_check():
|
||||||
|
"""Check API and MikroTik status"""
|
||||||
|
status = "healthy"
|
||||||
|
device_info = "N/A"
|
||||||
|
data_age = "N/A"
|
||||||
|
|
||||||
|
if assistant:
|
||||||
|
try:
|
||||||
|
summary = assistant.get_summary()
|
||||||
|
device_info = summary["device"]
|
||||||
|
data_age = summary["timestamp"]
|
||||||
|
except:
|
||||||
|
status = "degraded"
|
||||||
|
else:
|
||||||
|
status = "degraded"
|
||||||
|
|
||||||
|
return HealthResponse(
|
||||||
|
status=status,
|
||||||
|
service="MikroTik Gemini API",
|
||||||
|
version="1.0.0",
|
||||||
|
timestamp=datetime.now().isoformat(),
|
||||||
|
mikrotik_device=device_info,
|
||||||
|
data_age=data_age
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.post("/ask", response_model=AnswerResponse)
|
||||||
|
def ask_question(request: QuestionRequest):
|
||||||
|
"""Ask Gemini about MikroTik"""
|
||||||
|
if not assistant:
|
||||||
|
raise HTTPException(status_code=503, detail="Assistant not available")
|
||||||
|
|
||||||
|
try:
|
||||||
|
answer = assistant.ask(request.question)
|
||||||
|
|
||||||
|
return AnswerResponse(
|
||||||
|
question=request.question,
|
||||||
|
answer=answer,
|
||||||
|
timestamp=datetime.now().isoformat(),
|
||||||
|
success=True
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error: {str(e)}")
|
||||||
|
|
||||||
|
@app.get("/summary")
|
||||||
|
def get_summary():
|
||||||
|
"""Get MikroTik device summary"""
|
||||||
|
if not assistant:
|
||||||
|
raise HTTPException(status_code=503, detail="Assistant not available")
|
||||||
|
|
||||||
|
try:
|
||||||
|
return assistant.get_summary()
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error: {str(e)}")
|
||||||
|
|
||||||
|
# Run server
|
||||||
|
if __name__ == "__main__":
|
||||||
|
host = os.getenv("API_HOST", "0.0.0.0")
|
||||||
|
port = int(os.getenv("API_PORT", "8000"))
|
||||||
|
debug = os.getenv("API_DEBUG", "false").lower() == "true"
|
||||||
|
|
||||||
|
print(f"🚀 Starting MikroTik Gemini API on {host}:{port}")
|
||||||
|
print(f"📚 Documentation: http://{host}:{port}/docs")
|
||||||
|
|
||||||
|
uvicorn.run(
|
||||||
|
app,
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
log_level="info"
|
||||||
|
)
|
||||||
256
app/context_optimizer.py
Normal file
256
app/context_optimizer.py
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Context Optimizer untuk MikroTik Gemini Integration
|
||||||
|
|
||||||
|
Optimasi data context untuk Gemini AI agar sesuai dengan token limits
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from typing import Dict, List, Any
|
||||||
|
|
||||||
|
class ContextOptimizer:
|
||||||
|
"""Optimize MikroTik data for Gemini context"""
|
||||||
|
|
||||||
|
def __init__(self, max_tokens: int = 8000):
|
||||||
|
"""
|
||||||
|
Initialize optimizer dengan max tokens
|
||||||
|
"""
|
||||||
|
self.max_tokens = max_tokens
|
||||||
|
self.estimated_tokens_per_char = 0.25 # Estimasi kasar
|
||||||
|
|
||||||
|
def _is_true(self, value: Any) -> bool:
|
||||||
|
"""Helper untuk cek boolean dari MikroTik (bisa bool atau string 'true')"""
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
if isinstance(value, str):
|
||||||
|
return value.lower() == "true"
|
||||||
|
return False
|
||||||
|
|
||||||
|
def estimate_tokens(self, text: str) -> int:
|
||||||
|
"""Estimasi jumlah tokens dari text"""
|
||||||
|
return int(len(text) * self.estimated_tokens_per_char)
|
||||||
|
|
||||||
|
def optimize_system_info(self, system_data: Dict) -> Dict:
|
||||||
|
"""Optimize system information"""
|
||||||
|
resource = system_data.get("resource", {})
|
||||||
|
|
||||||
|
# Ambil hanya field penting
|
||||||
|
optimized = {
|
||||||
|
"board_name": resource.get("board-name", "N/A"),
|
||||||
|
"cpu_load": resource.get("cpu-load", "N/A"),
|
||||||
|
"cpu_count": resource.get("cpu-count", "N/A"),
|
||||||
|
"free_memory": self._format_memory(resource.get("free-memory", 0)),
|
||||||
|
"total_memory": self._format_memory(resource.get("total-memory", 0)),
|
||||||
|
"uptime": resource.get("uptime", "N/A"),
|
||||||
|
"version": resource.get("version", "N/A"),
|
||||||
|
}
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
def optimize_interfaces(self, interfaces: List[Dict], max_interfaces: int = 20) -> List[Dict]:
|
||||||
|
"""Optimize interfaces list"""
|
||||||
|
if not interfaces:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Prioritize: running interfaces, then physical, then others
|
||||||
|
running = [i for i in interfaces if self._is_true(i.get("running"))]
|
||||||
|
not_running = [i for i in interfaces if not self._is_true(i.get("running"))]
|
||||||
|
|
||||||
|
# Ambil sample dari masing-masing
|
||||||
|
optimized = []
|
||||||
|
|
||||||
|
# Running interfaces (prioritas tinggi)
|
||||||
|
for i in running[:max_interfaces//2]:
|
||||||
|
optimized.append({
|
||||||
|
"name": i.get("name", "N/A"),
|
||||||
|
"type": i.get("type", "N/A"),
|
||||||
|
"mtu": i.get("mtu", "N/A"),
|
||||||
|
"rx": i.get("rx-byte", "N/A"),
|
||||||
|
"tx": i.get("tx-byte", "N/A"),
|
||||||
|
"status": "running"
|
||||||
|
})
|
||||||
|
|
||||||
|
# Non-running interfaces
|
||||||
|
for i in not_running[:max_interfaces//4]:
|
||||||
|
optimized.append({
|
||||||
|
"name": i.get("name", "N/A"),
|
||||||
|
"type": i.get("type", "N/A"),
|
||||||
|
"status": "not running",
|
||||||
|
"disabled": i.get("disabled", "N/A")
|
||||||
|
})
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
def optimize_ppp_secrets(self, secrets: List[Dict], max_secrets: int = 10) -> List[Dict]:
|
||||||
|
"""Optimize PPP secrets list"""
|
||||||
|
if not secrets:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Ambil hanya field penting
|
||||||
|
optimized = []
|
||||||
|
for secret in secrets[:max_secrets]:
|
||||||
|
optimized.append({
|
||||||
|
"name": secret.get("name", "N/A"),
|
||||||
|
"service": secret.get("service", "N/A"),
|
||||||
|
"disabled": self._is_true(secret.get("disabled")),
|
||||||
|
"profile": secret.get("profile", "N/A")
|
||||||
|
})
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
def optimize_routes(self, routes: List[Dict], max_routes: int = 10) -> List[Dict]:
|
||||||
|
"""Optimize routes list"""
|
||||||
|
if not routes:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Prioritize default routes dan active routes
|
||||||
|
default_routes = [r for r in routes if r.get("dst-address", "") == "0.0.0.0/0"]
|
||||||
|
other_routes = [r for r in routes if r.get("dst-address", "") != "0.0.0.0/0"]
|
||||||
|
|
||||||
|
optimized = []
|
||||||
|
|
||||||
|
# Default routes
|
||||||
|
for route in default_routes[:2]:
|
||||||
|
optimized.append({
|
||||||
|
"dst": route.get("dst-address", "N/A"),
|
||||||
|
"gateway": route.get("gateway", "N/A"),
|
||||||
|
"distance": route.get("distance", "N/A"),
|
||||||
|
"scope": route.get("scope", "N/A")
|
||||||
|
})
|
||||||
|
|
||||||
|
# Other important routes
|
||||||
|
for route in other_routes[:max_routes-2]:
|
||||||
|
optimized.append({
|
||||||
|
"dst": route.get("dst-address", "N/A"),
|
||||||
|
"gateway": route.get("gateway", "N/A")
|
||||||
|
})
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
def optimize_logs(self, logs: List[Dict], max_logs: int = 40) -> List[Dict]:
|
||||||
|
"""Optimize and filter logs (Prioritas: critical, error, warning)"""
|
||||||
|
if not logs:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Prioritas topik
|
||||||
|
high_priority = ['critical', 'error', 'warning', 'caps']
|
||||||
|
|
||||||
|
important = []
|
||||||
|
others = []
|
||||||
|
|
||||||
|
# Sort logs (MikroTik biasanya kasih dari terlama ke terbaru, kita mau terbaru dulu)
|
||||||
|
sorted_logs = list(reversed(logs))
|
||||||
|
|
||||||
|
for log in sorted_logs:
|
||||||
|
topics = log.get("topics", "")
|
||||||
|
message = log.get("message", "")
|
||||||
|
|
||||||
|
# Cek apakah mengandung topik prioritas
|
||||||
|
if any(p in topics for p in high_priority):
|
||||||
|
important.append({
|
||||||
|
"time": log.get("time", "N/A"),
|
||||||
|
"topics": topics,
|
||||||
|
"msg": message
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
others.append({
|
||||||
|
"time": log.get("time", "N/A"),
|
||||||
|
"topics": topics,
|
||||||
|
"msg": message
|
||||||
|
})
|
||||||
|
|
||||||
|
# Gabungkan: Important dulu, lalu others sampai limit
|
||||||
|
optimized = important[:max_logs]
|
||||||
|
if len(optimized) < max_logs:
|
||||||
|
optimized.extend(others[:max_logs - len(optimized)])
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
def optimize_hotspot(self, active_users: List[Dict], max_users: int = 15) -> List[Dict]:
|
||||||
|
"""Optimize hotspot active users list"""
|
||||||
|
if not active_users:
|
||||||
|
return []
|
||||||
|
|
||||||
|
optimized = []
|
||||||
|
for user in active_users[:max_users]:
|
||||||
|
optimized.append({
|
||||||
|
"user": user.get("user", "N/A"),
|
||||||
|
"address": user.get("address", "N/A"),
|
||||||
|
"uptime": user.get("uptime", "N/A"),
|
||||||
|
"bytes_in": self._format_memory(user.get("bytes-in", 0)),
|
||||||
|
"bytes_out": self._format_memory(user.get("bytes-out", 0))
|
||||||
|
})
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
def create_optimized_context(self, mikrotik_data: Dict, question: str = "") -> Dict:
|
||||||
|
"""Create optimized context untuk Gemini"""
|
||||||
|
optimized = {
|
||||||
|
"metadata": {
|
||||||
|
"original_size": len(json.dumps(mikrotik_data)),
|
||||||
|
"optimized_for": question[:50] + "..." if len(question) > 50 else question,
|
||||||
|
"strategy": "priority_based_compression"
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"system": self.optimize_system_info(mikrotik_data.get("system", {})),
|
||||||
|
"interfaces_count": len(mikrotik_data.get("interfaces", {}).get("interfaces", [])),
|
||||||
|
"running_interfaces_count": sum(1 for i in mikrotik_data.get("interfaces", {}).get("interfaces", []) if self._is_true(i.get("running"))),
|
||||||
|
"ppp_secrets_count": len(mikrotik_data.get("ppp", {}).get("secrets", [])),
|
||||||
|
"routes_count": len(mikrotik_data.get("network", {}).get("routes", [])),
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"interfaces_sample": self.optimize_interfaces(mikrotik_data.get("interfaces", {}).get("interfaces", [])),
|
||||||
|
"ppp_secrets_sample": self.optimize_ppp_secrets(mikrotik_data.get("ppp", {}).get("secrets", [])),
|
||||||
|
"routes_sample": self.optimize_routes(mikrotik_data.get("network", {}).get("routes", [])),
|
||||||
|
"recent_logs": self.optimize_logs(mikrotik_data.get("logs", [])),
|
||||||
|
"hotspot_active": self.optimize_hotspot(mikrotik_data.get("hotspot", {}).get("active", [])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Estimate tokens
|
||||||
|
context_text = json.dumps(optimized)
|
||||||
|
optimized["metadata"]["estimated_tokens"] = self.estimate_tokens(context_text)
|
||||||
|
optimized["metadata"]["compression_ratio"] = optimized["metadata"]["original_size"] / len(context_text) if len(context_text) > 0 else 1
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
def _format_memory(self, bytes_value: Any) -> str:
|
||||||
|
"""Format memory bytes to human readable"""
|
||||||
|
try:
|
||||||
|
val = float(bytes_value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return "0 B"
|
||||||
|
|
||||||
|
if val == 0:
|
||||||
|
return "0 B"
|
||||||
|
|
||||||
|
for unit in ['B', 'KB', 'MB', 'GB']:
|
||||||
|
if val < 1024.0:
|
||||||
|
return f"{val:.1f} {unit}"
|
||||||
|
val /= 1024.0
|
||||||
|
return f"{val:.1f} TB"
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Load sample data
|
||||||
|
try:
|
||||||
|
with open("../mikrotik_mcp_data.json", "r") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except:
|
||||||
|
print("Error loading data")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
optimizer = ContextOptimizer()
|
||||||
|
optimized = optimizer.create_optimized_context(data, "test question")
|
||||||
|
|
||||||
|
print(f"Original size: {optimized['metadata']['original_size']} bytes")
|
||||||
|
print(f"Optimized size: {len(json.dumps(optimized))} bytes")
|
||||||
|
print(f"Compression ratio: {optimized['metadata']['compression_ratio']:.1f}x")
|
||||||
|
print(f"Estimated tokens: {optimized['metadata']['estimated_tokens']}")
|
||||||
|
print(f"Max tokens: {optimizer.max_tokens}")
|
||||||
|
|
||||||
|
if optimized["metadata"]["estimated_tokens"] > optimizer.max_tokens:
|
||||||
|
print("⚠️ Warning: Context mungkin terlalu besar")
|
||||||
|
else:
|
||||||
|
print("✅ Context size OK")
|
||||||
159
app/gemini_mikrotik_integration.py
Normal file
159
app/gemini_mikrotik_integration.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Integrasi MikroTik MCP Data dengan Gemini AI - Versi Sederhana
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from google import genai
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from datetime import datetime
|
||||||
|
from context_optimizer import ContextOptimizer
|
||||||
|
from update_data import gather_all_info, save_data
|
||||||
|
|
||||||
|
# Load environment
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
class MikroTikGeminiAssistant:
|
||||||
|
def __init__(self, data_file="data/mikrotik_mcp_data.json"):
|
||||||
|
# Setup Gemini Client (SDK Baru)
|
||||||
|
api_key = os.getenv("GEMINI_API_KEY")
|
||||||
|
if not api_key:
|
||||||
|
raise ValueError("GEMINI_API_KEY tidak ditemukan di .env")
|
||||||
|
|
||||||
|
self.client = genai.Client(api_key=api_key)
|
||||||
|
self.model_id = "gemini-2.0-flash"
|
||||||
|
|
||||||
|
|
||||||
|
# Load data
|
||||||
|
self.data_file = data_file
|
||||||
|
self.data = self._load_data()
|
||||||
|
|
||||||
|
# Setup Optimizer
|
||||||
|
self.optimizer = ContextOptimizer()
|
||||||
|
|
||||||
|
# Inisialisasi Chat Session
|
||||||
|
self.chat_session = None
|
||||||
|
self._reset_chat()
|
||||||
|
|
||||||
|
def refresh_data(self):
|
||||||
|
"""Ambil data terbaru langsung dari MikroTik API"""
|
||||||
|
print("\n⏳ Sedang mengambil data terbaru dari router...")
|
||||||
|
new_data = gather_all_info()
|
||||||
|
if new_data:
|
||||||
|
save_data(new_data, self.data_file)
|
||||||
|
self.data = new_data
|
||||||
|
self._reset_chat()
|
||||||
|
print("✅ Data berhasil diperbarui dan sesi chat di-reset.")
|
||||||
|
return True
|
||||||
|
print("❌ Gagal memperbarui data.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _reset_chat(self):
|
||||||
|
"""Reset session chat dengan konteks MikroTik terbaru yang dioptimasi"""
|
||||||
|
optimized = self.optimizer.create_optimized_context(self.data)
|
||||||
|
|
||||||
|
context = f"""Anda adalah asisten ahli MikroTik. Gunakan data JSON berikut sebagai SATU-SATUNYA sumber kebenaran kondisi router saat ini.
|
||||||
|
JANGAN membuat-buat nama interface, IP, atau status yang tidak ada di data ini.
|
||||||
|
|
||||||
|
DATA ROUTER (OPTIMIZED JSON):
|
||||||
|
{json.dumps(optimized, indent=2)}
|
||||||
|
|
||||||
|
INSTRUKSI:
|
||||||
|
1. Jika user bertanya tentang hal spesifik (seperti interface atau route), lihat di bagian 'details' pada JSON di atas.
|
||||||
|
2. Jika data tidak ada, katakan jujur bahwa data tersebut tidak tersedia di snapshot saat ini.
|
||||||
|
3. Jawab selalu dalam Bahasa Indonesia yang profesional dan format markdown.
|
||||||
|
4. Utamakan akurasi data daripada memberikan nasihat umum.
|
||||||
|
5. Jika user meminta data paling baru ("live" atau "sekarang"), beritahukan bahwa Anda menggunakan data terakhir yang diambil. User bisa mengetik `sync` atau `refresh` untuk melakukan sinkronisasi ulang data langsung dari router."""
|
||||||
|
|
||||||
|
self.chat_session = self.client.chats.create(model=self.model_id, history=[])
|
||||||
|
# Kirim konteks awal
|
||||||
|
self.chat_session.send_message(context)
|
||||||
|
|
||||||
|
def _load_data(self):
|
||||||
|
try:
|
||||||
|
with open(self.data_file, 'r') as f:
|
||||||
|
return json.load(f)
|
||||||
|
except:
|
||||||
|
return {"error": "Data tidak ditemukan"}
|
||||||
|
|
||||||
|
def get_summary(self):
|
||||||
|
"""Ringkasan data MikroTik"""
|
||||||
|
d = self.data
|
||||||
|
system = d.get("system", {})
|
||||||
|
|
||||||
|
# Handle cases where resource might be a list or missing
|
||||||
|
resource = system.get("resource", {})
|
||||||
|
if isinstance(resource, list):
|
||||||
|
resource = resource[0] if len(resource) > 0 else {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"device": resource.get("board-name", "N/A"),
|
||||||
|
"cpu": resource.get("cpu-load", "N/A"),
|
||||||
|
"memory": resource.get("free-memory", "N/A"),
|
||||||
|
"uptime": resource.get("uptime", "N/A"),
|
||||||
|
"version": resource.get("version", "N/A"),
|
||||||
|
"interfaces": len(d.get("interfaces", {}).get("interfaces", [])),
|
||||||
|
"ppp_secrets": len(d.get("ppp", {}).get("secrets", [])),
|
||||||
|
"timestamp": d.get("metadata", {}).get("timestamp", "N/A")
|
||||||
|
}
|
||||||
|
|
||||||
|
def ask(self, question):
|
||||||
|
"""Tanya Gemini menggunakan session chat yang aktif"""
|
||||||
|
if not self.chat_session:
|
||||||
|
self._reset_chat()
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self.chat_session.send_message(question)
|
||||||
|
return response.text
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error: {e}"
|
||||||
|
|
||||||
|
def chat(self):
|
||||||
|
"""Mode interaktif yang mendukung history"""
|
||||||
|
print("\n" + "="*40)
|
||||||
|
print("🤖 MIKROTIK GEMINI INTERACTIVE CHAT")
|
||||||
|
print("="*40)
|
||||||
|
print("Ketik 'exit' untuk keluar")
|
||||||
|
print("Ketik 'reset' untuk mengulang percakapan\n")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
q = input("👤 Anda: ").strip()
|
||||||
|
|
||||||
|
if not q:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if q.lower() in ['exit', 'quit', 'keluar']:
|
||||||
|
print("\nSampai jumpa! 👋")
|
||||||
|
break
|
||||||
|
|
||||||
|
if q.lower() in ['reset', 'refresh', 'sync', 'update']:
|
||||||
|
self.refresh_data()
|
||||||
|
continue
|
||||||
|
|
||||||
|
print("\n🤖 AI: Thinking...")
|
||||||
|
answer = self.ask(q)
|
||||||
|
print(f"\n{answer}\n")
|
||||||
|
print("-" * 20)
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if not os.getenv("GEMINI_API_KEY"):
|
||||||
|
print("ERROR: Set GEMINI_API_KEY di .env file")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
assistant = MikroTikGeminiAssistant()
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
# Command line mode
|
||||||
|
question = " ".join(sys.argv[1:])
|
||||||
|
answer = assistant.ask(question)
|
||||||
|
print(answer)
|
||||||
|
else:
|
||||||
|
# Interactive mode
|
||||||
|
assistant.chat()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
10
app/list_models.py
Normal file
10
app/list_models.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import google.generativeai as genai
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
|
||||||
|
|
||||||
|
for m in genai.list_models():
|
||||||
|
if 'generateContent' in m.supported_generation_methods:
|
||||||
|
print(m.name)
|
||||||
119
app/realtime_monitor.py
Normal file
119
app/realtime_monitor.py
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Real-time Monitoring untuk MikroTik dengan Gemini AI
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from gemini_mikrotik_integration import MikroTikGeminiAssistant
|
||||||
|
|
||||||
|
class RealTimeMonitor:
|
||||||
|
def __init__(self, interval=60):
|
||||||
|
"""Initialize monitor dengan interval detik"""
|
||||||
|
self.interval = interval
|
||||||
|
self.assistant = MikroTikGeminiAssistant()
|
||||||
|
self.metrics_history = []
|
||||||
|
|
||||||
|
def collect_metrics(self):
|
||||||
|
"""Kumpulkan metrics dari MikroTik"""
|
||||||
|
summary = self.assistant.get_summary()
|
||||||
|
|
||||||
|
metrics = {
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"cpu": summary["cpu"],
|
||||||
|
"memory": summary["memory"],
|
||||||
|
"interfaces": summary["interfaces"],
|
||||||
|
"ppp_secrets": summary["ppp_secrets"],
|
||||||
|
}
|
||||||
|
|
||||||
|
self.metrics_history.append(metrics)
|
||||||
|
# Keep only last 100 readings
|
||||||
|
if len(self.metrics_history) > 100:
|
||||||
|
self.metrics_history = self.metrics_history[-100:]
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
|
||||||
|
def check_alerts(self, metrics):
|
||||||
|
"""Check untuk alert conditions"""
|
||||||
|
alerts = []
|
||||||
|
|
||||||
|
# CPU alert
|
||||||
|
try:
|
||||||
|
cpu = int(metrics["cpu"].replace("%", ""))
|
||||||
|
if cpu > 80:
|
||||||
|
alerts.append(f"CPU tinggi: {cpu}%")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return alerts
|
||||||
|
|
||||||
|
def generate_report(self, hours=1):
|
||||||
|
"""Generate report untuk periode tertentu"""
|
||||||
|
# Filter metrics untuk periode terakhir
|
||||||
|
cutoff = datetime.now().timestamp() - (hours * 3600)
|
||||||
|
recent_metrics = [
|
||||||
|
m for m in self.metrics_history
|
||||||
|
if datetime.fromisoformat(m["timestamp"]).timestamp() > cutoff
|
||||||
|
]
|
||||||
|
|
||||||
|
if not recent_metrics:
|
||||||
|
return "Tidak ada data untuk periode ini"
|
||||||
|
|
||||||
|
# Analisis sederhana
|
||||||
|
avg_cpu = sum(int(m["cpu"].replace("%", "")) for m in recent_metrics) / len(recent_metrics)
|
||||||
|
|
||||||
|
report = f"""📊 **Laporan Monitoring ({hours} jam)**
|
||||||
|
|
||||||
|
**Statistik:**
|
||||||
|
- Periode: {len(recent_metrics)} readings
|
||||||
|
- CPU Rata-rata: {avg_cpu:.1f}%
|
||||||
|
- Interfaces: {recent_metrics[-1]['interfaces']}
|
||||||
|
- PPP Secrets: {recent_metrics[-1]['ppp_secrets']}
|
||||||
|
|
||||||
|
**Status:** {'⚠️' if avg_cpu > 70 else '✅'}"""
|
||||||
|
|
||||||
|
return report
|
||||||
|
|
||||||
|
def start_monitoring(self):
|
||||||
|
"""Start real-time monitoring loop"""
|
||||||
|
print(f"🔍 Starting real-time monitoring (interval: {self.interval}s)")
|
||||||
|
print("Press Ctrl+C to stop\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
metrics = self.collect_metrics()
|
||||||
|
alerts = self.check_alerts(metrics)
|
||||||
|
|
||||||
|
print(f"[{metrics['timestamp'][11:19]}] ", end="")
|
||||||
|
print(f"CPU: {metrics['cpu']} ", end="")
|
||||||
|
print(f"Intf: {metrics['interfaces']} ", end="")
|
||||||
|
|
||||||
|
if alerts:
|
||||||
|
print(f" ⚠️ Alerts: {', '.join(alerts)}")
|
||||||
|
else:
|
||||||
|
print(" ✅")
|
||||||
|
|
||||||
|
time.sleep(self.interval)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n\n🛑 Monitoring stopped")
|
||||||
|
print(f"Total readings: {len(self.metrics_history)}")
|
||||||
|
|
||||||
|
# Generate final report
|
||||||
|
if self.metrics_history:
|
||||||
|
report = self.generate_report()
|
||||||
|
print("\n" + report)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
|
||||||
|
interval = 60 # default 60 seconds
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
try:
|
||||||
|
interval = int(sys.argv[1])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
monitor = RealTimeMonitor(interval=interval)
|
||||||
|
monitor.start_monitoring()
|
||||||
20
app/test_history.py
Normal file
20
app/test_history.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from gemini_mikrotik_integration import MikroTikGeminiAssistant
|
||||||
|
import os
|
||||||
|
|
||||||
|
def test():
|
||||||
|
assistant = MikroTikGeminiAssistant()
|
||||||
|
|
||||||
|
print("--- Test 1: CPU Load ---")
|
||||||
|
ans1 = assistant.ask("Berapa CPU load router saat ini?")
|
||||||
|
print(f"A: {ans1}")
|
||||||
|
|
||||||
|
print("\n--- Test 2: History (Uptime) ---")
|
||||||
|
ans2 = assistant.ask("Berapa uptimenya?")
|
||||||
|
print(f"A: {ans2}")
|
||||||
|
|
||||||
|
print("\n--- Test 3: Context Connection ---")
|
||||||
|
ans3 = assistant.ask("Apakah angka-angka tersebut masih dalam batas normal?")
|
||||||
|
print(f"A: {ans3}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test()
|
||||||
114
app/update_data.py
Normal file
114
app/update_data.py
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script untuk update data MikroTik dari REST API
|
||||||
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# MikroTik credentials
|
||||||
|
MIKROTIK_HOST = os.getenv("MIKROTIK_HOST", "192.168.1.1")
|
||||||
|
MIKROTIK_PORT = os.getenv("MIKROTIK_PORT", "8728")
|
||||||
|
MIKROTIK_USER = os.getenv("MIKROTIK_USER", "admin")
|
||||||
|
MIKROTIK_PASSWORD = os.getenv("MIKROTIK_PASSWORD", "password")
|
||||||
|
|
||||||
|
# API endpoints
|
||||||
|
BASE_URL = f"http://{MIKROTIK_HOST}:{MIKROTIK_PORT}/rest"
|
||||||
|
AUTH = (MIKROTIK_USER, MIKROTIK_PASSWORD)
|
||||||
|
|
||||||
|
def fetch_data(endpoint):
|
||||||
|
"""Fetch data from MikroTik REST API"""
|
||||||
|
url = f"{BASE_URL}/{endpoint}"
|
||||||
|
try:
|
||||||
|
response = requests.get(url, auth=AUTH, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching {endpoint}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def gather_all_info():
|
||||||
|
"""Gather all MikroTik information"""
|
||||||
|
print("🔍 Gathering MikroTik data...")
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"metadata": {
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"source": "MikroTik REST API",
|
||||||
|
"host": MIKROTIK_HOST
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"resource": fetch_data("system/resource"),
|
||||||
|
"identity": fetch_data("system/identity"),
|
||||||
|
"license": fetch_data("system/license"),
|
||||||
|
"users": fetch_data("user")
|
||||||
|
},
|
||||||
|
"interfaces": {
|
||||||
|
"interfaces": fetch_data("interface")
|
||||||
|
},
|
||||||
|
"network": {
|
||||||
|
"ip_addresses": fetch_data("ip/address"),
|
||||||
|
"routes": fetch_data("ip/route")
|
||||||
|
},
|
||||||
|
"ppp": {
|
||||||
|
"secrets": fetch_data("ppp/secret")
|
||||||
|
},
|
||||||
|
"logs": fetch_data("log"),
|
||||||
|
"hotspot": {
|
||||||
|
"active": fetch_data("ip/hotspot/active"),
|
||||||
|
"users": fetch_data("ip/hotspot/user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Calculate statistics
|
||||||
|
if data["interfaces"]["interfaces"]:
|
||||||
|
total = len(data["interfaces"]["interfaces"])
|
||||||
|
running = sum(1 for i in data["interfaces"]["interfaces"] if i.get("running") == True)
|
||||||
|
data["interfaces"]["statistics"] = {
|
||||||
|
"total": total,
|
||||||
|
"running": running,
|
||||||
|
"not_running": total - running
|
||||||
|
}
|
||||||
|
|
||||||
|
if data["ppp"]["secrets"]:
|
||||||
|
total = len(data["ppp"]["secrets"])
|
||||||
|
enabled = sum(1 for s in data["ppp"]["secrets"] if s.get("disabled") == False)
|
||||||
|
data["ppp"]["statistics"] = {
|
||||||
|
"total_secrets": total,
|
||||||
|
"enabled_secrets": enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"✅ Data gathered: {len(str(data))} bytes")
|
||||||
|
return data
|
||||||
|
|
||||||
|
def save_data(data, filename="data/mikrotik_mcp_data.json"):
|
||||||
|
"""Save data to JSON file"""
|
||||||
|
try:
|
||||||
|
with open(filename, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||||
|
print(f"💾 Data saved to {filename}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error saving data: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🔄 Updating MikroTik MCP data...")
|
||||||
|
|
||||||
|
# Check credentials
|
||||||
|
if not all([MIKROTIK_HOST, MIKROTIK_USER, MIKROTIK_PASSWORD]):
|
||||||
|
print("⚠️ MikroTik credentials not set in .env file")
|
||||||
|
print(" Using existing data file only")
|
||||||
|
else:
|
||||||
|
data = gather_all_info()
|
||||||
|
if data:
|
||||||
|
save_data(data)
|
||||||
|
print("✅ Update completed successfully")
|
||||||
|
else:
|
||||||
|
print("❌ Failed to gather data")
|
||||||
64
config.yaml
Normal file
64
config.yaml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# Konfigurasi MikroTik Gemini Integration
|
||||||
|
|
||||||
|
# Gemini AI Settings
|
||||||
|
gemini:
|
||||||
|
model: "gemini-1.5-flash-latest"
|
||||||
|
temperature: 0.1
|
||||||
|
max_output_tokens: 2048
|
||||||
|
safety_settings: "BLOCK_NONE"
|
||||||
|
|
||||||
|
# MikroTik Settings
|
||||||
|
mikrotik:
|
||||||
|
data_file: "data/mikrotik_mcp_data.json"
|
||||||
|
update_interval: 300 # seconds (5 minutes)
|
||||||
|
|
||||||
|
# REST API settings (for data updates)
|
||||||
|
api:
|
||||||
|
host: "192.168.1.1"
|
||||||
|
port: 8728
|
||||||
|
timeout: 10
|
||||||
|
|
||||||
|
# Context Optimization
|
||||||
|
context:
|
||||||
|
max_tokens: 8000
|
||||||
|
max_interfaces_sample: 20
|
||||||
|
max_ppp_secrets_sample: 10
|
||||||
|
max_routes_sample: 10
|
||||||
|
|
||||||
|
# Monitoring
|
||||||
|
monitoring:
|
||||||
|
interval: 60 # seconds
|
||||||
|
alert_thresholds:
|
||||||
|
cpu: 80 # percentage
|
||||||
|
memory: 90 # percentage
|
||||||
|
interfaces_down: 10 # count
|
||||||
|
|
||||||
|
# API Server
|
||||||
|
api_server:
|
||||||
|
host: "0.0.0.0"
|
||||||
|
port: 8000
|
||||||
|
debug: false
|
||||||
|
cors_origins:
|
||||||
|
- "http://localhost:3000"
|
||||||
|
- "http://localhost:8000"
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging:
|
||||||
|
level: "INFO"
|
||||||
|
file: "logs/app.log"
|
||||||
|
max_size: 10485760 # 10MB
|
||||||
|
backup_count: 5
|
||||||
|
|
||||||
|
# Features
|
||||||
|
features:
|
||||||
|
enable_realtime_monitoring: true
|
||||||
|
enable_context_optimization: true
|
||||||
|
enable_auto_update: false
|
||||||
|
enable_alerts: true
|
||||||
|
|
||||||
|
# Security
|
||||||
|
security:
|
||||||
|
require_api_key: true
|
||||||
|
allowed_ips:
|
||||||
|
- "127.0.0.1"
|
||||||
|
- "192.168.1.0/24"
|
||||||
48215
data/mikrotik_mcp_data.json
Normal file
48215
data/mikrotik_mcp_data.json
Normal file
File diff suppressed because it is too large
Load Diff
52
docker-compose.yml
Normal file
52
docker-compose.yml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
mikrotik-gemini-api:
|
||||||
|
build: .
|
||||||
|
container_name: mikrotik-gemini-api
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
- GEMINI_API_KEY=${GEMINI_API_KEY}
|
||||||
|
- API_HOST=0.0.0.0
|
||||||
|
- API_PORT=8000
|
||||||
|
volumes:
|
||||||
|
- ../mikrotik_mcp_data.json:/app/mikrotik_mcp_data.json
|
||||||
|
- ./logs:/app/logs
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
networks:
|
||||||
|
- mikrotik-network
|
||||||
|
|
||||||
|
# Optional: Add data updater service
|
||||||
|
data-updater:
|
||||||
|
image: python:3.11-slim
|
||||||
|
container_name: mikrotik-data-updater
|
||||||
|
command: >
|
||||||
|
sh -c "
|
||||||
|
pip install requests &&
|
||||||
|
python /app/update_data.py
|
||||||
|
"
|
||||||
|
volumes:
|
||||||
|
- ./update_data.py:/app/update_data.py
|
||||||
|
- ../mikrotik_mcp_data.json:/app/mikrotik_mcp_data.json
|
||||||
|
environment:
|
||||||
|
- MIKROTIK_HOST=${MIKROTIK_HOST}
|
||||||
|
- MIKROTIK_PORT=${MIKROTIK_PORT}
|
||||||
|
- MIKROTIK_USER=${MIKROTIK_USER}
|
||||||
|
- MIKROTIK_PASSWORD=${MIKROTIK_PASSWORD}
|
||||||
|
restart: "no" # Run once manually
|
||||||
|
networks:
|
||||||
|
- mikrotik-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
mikrotik-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mikrotik-data:
|
||||||
130
example_prompts.md
Normal file
130
example_prompts.md
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# 📝 Contoh Prompt untuk MikroTik + Gemini
|
||||||
|
|
||||||
|
## 🎯 **Kategori: Monitoring & Status**
|
||||||
|
|
||||||
|
### **1. Status Sistem**
|
||||||
|
```
|
||||||
|
Berikan status lengkap perangkat MikroTik:
|
||||||
|
- CPU usage saat ini
|
||||||
|
- Memory usage
|
||||||
|
- Interface yang running/tidak
|
||||||
|
- PPPoE connections status
|
||||||
|
- Rekomendasi jika ada masalah
|
||||||
|
```
|
||||||
|
|
||||||
|
### **2. Health Check**
|
||||||
|
```
|
||||||
|
Lakukan health check perangkat:
|
||||||
|
1. Cek error pada interfaces
|
||||||
|
2. Cek PPPoE yang disconnected
|
||||||
|
3. Cek memory usage
|
||||||
|
4. Cek CPU load
|
||||||
|
5. Berikan summary
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 **Kategori: Troubleshooting**
|
||||||
|
|
||||||
|
### **3. Masalah Internet Lambat**
|
||||||
|
```
|
||||||
|
User mengeluh internet lambat. Analisis:
|
||||||
|
1. Interface dengan traffic tertinggi
|
||||||
|
2. Cek error counters
|
||||||
|
3. Identifikasi bottleneck
|
||||||
|
4. Berikan solusi
|
||||||
|
```
|
||||||
|
|
||||||
|
### **4. Koneksi Putus-Putus**
|
||||||
|
```
|
||||||
|
PPPoE sering disconnect. Periksa:
|
||||||
|
1. Log error PPPoE
|
||||||
|
2. Signal quality
|
||||||
|
3. MTU settings
|
||||||
|
4. Rekomendasi fix
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 **Kategori: Analisis Jaringan**
|
||||||
|
|
||||||
|
### **5. Analisis Traffic**
|
||||||
|
```
|
||||||
|
Analisis pola traffic jaringan:
|
||||||
|
1. Peak usage hours
|
||||||
|
2. Top talkers
|
||||||
|
3. Bandwidth utilization
|
||||||
|
4. Rekomendasi optimasi
|
||||||
|
```
|
||||||
|
|
||||||
|
### **6. Security Audit**
|
||||||
|
```
|
||||||
|
Lakukan audit keamanan:
|
||||||
|
1. Port terbuka ke internet
|
||||||
|
2. User accounts
|
||||||
|
3. Firewall rules
|
||||||
|
4. Rekomendasi hardening
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ **Kategori: Konfigurasi**
|
||||||
|
|
||||||
|
### **7. Tambah VLAN Baru**
|
||||||
|
```
|
||||||
|
Saya ingin menambahkan VLAN baru untuk departemen IT:
|
||||||
|
1. VLAN apa yang sudah ada?
|
||||||
|
2. Port available?
|
||||||
|
3. Contoh konfigurasi
|
||||||
|
4. Periksa konflik IP
|
||||||
|
```
|
||||||
|
|
||||||
|
### **8. Setup QoS**
|
||||||
|
```
|
||||||
|
Setup QoS untuk prioritas VoIP:
|
||||||
|
1. Current traffic patterns
|
||||||
|
2. Recommended queues
|
||||||
|
3. Configuration example
|
||||||
|
4. Testing procedure
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📈 **Kategori: Reporting**
|
||||||
|
|
||||||
|
### **9. Daily Report**
|
||||||
|
```
|
||||||
|
Buat daily report:
|
||||||
|
1. Uptime
|
||||||
|
2. Traffic statistics
|
||||||
|
3. Error counts
|
||||||
|
4. Performance metrics
|
||||||
|
5. Recommendations
|
||||||
|
```
|
||||||
|
|
||||||
|
### **10. Capacity Planning**
|
||||||
|
```
|
||||||
|
Analisis capacity untuk ekspansi:
|
||||||
|
1. Current utilization
|
||||||
|
2. Growth trends
|
||||||
|
3. Bottleneck identification
|
||||||
|
4. Upgrade recommendations
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 **Tips Penggunaan**
|
||||||
|
|
||||||
|
1. **Spesifik**: Semakin spesifik pertanyaan, semakin baik jawaban
|
||||||
|
2. **Context**: Gemini menggunakan data MikroTik sebagai context
|
||||||
|
3. **Format**: Jawaban dalam markdown dengan tabel jika perlu
|
||||||
|
4. **Bahasa**: Gunakan bahasa Indonesia untuk hasil terbaik
|
||||||
|
|
||||||
|
## 🚀 **Contoh Lengkap**
|
||||||
|
|
||||||
|
**Prompt:**
|
||||||
|
```
|
||||||
|
Berdasarkan data MikroTik, berikan analisis:
|
||||||
|
1. Device model dan spesifikasi
|
||||||
|
2. Current CPU dan memory usage
|
||||||
|
3. Jumlah interface aktif
|
||||||
|
4. Status PPPoE connections
|
||||||
|
5. Rekomendasi maintenance
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected Response:**
|
||||||
|
- Table dengan spesifikasi device
|
||||||
|
- Chart usage (jika support)
|
||||||
|
- List interface bermasalah
|
||||||
|
- Action items
|
||||||
|
```
|
||||||
8
requirements.txt
Normal file
8
requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Python dependencies for MikroTik Gemini Integration
|
||||||
|
google-genai>=0.1.0
|
||||||
|
python-dotenv>=1.0.0
|
||||||
|
requests>=2.31.0
|
||||||
|
fastapi>=0.104.0
|
||||||
|
uvicorn>=0.24.0
|
||||||
|
pydantic>=2.5.0
|
||||||
|
python-multipart>=0.0.6
|
||||||
Reference in New Issue
Block a user