Files
microdao-daarion/SWAPPER-INTEGRATION-GUIDE.md
Apple 3de3c8cb36 feat: Add presence heartbeat for Matrix online status
- matrix-gateway: POST /internal/matrix/presence/online endpoint
- usePresenceHeartbeat hook with activity tracking
- Auto away after 5 min inactivity
- Offline on page close/visibility change
- Integrated in MatrixChatRoom component
2025-11-27 00:19:40 -08:00

442 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Swapper Service - Інтеграція в кабінети Node #1 та Node #2
**Дата:** 2025-11-22
**Статус:** ✅ Готово до інтеграції
---
## 📋 Крок 1: Запуск Swapper Service
### Node #2 (MacBook - Development)
#### Варіант A: Docker (якщо Docker запущений)
```bash
cd /Users/apple/github-projects/microdao-daarion
# Запустити Swapper Service
docker-compose up -d swapper-service
# Перевірити статус
docker-compose ps swapper-service
# Перевірити логи
docker-compose logs -f swapper-service
# Перевірити health
curl http://localhost:8890/health
```
#### Варіант B: Локально (без Docker)
```bash
cd /Users/apple/github-projects/microdao-daarion/services/swapper-service
# Запустити скрипт (створює venv та встановлює залежності)
./start.sh
```
#### Варіант C: Вручну
```bash
cd /Users/apple/github-projects/microdao-daarion/services/swapper-service
# Створити virtual environment
python3 -m venv venv
source venv/bin/activate
# Встановити залежності
pip install -r requirements.txt
# Налаштувати змінні оточення
export OLLAMA_BASE_URL=http://localhost:11434
export SWAPPER_CONFIG_PATH=./config/swapper_config.yaml
export SWAPPER_MODE=single-active
# Запустити
python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8890
```
### Node #1 (Production Server)
```bash
# SSH до сервера
ssh root@144.76.224.179
# Перейти в директорію проекту
cd /opt/microdao-daarion
# Оновити код
git pull origin main
# Запустити Swapper Service
docker-compose up -d swapper-service
# Перевірити статус
docker-compose ps swapper-service
curl http://localhost:8890/health
```
---
## 📋 Крок 2: Перевірка роботи
### Тест 1: Health Check
```bash
curl http://localhost:8890/health
```
**Очікуваний результат:**
```json
{
"status": "healthy",
"service": "swapper-service",
"active_model": null,
"mode": "single-active"
}
```
### Тест 2: Status для кабінету
```bash
curl http://localhost:8890/api/cabinet/swapper/status | python3 -m json.tool
```
**Очікуваний результат:**
```json
{
"service": "swapper-service",
"status": "healthy",
"mode": "single-active",
"active_model": null,
"total_models": 8,
"available_models": [
"deepseek-r1-70b",
"qwen2.5-coder-32b",
"gemma2-27b",
...
],
"loaded_models": [],
"models": [...]
}
```
### Тест 3: Метрики
```bash
curl http://localhost:8890/api/cabinet/swapper/metrics/summary | python3 -m json.tool
```
---
## 📋 Крок 3: Інтеграція в кабінети
### 3.1 Додати Swapper секцію в Sidebar
**Файл:** `src/components/AdminConsole/Sidebar.tsx` (або аналогічний)
```typescript
const menuItems = [
{ id: 'overview', label: 'Overview', icon: 'dashboard' },
{ id: 'members', label: 'Members & Roles', icon: 'users' },
{ id: 'agents', label: 'Agents', icon: 'robot' },
{ id: 'swapper', label: 'Swapper Service', icon: 'swap' }, // ← Додати це
{ id: 'settings', label: 'Settings', icon: 'settings' },
];
```
### 3.2 Створити Swapper сторінку
**Файл:** `src/pages/Admin/SwapperPage.tsx`
```typescript
import React from 'react';
import { SwapperPage } from '@/services/swapper-service/cabinet-integration';
import '@/services/swapper-service/cabinet-integration.css';
export default function SwapperAdminPage() {
return <SwapperPage />;
}
```
### 3.3 Додати маршрут
**Файл:** `src/routes/admin.tsx` (або аналогічний)
```typescript
import SwapperAdminPage from '@/pages/Admin/SwapperPage';
const adminRoutes = [
{ path: '/admin/overview', component: OverviewPage },
{ path: '/admin/members', component: MembersPage },
{ path: '/admin/agents', component: AgentsPage },
{ path: '/admin/swapper', component: SwapperAdminPage }, // ← Додати це
{ path: '/admin/settings', component: SettingsPage },
];
```
### 3.4 Налаштувати API URL
**Файл:** `.env.local` (або `.env`)
```bash
# Node #2 (MacBook - Development)
NEXT_PUBLIC_SWAPPER_URL=http://localhost:8890
# Node #1 (Production Server)
NEXT_PUBLIC_SWAPPER_URL=http://swapper-service:8890
# або через Nginx proxy:
NEXT_PUBLIC_SWAPPER_URL=https://gateway.daarion.city/api/swapper
```
### 3.5 Копіювати компоненти
```bash
# Копіювати компоненти в проект
cp services/swapper-service/cabinet-integration.tsx src/components/Swapper/
cp services/swapper-service/cabinet-integration.css src/styles/swapper.css
```
---
## 📋 Крок 4: Альтернативна інтеграція (якщо немає React)
### 4.1 Vanilla JavaScript
**Файл:** `public/swapper-dashboard.html`
```html
<!DOCTYPE html>
<html>
<head>
<title>Swapper Service Dashboard</title>
<link rel="stylesheet" href="/styles/swapper.css">
</head>
<body>
<div id="swapper-app"></div>
<script>
const SWAPPER_API = 'http://localhost:8890';
async function loadSwapperStatus() {
try {
const response = await fetch(`${SWAPPER_API}/api/cabinet/swapper/status`);
const data = await response.json();
renderSwapperStatus(data);
} catch (error) {
console.error('Error loading Swapper status:', error);
}
}
function renderSwapperStatus(status) {
const app = document.getElementById('swapper-app');
app.innerHTML = `
<div class="swapper-status-card">
<h3>Swapper Service</h3>
<p>Status: ${status.status}</p>
<p>Mode: ${status.mode}</p>
${status.active_model ? `
<div class="active-model">
<h4>Active Model: ${status.active_model.name}</h4>
<p>Uptime: ${status.active_model.uptime_hours.toFixed(2)} hours</p>
</div>
` : '<p>No active model</p>'}
</div>
`;
}
// Load status on page load
loadSwapperStatus();
// Refresh every 30 seconds
setInterval(loadSwapperStatus, 30000);
</script>
</body>
</html>
```
### 4.2 Vue.js компонент
**Файл:** `src/components/Swapper/SwapperStatus.vue`
```vue
<template>
<div class="swapper-status-card">
<h3>Swapper Service</h3>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<div v-else>
<p>Status: {{ status.status }}</p>
<p>Mode: {{ status.mode }}</p>
<div v-if="status.active_model" class="active-model">
<h4>Active Model: {{ status.active_model.name }}</h4>
<p>Uptime: {{ status.active_model.uptime_hours.toFixed(2) }} hours</p>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const status = ref(null);
const loading = ref(true);
const error = ref(null);
const SWAPPER_API = import.meta.env.VITE_SWAPPER_URL || 'http://localhost:8890';
async function fetchStatus() {
try {
const response = await fetch(`${SWAPPER_API}/api/cabinet/swapper/status`);
status.value = await response.json();
error.value = null;
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
}
onMounted(() => {
fetchStatus();
const interval = setInterval(fetchStatus, 30000);
onUnmounted(() => clearInterval(interval));
});
</script>
```
---
## 📋 Крок 5: Інтеграція через Node Registry (опціонально)
Якщо використовується Node Registry Service, можна додати Swapper статус туди:
**Файл:** `services/node-registry/app/main.py`
```python
@app.get("/api/nodes/{node_id}/swapper")
async def get_node_swapper_status(node_id: str):
"""Get Swapper Service status for a node"""
# Determine Swapper URL based on node
if node_id == "node-2-macbook-m4max":
swapper_url = "http://localhost:8890"
elif node_id == "node-1-hetzner-gex44":
swapper_url = "http://swapper-service:8890"
else:
raise HTTPException(404, "Node not found")
async with httpx.AsyncClient() as client:
response = await client.get(f"{swapper_url}/api/cabinet/swapper/status")
return response.json()
```
---
## 📋 Крок 6: Додати в Overview сторінку
Додати Swapper статус на головну сторінку Overview:
**Файл:** `src/pages/Admin/Overview.tsx`
```typescript
import { SwapperStatusCard } from '@/services/swapper-service/cabinet-integration';
export default function OverviewPage() {
return (
<div className="overview-page">
<h1>DAO Overview</h1>
{/* Existing overview content */}
{/* Add Swapper status widget */}
<div className="swapper-widget">
<SwapperStatusCard />
</div>
</div>
);
}
```
---
## 🧪 Тестування інтеграції
### 1. Перевірити API доступність
```bash
# З браузера або curl
curl http://localhost:8890/api/cabinet/swapper/status
```
### 2. Перевірити CORS (якщо frontend на іншому порту)
Якщо frontend на іншому порту (наприклад, 3000), переконайтеся що CORS налаштовано:
**Файл:** `services/swapper-service/app/main.py`
```python
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "https://daarion.city"], # ← Додати ваші домени
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
```
### 3. Перевірити в браузері
1. Відкрити кабінет
2. Перейти на `/admin/swapper`
3. Перевірити що дані завантажуються
4. Перевірити що кнопки Load/Unload працюють
---
## 🐛 Troubleshooting
### Проблема: API не доступний
**Рішення:**
```bash
# Перевірити чи Swapper запущений
curl http://localhost:8890/health
# Перевірити логи
docker logs swapper-service
# або
tail -f /tmp/swapper.log
```
### Проблема: CORS помилка
**Рішення:**
Додати ваш домен в `allow_origins` в `app/main.py`
### Проблема: Компоненти не відображаються
**Рішення:**
1. Перевірити що файли скопійовані
2. Перевірити імпорти
3. Перевірити консоль браузера на помилки
---
## ✅ Чеклист інтеграції
- [ ] Swapper Service запущений
- [ ] API доступний (`/health` працює)
- [ ] Компоненти скопійовані в проект
- [ ] Маршрут додано в роутер
- [ ] Sidebar оновлено
- [ ] API URL налаштовано
- [ ] CORS налаштовано (якщо потрібно)
- [ ] Тестування в браузері пройдено
---
**Last Updated:** 2025-11-22
**Status:** ✅ Готово до інтеграції
**Next:** Виконати кроки вище для Node #1 та Node #2