fix(web): запуск синхронизации почты с веб-кнопки (rw-монтирование mutt, MUTT_DIR env, поддержка split PDF)

This commit is contained in:
Admin 2026-10-13 13:56:38 +04:00
parent 99fd5ebe88
commit 8cb5ee7036
4 changed files with 29 additions and 47 deletions

View file

@ -90,7 +90,7 @@ if not ADMIN_USER_ID:
SAFETY_MODE = os.getenv('SAFETY_MODE', 'production').lower() # 'production' или 'safe'
# ===== ДИНАМИЧЕСКИЕ ПУТИ (ПЕРЕНОСИМОСТЬ) =====
MUTT_DIR = os.getenv('MUTT_DIR', '/app/mutt' if os.path.exists('/app/mutt') else str(BASE_DIR.parent.parent / 'mutt'))
MUTT_DIR = os.getenv('MUTT_DIR', '/home/matrixhasyou/mutt' if os.path.exists('/home/matrixhasyou/mutt') else ('/app/mutt' if os.path.exists('/app/mutt') else str(BASE_DIR.parent.parent / 'mutt')))
GOOGLE_CREDS_FILE = os.getenv('GOOGLE_CREDS_FILE', '/app/config/google_creds.json' if os.path.exists('/app/config/google_creds.json') else str(BASE_DIR.parent.parent / 'domovoy_google_creds.json'))

View file

@ -13,6 +13,7 @@ services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./.env:/app/.env:ro
- ./config.py:/app/config.py:ro
- ./main.py:/app/main.py
- ./logs:/app/logs
- ./exports:/app/exports
@ -39,10 +40,12 @@ services:
- PYTHONPATH=/app:/app/services
- GOOGLE_CREDS_FILE=/home/matrixhasyou/domovoy_google_creds.json
- GOOGLE_API_KEY=AIzaSyAJMfQ_mRZ1picRXVFNaeFJ7fpAkZxUKyk
- MUTT_DIR=/home/matrixhasyou/mutt
- TZ=Europe/Ulyanovsk
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./.env:/app/.env:ro
- ./config.py:/app/config.py:ro
- ./web:/app/web
- ./podcasts:/app/podcasts
- ./logs:/app/logs
@ -50,7 +53,8 @@ services:
- ./data:/app/data
- ./handlers:/app/handlers
- ./services:/app/services
- /home/matrixhasyou/mutt:/home/matrixhasyou/mutt:ro
- /home/matrixhasyou/mutt:/home/matrixhasyou/mutt:rw
- /home/matrixhasyou/domovoy_drive_sync.py:/home/matrixhasyou/domovoy_drive_sync.py:ro
- ../libs/swarmlib:/app/swarmlib:ro
- /home/matrixhasyou/domovoy_google_creds.json:/home/matrixhasyou/domovoy_google_creds.json:ro
- /home/matrixhasyou/.notebooklm:/root/.notebooklm:rw

View file

