feat: implement TTS, Document processing, and Memory Service /facts API

- TTS: xtts-v2 integration with voice cloning support
- Document: docling integration for PDF/DOCX/PPTX processing
- Memory Service: added /facts/upsert, /facts/{key}, /facts endpoints
- Added required dependencies (TTS, docling)
This commit is contained in:
Apple
2026-01-17 08:16:37 -08:00
parent a9fcadc6e2
commit 5290287058
121 changed files with 17071 additions and 436 deletions

View File

@@ -205,6 +205,8 @@ export function DagiMonitorPage() {
{ name: 'NATS JetStream', url: 'http://144.76.224.179:8222/varz', type: 'message-broker', port: 4222, description: 'Message broker for async communication' },
{ name: 'Swapper Node1', url: 'http://144.76.224.179:8890/health', type: 'service', port: 8890, description: 'LLM routing service on Node1' },
{ name: 'Swapper Node2', url: 'http://localhost:8890/health', type: 'service', port: 8890, description: 'LLM routing service on Node2' },
{ name: 'Image Gen Node1', url: 'http://144.76.224.179:8892/health', type: 'image-gen', port: 8892, description: 'FLUX image generation on Node1' },
{ name: 'Image Gen Node3', url: 'http://80.77.35.151:8892/health', type: 'image-gen', port: 8892, description: 'FLUX image generation on Node3' },
{ name: 'DAGI Router Node1', url: 'http://144.76.224.179:9102/health', type: 'router', port: 9102, description: 'DAGI Router on Node1' },
{ name: 'DAGI Router Node2', url: 'http://localhost:9102/health', type: 'router', port: 9102, description: 'DAGI Router on Node2' },
{ name: 'Main API', url: `${API_BASE_URL}/health`, type: 'api', description: 'Main MicroDAO API' },

View File

@@ -1,5 +1,5 @@
import { useParams, useNavigate } from 'react-router-dom';
import { ArrowLeft, Server, Activity, Cpu, HardDrive, Network, Users, Settings, BarChart3, Plug, RefreshCw, CheckCircle2, XCircle, AlertCircle, Filter, Play, Loader2, Wrench, Download, Bot, Database, AlertTriangle, PlusCircle, Boxes, Shield } from 'lucide-react';
import { ArrowLeft, Server, Activity, Cpu, HardDrive, Network, Users, Settings, BarChart3, Plug, RefreshCw, CheckCircle2, XCircle, AlertCircle, Filter, Play, Loader2, Wrench, Download, Bot, Database, AlertTriangle, PlusCircle, Boxes, Shield, Zap } from 'lucide-react';
import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import { apiGet } from '../api/client';
@@ -8,6 +8,7 @@ import { getNode1Agents, type Node1Agent } from '../api/node1Agents';
import { deployAgentToNode2, deployAllAgentsToNode2, checkNode2AgentsDeployment } from '../api/node2Deployment';
import { SwapperStatusCard, SwapperMetricsSummary } from '../components/swapper/SwapperComponents';
import { SwapperDetailedMetrics } from '../components/swapper/SwapperDetailedMetrics';
import { ImageGenStatusCard } from '../components/image-gen/ImageGenStatusCard';
import { getNodeInventory, type NodeInventory } from '../api/nodeInventory';
import { NodeMonitorChat } from '../components/monitor/NodeMonitorChat';
import '../styles/swapper.css';
@@ -66,6 +67,14 @@ interface NodeDetails {
const GRAFANA_URL = import.meta.env.VITE_GRAFANA_URL || 'http://localhost:3000';
const PROMETHEUS_URL = import.meta.env.VITE_PROMETHEUS_URL || 'http://localhost:9090';
const formatServiceName = (name: string) => {
return name
.replace('dagi-', '')
.replace('swapper-service', 'Swapper Service')
.replace('image-gen-service', 'Image Gen Service')
.replace(/-/g, ' ');
};
export function NodeCabinetPage() {
const { nodeId } = useParams<{ nodeId: string }>();
const navigate = useNavigate();
@@ -151,7 +160,7 @@ export function NodeCabinetPage() {
const port = portStr.includes(':') ? portStr.split(':')[0] : portStr;
const portNum = parseInt(port) || 0;
services.push({
name: container.name.replace('dagi-', '').replace('swapper-service', 'Swapper Service').replace(/-/g, ' '),
name: formatServiceName(container.name),
status: 'running',
port: portNum,
url: isNode1
@@ -166,7 +175,7 @@ export function NodeCabinetPage() {
const port = portStr.includes(':') ? portStr.split(':')[0] : portStr;
const portNum = parseInt(port) || 0;
services.push({
name: container.name.replace('dagi-', '').replace(/-/g, ' '),
name: formatServiceName(container.name),
status: 'running',
port: portNum,
url: isNode1
@@ -181,7 +190,7 @@ export function NodeCabinetPage() {
const port = portStr.includes(':') ? portStr.split(':')[0] : portStr;
const portNum = parseInt(port) || 0;
services.push({
name: container.name.replace('dagi-', '').replace(/-/g, ' '),
name: formatServiceName(container.name),
status: container.state === 'restarting' ? 'restarting' : 'unhealthy',
port: portNum,
url: isNode1
@@ -193,6 +202,7 @@ export function NodeCabinetPage() {
// Fallback дані
services.push(
{ name: 'Swapper Service', status: 'running', port: 8890, url: isNode1 ? 'http://144.76.224.179:8890' : 'http://192.168.1.244:8890' },
{ name: 'Image Gen Service', status: 'running', port: 8892, url: isNode1 ? 'http://144.76.224.179:8892' : 'http://80.77.35.151:8892' },
{ name: 'Node Registry', status: 'running', port: 9205, url: isNode1 ? 'http://144.76.224.179:9205' : 'http://192.168.1.244:9205' },
{ name: 'NATS JetStream', status: 'running', port: 4222, url: 'nats://localhost:4222' }
);
@@ -604,6 +614,7 @@ export function NodeCabinetPage() {
{ name: 'Node Registry', icon: Database },
{ name: 'NATS JetStream', icon: Network },
{ name: 'Swapper Service', icon: RefreshCw },
{ name: 'Image Gen', icon: Zap },
{ name: 'Ollama', icon: Bot },
].map((service) => {
const s = nodeDetails.services?.find(s => s.name.includes(service.name) || (service.name === 'Ollama' && s.name.includes('ollama')));
@@ -945,6 +956,19 @@ export function NodeCabinetPage() {
</div>
</div>
{/* Image Generation Service */}
<div className="bg-white rounded-lg shadow">
<div className="p-6 border-b border-gray-200">
<h2 className="text-xl font-semibold text-gray-900">🎨 Image Gen (FLUX)</h2>
<p className="text-sm text-gray-500 mt-1">
Генерація зображень для {nodeDetails.node_name} (FLUX.2 Klein 4B Base)
</p>
</div>
<div className="p-6">
<ImageGenStatusCard nodeId={nodeId} />
</div>
</div>
{/* Інші сервіси ноди */}
<div className="bg-white rounded-lg shadow">
<div className="p-6 border-b border-gray-200">