docs: требования к Flask-приложению для Штурвала — health, no_cache, SSE, BOM, etc
Deploy drhider / validate (push) Waiting to run
Deploy drhider / validate (push) Waiting to run
This commit is contained in:
@@ -178,6 +178,108 @@ api_bp.drhider()
|
|||||||
│ → [(filename, bytes, mimetype), ...]
|
│ → [(filename, bytes, mimetype), ...]
|
||||||
▼
|
▼
|
||||||
obfuscate_files(files, llm_client=LLMClient())
|
obfuscate_files(files, llm_client=LLMClient())
|
||||||
|
│ Scanner → Extractor → LLM NER → Obfuscator → Replacer → Builder
|
||||||
|
▼
|
||||||
|
bytes (ZIP-архив с обезличенными документами + mapping.csv)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Требования к Flask-приложению для Штурвала
|
||||||
|
|
||||||
|
### 1. `/health` — liveness probe
|
||||||
|
|
||||||
|
```python
|
||||||
|
@health_bp.route("/health")
|
||||||
|
def health():
|
||||||
|
return jsonify({"ok": True, "version": "0.0.26"})
|
||||||
|
```
|
||||||
|
|
||||||
|
**Обязательно.** Штурвал дёргает `/health` для readiness/liveness checks. Без этого под не поднимется. Ответ должен быть `200 OK`.
|
||||||
|
|
||||||
|
### 2. `no_cache` на все ответы
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.after_request
|
||||||
|
def no_cache(response):
|
||||||
|
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
||||||
|
response.headers["Pragma"] = "no-cache"
|
||||||
|
response.headers["Expires"] = "0"
|
||||||
|
return response
|
||||||
|
```
|
||||||
|
|
||||||
|
**Критично для SPA-подобного UI.** Без этого nginx/браузер кэшируют страницу → F5 показывает старую версию, кнопки не работают, версия не обновляется.
|
||||||
|
|
||||||
|
### 3. `X-Accel-Buffering: no` для SSE
|
||||||
|
|
||||||
|
```python
|
||||||
|
return Response(
|
||||||
|
stream_with_context(generate()),
|
||||||
|
content_type="text/event-stream",
|
||||||
|
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Критично для SSE-прогресса.** Без этого nginx буферизует поток → прогресс не отображается в реальном времени, все события приходят одним блоком в конце.
|
||||||
|
|
||||||
|
### 4. `MAX_CONTENT_LENGTH`
|
||||||
|
|
||||||
|
```python
|
||||||
|
app.config["MAX_CONTENT_LENGTH"] = 200 * 1024 * 1024 # 200 MB
|
||||||
|
```
|
||||||
|
|
||||||
|
Без этого Flask использует дефолтный лимит (~1MB) и отвергает docx/pdf.
|
||||||
|
|
||||||
|
### 5. `GeneratorExit` в SSE-генераторе
|
||||||
|
|
||||||
|
```python
|
||||||
|
try:
|
||||||
|
yield f"event: start\n..."
|
||||||
|
except GeneratorExit:
|
||||||
|
return # клиент отключился — не продолжаем обработку
|
||||||
|
```
|
||||||
|
|
||||||
|
**Критично.** При закрытии вкладки браузер рвёт SSE-соединение. Без `GeneratorExit` генератор продолжает слать запросы в LLM, тратя токены впустую.
|
||||||
|
|
||||||
|
### 6. `stream_with_context`
|
||||||
|
|
||||||
|
```python
|
||||||
|
from flask import stream_with_context
|
||||||
|
|
||||||
|
return Response(stream_with_context(generate()), ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Обязательно для SSE.** Без этого Flask держит приложение заблокированным на время SSE-соединения, другие запросы не обрабатываются.
|
||||||
|
|
||||||
|
### 7. `sys.path` для импорта пакета drhider
|
||||||
|
|
||||||
|
```python
|
||||||
|
_sys_path_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
if _sys_path_root not in sys.path:
|
||||||
|
sys.path.insert(0, _sys_path_root)
|
||||||
|
```
|
||||||
|
|
||||||
|
Штурвал запускает из `site/`, пакет `drhider/` на уровень выше. Без этого импорт не работает.
|
||||||
|
|
||||||
|
### 8. In-memory session storage
|
||||||
|
|
||||||
|
Сессии хранятся в `site/session.py` как `Dict[str, dict]`. **Не персистентны** — теряются при рестарте пода. Очистка по таймауту (2 часа).
|
||||||
|
|
||||||
|
### 9. LLM-клиент через переменные окружения
|
||||||
|
|
||||||
|
```python
|
||||||
|
LLM_KEY # API ключ
|
||||||
|
LLM_URL # эндпоинт (по умолчанию https://api.aillm.ru/v1/chat/completions)
|
||||||
|
LLM_MODEL # модель (по умолчанию gpt-oss-120b)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10. BOM в CSV
|
||||||
|
|
||||||
|
```python
|
||||||
|
buf.write('\ufeff'.encode('utf-8') + csv_str.encode('utf-8'))
|
||||||
|
```
|
||||||
|
|
||||||
|
BOM (`\ufeff`) нужен для корректного открытия CSV в Excel (чтобы русские буквы не ломались).
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
TwoPassObfuscator.obfuscate(files)
|
TwoPassObfuscator.obfuscate(files)
|
||||||
|
|||||||
Reference in New Issue
Block a user