@ -115,40 +115,7 @@ async def upload_to_tg(content, filename, content_type):
file_id = msg["photo"][-1]["file_id"] if file_type == "photo" else msg["document"]["file_id"]
return file_id, file_type
@app.post("/api/emails/sync_ai")
async def api_sync_emails_to_ai(username: str = Depends(get_current_admin)):
sync_script = "/app/domovoy_drive_sync.py" if os.path.exists("/app/domovoy_drive_sync.py") else str(Path(config.MUTT_DIR).parent / "domovoy_drive_sync.py")
python_path = sys.executable
try:
# Запуск синхронизации
process = subprocess.run(
[python_path, sync_script],
capture_output=True, text=True, timeout=300
)
if process.returncode == 0:
# Уведомляем админа в ТГ
msg = "🤖 <b>AI Синхронизация Успешна!</b>\n\n📄 Архив почты обновлен на Google Drive.\n👉 Не забудь нажать <b>'Sync'</b> в NotebookLM!"
# Отправка через API Telegram (упрощенно)
async with aiohttp.ClientSession() as session:
url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendMessage"
params = {
"chat_id": config.ADMIN_USER_ID,
"text": msg,
"parse_mode": "HTML"
}
# Используем прокси если нужно
proxy = f"http://{config.PROXY_HOST}:{config.PROXY_PORT}" if config.USE_PROXY else None
await session.get(url, params=params, proxy=proxy)
return {"success": True, "message": "Синхронизация завершена, уведомление отправлено."}
else:
return {"success": False, "error": process.stderr or process.stdout}
except Exception as e:
return JSONResponse(status_code=500, content={"success": False, "error": str(e)})
# ============================================================================
# ГЛАВНАЯ ПАНЕЛЬ (DASHBOARD)
@ -679,7 +646,16 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi
latest_emails.append({"date": "-", "domain": "other", "subject": f.stem})
master_pdf_path = Path(config.MUTT_DIR) / "ALL_EMAILS_CONSOLIDATED.pdf"
last_update = datetime.fromtimestamp(master_pdf_path.stat().st_mtime, tz=timezone.utc) if master_pdf_path.exists() else None
parts = list(Path(config.MUTT_DIR).glob("ALL_EMAILS_CONSOLIDATED_part*.pdf"))
has_master_pdf = master_pdf_path.exists() or bool(parts)
pdf_size_mb = 0.0
last_update = None
if master_pdf_path.exists():
pdf_size_mb = round(master_pdf_path.stat().st_size / (1024 * 1024), 2)
last_update = datetime.fromtimestamp(master_pdf_path.stat().st_mtime, tz=timezone.utc)
elif parts:
pdf_size_mb = round(sum(p.stat().st_size for p in parts) / (1024 * 1024), 2)
last_update = datetime.fromtimestamp(max(p.stat().st_mtime for p in parts), tz=timezone.utc)
# Drive sync status
sync_time_file = Path(config.MUTT_DIR) / "last_ai_sync.txt"
@ -705,10 +681,6 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi
total_attachments = sum(int(m) for m in matches)
except Exception as e:
pass
pdf_size_mb = 0.0
if master_pdf_path.exists():
pdf_size_mb = round(master_pdf_path.stat().st_size / (1024 * 1024), 2)
last_email_date = None
if audit_data:
@ -735,15 +707,17 @@ async def api_emails_run_full_sync(username: str = Depends(get_current_admin)):
return JSONResponse(status_code=404, content={"message": "Master sync script not found"})
try:
# Run master sync script in background
subprocess.Popen([python_path, master_script], start_new_session=True)
# Run master sync script in background with logging
log_path = Path(config.MUTT_DIR) / "master_sync.log"
log_file = open(log_path, "a")
subprocess.Popen([python_path, master_script], stdout=log_file, stderr=log_file, start_new_session=True)
return JSONResponse(content={"message": "Полная синхронизация (Сбор -> PDF -> G-Drive) запущена в фоне. Следите за уведомлениями в Telegram."})
except Exception as e:
return JSONResponse(status_code=500, content={"message": str(e)})
@app.post("/api/emails/sync_ai")
async def api_emails_sync_ai(username: str = Depends(get_current_admin)):
sync_script = "/app/domovoy_drive_sync.py" if os.path.exists("/app/domovoy_drive_sync.py") else str(Path(config.MUTT_DIR).parent / "domovoy_drive_sync.py")
sync_script = "/home/matrixhasyou/domovoy_drive_sync.py" if os.path.exists("/home/matrixhasyou/domovoy_drive_sync.py") else "/app/domovoy_drive_sync.py"
python_path = sys.executable
master_pdf = str(Path(config.MUTT_DIR) / "TOTAL_ARCHIVE_2025-2026.pdf")
@ -751,8 +725,10 @@ async def api_emails_sync_ai(username: str = Depends(get_current_admin)):
return JSONResponse(status_code=404, content={"message": "Sync script not found"})
try:
# Run sync script in background
subprocess.Popen([python_path, sync_script, master_pdf], start_new_session=True)
# Run sync script in background with logging
log_path = Path(config.MUTT_DIR) / "master_sync.log"
log_file = open(log_path, "a")
subprocess.Popen([python_path, sync_script, master_pdf], stdout=log_file, stderr=log_file, start_new_session=True)
return JSONResponse(content={"message": "Синхронизация с Google Drive запущена в фоне. Это займет около минуты."})
except Exception as e:
return JSONResponse(status_code=500, content={"message": str(e)})
@ -762,11 +738,14 @@ async def api_emails_pipeline_status(username: str = Depends(get_current_admin))
import time
status_file = Path(config.MUTT_DIR) / "pipeline_status.json"
master_pdf_path = Path(config.MUTT_DIR) / "ALL_EMAILS_CONSOLIDATED.pdf"
parts = list(Path(config.MUTT_DIR).glob("ALL_EMAILS_CONSOLIDATED_part*.pdf"))
# Calculate fallback values
pdf_size_mb = 0.0
if master_pdf_path.exists():
pdf_size_mb = round(master_pdf_path.stat().st_size / (1024 * 1024), 2)
elif parts:
pdf_size_mb = round(sum(p.stat().st_size for p in parts) / (1024 * 1024), 2)
total_emails = 0
total_inbound = 0

View file

@ -208,7 +208,6 @@
<aside class="sidebar">
<div class="sidebar-header">
<h4>МКД ЛЕНКОМ 37</h4>
<small>СИСТЕМА УПРАВЛЕНИЯ & ЯДЕРНЫЙ ЩИТ</small>
</div>
<nav>
@ -216,7 +215,7 @@
<i class="bi bi-terminal"></i> Дашборд
</a>
<div class="nav-section-title">Юридический щит</div>
<div class="nav-section-title">Правовая база</div>
<a class="nav-link {% block nav_legal %}{% endblock %}" href="/legal">
<i class="bi bi-shield-check"></i> Законы РФ & ИИ-Юрист
</a>