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