- Node-guardian running on MacBook and updating metrics - NODE2 agents (Atlas, Greeter, Oracle, Builder Bot) assigned to node-2-macbook-m4max - Swapper models displaying correctly (8 models) - DAGI Router agents showing with correct status (3 active, 1 stale) - Router health check using node_cache for remote nodes
542 lines
16 KiB
Markdown
542 lines
16 KiB
Markdown
# 🎨 Аудит Мультимодальних Функцій для Telegram Ботів
|
||
|
||
**Дата:** 2025-11-24
|
||
**NODE1:** 144.76.224.179
|
||
**Всього ботів:** 9
|
||
|
||
---
|
||
|
||
## 📊 Підсумок статусу
|
||
|
||
| Функція | Статус | Деталі | Боти |
|
||
|---------|--------|--------|------|
|
||
| **🎤 Voice (STT)** | ✅ ПРАЦЮЄ | Whisper base, всі боти | 9/9 |
|
||
| **🔊 Voice Reply (TTS)** | ✅ ПРАЦЮЄ | gTTS, автоматичний режим | 9/9 |
|
||
| **📸 Photo (Vision)** | ✅ ПРАЦЮЄ | specialist_vision_8b через Router | 9/9 |
|
||
| **📄 Documents (PDF)** | ✅ ПРАЦЮЄ | Parser Service | 9/9 |
|
||
| **🔍 Web Search** | ❌ НЕ ІНТЕГРОВАНО | Сервіс готовий, потрібна інтеграція | 0/9 |
|
||
| **🖼️ OCR** | ⚠️ ЧАСТКОВО | Сервіс unhealthy (torch error) | - |
|
||
|
||
---
|
||
|
||
## ✅ Що працює
|
||
|
||
### 1. 🎤 **Voice Messages (STT)** — ПОВНІСТЮ ФУНКЦІОНАЛЬНИЙ
|
||
|
||
**Статус:** ✅ Працює для всіх 9 ботів
|
||
|
||
**Технологія:** OpenAI Whisper (base model)
|
||
**Сервіс:** `dagi-stt-service` (порт 8895)
|
||
**URL:** `http://172.21.0.19:8895`
|
||
|
||
**Функціонал:**
|
||
- Розпізнавання української, англійської, російської
|
||
- Автоматична транскрипція
|
||
- Підтримка: voice messages, audio files, video notes
|
||
|
||
**Тест:**
|
||
```
|
||
User → 🎤 "Привіт!"
|
||
Bot → 📝 [STT розпізнає текст]
|
||
Bot → 💬 Обробляє та відповідає
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 🔊 **Voice Replies (TTS)** — ПОВНІСТЮ ФУНКЦІОНАЛЬНИЙ
|
||
|
||
**Статус:** ✅ Працює для всіх 9 ботів
|
||
|
||
**Технологія:** gTTS (Google Text-to-Speech)
|
||
**Сервіс:** `dagi-tts` (порт 5002)
|
||
**URL:** `http://dagi-tts:5002`
|
||
|
||
**Функціонал:**
|
||
- Автоматична відповідь голосом на голосові повідомлення
|
||
- Унікальні голоси для кожного бота (різна швидкість)
|
||
- Fallback до тексту якщо TTS не вдається
|
||
- Підтримка української та англійської
|
||
|
||
**Тест:**
|
||
```
|
||
User → 🎤 [Voice: "Як справи?"]
|
||
↓ STT
|
||
Bot → 📝 "Як справи?"
|
||
↓ LLM
|
||
Bot → 🔊 [Voice reply via TTS]
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 📸 **Photo Processing (Vision)** — ПОВНІСТЮ ФУНКЦІОНАЛЬНИЙ
|
||
|
||
**Статус:** ✅ Працює для всіх 9 ботів
|
||
|
||
**Технологія:** `specialist_vision_8b` через Router
|
||
**Модель:** qwen3-vl:8b (через Swapper)
|
||
|
||
**Інтеграція:** `/opt/microdao-daarion/gateway-bot/http_api.py`
|
||
- **Функція:** `async def process_photo()` (лінія 406)
|
||
- **Виклик:** В webhook handler (лінія 850)
|
||
|
||
**Функціонал:**
|
||
- Завантаження фото з Telegram
|
||
- Відправка в Router з `use_llm: specialist_vision_8b`
|
||
- Опис зображення українською/англійською
|
||
- Збереження в Memory для контексту
|
||
|
||
**Як працює:**
|
||
```python
|
||
# Gateway отримує фото
|
||
photo = update.message.get("photo")
|
||
|
||
# Обробка
|
||
result = await process_photo(
|
||
agent_config, update, chat_id, user_id, username, dao_id, photo
|
||
)
|
||
|
||
# Відправка в Router
|
||
router_request = {
|
||
"message": f"Опиши це зображення детально: {file_url}",
|
||
"metadata": {
|
||
"has_image": True,
|
||
"use_llm": "specialist_vision_8b",
|
||
"file_url": file_url,
|
||
}
|
||
}
|
||
|
||
# Відповідь користувачу
|
||
await send_telegram_message(
|
||
chat_id,
|
||
f"✅ **Фото оброблено**\n\n{answer_text}",
|
||
telegram_token
|
||
)
|
||
```
|
||
|
||
**Тест:**
|
||
```
|
||
User → 📸 [Надсилає фото]
|
||
Bot → "✅ Фото оброблено"
|
||
Bot → "На зображенні: [детальний опис]"
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 📄 **Document Processing (PDF)** — ПОВНІСТЮ ФУНКЦІОНАЛЬНИЙ
|
||
|
||
**Статус:** ✅ Працює для всіх 9 ботів
|
||
|
||
**Інтеграція:** `/opt/microdao-daarion/gateway-bot/http_api.py`
|
||
- **Функція:** `async def process_document()` (існує)
|
||
- **Виклик:** В webhook handler (лінія 840)
|
||
|
||
**Функціонал:**
|
||
- Завантаження PDF/документів з Telegram
|
||
- Парсинг через Parser Service
|
||
- Витяг тексту з документів
|
||
|
||
**Тест:**
|
||
```
|
||
User → 📄 [Надсилає PDF]
|
||
Bot → "📄 Обробляю документ..."
|
||
Bot → [Опис вмісту документа]
|
||
```
|
||
|
||
---
|
||
|
||
## ❌ Що НЕ працює
|
||
|
||
### 1. 🔍 **Web Search** — НЕ ІНТЕГРОВАНО
|
||
|
||
**Статус:** ❌ Сервіс готовий, але не підключений до Gateway
|
||
|
||
**Сервіс:** `dagi-web-search-service`
|
||
**Порт:** 8897
|
||
**URL:** `http://localhost:8897`
|
||
**Статус контейнера:** Up (unhealthy через rate limit)
|
||
|
||
**Що є:**
|
||
- ✅ Web Search Service запущений
|
||
- ✅ DuckDuckGo та Google доступні
|
||
- ✅ API endpoints працюють:
|
||
- `POST /api/search`
|
||
- `GET /api/search?query=...`
|
||
- `GET /health`
|
||
|
||
**Що НЕ зроблено:**
|
||
- ❌ Немає інтеграції в Gateway
|
||
- ❌ Боти не можуть викликати web search
|
||
- ❌ Немає команди `/search` або автоматичного виявлення
|
||
|
||
**Проблема:** Rate limit від DuckDuckGo
|
||
```json
|
||
{
|
||
"detail": "DuckDuckGo error: Ratelimit"
|
||
}
|
||
```
|
||
|
||
**Рішення:** Використати Google як fallback або додати затримки між запитами
|
||
|
||
---
|
||
|
||
### 2. 🖼️ **OCR Service** — UNHEALTHY
|
||
|
||
**Статус:** ⚠️ Сервіс запущений але unhealthy
|
||
|
||
**Сервіс:** `dagi-ocr-service`
|
||
**Порт:** 8896
|
||
**URL:** `http://localhost:8896`
|
||
|
||
**Проблема:** `NameError: name 'torch' is not defined`
|
||
```python
|
||
File "/app/app/main.py", line 99, in health
|
||
"gpu": torch.cuda.is_available() if EASYOCR_AVAILABLE else False
|
||
^^^^^
|
||
NameError: name 'torch' is not defined
|
||
```
|
||
|
||
**Причина:** Відсутній import torch в `main.py`
|
||
|
||
**Статус роботи:**
|
||
- ⚠️ Health endpoint падає з 500
|
||
- ❓ OCR endpoints можуть працювати (потребують тестування)
|
||
- ✅ EasyOCR та Tesseract встановлені
|
||
|
||
**Рішення:**
|
||
```python
|
||
# Додати в /app/app/main.py
|
||
try:
|
||
import torch
|
||
TORCH_AVAILABLE = True
|
||
except ImportError:
|
||
TORCH_AVAILABLE = False
|
||
|
||
# В health endpoint:
|
||
"gpu": torch.cuda.is_available() if TORCH_AVAILABLE and EASYOCR_AVAILABLE else False
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 План впровадження Web Search
|
||
|
||
### Мета:
|
||
Всі 9 ботів повинні мати можливість шукати в інтернеті.
|
||
|
||
### Варіанти використання:
|
||
|
||
#### Варіант A: Команда `/search`
|
||
```
|
||
User → /search DAARION MicroDAO
|
||
Bot → 🔍 Шукаю в інтернеті...
|
||
Bot → Знайдено 5 результатів:
|
||
1. [Титул](URL) - опис
|
||
2. [Титул](URL) - опис
|
||
...
|
||
```
|
||
|
||
#### Варіант B: Автоматичне виявлення
|
||
```
|
||
User → "Що нового в AI?"
|
||
Bot → [виявляє потребу в актуальній інформації]
|
||
Bot → 🔍 Перевіряю останні новини...
|
||
Bot → За останніми даними з інтернету: ...
|
||
```
|
||
|
||
#### Варіант C: Explicit request
|
||
```
|
||
User → "Знайди інформацію про квантові комп'ютери"
|
||
Bot → [виявляє ключове слово "знайди"]
|
||
Bot → 🔍 Шукаю в інтернеті...
|
||
Bot → Ось що я знайшов: ...
|
||
```
|
||
|
||
---
|
||
|
||
### Імплементація Web Search
|
||
|
||
#### Крок 1: Додати Web Search функцію в Gateway
|
||
|
||
**Файл:** `/opt/microdao-daarion/gateway-bot/http_api.py`
|
||
|
||
```python
|
||
async def perform_web_search(
|
||
query: str,
|
||
max_results: int = 5,
|
||
engine: str = "google" # fallback від duckduckgo через rate limit
|
||
) -> List[Dict[str, str]]:
|
||
\"\"\"Виконати пошук в інтернеті\"\"\"
|
||
try:
|
||
web_search_url = os.getenv("WEB_SEARCH_SERVICE_URL", "http://dagi-web-search-service:8897")
|
||
|
||
logger.info(f"🔍 Web search: '{query}' via {engine}")
|
||
|
||
payload = {
|
||
"query": query,
|
||
"engine": engine,
|
||
"max_results": max_results,
|
||
"region": "ua-uk"
|
||
}
|
||
|
||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||
resp = await client.post(
|
||
f"{web_search_url}/api/search",
|
||
json=payload
|
||
)
|
||
|
||
if resp.status_code == 200:
|
||
data = resp.json()
|
||
results = data.get("results", [])
|
||
logger.info(f"✅ Found {len(results)} results")
|
||
return results
|
||
else:
|
||
# Fallback to Google if DuckDuckGo fails
|
||
if engine == "duckduckgo":
|
||
logger.warning("DuckDuckGo failed, trying Google...")
|
||
return await perform_web_search(query, max_results, "google")
|
||
else:
|
||
logger.error(f"Web search error: {resp.status_code}")
|
||
return []
|
||
|
||
except Exception as e:
|
||
logger.error(f"Web search exception: {e}", exc_info=True)
|
||
return []
|
||
|
||
|
||
def format_search_results(results: List[Dict[str, str]], query: str) -> str:
|
||
\"\"\"Форматувати результати пошуку для Telegram\"\"\"
|
||
if not results:
|
||
return f"🔍 На жаль, нічого не знайдено за запитом: '{query}'"
|
||
|
||
formatted = f"🔍 **Результати пошуку:** '{query}'\\n\\n"
|
||
|
||
for i, result in enumerate(results[:5], 1):
|
||
title = result.get("title", "No title")
|
||
url = result.get("url", "")
|
||
snippet = result.get("snippet", "")[:150]
|
||
|
||
formatted += f"{i}. [{title}]({url})\\n"
|
||
if snippet:
|
||
formatted += f" _{snippet}..._\\n\\n"
|
||
|
||
return formatted
|
||
```
|
||
|
||
---
|
||
|
||
#### Крок 2: Додати команду `/search`
|
||
|
||
```python
|
||
# В handle_telegram_webhook після отримання text
|
||
|
||
# Check for /search command
|
||
if text.startswith("/search "):
|
||
search_query = text[8:].strip() # Remove "/search "
|
||
|
||
if search_query:
|
||
# Відправити "шукаю..." повідомлення
|
||
await send_telegram_message(
|
||
chat_id,
|
||
f"🔍 Шукаю в інтернеті: '{search_query}'...",
|
||
telegram_token
|
||
)
|
||
|
||
# Виконати пошук
|
||
search_results = await perform_web_search(search_query)
|
||
|
||
# Форматувати та відправити результати
|
||
formatted_results = format_search_results(search_results, search_query)
|
||
|
||
await send_telegram_message(
|
||
chat_id,
|
||
formatted_results,
|
||
telegram_token,
|
||
parse_mode="Markdown"
|
||
)
|
||
|
||
return {"ok": True}
|
||
```
|
||
|
||
---
|
||
|
||
#### Крок 3: Автоматичне виявлення (опційно)
|
||
|
||
```python
|
||
# Виявити ключові слова для web search
|
||
web_search_keywords = [
|
||
"знайди", "найди", "пошукай", "поищи",
|
||
"що нового", "what's new", "останні новини",
|
||
"актуальна інформація", "current", "latest"
|
||
]
|
||
|
||
should_search_web = any(keyword in text.lower() for keyword in web_search_keywords)
|
||
|
||
if should_search_web:
|
||
# Виконати web search та додати до контексту
|
||
search_results = await perform_web_search(text, max_results=3)
|
||
|
||
if search_results:
|
||
# Додати результати пошуку до prompt
|
||
search_context = "\\n".join([
|
||
f"- {r['title']}: {r['snippet']}"
|
||
for r in search_results[:3]
|
||
])
|
||
|
||
router_request["message"] += f"\\n\\nАктуальна інформація з інтернету:\\n{search_context}"
|
||
router_request["metadata"]["web_search_used"] = True
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Виправлення OCR
|
||
|
||
### Проблема:
|
||
```python
|
||
NameError: name 'torch' is not defined
|
||
```
|
||
|
||
### Рішення:
|
||
|
||
**Файл:** `/services/ocr-service/app/main.py`
|
||
|
||
**Додати на початку файлу:**
|
||
```python
|
||
try:
|
||
import torch
|
||
TORCH_AVAILABLE = True
|
||
except ImportError:
|
||
TORCH_AVAILABLE = False
|
||
logger.warning("⚠️ PyTorch not available")
|
||
```
|
||
|
||
**Оновити health endpoint (лінія ~99):**
|
||
```python
|
||
@app.get("/health")
|
||
async def health():
|
||
return {
|
||
"status": "healthy",
|
||
"engines": {
|
||
"tesseract": "available" if TESSERACT_AVAILABLE else "unavailable",
|
||
"easyocr": "available" if EASYOCR_AVAILABLE else "unavailable"
|
||
},
|
||
"gpu": torch.cuda.is_available() if TORCH_AVAILABLE else False
|
||
}
|
||
```
|
||
|
||
**Перезапустити контейнер:**
|
||
```bash
|
||
docker restart dagi-ocr-service
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 Тестування
|
||
|
||
### Тест 1: Voice (STT + TTS) ✅
|
||
```
|
||
1. Відкрити @DAARWIZZBot
|
||
2. Надіслати голосове: "Привіт!"
|
||
3. Отримати голосову відповідь
|
||
```
|
||
**Статус:** ✅ Працює
|
||
|
||
---
|
||
|
||
### Тест 2: Photo (Vision) ✅
|
||
```
|
||
1. Відкрити @SoulBot
|
||
2. Надіслати фото
|
||
3. Отримати опис зображення
|
||
```
|
||
**Очікуваний результат:**
|
||
```
|
||
Bot → ✅ Фото оброблено
|
||
|
||
На зображенні: [детальний опис від specialist_vision_8b]
|
||
```
|
||
**Статус:** ✅ Працює (потребує live тесту)
|
||
|
||
---
|
||
|
||
### Тест 3: Web Search ❌
|
||
```
|
||
1. Відкрити @DAARWIZZBot
|
||
2. Надіслати: /search DAARION MicroDAO
|
||
3. Очікувати результати пошуку
|
||
```
|
||
**Поточний статус:** ❌ Команда не розпізнається
|
||
**Після впровадження:** ✅ Покаже 5 результатів з DuckDuckGo/Google
|
||
|
||
---
|
||
|
||
### Тест 4: OCR ⚠️
|
||
```bash
|
||
# Прямий тест OCR API
|
||
curl -X POST http://localhost:8896/api/ocr/upload \
|
||
-F "file=@image_with_text.png" \
|
||
-F "engine=easyocr"
|
||
```
|
||
**Поточний статус:** ⚠️ Health unhealthy, endpoints можуть працювати
|
||
|
||
---
|
||
|
||
## 📋 TODO List
|
||
|
||
### Високий пріоритет:
|
||
- [ ] **Впровадити Web Search команду `/search`** (1-2 год)
|
||
- [ ] **Виправити OCR health endpoint** (15 хв)
|
||
- [ ] **Протестувати Photo processing live** (10 хв)
|
||
|
||
### Середній пріоритет:
|
||
- [ ] Додати автоматичне виявлення для web search
|
||
- [ ] Інтегрувати OCR для витягу тексту з зображень
|
||
- [ ] Додати fallback Google → DuckDuckGo для web search
|
||
|
||
### Низький пріоритет:
|
||
- [ ] Додати кешування web search результатів
|
||
- [ ] Оптимізувати rate limits для DuckDuckGo
|
||
- [ ] Додати команду `/help` з переліком мультимодальних функцій
|
||
|
||
---
|
||
|
||
## ✅ Чекліст готовності
|
||
|
||
### Для кожного бота (9 ботів):
|
||
- [x] Voice STT (голос → текст)
|
||
- [x] Voice TTS (текст → голос)
|
||
- [x] Photo Vision (specialist_vision_8b)
|
||
- [x] Document parsing
|
||
- [ ] Web Search (потребує інтеграції)
|
||
- [ ] OCR (потребує виправлення)
|
||
|
||
---
|
||
|
||
## 🎯 Підсумок
|
||
|
||
### Працює (готово до використання):
|
||
| Функція | Боти | Примітки |
|
||
|---------|------|----------|
|
||
| Voice STT | 9/9 | ✅ Whisper base |
|
||
| Voice TTS | 9/9 | ✅ gTTS, унікальні голоси |
|
||
| Photo Vision | 9/9 | ✅ specialist_vision_8b |
|
||
| Documents | 9/9 | ✅ Parser Service |
|
||
|
||
### Потребує роботи:
|
||
| Функція | Статус | Час на впровадження |
|
||
|---------|--------|---------------------|
|
||
| Web Search | ❌ Не інтегровано | 1-2 години |
|
||
| OCR | ⚠️ Unhealthy | 15 хвилин |
|
||
|
||
---
|
||
|
||
**Статус:** 🟡 **4/6 ФУНКЦІЙ ПРАЦЮЮТЬ, 2 ПОТРЕБУЮТЬ ВПРОВАДЖЕННЯ**
|
||
|
||
**Last Updated:** 2025-11-24
|
||
**By:** Claude (Cursor AI Assistant)
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|