| # Архітектура додатку | |
| ## Загальна схема | |
| ``` | |
| ┌─────────────────────────────────────────────────────────────────┐ | |
| │ GRADIO INTERFACE │ | |
| │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ | |
| │ │💡Генерація│ │🔍 Пошук │ │⚖️ Аналіз │ │⚙️ Налаштування │ │ | |
| │ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │ | |
| └─────────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────────┐ | |
| │ SESSION MANAGER │ | |
| │ ┌────────────────────────────────────────────────────────┐ │ | |
| │ │ Session ID: abc-123-def │ │ | |
| │ │ ├─ legal_position_json: {...} │ │ | |
| │ │ ├─ search_nodes: [...] │ │ | |
| │ │ └─ custom_prompts: │ │ | |
| │ │ ├─ system: "Ти кваліфікований юрист..." │ │ | |
| │ │ ├─ legal_position: "Дотримуйся інструкцій..." │ │ | |
| │ │ └─ analysis: "Проаналізуй..." │ │ | |
| │ └────────────────────────────────────────────────────────┘ │ | |
| └─────────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────────┐ | |
| │ STORAGE │ | |
| │ ┌─────────────────┐ ┌──────────────────┐ │ | |
| │ │ Memory Storage │ OR │ Redis Storage │ │ | |
| │ │ (Development) │ │ (Production) │ │ | |
| │ └─────────────────┘ └──────────────────┘ │ | |
| └─────────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────────┐ | |
| │ CORE FUNCTIONS │ | |
| │ ┌──────────────────┐ ┌──────────────┐ ┌─────────────────┐ │ | |
| │ │ generate_legal_ │ │ search_with_ │ │ analyze_action │ │ | |
| │ │ position() │ │ ai_action() │ │ │ │ | |
| │ └──────────────────┘ └──────────────┘ └─────────────────┘ │ | |
| └─────────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────────┐ | |
| │ AI PROVIDERS │ | |
| │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ | |
| │ │ OpenAI │ │ Anthropic│ │ Google │ │ DeepSeek │ │ | |
| │ │ GPT-4 │ │ Claude │ │ Gemini │ │ Chat │ │ | |
| │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │ | |
| └─────────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────────┐ | |
| │ KNOWLEDGE BASE │ | |
| │ ┌────────────────────────────────────────────────────────┐ │ | |
| │ │ Vector Index + BM25 Index │ │ | |
| │ │ Правові позиції Верховного Суду України │ │ | |
| │ └────────────────────────────────────────────────────────┘ │ | |
| └─────────────────────────────────────────────────────────────────┘ | |
| ``` | |
| ## Потік даних при генерації правової позиції | |
| ``` | |
| 1. Користувач вводить текст судового рішення | |
| │ | |
| ▼ | |
| 2. interface.py → process_input() | |
| ├─ Отримує session_id | |
| ├─ Завантажує сесію з SessionManager | |
| └─ Витягує custom_prompts з сесії | |
| │ | |
| ▼ | |
| 3. main.py → generate_legal_position() | |
| ├─ Приймає custom_system_prompt | |
| ├─ Приймає custom_lp_prompt | |
| └─ Використовує їх замість стандартних | |
| │ | |
| ▼ | |
| 4. AI Provider (OpenAI/Anthropic/Gemini/DeepSeek) | |
| ├─ System Prompt: кастомний або стандартний | |
| ├─ User Prompt: форматований з court_decision_text | |
| └─ Генерує JSON відповідь | |
| │ | |
| ▼ | |
| 5. Результат зберігається в сесію | |
| ├─ session.legal_position_json = {...} | |
| └─ SessionManager.update_session(session) | |
| │ | |
| ▼ | |
| 6. Відображення результату користувачу | |
| ``` | |
| ## Потік даних при редагуванні промптів | |
| ``` | |
| 1. Користувач відкриває "⚙️ Налаштування" | |
| │ | |
| ▼ | |
| 2. app.load → load_session_prompts() | |
| ├─ Отримує session_id | |
| ├─ Завантажує сесію | |
| └─ Витягує збережені промпти або стандартні | |
| │ | |
| ▼ | |
| 3. Користувач редагує промпти | |
| │ | |
| ▼ | |
| 4. Натискає "💾 Зберегти промпти" | |
| │ | |
| ▼ | |
| 5. save_custom_prompts() | |
| ├─ Валідує довжину (max 50,000 символів) | |
| ├─ session.set_prompt('system', new_value) | |
| ├─ session.set_prompt('legal_position', new_value) | |
| ├─ session.set_prompt('analysis', new_value) | |
| └─ SessionManager.update_session(session) | |
| │ | |
| ▼ | |
| 6. Промпти збережено ✅ | |
| (Будуть використані при наступній генерації) | |
| ``` | |
| ## Багатокористувацька архітектура | |
| ``` | |
| ┌─────────────────────────────────────────────────────────────────┐ | |
| │ MULTIPLE USERS │ | |
| └─────────────────────────────────────────────────────────────────┘ | |
| │ │ │ | |
| ▼ ▼ ▼ | |
| ┌──────────┐ ┌──────────┐ ┌──────────┐ | |
| │ User 1 │ │ User 2 │ │ User 3 │ | |
| │ Browser │ │ Browser │ │ Browser │ | |
| └──────────┘ └──────────┘ └──────────┘ | |
| │ │ │ | |
| ▼ ▼ ▼ | |
| session_id: session_id: session_id: | |
| abc-123 def-456 ghi-789 | |
| │ │ │ | |
| └────────────────────┴────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────┐ | |
| │ SESSION MANAGER │ | |
| │ (with asyncio.Lock)│ | |
| └─────────────────────┘ | |
| │ | |
| ┌────────────────────┼────────────────────┐ | |
| ▼ ▼ ▼ | |
| ┌──────────┐ ┌──────────┐ ┌──────────┐ | |
| │Session 1 │ │Session 2 │ │Session 3 │ | |
| │prompts: A│ │prompts: B│ │prompts: C│ | |
| │data: X │ │data: Y │ │data: Z │ | |
| └──────────┘ └──────────┘ └──────────┘ | |
| ✅ Повністю ізольовані! | |
| ``` | |
| ## Структура даних UserSessionState | |
| ```python | |
| @dataclass | |
| class UserSessionState: | |
| # Унікальний ідентифікатор сесії | |
| session_id: str # UUID4 (наприклад: "abc-123-def-456") | |
| # Згенерована правова позиція | |
| legal_position_json: Optional[Dict[str, Any]] = { | |
| "title": "Заголовок правової позиції", | |
| "text": "Текст позиції...", | |
| "proceeding": "Цивільне судочинство", | |
| "category": "Категорія справи" | |
| } | |
| # Результати пошуку | |
| search_nodes: Optional[List[NodeWithScore]] = [ | |
| NodeWithScore( | |
| node=Document( | |
| text="Текст правової позиції...", | |
| metadata={"lp_id": "123", "url": "..."} | |
| ), | |
| score=0.85 | |
| ), | |
| ... | |
| ] | |
| # 🆕 Кастомні промпти користувача | |
| custom_prompts: Dict[str, str] = { | |
| 'system': "Ти - кваліфікований юрист...", | |
| 'legal_position': "Дотримуйся інструкцій...", | |
| 'analysis': "Проаналізуй рішення..." | |
| } | |
| # Метадані сесії | |
| created_at: datetime | |
| last_activity: datetime | |
| ``` | |
| ## Життєвий цикл сесії | |
| ``` | |
| ┌─────────────────────────────────────────────────────────────┐ | |
| │ 1. СТВОРЕННЯ СЕСІЇ │ | |
| │ ├─ Користувач відкриває додаток │ | |
| │ ├─ generate_session_id() → UUID4 │ | |
| │ ├─ SessionManager.get_session(session_id) │ | |
| │ └─ Нова сесія зберігається в storage │ | |
| └─────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────┐ | |
| │ 2. АКТИВНА СЕСІЯ (0-30 хв) │ | |
| │ ├─ Користувач генерує позиції │ | |
| │ ├─ Користувач налаштовує промпти │ | |
| │ ├─ Користувач виконує пошук/аналіз │ | |
| │ └─ last_activity оновлюється при кожній дії │ | |
| └─────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────┐ | |
| │ 3. ПЕРЕВІРКА НА ЕКСПІРАЦІЮ │ | |
| │ └─ Background cleanup task (кожні 5 хв) │ | |
| │ ├─ session.is_expired(30 minutes)? │ | |
| │ │ ├─ YES → видалити сесію │ | |
| │ │ └─ NO → залишити активною │ | |
| │ └─ Повторювати... │ | |
| └─────────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌─────────────────────────────────────────────────────────────┐ | |
| │ 4. ВИДАЛЕННЯ СЕСІЇ │ | |
| │ ├─ Сесія видалена з storage │ | |
| │ ├─ Пам'ять звільнена │ | |
| │ └─ Кастомні промпти втрачено │ | |
| └─────────────────────────────────────────────────────────────┘ | |
| ``` | |
| ## Безпека та ізоляція | |
| ### Thread-safe операції | |
| ```python | |
| class SessionManager: | |
| def __init__(self): | |
| self._lock = asyncio.Lock() # 🔒 Для thread-safety | |
| async def get_session(self, session_id): | |
| async with self._lock: # Блокування доступу | |
| # Тільки один запит обробляється одночасно | |
| session = await self.storage.get(session_id) | |
| return session | |
| async def update_session(self, session): | |
| async with self._lock: # Блокування доступу | |
| session.update_activity() | |
| await self.storage.set(session) | |
| ``` | |
| ### Ізоляція даних | |
| ``` | |
| ┌───────────────────────────────────────────────────────────┐ | |
| │ ГАРАНТІЇ БЕЗПЕКИ │ | |
| ├───────────────────────────────────────────────────────────┤ | |
| │ ✅ Session ID генерується криптографічно (UUID4) │ | |
| │ ✅ Неможливо вгадати чужий session_id │ | |
| │ ✅ Дані зберігаються тільки в межах сесії │ | |
| │ ✅ Автоматичне видалення застарілих даних │ | |
| │ ✅ Thread-safe операції через asyncio.Lock │ | |
| │ ✅ Немає глобального стану (окрім SessionManager) │ | |
| └───────────────────────────────────────────────────────────┘ | |
| ``` | |
| ## Інтеграція з існуючим кодом | |
| ### До (Legacy) | |
| ```python | |
| # interface.py | |
| state_lp_json = gr.State() # Gradio state | |
| state_nodes = gr.State() | |
| def process_input(...): | |
| # Генерація без кастомних промптів | |
| legal_position_json = generate_legal_position( | |
| input_text, input_type, comment, provider, model | |
| ) | |
| return output, legal_position_json # Повертаємо в Gradio state | |
| ``` | |
| ### Після (з Session Manager) | |
| ```python | |
| # interface.py | |
| session_id_state = gr.State(value=generate_session_id) # 🆕 Унікальний ID | |
| async def process_input(..., session_id: str): | |
| # Завантажуємо сесію | |
| manager = get_session_manager() | |
| session = await manager.get_session(session_id) | |
| # Витягуємо кастомні промпти | |
| custom_system = session.get_prompt('system', SYSTEM_PROMPT) | |
| custom_lp = session.get_prompt('legal_position', LEGAL_POSITION_PROMPT) | |
| # Генерація з кастомними промптами | |
| legal_position_json = generate_legal_position( | |
| input_text, input_type, comment, provider, model, | |
| custom_system_prompt=custom_system, # 🆕 | |
| custom_lp_prompt=custom_lp # 🆕 | |
| ) | |
| # Зберігаємо в сесію | |
| session.legal_position_json = legal_position_json | |
| await manager.update_session(session) | |
| return output, legal_position_json, session_id | |
| ``` | |
| ## Переваги нової архітектури | |
| ``` | |
| ┌────────────────────────────────────────────────────────────┐ | |
| │ ПЕРЕВАГИ │ | |
| ├────────────────────────────────────────────────────────────┤ | |
| │ ✅ Повна ізоляція між користувачами │ | |
| │ ✅ Персоналізація промптів для кожного користувача │ | |
| │ ✅ Підготовка до deployment на Hugging Face Spaces │ | |
| │ ✅ Можливість використання Redis для масштабування │ | |
| │ ✅ Автоматична очистка пам'яті │ | |
| │ ✅ Thread-safe для багатопоточності │ | |
| │ ✅ Легка розширюваність (додавання нових полів) │ | |
| │ ✅ Централізоване управління станом │ | |
| └────────────────────────────────────────────────────────────┘ | |
| ``` | |
| ## Майбутні покращення | |
| ### Фаза 1: Повна міграція на Session Manager | |
| ``` | |
| ┌───────────────────────────────────────────────────────────┐ | |
| │ ПОТОЧНИЙ СТАН │ | |
| │ ├─ session_id_state ✅ (реалізовано) │ | |
| │ ├─ state_lp_json ⚠️ (legacy, дублюється) │ | |
| │ └─ state_nodes ⚠️ (legacy, дублюється) │ | |
| └───────────────────────────────────────────────────────────┘ | |
| │ | |
| ▼ | |
| ┌───────────────────────────────────────────────────────────┐ | |
| │ МАЙБУТНЄ │ | |
| │ ├─ session_id_state ✅ (єдине джерело істини) │ | |
| │ ├─ Всі дані в SessionManager │ | |
| │ └─ Видалити legacy states │ | |
| └───────────────────────────────────────────────────────────┘ | |
| ``` | |
| ### Фаза 2: Розширені можливості | |
| ``` | |
| ┌───────────────────────────────────────────────────────────┐ | |
| │ НОВІ FEATURES │ | |
| │ ├─ Експорт/імпорт промптів (JSON/YAML) │ | |
| │ ├─ Бібліотека шаблонів промптів │ | |
| │ ├─ Версіонування промптів (історія змін) │ | |
| │ ├─ A/B тестування різних промптів │ | |
| │ └─ Метрики якості генерації │ | |
| └───────────────────────────────────────────────────────────┘ | |
| ``` | |
| ## Висновок | |
| Нова архітектура забезпечує: | |
| - 🔒 Безпеку: повна ізоляція між користувачами | |
| - ⚡ Продуктивність: ефективне управління пам'яттю | |
| - 🎨 Гнучкість: персоналізація для кожного користувача | |
| - 🚀 Масштабованість: готовність до production deployment | |
| Система готова до використання на Hugging Face Spaces та інших хмарних платформах! | |