# Архітектура додатку ## Загальна схема ``` ┌─────────────────────────────────────────────────────────────────┐ │ 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 та інших хмарних платформах!