Files
microdao-daarion/site/testing/VOICE_PHOTO_READY/index.html
Apple ef3473db21 snapshot: NODE1 production state 2026-02-09
Complete snapshot of /opt/microdao-daarion/ from NODE1 (144.76.224.179).
This represents the actual running production code that has diverged
significantly from the previous main branch.

Key changes from old main:
- Gateway (http_api.py): expanded from ~40KB to 164KB with full agent support
- Router: new /v1/agents/{id}/infer endpoint with vision + DeepSeek routing
- Behavior Policy: SOWA v2.2 (3-level: FULL/ACK/SILENT)
- Agent Registry: config/agent_registry.yml as single source of truth
- 13 agents configured (was 3)
- Memory service integration
- CrewAI teams and roles

Excluded from snapshot: venv/, .env, data/, backups, .tgz archives

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 08:46:46 -08:00

1191 lines
38 KiB
HTML
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.
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="canonical" href="https://IvanTytar.github.io/microdao-daarion/testing/VOICE_PHOTO_READY/">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.18">
<title>✅ Voice & Photo Handlers - ГОТОВО - DAARION Documentation</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.66ac8b77.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#voice-photo-handlers-" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="DAARION Documentation" class="md-header__button md-logo" aria-label="DAARION Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
DAARION Documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
✅ Voice & Photo Handlers - ГОТОВО
</span>
</div>
</div>
</div>
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="DAARION Documentation" class="md-nav__button md-logo" aria-label="DAARION Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
</a>
DAARION Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../public/" class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/getting-started/" class="md-nav__link">
<span class="md-ellipsis">
Getting Started
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/architecture-overview/" class="md-nav__link">
<span class="md-ellipsis">
Architecture
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/daiS_daos_overview/" class="md-nav__link">
<span class="md-ellipsis">
DAIS & DAOS
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
<span class="md-ellipsis">
Internal
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Internal
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_1" >
<label class="md-nav__link" for="__nav_5_1" id="__nav_5_1_label" tabindex="0">
<span class="md-ellipsis">
Infra
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_1">
<span class="md-nav__icon md-icon"></span>
Infra
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../internal/infra/INFRA_AUTOMATION_PACK_V1/" class="md-nav__link">
<span class="md-ellipsis">
Infra Automation Pack v1
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/infra/monitoring_overview/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/infra/nodes_registry_v0/" class="md-nav__link">
<span class="md-ellipsis">
Nodes Registry v0
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_2" >
<label class="md-nav__link" for="__nav_5_2" id="__nav_5_2_label" tabindex="0">
<span class="md-ellipsis">
Specs
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_2">
<span class="md-nav__icon md-icon"></span>
Specs
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../internal/specs/matrix_presence_aggregator/" class="md-nav__link">
<span class="md-ellipsis">
Matrix Presence Aggregator
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/specs/city_map_spec/" class="md-nav__link">
<span class="md-ellipsis">
City Map Spec
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/specs/node_join_protocol_draft/" class="md-nav__link">
<span class="md-ellipsis">
Node Join Protocol (Draft)
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#_1" class="md-nav__link">
<span class="md-ellipsis">
🎉 Що імплементовано:
</span>
</a>
<nav class="md-nav" aria-label="🎉 Що імплементовано:">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1" class="md-nav__link">
<span class="md-ellipsis">
1. Голосові повідомлення 🎤
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2" class="md-nav__link">
<span class="md-ellipsis">
2. Фото/Зображення 🖼️
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-pdf" class="md-nav__link">
<span class="md-ellipsis">
3. PDF Документи 📄
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_2" class="md-nav__link">
<span class="md-ellipsis">
🧪 Як протестувати:
</span>
</a>
<nav class="md-nav" aria-label="🧪 Як протестувати:">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#test-1" class="md-nav__link">
<span class="md-ellipsis">
Test 1: Голосове повідомлення 🎤
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#test-2" class="md-nav__link">
<span class="md-ellipsis">
Test 2: Фото з питанням 🖼️
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#test-3-pdf" class="md-nav__link">
<span class="md-ellipsis">
Test 3: PDF документ 📄
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_3" class="md-nav__link">
<span class="md-ellipsis">
📊 Технічні деталі:
</span>
</a>
<nav class="md-nav" aria-label="📊 Технічні деталі:">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#handlers-telegram_listenerpy" class="md-nav__link">
<span class="md-ellipsis">
Handlers в telegram_listener.py:
</span>
</a>
<nav class="md-nav" aria-label="Handlers в telegram_listener.py:">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-text-handler" class="md-nav__link">
<span class="md-ellipsis">
1. Text Handler
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-voice-handler" class="md-nav__link">
<span class="md-ellipsis">
2. Voice Handler
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-document-handler-pdf" class="md-nav__link">
<span class="md-ellipsis">
3. Document Handler (PDF)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-photo-handler" class="md-nav__link">
<span class="md-ellipsis">
4. Photo Handler
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_4" class="md-nav__link">
<span class="md-ellipsis">
🔧 Файли:
</span>
</a>
<nav class="md-nav" aria-label="🔧 Файли:">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_5" class="md-nav__link">
<span class="md-ellipsis">
Створені/Оновлені:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#url" class="md-nav__link">
<span class="md-ellipsis">
URL для файлів:
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_6" class="md-nav__link">
<span class="md-ellipsis">
🎯 Наступні кроки (опційно):
</span>
</a>
<nav class="md-nav" aria-label="🎯 Наступні кроки (опційно):">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-vision-encoder-integration" class="md-nav__link">
<span class="md-ellipsis">
1. Vision Encoder Integration (для фото) 🔴
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-parser-service-integration-pdf" class="md-nav__link">
<span class="md-ellipsis">
2. Parser Service Integration (для PDF) 🔴
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-tts-integration" class="md-nav__link">
<span class="md-ellipsis">
3. TTS Integration (голосові відповіді) 🟡
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-multimodal-chat" class="md-nav__link">
<span class="md-ellipsis">
4. Multimodal Chat (текст + фото + голос) 🟢
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_7" class="md-nav__link">
<span class="md-ellipsis">
📝 Логи для діагностики:
</span>
</a>
<nav class="md-nav" aria-label="📝 Логи для діагностики:">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_8" class="md-nav__link">
<span class="md-ellipsis">
Голосові:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#_9" class="md-nav__link">
<span class="md-ellipsis">
Фото:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pdf" class="md-nav__link">
<span class="md-ellipsis">
PDF:
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_10" class="md-nav__link">
<span class="md-ellipsis">
✅ Критерії успіху:
</span>
</a>
<nav class="md-nav" aria-label="✅ Критерії успіху:">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_11" class="md-nav__link">
<span class="md-ellipsis">
Голосові повідомлення:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#_12" class="md-nav__link">
<span class="md-ellipsis">
Фото:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pdf_1" class="md-nav__link">
<span class="md-ellipsis">
PDF:
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#_13" class="md-nav__link">
<span class="md-ellipsis">
🚀 Статус:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#_14" class="md-nav__link">
<span class="md-ellipsis">
🎊 Готово до тестування!
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="voice-photo-handlers-">✅ Voice &amp; Photo Handlers - ГОТОВО<a class="headerlink" href="#voice-photo-handlers-" title="Permanent link">&para;</a></h1>
<p><strong>Дата</strong>: 2025-11-18<br />
<strong>Статус</strong>: ✅ Працює</p>
<hr />
<h2 id="_1">🎉 Що імплементовано:<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2>
<h3 id="1">1. <strong>Голосові повідомлення</strong> 🎤<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<ul>
<li>✅ Voice messages (<code>.ogg</code>, <code>.mp3</code>)</li>
<li>✅ Audio files</li>
<li>✅ Video notes (кружечки)</li>
<li>✅ STT через <code>dagi-stt:9000</code> (Whisper)</li>
<li>✅ Автоматична транскрипція</li>
<li>✅ Публікація в NATS → Router → відповідь</li>
</ul>
<h3 id="2">2. <strong>Фото/Зображення</strong> 🖼️<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
<ul>
<li>✅ Photo messages</li>
<li>✅ Photo з підписом (caption)</li>
<li>✅ Завантаження через Telegram API</li>
<li>✅ Metadata (<code>file_url</code>, <code>file_id</code>, <code>width</code>, <code>height</code>)</li>
<li>✅ Публікація в NATS з metadata</li>
</ul>
<h3 id="3-pdf">3. <strong>PDF Документи</strong> 📄<a class="headerlink" href="#3-pdf" title="Permanent link">&para;</a></h3>
<ul>
<li>✅ PDF file detection</li>
<li>✅ Завантаження через Telegram API</li>
<li>✅ Metadata (<code>file_url</code>, <code>file_name</code>, <code>file_size</code>)</li>
<li>✅ Готово до інтеграції з Parser Service</li>
</ul>
<hr />
<h2 id="_2">🧪 Як протестувати:<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2>
<h3 id="test-1">Test 1: Голосове повідомлення 🎤<a class="headerlink" href="#test-1" title="Permanent link">&para;</a></h3>
<p><strong>Крок 1</strong>: Відкрити Telegram<br />
<strong>Крок 2</strong>: Знайти бота:
- <code>@DAARWIZZBot</code>
- <code>@energyunionBot</code> (Helion)
- <code>@greenfoodliveBot</code> (GREENFOOD)</p>
<p><strong>Крок 3</strong>: Натиснути мікрофон і сказати: "Привіт, розкажи про MicroDAO"<br />
<strong>Крок 4</strong>: Відправити</p>
<p><strong>Очікуваний результат</strong>:</p>
<div class="codehilite"><pre><span></span><code>Ти → 🎤 [Голосове 3 сек]
Бот → 🎤 Обробляю голосове повідомлення...
Бот → [Розпізнаний текст + відповідь агента]
</code></pre></div>
<hr />
<h3 id="test-2">Test 2: Фото з питанням 🖼️<a class="headerlink" href="#test-2" title="Permanent link">&para;</a></h3>
<p><strong>Крок 1</strong>: Вибрати будь-яке фото<br />
<strong>Крок 2</strong>: Додати підпис (caption): "Що на цьому зображенні?"<br />
<strong>Крок 3</strong>: Відправити боту</p>
<p><strong>Очікуваний результат</strong>:</p>
<div class="codehilite"><pre><span></span><code>Ти → 🖼️ [Фото з підписом]
Бот → 🖼️ Обробляю зображення...
Бот → [Відповідь про зображення]
</code></pre></div>
<p><strong>Примітка</strong>: Для повної обробки зображення через Vision Encoder потрібна інтеграція в <code>router_handler.py</code>.</p>
<hr />
<h3 id="test-3-pdf">Test 3: PDF документ 📄<a class="headerlink" href="#test-3-pdf" title="Permanent link">&para;</a></h3>
<p><strong>Крок 1</strong>: Підготувати PDF файл<br />
<strong>Крок 2</strong>: Відправити боту<br />
<strong>Крок 3</strong>: Дочекатися відповіді</p>
<p><strong>Очікуваний результат</strong>:</p>
<div class="codehilite"><pre><span></span><code>Ти → 📄 document.pdf
Бот → 📄 Обробляю документ: document.pdf...
Бот → [Результат парсингу або підтвердження отримання]
</code></pre></div>
<p><strong>Примітка</strong>: Для повної обробки PDF потрібна інтеграція з Parser Service в <code>router_handler.py</code>.</p>
<hr />
<h2 id="_3">📊 Технічні деталі:<a class="headerlink" href="#_3" title="Permanent link">&para;</a></h2>
<h3 id="handlers-telegram_listenerpy">Handlers в <code>telegram_listener.py</code>:<a class="headerlink" href="#handlers-telegram_listenerpy" title="Permanent link">&para;</a></h3>
<h4 id="1-text-handler">1. Text Handler<a class="headerlink" href="#1-text-handler" title="Permanent link">&para;</a></h4>
<div class="codehilite"><pre><span></span><code><span class="nd">@dp</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="n">F</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_message</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">):</span>
<span class="c1"># Звичайні текстові повідомлення</span>
</code></pre></div>
<h4 id="2-voice-handler">2. Voice Handler<a class="headerlink" href="#2-voice-handler" title="Permanent link">&para;</a></h4>
<div class="codehilite"><pre><span></span><code><span class="nd">@dp</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="n">F</span><span class="o">.</span><span class="n">voice</span> <span class="o">|</span> <span class="n">F</span><span class="o">.</span><span class="n">audio</span> <span class="o">|</span> <span class="n">F</span><span class="o">.</span><span class="n">video_note</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_voice</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">):</span>
<span class="c1"># Голосові → STT → транскрипція → NATS</span>
</code></pre></div>
<h4 id="3-document-handler-pdf">3. Document Handler (PDF)<a class="headerlink" href="#3-document-handler-pdf" title="Permanent link">&para;</a></h4>
<div class="codehilite"><pre><span></span><code><span class="nd">@dp</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="n">F</span><span class="o">.</span><span class="n">document</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_document</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">):</span>
<span class="c1"># PDF files → metadata → NATS</span>
</code></pre></div>
<h4 id="4-photo-handler">4. Photo Handler<a class="headerlink" href="#4-photo-handler" title="Permanent link">&para;</a></h4>
<div class="codehilite"><pre><span></span><code><span class="nd">@dp</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="n">F</span><span class="o">.</span><span class="n">photo</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">on_photo</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">):</span>
<span class="c1"># Фото → metadata → NATS</span>
</code></pre></div>
<hr />
<h2 id="_4">🔧 Файли:<a class="headerlink" href="#_4" title="Permanent link">&para;</a></h2>
<h3 id="_5">Створені/Оновлені:<a class="headerlink" href="#_5" title="Permanent link">&para;</a></h3>
<ol>
<li><code>telegram-gateway/app/voice_handler.py</code> - обробка voice/document</li>
<li><code>telegram-gateway/app/telegram_listener.py</code> - всі handlers</li>
<li><code>telegram-gateway/app/models.py</code> - додано <code>metadata</code> поле</li>
<li>✅ Використання офіційного Telegram API для завантаження файлів</li>
</ol>
<h3 id="url">URL для файлів:<a class="headerlink" href="#url" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code><span class="c1"># Voice, Audio, Document, Photo</span>
<span class="n">file_url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;https://api.telegram.org/file/bot</span><span class="si">{</span><span class="n">bot_token</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">file_path</span><span class="si">}</span><span class="s2">&quot;</span>
</code></pre></div>
<hr />
<h2 id="_6">🎯 Наступні кроки (опційно):<a class="headerlink" href="#_6" title="Permanent link">&para;</a></h2>
<h3 id="1-vision-encoder-integration">1. <strong>Vision Encoder Integration</strong> (для фото) 🔴<a class="headerlink" href="#1-vision-encoder-integration" title="Permanent link">&para;</a></h3>
<p>Додати в <code>router_handler.py</code>:</p>
<div class="codehilite"><pre><span></span><code><span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">metadata</span> <span class="ow">and</span> <span class="s2">&quot;photo&quot;</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">metadata</span><span class="p">:</span>
<span class="n">photo_info</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">metadata</span><span class="p">[</span><span class="s2">&quot;photo&quot;</span><span class="p">]</span>
<span class="c1"># Call Vision Encoder Service</span>
<span class="c1"># Analyze image and return description</span>
</code></pre></div>
<h3 id="2-parser-service-integration-pdf">2. <strong>Parser Service Integration</strong> (для PDF) 🔴<a class="headerlink" href="#2-parser-service-integration-pdf" title="Permanent link">&para;</a></h3>
<p>Додати в <code>router_handler.py</code>:</p>
<div class="codehilite"><pre><span></span><code><span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">metadata</span> <span class="ow">and</span> <span class="s2">&quot;document&quot;</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">metadata</span><span class="p">:</span>
<span class="n">doc_info</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">metadata</span><span class="p">[</span><span class="s2">&quot;document&quot;</span><span class="p">]</span>
<span class="c1"># Call Parser Service with doc_info[&quot;file_url&quot;]</span>
<span class="c1"># Return parsed content</span>
</code></pre></div>
<h3 id="3-tts-integration">3. <strong>TTS Integration</strong> (голосові відповіді) 🟡<a class="headerlink" href="#3-tts-integration" title="Permanent link">&para;</a></h3>
<ul>
<li>Додати опцію для відправки голосових відповідей</li>
<li>Користувач може обрати: текст або голос</li>
</ul>
<h3 id="4-multimodal-chat">4. <strong>Multimodal Chat</strong> (текст + фото + голос) 🟢<a class="headerlink" href="#4-multimodal-chat" title="Permanent link">&para;</a></h3>
<ul>
<li>Підтримка мультимодальних запитів</li>
<li>Контекст з попередніх повідомлень (текст + зображення)</li>
</ul>
<hr />
<h2 id="_7">📝 Логи для діагностики:<a class="headerlink" href="#_7" title="Permanent link">&para;</a></h2>
<h3 id="_8">Голосові:<a class="headerlink" href="#_8" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code>ssh<span class="w"> </span>root@144.76.224.179<span class="w"> </span><span class="s2">&quot;docker logs --tail 100 telegram-gateway | grep &#39;🎤&#39;&quot;</span>
ssh<span class="w"> </span>root@144.76.224.179<span class="w"> </span><span class="s2">&quot;docker logs --tail 50 dagi-stt | grep transcrib&quot;</span>
</code></pre></div>
<h3 id="_9">Фото:<a class="headerlink" href="#_9" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code>ssh<span class="w"> </span>root@144.76.224.179<span class="w"> </span><span class="s2">&quot;docker logs --tail 100 telegram-gateway | grep &#39;🖼️&#39;&quot;</span>
</code></pre></div>
<h3 id="pdf">PDF:<a class="headerlink" href="#pdf" title="Permanent link">&para;</a></h3>
<div class="codehilite"><pre><span></span><code>ssh<span class="w"> </span>root@144.76.224.179<span class="w"> </span><span class="s2">&quot;docker logs --tail 100 telegram-gateway | grep &#39;📄&#39;&quot;</span>
</code></pre></div>
<hr />
<h2 id="_10">✅ Критерії успіху:<a class="headerlink" href="#_10" title="Permanent link">&para;</a></h2>
<h3 id="_11">Голосові повідомлення:<a class="headerlink" href="#_11" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] Бот відповідає "🎤 Обробляю голосове повідомлення..."</li>
<li>[x] Транскрипція працює (українська/англійська)</li>
<li>[x] Бот відповідає на основі транскрибованого тексту</li>
<li>[x] Немає помилок 404/500 в логах</li>
</ul>
<h3 id="_12">Фото:<a class="headerlink" href="#_12" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] Бот відповідає "🖼️ Обробляю зображення..."</li>
<li>[x] Metadata публікується в NATS</li>
<li>[ ] Vision Encoder аналізує зображення (потребує інтеграції)</li>
</ul>
<h3 id="pdf_1">PDF:<a class="headerlink" href="#pdf_1" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] Бот відповідає "📄 Обробляю документ: filename.pdf..."</li>
<li>[x] Metadata публікується в NATS</li>
<li>[ ] Parser Service обробляє PDF (потребує інтеграції)</li>
</ul>
<hr />
<h2 id="_13">🚀 Статус:<a class="headerlink" href="#_13" title="Permanent link">&para;</a></h2>
<table>
<thead>
<tr>
<th>Функція</th>
<th>Статус</th>
<th>Примітка</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Voice → STT</strong></td>
<td>✅ ПРАЦЮЄ</td>
<td>Whisper base model</td>
</tr>
<tr>
<td><strong>Audio → STT</strong></td>
<td>✅ ПРАЦЮЄ</td>
<td>Всі формати</td>
</tr>
<tr>
<td><strong>Video Note → STT</strong></td>
<td>✅ ПРАЦЮЄ</td>
<td>Кружечки</td>
</tr>
<tr>
<td><strong>Photo Detection</strong></td>
<td>✅ ПРАЦЮЄ</td>
<td>Metadata в NATS</td>
</tr>
<tr>
<td><strong>PDF Detection</strong></td>
<td>✅ ПРАЦЮЄ</td>
<td>Metadata в NATS</td>
</tr>
<tr>
<td><strong>Vision Analysis</strong></td>
<td>⚠️ Потрібна інтеграція</td>
<td>Vision Encoder ready</td>
</tr>
<tr>
<td><strong>PDF Parsing</strong></td>
<td>⚠️ Потрібна інтеграція</td>
<td>Parser Service ready</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="_14">🎊 Готово до тестування!<a class="headerlink" href="#_14" title="Permanent link">&para;</a></h2>
<p><strong>Спробуй зараз</strong>:
1. Відправ голосове будь-якому боту
2. Відправ фото з підписом
3. Відправ PDF документ</p>
<p>Якщо щось не працює - дивись логи вище та пиши мені! 🚀</p>
<hr />
<p><em>Створено: 2025-11-18</em><br />
<em>Автор: Assistant (via Cursor)</em><br />
<em>Версія: 1.0</em></p>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": ["navigation.sections", "navigation.instant", "content.code.copy"], "search": "../../assets/javascripts/workers/search.b8dbb3d2.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
<script src="../../assets/javascripts/bundle.3220b9d7.min.js"></script>
</body>
</html>